]> git.rm.cloudns.org Git - voretournament/voretournament.git/commitdiff
Update the engine
authorMirceaKitsune <sonichedgehog_hyperblast00@yahoo.com>
Thu, 17 Nov 2011 21:29:02 +0000 (23:29 +0200)
committerMirceaKitsune <sonichedgehog_hyperblast00@yahoo.com>
Thu, 17 Nov 2011 21:29:02 +0000 (23:29 +0200)
162 files changed:
misc/buildfiles/engine/voretournament-dedicated.exe
misc/buildfiles/engine/voretournament-linux32-dedicated
misc/buildfiles/engine/voretournament-linux32-glx
misc/buildfiles/engine/voretournament-linux32-sdl
misc/buildfiles/engine/voretournament-linux64-dedicated
misc/buildfiles/engine/voretournament-linux64-glx
misc/buildfiles/engine/voretournament-linux64-sdl
misc/buildfiles/engine/voretournament-sdl.exe
misc/buildfiles/engine/voretournament-x64-dedicated.exe
misc/buildfiles/engine/voretournament-x64-sdl.exe
misc/buildfiles/engine/voretournament-x64.exe
misc/buildfiles/engine/voretournament.exe
misc/source/darkplaces-src/Darkplaces.app/Contents/Info.plist
misc/source/darkplaces-src/Darkplaces.app/Contents/Resources/English.lproj/InfoPlist.strings
misc/source/darkplaces-src/cap_avi.c
misc/source/darkplaces-src/cap_ogg.c
misc/source/darkplaces-src/cd_null.c
misc/source/darkplaces-src/cd_shared.c
misc/source/darkplaces-src/cdaudio.h
misc/source/darkplaces-src/cl_collision.c
misc/source/darkplaces-src/cl_collision.h
misc/source/darkplaces-src/cl_demo.c
misc/source/darkplaces-src/cl_input.c
misc/source/darkplaces-src/cl_main.c
misc/source/darkplaces-src/cl_parse.c
misc/source/darkplaces-src/cl_particles.c
misc/source/darkplaces-src/cl_screen.c
misc/source/darkplaces-src/cl_video.c
misc/source/darkplaces-src/cl_video_jamdecode.c
misc/source/darkplaces-src/client.h
misc/source/darkplaces-src/clvm_cmds.c
misc/source/darkplaces-src/clvm_cmds.h
misc/source/darkplaces-src/cmd.c
misc/source/darkplaces-src/cmd.h
misc/source/darkplaces-src/collision.c
misc/source/darkplaces-src/collision.h
misc/source/darkplaces-src/common.c
misc/source/darkplaces-src/common.h
misc/source/darkplaces-src/console.c
misc/source/darkplaces-src/console.h
misc/source/darkplaces-src/crypto.c
misc/source/darkplaces-src/crypto.h
misc/source/darkplaces-src/csprogs.c
misc/source/darkplaces-src/csprogs.h
misc/source/darkplaces-src/curves.c
misc/source/darkplaces-src/cvar.c
misc/source/darkplaces-src/darkplaces-dedicated.dev
misc/source/darkplaces-src/darkplaces-dedicated.vcproj
misc/source/darkplaces-src/darkplaces-sdl.vcproj
misc/source/darkplaces-src/darkplaces-wgl.vcproj
misc/source/darkplaces-src/darkplaces.dev
misc/source/darkplaces-src/dpdefs/csprogsdefs.qc
misc/source/darkplaces-src/dpdefs/dpextensions.qc
misc/source/darkplaces-src/dpsoftrast.c
misc/source/darkplaces-src/dpsoftrast.h
misc/source/darkplaces-src/dpvsimpledecode.c
misc/source/darkplaces-src/draw.h
misc/source/darkplaces-src/fs.c
misc/source/darkplaces-src/fs.h
misc/source/darkplaces-src/ft2.c
misc/source/darkplaces-src/gl_backend.c
misc/source/darkplaces-src/gl_backend.h
misc/source/darkplaces-src/gl_draw.c
misc/source/darkplaces-src/gl_rmain.c
misc/source/darkplaces-src/gl_rsurf.c
misc/source/darkplaces-src/gl_textures.c
misc/source/darkplaces-src/glquake.h
misc/source/darkplaces-src/hmac.c
misc/source/darkplaces-src/host.c
misc/source/darkplaces-src/host_cmd.c
misc/source/darkplaces-src/image.c
misc/source/darkplaces-src/image.h
misc/source/darkplaces-src/image_png.c
misc/source/darkplaces-src/jpeg.c
misc/source/darkplaces-src/keys.c
misc/source/darkplaces-src/keys.h
misc/source/darkplaces-src/keysym2ucs.c
misc/source/darkplaces-src/lhnet.c
misc/source/darkplaces-src/lhnet.h
misc/source/darkplaces-src/libcurl.c
misc/source/darkplaces-src/libcurl.h
misc/source/darkplaces-src/makefile
misc/source/darkplaces-src/makefile.inc
misc/source/darkplaces-src/mathlib.h
misc/source/darkplaces-src/menu.c
misc/source/darkplaces-src/menu.h
misc/source/darkplaces-src/meshqueue.c
misc/source/darkplaces-src/meshqueue.h
misc/source/darkplaces-src/mod_skeletal_animatevertices_generic.c
misc/source/darkplaces-src/mod_skeletal_animatevertices_sse.c
misc/source/darkplaces-src/model_alias.c
misc/source/darkplaces-src/model_brush.c
misc/source/darkplaces-src/model_brush.h
misc/source/darkplaces-src/model_shared.c
misc/source/darkplaces-src/model_shared.h
misc/source/darkplaces-src/model_sprite.c
misc/source/darkplaces-src/mvm_cmds.c
misc/source/darkplaces-src/netconn.c
misc/source/darkplaces-src/netconn.h
misc/source/darkplaces-src/palette.c
misc/source/darkplaces-src/portals.c
misc/source/darkplaces-src/progs.h
misc/source/darkplaces-src/progsvm.h
misc/source/darkplaces-src/protocol.c
misc/source/darkplaces-src/protocol.h
misc/source/darkplaces-src/prvm_cmds.c
misc/source/darkplaces-src/prvm_cmds.h
misc/source/darkplaces-src/prvm_edict.c
misc/source/darkplaces-src/prvm_exec.c
misc/source/darkplaces-src/prvm_execprogram.h
misc/source/darkplaces-src/prvm_offsets.h
misc/source/darkplaces-src/quakedef.h
misc/source/darkplaces-src/r_explosion.c
misc/source/darkplaces-src/r_lightning.c
misc/source/darkplaces-src/r_shadow.c
misc/source/darkplaces-src/r_shadow.h
misc/source/darkplaces-src/r_sky.c
misc/source/darkplaces-src/r_sprites.c
misc/source/darkplaces-src/r_textures.h
misc/source/darkplaces-src/render.h
misc/source/darkplaces-src/sbar.c
misc/source/darkplaces-src/sbar.h
misc/source/darkplaces-src/server.h
misc/source/darkplaces-src/shader_glsl.h
misc/source/darkplaces-src/shader_hlsl.h
misc/source/darkplaces-src/snd_main.c
misc/source/darkplaces-src/snd_main.h
misc/source/darkplaces-src/snd_mem.c
misc/source/darkplaces-src/snd_mix.c
misc/source/darkplaces-src/snd_modplug.c
misc/source/darkplaces-src/snd_null.c
misc/source/darkplaces-src/snd_ogg.c
misc/source/darkplaces-src/snd_wav.c
misc/source/darkplaces-src/sound.h
misc/source/darkplaces-src/sv_demo.c
misc/source/darkplaces-src/sv_main.c
misc/source/darkplaces-src/sv_move.c
misc/source/darkplaces-src/sv_phys.c
misc/source/darkplaces-src/sv_user.c
misc/source/darkplaces-src/svvm_cmds.c
misc/source/darkplaces-src/sys.h
misc/source/darkplaces-src/sys_sdl.c
misc/source/darkplaces-src/sys_shared.c
misc/source/darkplaces-src/thread.h
misc/source/darkplaces-src/thread_null.c
misc/source/darkplaces-src/thread_pthread.c
misc/source/darkplaces-src/thread_sdl.c
misc/source/darkplaces-src/thread_win.c
misc/source/darkplaces-src/timing.h
misc/source/darkplaces-src/utf8lib.c
misc/source/darkplaces-src/utf8lib.h
misc/source/darkplaces-src/vid.h
misc/source/darkplaces-src/vid_agl.c
misc/source/darkplaces-src/vid_glx.c
misc/source/darkplaces-src/vid_null.c
misc/source/darkplaces-src/vid_sdl.c
misc/source/darkplaces-src/vid_shared.c
misc/source/darkplaces-src/vid_wgl.c
misc/source/darkplaces-src/view.c
misc/source/darkplaces-src/world.c
misc/source/darkplaces-src/world.h
misc/source/darkplaces-src/zone.c

index 12f93769c7d5313aaa0d04af69ad4381cf3abdd0..4bb722cb8fef758f079abc1ed684163cfe9cfbb8 100644 (file)
Binary files a/misc/buildfiles/engine/voretournament-dedicated.exe and b/misc/buildfiles/engine/voretournament-dedicated.exe differ
index f6f10ceb4b1d8b55feaee3dde1dd2f41482f9c7c..e900fbf05558eb16df6c70cd9690e6f5cc7c1e65 100644 (file)
Binary files a/misc/buildfiles/engine/voretournament-linux32-dedicated and b/misc/buildfiles/engine/voretournament-linux32-dedicated differ
index e9f84f35e45016a0de70bd4f6581508666478650..b7fac265326fa46d2d86fd76051020d725cc894a 100644 (file)
Binary files a/misc/buildfiles/engine/voretournament-linux32-glx and b/misc/buildfiles/engine/voretournament-linux32-glx differ
index 412b83bfc99d102849f438b80c7abefa39894d86..cf995d244bbee5c91692c73df9cadcee9d188ca3 100644 (file)
Binary files a/misc/buildfiles/engine/voretournament-linux32-sdl and b/misc/buildfiles/engine/voretournament-linux32-sdl differ
index 66e9cae1ab282dd80873fe57f425785959b539cb..b0896b5e9021d51f0eaf18acccbaef701dfebbe3 100644 (file)
Binary files a/misc/buildfiles/engine/voretournament-linux64-dedicated and b/misc/buildfiles/engine/voretournament-linux64-dedicated differ
index 244d62e8516751b87d9a8a078193b166c61b5480..711dfe7c55c4c628352b1780af1bb34410e87be9 100644 (file)
Binary files a/misc/buildfiles/engine/voretournament-linux64-glx and b/misc/buildfiles/engine/voretournament-linux64-glx differ
index 3d39a5264ddee89b7c85e4549a07ca476da2a1f5..7f0c12bc63943dbee319e2b3fec6edbbf4e26ca8 100644 (file)
Binary files a/misc/buildfiles/engine/voretournament-linux64-sdl and b/misc/buildfiles/engine/voretournament-linux64-sdl differ
index eed41a6a9eb7906d5c89bfa6061f543984cc255b..fceeb2745ac561f08cd8f8738f95a9260b64ce2a 100644 (file)
Binary files a/misc/buildfiles/engine/voretournament-sdl.exe and b/misc/buildfiles/engine/voretournament-sdl.exe differ
index faa85c2dd0315d8e865f12d487ffd6789abd23d5..69ba7c1f7b688bf0e3af739409cf89c9defba2f6 100644 (file)
Binary files a/misc/buildfiles/engine/voretournament-x64-dedicated.exe and b/misc/buildfiles/engine/voretournament-x64-dedicated.exe differ
index b6bdfb4bf2a057764ecf8b99c1a6810b8fa23289..fa4442462f60ad8d41b2a6cdf5c08a46ff8d1dfd 100644 (file)
Binary files a/misc/buildfiles/engine/voretournament-x64-sdl.exe and b/misc/buildfiles/engine/voretournament-x64-sdl.exe differ
index f1a6e7f1541d242536d7564f557199bc39ea41f3..52d389057e70addb30c83b03829a12df509cd40b 100644 (file)
Binary files a/misc/buildfiles/engine/voretournament-x64.exe and b/misc/buildfiles/engine/voretournament-x64.exe differ
index 0d9713145863840690a3581f5ac57d8cd0e962b6..57efed687d6947383e1addb4c10e137791bf7e6f 100644 (file)
Binary files a/misc/buildfiles/engine/voretournament.exe and b/misc/buildfiles/engine/voretournament.exe differ
index 68abd985bacf4e1a503b680d0a9196f04080ee6d..b2aa11d6172f12f59605db72be7d6c020dea8d20 100644 (file)
@@ -5,7 +5,7 @@
        <key>CFBundleDevelopmentRegion</key>
        <string>English</string>
        <key>CFBundleExecutable</key>
-       <string>darkplaces-sdl</string>
+       <string>darkplaces-osx-sdl</string>
        <key>CFBundleIconFile</key>
        <string>Darkplaces</string>
        <key>CFBundlePackageType</key>
index 5d6a57efba81ef72d24910abb7accee71b1ab29c..765ba09dbc78738926c99db7d2a80b985347ec02 100644 (file)
Binary files a/misc/source/darkplaces-src/Darkplaces.app/Contents/Resources/English.lproj/InfoPlist.strings and b/misc/source/darkplaces-src/Darkplaces.app/Contents/Resources/English.lproj/InfoPlist.strings differ
index e7cf88d675f9cf363a5876d7c0b4f2fec8fcf8b5..9a238e80ff4d335994191019f6237e92acc3bf77 100644 (file)
@@ -188,7 +188,7 @@ static void SCR_CaptureVideo_RIFF_IndexEntry(const char *chunkfourcc, int chunks
 {
        LOAD_FORMATSPECIFIC_AVI();
        if(!format->canseek)
-               Host_Error("SCR_CaptureVideo_RIFF_IndexEntry called on non-seekable AVI");
+               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);
@@ -209,7 +209,7 @@ static void SCR_CaptureVideo_RIFF_MakeIxChunk(const char *fcc, const char *dwChu
        fs_offset_t pos, sz;
        
        if(!format->canseek)
-               Host_Error("SCR_CaptureVideo_RIFF_MakeIxChunk called on non-seekable AVI");
+               Sys_Error("SCR_CaptureVideo_RIFF_MakeIxChunk called on non-seekable AVI");
 
        if(*masteridx_count >= AVI_MASTER_INDEX_SIZE)
                return;
@@ -352,7 +352,7 @@ static void SCR_CaptureVideo_ConvertFrame_BGRA_to_I420_flip(int width, int heigh
                        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)
+               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;
@@ -404,7 +404,7 @@ static void SCR_CaptureVideo_Avi_VideoFrames(int num)
        }
 }
 
-void SCR_CaptureVideo_Avi_EndVideo(void)
+static void SCR_CaptureVideo_Avi_EndVideo(void)
 {
        LOAD_FORMATSPECIFIC_AVI();
 
@@ -449,7 +449,7 @@ void SCR_CaptureVideo_Avi_EndVideo(void)
        Mem_Free(format);
 }
 
-void SCR_CaptureVideo_Avi_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length)
+static void SCR_CaptureVideo_Avi_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length)
 {
        LOAD_FORMATSPECIFIC_AVI();
        int x;
@@ -462,12 +462,12 @@ void SCR_CaptureVideo_Avi_SoundFrame(const portable_sampleframe_t *paintbuffer,
        {
                int n0, n1;
 
-               n0 = paintbuffer[i].sample[0];
+               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];
+               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);
@@ -502,12 +502,13 @@ void SCR_CaptureVideo_Avi_BeginVideo(void)
        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("%s.%s", cls.capturevideo.basename, cls.capturevideo.formatextension), "wb", false);
+       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;
index eef3f90d6e3503b5febb2172d58ca318915a6389..de3132d14552b539c692260fe7dc7862a98f2eb9 100644 (file)
@@ -523,7 +523,7 @@ static dllfunction_t theorafuncs[] =
 
 static dllhandle_t og_dll = NULL, vo_dll = NULL, ve_dll = NULL, th_dll = NULL;
 
-qboolean SCR_CaptureVideo_Ogg_OpenLibrary(void)
+static qboolean SCR_CaptureVideo_Ogg_OpenLibrary(void)
 {
        const char* dllnames_og [] =
        {
@@ -677,7 +677,7 @@ static void SCR_CaptureVideo_Ogg_Interleave(void)
                                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))
-                                       Host_Error("video page too long");
+                                       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);
                        }
@@ -687,7 +687,7 @@ static void SCR_CaptureVideo_Ogg_Interleave(void)
                                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))
-                                       Host_Error("audio page too long");
+                                       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);
                        }
@@ -782,7 +782,7 @@ static void SCR_CaptureVideo_Ogg_EndVideo(void)
        while (1) {
                int result = qogg_stream_flush (&format->to, &pg);
                if (result < 0)
-                       fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
+                       fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error
                if (result <= 0)
                        break;
                FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
@@ -794,7 +794,7 @@ static void SCR_CaptureVideo_Ogg_EndVideo(void)
                while (1) {
                        int result = qogg_stream_flush (&format->vo, &pg);
                        if (result < 0)
-                               fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
+                               fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error
                        if (result <= 0)
                                break;
                        FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
@@ -847,7 +847,7 @@ static void SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV(void)
                        b += 4;
                }
 
-               if((y & 1) == 0)
+               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)
                        {
@@ -919,7 +919,7 @@ static void SCR_CaptureVideo_Ogg_SoundFrame(const portable_sampleframe_t *paintb
        {
                float *b = vorbis_buffer[map[j]];
                for(i = 0; i < length; ++i)
-                       b[i] = paintbuffer[i].sample[j] / 32768.0f;
+                       b[i] = paintbuffer[i].sample[j];
        }
        qvorbis_analysis_wrote(&format->vd, length);
 
@@ -937,9 +937,10 @@ static void SCR_CaptureVideo_Ogg_SoundFrame(const portable_sampleframe_t *paintb
 
 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("%s.%s", cls.capturevideo.basename, cls.capturevideo.formatextension), "wb", false);
+       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;
@@ -1098,7 +1099,7 @@ void SCR_CaptureVideo_Ogg_BeginVideo(void)
                {
                        int result = qogg_stream_flush (&format->to, &pg);
                        if (result < 0)
-                               fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
+                               fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error
                        if (result <= 0)
                                break;
                        FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
@@ -1110,7 +1111,7 @@ void SCR_CaptureVideo_Ogg_BeginVideo(void)
                {
                        int result = qogg_stream_flush (&format->vo, &pg);
                        if (result < 0)
-                               fprintf (stderr, "Internal Ogg library error.\n"); // TODO Host_Error
+                               fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error
                        if (result <= 0)
                                break;
                        FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len);
index 18987ada4b78383725534ee4822945784a6c8f6c..13826f0505749368ff83375e4756b9663b876a1c 100644 (file)
@@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 
 #include "quakedef.h"
+#include "cdaudio.h"
 
 
 void CDAudio_SysEject (void)
index 453aba622b1b565afc8b83ac7efd2f99ee3c1745..43b4a7f43338cadf08df419faf21c4da21ac66d2 100644 (file)
@@ -24,21 +24,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "cdaudio.h"
 #include "sound.h"
 
-// Prototypes of the system dependent functions
-extern void CDAudio_SysEject (void);
-extern void CDAudio_SysCloseDoor (void);
-extern int CDAudio_SysGetAudioDiskInfo (void);
-extern float CDAudio_SysGetVolume (void);
-extern void CDAudio_SysSetVolume (float volume);
-extern int CDAudio_SysPlay (int track);
-extern int CDAudio_SysStop (void);
-extern int CDAudio_SysPause (void);
-extern int CDAudio_SysResume (void);
-extern int CDAudio_SysUpdate (void);
-extern void CDAudio_SysInit (void);
-extern int CDAudio_SysStartup (void);
-extern void CDAudio_SysShutdown (void);
-
 // 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)"};
@@ -164,7 +149,7 @@ static int CDAudio_GetAudioDiskInfo (void)
        return 0;
 }
 
-qboolean CDAudio_Play_real (int track, qboolean looping, qboolean complain)
+static qboolean CDAudio_Play_real (int track, qboolean looping, qboolean complain)
 {
        if(track < 1)
        {
@@ -324,7 +309,7 @@ void CDAudio_Play_byName (const char *trackname, qboolean looping, qboolean tryr
        }
        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);
+               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)
@@ -583,7 +568,7 @@ static void CD_f (void)
        Con_Printf("cd info - prints basic disc information (number of tracks, currently playing track, volume level)\n");
 }
 
-void CDAudio_SetVolume (float newvol)
+static void CDAudio_SetVolume (float newvol)
 {
        // If the volume hasn't changed
        if (newvol == cdvolume)
index 3fed67fa5132167238aa84ebb5ba05f5ced6a691..5eac430a89a940b9ad97b0e6d85d3486a20e6e8a 100644 (file)
@@ -49,3 +49,18 @@ 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);
index 8c9540669c9ba6518bcb472962286efa79b71446..1fc448da57d7300560b7c512c8ecce4c5c000554 100644 (file)
@@ -128,6 +128,7 @@ dp_model_t *CL_GetModelByIndex(int modelindex)
 
 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));
@@ -135,6 +136,7 @@ dp_model_t *CL_GetModelFromEdict(prvm_edict_t *ed)
 
 void CL_LinkEdict(prvm_edict_t *ent)
 {
+       prvm_prog_t *prog = CLVM_prog;
        vec3_t mins, maxs;
 
        if (ent == prog->edicts)
@@ -197,6 +199,7 @@ void CL_LinkEdict(prvm_edict_t *ent)
 
 int CL_GenericHitSuperContentsMask(const prvm_edict_t *passedict)
 {
+       prvm_prog_t *prog = CLVM_prog;
        if (passedict)
        {
                int dphitcontentsmask = (int)PRVM_clientedictfloat(passedict, dphitcontentsmask);
@@ -227,6 +230,7 @@ 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;
@@ -439,6 +443,7 @@ trace_t CL_TraceLine(const vec3_t start, const vec3_t pEnd, int type, prvm_edict
 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;
@@ -676,6 +681,7 @@ trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
 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;
@@ -938,3 +944,124 @@ finished:
 #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.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;
+}
+
index 27ce51be26db7bdd7f3ebb48f2072efe9a668572..851502cfa349537789da8f9f65683a3edeb56290 100644 (file)
@@ -13,6 +13,7 @@ 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
index ea10bff641738fdbcc909187d2d6e5a828c5a58b..e60ac367d64fa0760c4a0d10a2c24ff652a0f8b2 100644 (file)
@@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 extern cvar_t cl_capturevideo;
 int old_vsync = 0;
 
-void CL_FinishTimeDemo (void);
+static void CL_FinishTimeDemo (void);
 
 /*
 ==============================================================================
@@ -88,8 +88,9 @@ void CL_StopPlayback (void)
        if (cls.timedemo)
                CL_FinishTimeDemo ();
 
-       if (COM_CheckParm("-demo") || COM_CheckParm("-capturedemo"))
-               Host_Quit_f();
+       if (!cls.demostarting) // only quit if not starting another demo
+               if (COM_CheckParm("-demo") || COM_CheckParm("-capturedemo"))
+                       Host_Quit_f();
 
 }
 
@@ -98,7 +99,7 @@ void CL_StopPlayback (void)
 CL_WriteDemoMessage
 
 Dumps the current net message, prefixed by the length and view angles
-====================
+#====================
 */
 void CL_WriteDemoMessage (sizebuf_t *message)
 {
@@ -138,7 +139,7 @@ void CL_CutDemo (unsigned char **buf, fs_offset_t *filesize)
        // restart the demo recording
        cls.demofile = FS_OpenRealFile(cls.demoname, "wb", false);
        if(!cls.demofile)
-               Host_Error("failed to reopen the demo file");
+               Sys_Error("failed to reopen the demo file");
        FS_Printf(cls.demofile, "%i\n", cls.forcetrack);
 }
 
@@ -238,16 +239,21 @@ void CL_ReadDemoMessage(void)
                }
 
                // get the next message
-               FS_Read(cls.demofile, &net_message.cursize, 4);
-               net_message.cursize = LittleLong(net_message.cursize);
-               if(net_message.cursize & DEMOMSG_CLIENT_TO_SERVER) // This is a client->server message! Ignore for now!
+               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 + (net_message.cursize & (~DEMOMSG_CLIENT_TO_SERVER)), SEEK_CUR);
+                       FS_Seek(cls.demofile, 12 + (cl_message.cursize & (~DEMOMSG_CLIENT_TO_SERVER)), SEEK_CUR);
                        continue;
                }
-               if (net_message.cursize > net_message.maxsize)
-                       Host_Error("Demo message (%i) > net_message.maxsize (%i)", net_message.cursize, net_message.maxsize);
+               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++)
                {
@@ -255,9 +261,9 @@ void CL_ReadDemoMessage(void)
                        cl.mviewangles[0][i] = LittleFloat(f);
                }
 
-               if (FS_Read(cls.demofile, net_message.data, net_message.cursize) == net_message.cursize)
+               if (FS_Read(cls.demofile, cl_message.data, cl_message.cursize) == cl_message.cursize)
                {
-                       MSG_BeginReading();
+                       MSG_BeginReading(&cl_message);
                        CL_ParseServerMessage();
 
                        if (cls.signon != SIGNONS)
@@ -298,7 +304,7 @@ void CL_Stop_f (void)
        }
 
 // write a disconnect message to the demo file
-       // LordHavoc: don't replace the net_message when doing this
+       // LordHavoc: don't replace the cl_message when doing this
        buf.data = bufdata;
        buf.maxsize = sizeof(bufdata);
        SZ_Clear(&buf);
@@ -329,6 +335,7 @@ 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)
@@ -367,7 +374,7 @@ void CL_Record_f (void)
 
        // start the map up
        if (c > 2)
-               Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command);
+               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);
@@ -400,6 +407,7 @@ void CL_PlayDemo_f (void)
        char    name[MAX_QPATH];
        int c;
        qboolean neg = false;
+       qfile_t *f;
 
        if (Cmd_Argc() != 2)
        {
@@ -407,6 +415,19 @@ void CL_PlayDemo_f (void)
                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 ();
@@ -414,19 +435,10 @@ void CL_PlayDemo_f (void)
        // update networking ports (this is mainly just needed at startup)
        NetConn_UpdateSockets();
 
-       // open the demo file
-       strlcpy (name, Cmd_Argv(1), sizeof (name));
-       FS_DefaultExtension (name, ".dem", sizeof (name));
        cls.protocol = PROTOCOL_QUAKE;
 
        Con_Printf("Playing demo %s.\n", name);
-       cls.demofile = FS_OpenVirtualFile(name, false);
-       if (!cls.demofile)
-       {
-               Con_Print("ERROR: couldn't open.\n");
-               cls.demonum = -1;               // stop demo loop
-               return;
-       }
+       cls.demofile = f;
        strlcpy(cls.demoname, name, sizeof(cls.demoname));
 
        cls.demoplayback = true;
@@ -441,6 +453,27 @@ void CL_PlayDemo_f (void)
 
        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;
 }
 
 /*
@@ -449,13 +482,14 @@ CL_FinishTimeDemo
 
 ====================
 */
-void CL_FinishTimeDemo (void)
+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;
 
@@ -474,14 +508,71 @@ void CL_FinishTimeDemo (void)
                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("timedemo %s\n", cls.demoname));
+                               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();
index 8fe0d4cbeffc5dd513a1ae86c855836b135339f1..af5289f58690c2ae48adebf1a4dba695966224b4 100644 (file)
@@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 #include "csprogs.h"
+#include "thread.h"
 
 /*
 ===============================================================================
@@ -61,7 +62,7 @@ int                   in_impulse;
 
 
 
-void KeyDown (kbutton_t *b)
+static void KeyDown (kbutton_t *b)
 {
        int k;
        const char *c;
@@ -90,7 +91,7 @@ void KeyDown (kbutton_t *b)
        b->state |= 1 + 2;      // down + impulse down
 }
 
-void KeyUp (kbutton_t *b)
+static void KeyUp (kbutton_t *b)
 {
        int k;
        const char *c;
@@ -120,86 +121,86 @@ void KeyUp (kbutton_t *b)
        b->state |= 4;          // impulse up
 }
 
-void IN_KLookDown (void) {KeyDown(&in_klook);}
-void IN_KLookUp (void) {KeyUp(&in_klook);}
-void IN_MLookDown (void) {KeyDown(&in_mlook);}
-void IN_MLookUp (void)
+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();
 }
-void IN_UpDown(void) {KeyDown(&in_up);}
-void IN_UpUp(void) {KeyUp(&in_up);}
-void IN_DownDown(void) {KeyDown(&in_down);}
-void IN_DownUp(void) {KeyUp(&in_down);}
-void IN_LeftDown(void) {KeyDown(&in_left);}
-void IN_LeftUp(void) {KeyUp(&in_left);}
-void IN_RightDown(void) {KeyDown(&in_right);}
-void IN_RightUp(void) {KeyUp(&in_right);}
-void IN_ForwardDown(void) {KeyDown(&in_forward);}
-void IN_ForwardUp(void) {KeyUp(&in_forward);}
-void IN_BackDown(void) {KeyDown(&in_back);}
-void IN_BackUp(void) {KeyUp(&in_back);}
-void IN_LookupDown(void) {KeyDown(&in_lookup);}
-void IN_LookupUp(void) {KeyUp(&in_lookup);}
-void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
-void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
-void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
-void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
-void IN_MoverightDown(void) {KeyDown(&in_moveright);}
-void IN_MoverightUp(void) {KeyUp(&in_moveright);}
-
-void IN_SpeedDown(void) {KeyDown(&in_speed);}
-void IN_SpeedUp(void) {KeyUp(&in_speed);}
-void IN_StrafeDown(void) {KeyDown(&in_strafe);}
-void IN_StrafeUp(void) {KeyUp(&in_strafe);}
-
-void IN_AttackDown(void) {KeyDown(&in_attack);}
-void IN_AttackUp(void) {KeyUp(&in_attack);}
-
-void IN_UseDown(void) {KeyDown(&in_use);}
-void IN_UseUp(void) {KeyUp(&in_use);}
+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
-void IN_Button3Down(void) {KeyDown(&in_button3);}
-void IN_Button3Up(void) {KeyUp(&in_button3);}
-void IN_Button4Down(void) {KeyDown(&in_button4);}
-void IN_Button4Up(void) {KeyUp(&in_button4);}
-void IN_Button5Down(void) {KeyDown(&in_button5);}
-void IN_Button5Up(void) {KeyUp(&in_button5);}
-void IN_Button6Down(void) {KeyDown(&in_button6);}
-void IN_Button6Up(void) {KeyUp(&in_button6);}
-void IN_Button7Down(void) {KeyDown(&in_button7);}
-void IN_Button7Up(void) {KeyUp(&in_button7);}
-void IN_Button8Down(void) {KeyDown(&in_button8);}
-void IN_Button8Up(void) {KeyUp(&in_button8);}
-
-void IN_Button9Down(void) {KeyDown(&in_button9);}
-void IN_Button9Up(void) {KeyUp(&in_button9);}
-void IN_Button10Down(void) {KeyDown(&in_button10);}
-void IN_Button10Up(void) {KeyUp(&in_button10);}
-void IN_Button11Down(void) {KeyDown(&in_button11);}
-void IN_Button11Up(void) {KeyUp(&in_button11);}
-void IN_Button12Down(void) {KeyDown(&in_button12);}
-void IN_Button12Up(void) {KeyUp(&in_button12);}
-void IN_Button13Down(void) {KeyDown(&in_button13);}
-void IN_Button13Up(void) {KeyUp(&in_button13);}
-void IN_Button14Down(void) {KeyDown(&in_button14);}
-void IN_Button14Up(void) {KeyUp(&in_button14);}
-void IN_Button15Down(void) {KeyDown(&in_button15);}
-void IN_Button15Up(void) {KeyUp(&in_button15);}
-void IN_Button16Down(void) {KeyDown(&in_button16);}
-void IN_Button16Up(void) {KeyUp(&in_button16);}
-
-void IN_JumpDown (void) {KeyDown(&in_jump);}
-void IN_JumpUp (void) {KeyUp(&in_jump);}
-
-void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}
+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];
 
-void IN_BestWeapon_Register(const char *name, int impulse, int weaponbit, int activeweaponcode, int ammostat, int ammomin)
+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)
@@ -240,7 +241,7 @@ void IN_BestWeapon_ResetData (void)
        IN_BestWeapon_Register("h", 226, HIT_MJOLNIR, HIT_MJOLNIR, STAT_CELLS, 0); // hipnotic mjolnir hammer
 }
 
-void IN_BestWeapon_Register_f (void)
+static void IN_BestWeapon_Register_f (void)
 {
        if(Cmd_Argc() == 7)
        {
@@ -267,7 +268,7 @@ void IN_BestWeapon_Register_f (void)
        }
 }
 
-void IN_BestWeapon (void)
+static void IN_BestWeapon (void)
 {
        int i, n;
        const char *t;
@@ -457,6 +458,8 @@ cvar_t cl_netimmediatebuttons = {CVAR_SAVE, "cl_netimmediatebuttons", "1", "send
 
 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;
 
 /*
@@ -466,7 +469,7 @@ CL_AdjustAngles
 Moves the local angle positions
 ================
 */
-void CL_AdjustAngles (void)
+static void CL_AdjustAngles (void)
 {
        float   speed;
        float   up, down;
@@ -562,6 +565,27 @@ void CL_Input (void)
        // 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)
        {
@@ -732,7 +756,7 @@ void CL_Input (void)
 
 #include "cl_collision.h"
 
-void CL_UpdatePrydonCursor(void)
+static void CL_UpdatePrydonCursor(void)
 {
        vec3_t temp;
 
@@ -782,40 +806,6 @@ void CL_UpdatePrydonCursor(void)
                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);
 }
 
-typedef enum waterlevel_e
-{
-       WATERLEVEL_NONE,
-       WATERLEVEL_WETFEET,
-       WATERLEVEL_SWIMMING,
-       WATERLEVEL_SUBMERGED
-}
-waterlevel_t;
-
-typedef struct cl_clientmovement_state_s
-{
-       // 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;
-
 #define NUMOFFSETS 27
 static vec3_t offsets[NUMOFFSETS] =
 {
@@ -840,14 +830,14 @@ static vec3_t offsets[NUMOFFSETS] =
        {-0.125,  0.125, -0.125}, { 0.125,  0.125, -0.125},
 };
 
-qboolean CL_ClientMovement_Unstick(cl_clientmovement_state_t *s)
+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, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false).startsolid)
+               if (!CL_TraceBox(neworigin, cl.playercrouchmins, cl.playercrouchmaxs, neworigin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true).startsolid)
                {
                        VectorCopy(neworigin, s->origin);
                        return true;
@@ -857,8 +847,9 @@ qboolean CL_ClientMovement_Unstick(cl_clientmovement_state_t *s)
        return false;
 }
 
-void CL_ClientMovement_UpdateStatus(cl_clientmovement_state_t *s)
+static void CL_ClientMovement_UpdateStatus(cl_clientmovement_state_t *s)
 {
+       vec_t f;
        vec3_t origin1, origin2;
        trace_t trace;
 
@@ -878,7 +869,7 @@ void CL_ClientMovement_UpdateStatus(cl_clientmovement_state_t *s)
                // low ceiling first
                if (s->crouched)
                {
-                       trace = CL_TraceBox(s->origin, cl.playerstandmins, cl.playerstandmaxs, s->origin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false);
+                       trace = CL_TraceBox(s->origin, cl.playerstandmins, cl.playerstandmaxs, s->origin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true);
                        if (!trace.startsolid)
                                s->crouched = false;
                }
@@ -897,8 +888,18 @@ void CL_ClientMovement_UpdateStatus(cl_clientmovement_state_t *s)
        // 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, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false);
-       s->onground = trace.fraction < 1 && trace.plane.normal[2] > 0.7;
+       trace = CL_TraceBox(origin1, s->mins, s->maxs, origin2, MOVE_NORMAL, NULL, 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);
@@ -922,7 +923,7 @@ void CL_ClientMovement_UpdateStatus(cl_clientmovement_state_t *s)
                s->waterjumptime = 0;
 }
 
-void CL_ClientMovement_Move(cl_clientmovement_state_t *s)
+static void CL_ClientMovement_Move(cl_clientmovement_state_t *s)
 {
        int bump;
        double t;
@@ -939,20 +940,20 @@ void CL_ClientMovement_Move(cl_clientmovement_state_t *s)
        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, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false);
+               trace = CL_TraceBox(s->origin, s->mins, s->maxs, neworigin, MOVE_NORMAL, NULL, 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, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false);
+                       trace2 = CL_TraceBox(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, NULL, 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, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false);
+                               trace3 = CL_TraceBox(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, NULL, 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)
@@ -984,7 +985,7 @@ void CL_ClientMovement_Move(cl_clientmovement_state_t *s)
 }
 
 
-void CL_ClientMovement_Physics_Swim(cl_clientmovement_state_t *s)
+static void CL_ClientMovement_Physics_Swim(cl_clientmovement_state_t *s)
 {
        vec_t wishspeed;
        vec_t f;
@@ -1111,7 +1112,7 @@ static vec_t CL_GeomLerp(vec_t a, vec_t lerp, vec_t b)
        return a * pow(fabs(b / a), lerp);
 }
 
-void CL_ClientMovement_Physics_CPM_PM_Aircontrol(cl_clientmovement_state_t *s, vec3_t wishdir, vec_t wishspeed)
+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;
 
@@ -1146,7 +1147,7 @@ void CL_ClientMovement_Physics_CPM_PM_Aircontrol(cl_clientmovement_state_t *s, v
        s->velocity[2] = zspeed;
 }
 
-float CL_ClientMovement_Physics_AdjustAirAccelQW(float accelqw, float factor)
+static float CL_ClientMovement_Physics_AdjustAirAccelQW(float accelqw, float factor)
 {
        return
                (accelqw < 0 ? -1 : +1)
@@ -1154,7 +1155,7 @@ float CL_ClientMovement_Physics_AdjustAirAccelQW(float accelqw, float factor)
                bound(0.000001, 1 - (1 - fabs(accelqw)) * factor, 1);
 }
 
-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)
+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;
@@ -1234,7 +1235,7 @@ void CL_ClientMovement_Physics_PM_Accelerate(cl_clientmovement_state_t *s, vec3_
        s->velocity[2] += vel_z;
 }
 
-void CL_ClientMovement_Physics_PM_AirAccelerate(cl_clientmovement_state_t *s, vec3_t wishdir, vec_t wishspeed)
+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;
@@ -1285,7 +1286,7 @@ void CL_ClientMovement_Physics_PM_AirAccelerate(cl_clientmovement_state_t *s, ve
     VectorMA( s->velocity, accelspeed, acceldir, s->velocity );
 }
 
-void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s)
+static void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s)
 {
        vec_t friction;
        vec_t wishspeed;
@@ -1305,7 +1306,7 @@ void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s)
        // released at least once since the last jump
        if (s->cmd.jump)
        {
-               if (s->onground && (s->cmd.canjump || !cl_movement_track_canjump.integer)) // FIXME remove this cvar again when canjump logic actually works, or maybe keep it for mods that allow "pogo-ing"
+               if (s->onground && (s->cmd.canjump || !cl_movement_track_canjump.integer))
                {
                        s->velocity[2] += cl.movevars_jumpvelocity;
                        s->onground = false;
@@ -1348,9 +1349,9 @@ void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s)
                                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, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false);
+                                       trace = CL_TraceBox(neworigin2, s->mins, s->maxs, neworigin3, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true);
                                else
-                                       trace = CL_TraceLine(neworigin2, neworigin3, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false, false);
+                                       trace = CL_TraceLine(neworigin2, neworigin3, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true, false);
                                if (trace.fraction == 1 && !trace.startsolid)
                                        friction *= cl.movevars_edgefriction;
                        }
@@ -1550,6 +1551,8 @@ void CL_ClientMovement_Replay(void)
        double totalmovemsec;
        cl_clientmovement_state_t s;
 
+       VectorCopy(cl.mvelocity[0], cl.movement_velocity);
+
        if (cl.movement_predicted && !cl.movement_replay)
                return;
 
@@ -1586,6 +1589,7 @@ void CL_ClientMovement_Replay(void)
                        s.cmd = cl.movecmd[i];
                        if (i < CL_MAX_USERCMDS - 1)
                                s.cmd.canjump = cl.movecmd[i+1].canjump;
+
                        // 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)
@@ -1596,8 +1600,14 @@ void CL_ClientMovement_Replay(void)
                                        CL_ClientMovement_PlayerMove(&s);
                                }
                                CL_ClientMovement_PlayerMove(&s);
-                               cl.movecmd[i].canjump = s.cmd.canjump;
                        }
+                       else
+                       {
+                               // we REALLY need this handling to happen, even if the move is not executed
+                               if (!s.cmd.jump)
+                                       s.cmd.canjump = true;
+                       }
+                       cl.movecmd[i].canjump = s.cmd.canjump;
                }
                //Con_Printf("\n");
                CL_ClientMovement_UpdateStatus(&s);
@@ -1608,9 +1618,7 @@ void CL_ClientMovement_Replay(void)
                s.cmd = cl.movecmd[0];
        }
 
-       if (cls.demoplayback) // for bob, speedometer
-               VectorCopy(cl.mvelocity[0], cl.movement_velocity);
-       else
+       if (!cls.demoplayback) // for bob, speedometer
        {
                cl.movement_replay = false;
                // update the interpolation target position and velocity
@@ -1638,18 +1646,9 @@ void CL_ClientMovement_Replay(void)
                if (s.onground)
                        cl.onground = true;
        }
-
-       // react to onground state changes (for gun bob)
-       if (cl.onground)
-       {
-               if (!cl.oldonground)
-                       cl.hitgroundtime = cl.movecmd[0].time;
-               cl.lastongroundtime = cl.movecmd[0].time;
-       }
-       cl.oldonground = cl.onground;
 }
 
-void QW_MSG_WriteDeltaUsercmd(sizebuf_t *buf, usercmd_t *from, usercmd_t *to)
+static void QW_MSG_WriteDeltaUsercmd(sizebuf_t *buf, usercmd_t *from, usercmd_t *to)
 {
        int bits;
 
@@ -2114,7 +2113,9 @@ void CL_SendMove(void)
        {
                Con_Print("CL_SendMove: lost server connection\n");
                CL_Disconnect();
+               SV_LockThreadMutex();
                Host_ShutdownServer();
+               SV_UnlockThreadMutex();
        }
 }
 
@@ -2234,5 +2235,7 @@ void CL_InitInput (void)
        Cvar_RegisterVariable(&cl_netimmediatebuttons);
 
        Cvar_RegisterVariable(&cl_nodelta);
+
+       Cvar_RegisterVariable(&cl_csqc_generatemousemoveevents);
 }
 
index 420203b4f4e0c641d2fe54887432550e4c1a46d1..cb03ffab1d8154ec72a966686125934eb6d30008 100644 (file)
@@ -21,7 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 #include "cl_collision.h"
-#include "cl_gecko.h"
 #include "cl_video.h"
 #include "image.h"
 #include "csprogs.h"
@@ -35,6 +34,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 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"};
@@ -104,7 +104,6 @@ CL_ClearState
 
 =====================
 */
-void CL_VM_ShutDown (void);
 void CL_ClearState(void)
 {
        int i;
@@ -216,6 +215,7 @@ void CL_SetInfo(const char *key, const char *value, qboolean send, qboolean allo
 {
        int i;
        qboolean fail = false;
+       char vabuf[1024];
        if (!allowstarkey && key[0] == '*')
                fail = true;
        if (!allowmodel && (!strcasecmp(key, "pmodel") || !strcasecmp(key, "emodel")))
@@ -238,22 +238,22 @@ void CL_SetInfo(const char *key, const char *value, qboolean send, qboolean allo
                if (cls.protocol == PROTOCOL_QUAKEWORLD)
                {
                        MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
-                       MSG_WriteString(&cls.netcon->message, va("setinfo \"%s\" \"%s\"", key, value));
+                       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("name \"%s\"", value));
+                       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("playermodel \"%s\"", value));
+                       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("playerskin \"%s\"", value));
+                       MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "playerskin \"%s\"", value));
                }
                else if (!strcasecmp(key, "topcolor"))
                {
@@ -266,7 +266,7 @@ void CL_SetInfo(const char *key, const char *value, qboolean send, qboolean allo
                else if (!strcasecmp(key, "rate"))
                {
                        MSG_WriteByte(&cls.netcon->message, clc_stringcmd);
-                       MSG_WriteString(&cls.netcon->message, va("rate \"%s\"", value));
+                       MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "rate \"%s\"", value));
                }
        }
 }
@@ -390,6 +390,7 @@ void CL_Disconnect(void)
                cls.netcon = NULL;
        }
        cls.state = ca_disconnected;
+       cl.islocalgame = false;
 
        cls.demoplayback = cls.timedemo = false;
        cls.signon = 0;
@@ -435,9 +436,6 @@ void CL_EstablishConnection(const char *host, int firstarg)
        // make sure the client ports are open before attempting to connect
        NetConn_UpdateSockets();
 
-       // run a network frame
-       //NetConn_ClientFrame();SV_VM_Begin();NetConn_ServerFrame();SV_VM_End();
-
        if (LHNETADDRESS_FromString(&cls.connect_address, host, 26000) && (cls.connect_mysocket = NetConn_ChooseClientSocketForAddress(&cls.connect_address)))
        {
                cls.connect_trying = true;
@@ -460,15 +458,6 @@ void CL_EstablishConnection(const char *host, int firstarg)
                }
 
                M_Update_Return_Reason("Trying to connect...");
-
-               // run several network frames to jump into the game quickly
-               //if (sv.active)
-               //{
-               //      NetConn_ClientFrame();SV_VM_Begin();NetConn_ServerFrame();SV_VM_End();
-               //      NetConn_ClientFrame();SV_VM_Begin();NetConn_ServerFrame();SV_VM_End();
-               //      NetConn_ClientFrame();SV_VM_Begin();NetConn_ServerFrame();SV_VM_End();
-               //      NetConn_ClientFrame();SV_VM_Begin();NetConn_ServerFrame();SV_VM_End();
-               //}
        }
        else
        {
@@ -520,6 +509,8 @@ static void CL_ModelIndexList_f(void)
        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
@@ -754,7 +745,7 @@ void CL_AllocLightFlash(entity_render_t *ent, matrix4x4_t *matrix, float radius,
        dl->specularscale = specularscale;
 }
 
-void CL_DecayLightFlashes(void)
+static void CL_DecayLightFlashes(void)
 {
        int i, oldmax;
        dlight_t *dl;
@@ -854,7 +845,7 @@ void CL_RelinkLightFlashes(void)
        }
 }
 
-void CL_AddQWCTFFlagModel(entity_t *player, int skin)
+static void CL_AddQWCTFFlagModel(entity_t *player, int skin)
 {
        int frame = player->render.framegroupblend[0].frame;
        float f;
@@ -913,11 +904,6 @@ matrix4x4_t viewmodelmatrix_nobob;
 
 static const vec3_t muzzleflashorigin = {18, 0, 0};
 
-extern void V_DriftPitch(void);
-extern void V_FadeViewFlashs(void);
-extern void V_CalcViewBlend(void);
-extern void V_CalcRefdef(void);
-
 void CL_SetEntityColormapColors(entity_render_t *ent, int colormap)
 {
        const unsigned char *cbcolor;
@@ -936,7 +922,7 @@ void CL_SetEntityColormapColors(entity_render_t *ent, int colormap)
 }
 
 // note this is a recursive function, recursionlimit should be 32 or so on the initial call
-void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit, qboolean interpolate)
+static void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit, qboolean interpolate)
 {
        const matrix4x4_t *matrix;
        matrix4x4_t blendmatrix, tempmatrix, matrix2;
@@ -1195,7 +1181,7 @@ void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit, qboolean interpolat
 }
 
 // creates light and trails from an entity
-void CL_UpdateNetworkEntityTrail(entity_t *e)
+static void CL_UpdateNetworkEntityTrail(entity_t *e)
 {
        effectnameindex_t trailtype;
        vec3_t origin;
@@ -1273,7 +1259,8 @@ void CL_UpdateNetworkEntityTrail(entity_t *e)
                if (len > 0)
                        len = 1.0f / len;
                VectorScale(vel, len, vel);
-               CL_ParticleTrail(trailtype, 1, e->persistent.trail_origin, origin, vel, vel, e, e->state_current.glowcolor, false, true, NULL, NULL);
+               // 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
@@ -1309,7 +1296,7 @@ void CL_UpdateViewEntities(void)
 CL_UpdateNetworkCollisionEntities
 ===============
 */
-void CL_UpdateNetworkCollisionEntities(void)
+static void CL_UpdateNetworkCollisionEntities(void)
 {
        entity_t *ent;
        int i;
@@ -1331,14 +1318,12 @@ void CL_UpdateNetworkCollisionEntities(void)
        }
 }
 
-extern void R_DecalSystem_Reset(decalsystem_t *decalsystem);
-
 /*
 ===============
 CL_UpdateNetworkEntities
 ===============
 */
-void CL_UpdateNetworkEntities(void)
+static void CL_UpdateNetworkEntities(void)
 {
        entity_t *ent;
        int i;
@@ -1365,7 +1350,7 @@ void CL_UpdateNetworkEntities(void)
        }
 }
 
-void CL_UpdateViewModel(void)
+static void CL_UpdateViewModel(void)
 {
        entity_t *ent;
        ent = &cl.viewent;
@@ -1400,12 +1385,13 @@ void CL_UpdateViewModel(void)
 }
 
 // note this is a recursive function, but it can never get in a runaway loop (because of the delayedlink flags)
-void CL_LinkNetworkEntity(entity_t *e)
+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)
@@ -1542,7 +1528,7 @@ void CL_LinkNetworkEntity(entity_t *e)
                // 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("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_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
@@ -1573,7 +1559,7 @@ void CL_LinkNetworkEntity(entity_t *e)
        //      Matrix4x4_Print(&e->render.matrix);
 }
 
-void CL_RelinkWorld(void)
+static void CL_RelinkWorld(void)
 {
        entity_t *ent = &cl.entities[0];
        // FIXME: this should be done at load
@@ -1850,7 +1836,7 @@ static void CL_RelinkQWNails(void)
        }
 }
 
-void CL_LerpPlayer(float frac)
+static void CL_LerpPlayer(float frac)
 {
        int i;
 
@@ -2032,23 +2018,23 @@ For program optimization
 static void CL_TimeRefresh_f (void)
 {
        int i;
-       float timestart, timedelta;
+       double timestart, timedelta;
 
        r_refdef.scene.extraupdate = false;
 
-       timestart = Sys_DoubleTime();
+       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_UpdateScreen();
        }
-       timedelta = Sys_DoubleTime() - timestart;
+       timedelta = Sys_DirtyTime() - timestart;
 
        Con_Printf("%f seconds (%f fps)\n", timedelta, 128/timedelta);
 }
 
-void CL_AreaStats_f(void)
+static void CL_AreaStats_f(void)
 {
        World_PrintAreaStats(&cl.world, "client");
 }
@@ -2088,7 +2074,7 @@ void CL_Locs_FindLocationName(char *buffer, size_t buffersize, vec3_t point)
                dpsnprintf(buffer, buffersize, "LOC=%.0f:%.0f:%.0f", point[0], point[1], point[2]);
 }
 
-void CL_Locs_FreeNode(cl_locnode_t *node)
+static void CL_Locs_FreeNode(cl_locnode_t *node)
 {
        cl_locnode_t **pointer, **next;
        for (pointer = &cl.locnodes;*pointer;pointer = next)
@@ -2104,7 +2090,7 @@ void CL_Locs_FreeNode(cl_locnode_t *node)
        Con_Printf("CL_Locs_FreeNode: no such node! (%p)\n", (void *)node);
 }
 
-void CL_Locs_AddNode(vec3_t mins, vec3_t maxs, const char *name)
+static void CL_Locs_AddNode(vec3_t mins, vec3_t maxs, const char *name)
 {
        cl_locnode_t *node, **pointer;
        int namelen;
@@ -2123,7 +2109,7 @@ void CL_Locs_AddNode(vec3_t mins, vec3_t maxs, const char *name)
        *pointer = node;
 }
 
-void CL_Locs_Add_f(void)
+static void CL_Locs_Add_f(void)
 {
        vec3_t mins, maxs;
        if (Cmd_Argc() != 5 && Cmd_Argc() != 8)
@@ -2145,7 +2131,7 @@ void CL_Locs_Add_f(void)
                CL_Locs_AddNode(mins, mins, Cmd_Argv(4));
 }
 
-void CL_Locs_RemoveNearest_f(void)
+static void CL_Locs_RemoveNearest_f(void)
 {
        cl_locnode_t *loc;
        loc = CL_Locs_FindNearest(r_refdef.view.origin);
@@ -2155,13 +2141,13 @@ void CL_Locs_RemoveNearest_f(void)
                Con_Printf("no loc point or box found for your location\n");
 }
 
-void CL_Locs_Clear_f(void)
+static void CL_Locs_Clear_f(void)
 {
        while (cl.locnodes)
                CL_Locs_FreeNode(cl.locnodes);
 }
 
-void CL_Locs_Save_f(void)
+static void CL_Locs_Save_f(void)
 {
        cl_locnode_t *loc;
        qfile_t *outfile;
@@ -2501,7 +2487,6 @@ void CL_Init (void)
        CL_Screen_Init();
 
        CL_Video_Init();
-       CL_Gecko_Init();
 }
 
 
index 3d56d11199524f718b880249a9707b05a3952524..55e1a79a50410d36793ffaba9c3db78f2838639e 100644 (file)
@@ -191,18 +191,15 @@ cvar_t cl_iplog_name = {CVAR_SAVE, "cl_iplog_name", "darkplaces_iplog.txt", "nam
 static qboolean QW_CL_CheckOrDownloadFile(const char *filename);
 static void QW_CL_RequestNextDownload(void);
 static void QW_CL_NextUpload(void);
-void QW_CL_StartUpload(unsigned char *data, int size);
 //static qboolean QW_CL_IsUploading(void);
 static void QW_CL_StopUpload(void);
-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);
 
 /*
 ==================
 CL_ParseStartSoundPacket
 ==================
 */
-void CL_ParseStartSoundPacket(int largesoundindex)
+static void CL_ParseStartSoundPacket(int largesoundindex)
 {
        vec3_t  pos;
        int     channel, ent;
@@ -210,61 +207,70 @@ void CL_ParseStartSoundPacket(int largesoundindex)
        int     volume;
        int     field_mask;
        float   attenuation;
+       float   speed;
+       int             fflags = CHANNELFLAG_NONE;
 
        if (cls.protocol == PROTOCOL_QUAKEWORLD)
        {
-               channel = MSG_ReadShort();
+               channel = MSG_ReadShort(&cl_message);
 
                if (channel & (1<<15))
-                       volume = MSG_ReadByte ();
+                       volume = MSG_ReadByte(&cl_message);
                else
                        volume = DEFAULT_SOUND_PACKET_VOLUME;
 
                if (channel & (1<<14))
-                       attenuation = MSG_ReadByte () / 64.0;
+                       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 ();
+               sound_num = MSG_ReadByte(&cl_message);
        }
        else
        {
-               field_mask = MSG_ReadByte();
+               field_mask = MSG_ReadByte(&cl_message);
 
                if (field_mask & SND_VOLUME)
-                       volume = MSG_ReadByte ();
+                       volume = MSG_ReadByte(&cl_message);
                else
                        volume = DEFAULT_SOUND_PACKET_VOLUME;
 
                if (field_mask & SND_ATTENUATION)
-                       attenuation = MSG_ReadByte () / 64.0;
+                       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 ();
-                       channel = MSG_ReadChar ();
+                       ent = (unsigned short) MSG_ReadShort(&cl_message);
+                       channel = MSG_ReadChar(&cl_message);
                }
                else
                {
-                       channel = (unsigned short) MSG_ReadShort ();
+                       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 ();
+                       sound_num = (unsigned short) MSG_ReadShort(&cl_message);
                else
-                       sound_num = MSG_ReadByte ();
+                       sound_num = MSG_ReadByte(&cl_message);
        }
 
        channel = CHAN_NET2ENGINE(channel);
 
-       MSG_ReadVector(pos, cls.protocol);
+       MSG_ReadVector(&cl_message, pos, cls.protocol);
 
        if (sound_num >= MAX_SOUNDS)
        {
@@ -281,8 +287,8 @@ void CL_ParseStartSoundPacket(int largesoundindex)
        if (ent >= cl.max_entities)
                CL_ExpandEntities(ent);
 
-       if( !CL_VM_Event_Sound(sound_num, volume / 255.0f, channel, attenuation, ent, pos) )
-               S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0f, attenuation);
+       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);
 }
 
 /*
@@ -297,58 +303,64 @@ so the server doesn't disconnect.
 static unsigned char olddata[NET_MAXMESSAGE];
 void CL_KeepaliveMessage (qboolean readmessages)
 {
-       float time;
-       static double nextmsg = -1;
-       static double nextupdate = -1;
-#if 0
-       static double lasttime = -1;
-#endif
-       int oldreadcount;
-       qboolean oldbadread;
+       static double lastdirtytime = 0;
+       static qboolean recursive = false;
+       double dirtytime;
+       double deltatime;
+       static double countdownmsg = 0;
+       static double countdownupdate = 0;
        sizebuf_t old;
 
-       if(cls.state != ca_dedicated)
+       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((time = Sys_DoubleTime()) >= nextupdate)
+               if(cls.state != ca_dedicated)
                {
-                       SCR_UpdateLoadingScreenIfShown();
-                       nextupdate = time + 2;
+                       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 (!cls.netcon || cls.protocol == PROTOCOL_QUAKEWORLD || cls.signon >= SIGNONS)
+       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
-               oldreadcount = msg_readcount;
-               oldbadread = msg_badread;
-               old = net_message;
-               memcpy(olddata, net_message.data, net_message.cursize);
+               old = cl_message;
+               memcpy(olddata, cl_message.data, cl_message.cursize);
 
                NetConn_ClientFrame();
 
-               msg_readcount = oldreadcount;
-               msg_badread = oldbadread;
-               net_message = old;
-               memcpy(net_message.data, olddata, net_message.cursize);
-       }
-
-#if 0
-       if((time = Sys_DoubleTime()) >= lasttime + 1)
-       {
-               Con_Printf("long delta: %f\n", time - lasttime);
+               cl_message = old;
+               memcpy(cl_message.data, olddata, cl_message.cursize);
        }
-       lasttime = Sys_DoubleTime();
-#endif
 
-       if (cls.netcon && (time = Sys_DoubleTime()) >= nextmsg)
+       if (cls.netcon && countdownmsg <= 0) // check if time stepped backwards
        {
                sizebuf_t       msg;
                unsigned char           buf[4];
-               nextmsg = time + 5;
+               countdownmsg = 5;
                // write out a nop
                // LordHavoc: must use unreliable because reliable could kill the sigon message!
                Con_Print("--> client to server keepalive\n");
@@ -358,6 +370,8 @@ void CL_KeepaliveMessage (qboolean readmessages)
                MSG_WriteChar(&msg, clc_nop);
                NetConn_SendUnreliableMessage(cls.netcon, &msg, cls.protocol, 10000, false);
        }
+
+       recursive = thisrecursive;
 }
 
 void CL_ParseEntityLump(char *entdata)
@@ -370,13 +384,13 @@ void CL_ParseEntityLump(char *entdata)
        data = entdata;
        if (!data)
                return;
-       if (!COM_ParseToken_Simple(&data, false, false))
+       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))
+               if (!COM_ParseToken_Simple(&data, false, false, true))
                        return; // error
                if (com_token[0] == '}')
                        break; // end of worldspawn
@@ -386,7 +400,7 @@ void CL_ParseEntityLump(char *entdata)
                        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))
+               if (!COM_ParseToken_Simple(&data, false, false, true))
                        return; // error
                strlcpy (value, com_token, sizeof (value));
                if (!strcmp("sky", key))
@@ -439,12 +453,11 @@ void CL_ParseEntityLump(char *entdata)
        }
 }
 
-extern void CL_Locs_Reload_f(void);
-extern void CL_VM_Init (void);
 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);
@@ -460,14 +473,14 @@ static void CL_SetupWorldModel(void)
                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);
+               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);
+               World_SetSize(&cl.world, "", defaultmins, defaultmaxs, prog);
        }
        World_Start(&cl.world);
 
@@ -504,6 +517,7 @@ static void CL_SetupWorldModel(void)
 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);
@@ -535,7 +549,7 @@ static qboolean QW_CL_CheckOrDownloadFile(const char *filename)
        }
 
        MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
-       MSG_WriteString(&cls.netcon->message, va("download %s", filename));
+       MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "download %s", filename));
 
        cls.qw_downloadnumber++;
        cls.qw_downloadpercent = 0;
@@ -548,6 +562,7 @@ 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;
@@ -564,7 +579,7 @@ static void QW_CL_RequestNextDownload(void)
                        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("skins/%s.pcx", cl.scores[cls.qw_downloadnumber].qw_skin)))
+                       if (!QW_CL_CheckOrDownloadFile(va(vabuf, sizeof(vabuf), "skins/%s.pcx", cl.scores[cls.qw_downloadnumber].qw_skin)))
                                return;
                }
 
@@ -580,7 +595,7 @@ static void QW_CL_RequestNextDownload(void)
                        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("begin %i", cl.qw_servercount));
+                       MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "begin %i", cl.qw_servercount));
                }
                break;
        case dl_model:
@@ -645,12 +660,12 @@ static void QW_CL_RequestNextDownload(void)
                CL_SetupWorldModel();
 
                // add pmodel/emodel CRCs to userinfo
-               CL_SetInfo("pmodel", va("%i", FS_CRCFile("progs/player.mdl", NULL)), true, true, true, true);
-               CL_SetInfo("emodel", va("%i", FS_CRCFile("progs/eyes.mdl", NULL)), true, true, true, true);
+               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("prespawn %i 0 %i", cl.qw_servercount, cl.model_precache[1]->brush.qw_md4sum2));
+               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)
                {
@@ -671,7 +686,7 @@ static void QW_CL_RequestNextDownload(void)
                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("sound/%s", cl.sound_name[cls.qw_downloadnumber])))
+                       if (!QW_CL_CheckOrDownloadFile(va(vabuf, sizeof(vabuf), "sound/%s", cl.sound_name[cls.qw_downloadnumber])))
                                return;
                }
 
@@ -701,7 +716,7 @@ static void QW_CL_RequestNextDownload(void)
 
                // done with sound downloads, next we check models
                MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
-               MSG_WriteString(&cls.netcon->message, va("modellist %i %i", cl.qw_servercount, 0));
+               MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "modellist %i %i", cl.qw_servercount, 0));
                break;
        case dl_none:
        default:
@@ -711,8 +726,8 @@ static void QW_CL_RequestNextDownload(void)
 
 static void QW_CL_ParseDownload(void)
 {
-       int size = (signed short)MSG_ReadShort();
-       int percent = MSG_ReadByte();
+       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);
 
@@ -720,7 +735,7 @@ static void QW_CL_ParseDownload(void)
        if (!cls.netcon)
        {
                if (size > 0)
-                       msg_readcount += size;
+                       cl_message.readcount += size;
                return;
        }
 
@@ -731,7 +746,7 @@ static void QW_CL_ParseDownload(void)
                return;
        }
 
-       if (msg_readcount + (unsigned short)size > net_message.cursize)
+       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
@@ -750,7 +765,7 @@ static void QW_CL_ParseDownload(void)
        }
 
        // read the fragment out of the packet
-       MSG_ReadBytes(size, cls.qw_downloadmemory + cls.qw_downloadmemorycursize);
+       MSG_ReadBytes(&cl_message, size, cls.qw_downloadmemory + cls.qw_downloadmemorycursize);
        cls.qw_downloadmemorycursize += size;
        cls.qw_downloadspeedcount += size;
 
@@ -779,13 +794,14 @@ static void QW_CL_ParseDownload(void)
 static void QW_CL_ParseModelList(void)
 {
        int n;
-       int nummodels = MSG_ReadByte();
+       int nummodels = MSG_ReadByte(&cl_message);
        char *str;
+       char vabuf[1024];
 
        // parse model precache list
        for (;;)
        {
-               str = MSG_ReadString();
+               str = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
                if (!str[0])
                        break;
                nummodels++;
@@ -796,11 +812,11 @@ static void QW_CL_ParseModelList(void)
                strlcpy(cl.model_name[nummodels], str, sizeof (cl.model_name[nummodels]));
        }
 
-       n = MSG_ReadByte();
+       n = MSG_ReadByte(&cl_message);
        if (n)
        {
                MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
-               MSG_WriteString(&cls.netcon->message, va("modellist %i %i", cl.qw_servercount, n));
+               MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "modellist %i %i", cl.qw_servercount, n));
                return;
        }
 
@@ -813,13 +829,14 @@ static void QW_CL_ParseModelList(void)
 static void QW_CL_ParseSoundList(void)
 {
        int n;
-       int numsounds = MSG_ReadByte();
+       int numsounds = MSG_ReadByte(&cl_message);
        char *str;
+       char vabuf[1024];
 
        // parse sound precache list
        for (;;)
        {
-               str = MSG_ReadString();
+               str = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
                if (!str[0])
                        break;
                numsounds++;
@@ -830,12 +847,12 @@ static void QW_CL_ParseSoundList(void)
                strlcpy(cl.sound_name[numsounds], str, sizeof (cl.sound_name[numsounds]));
        }
 
-       n = MSG_ReadByte();
+       n = MSG_ReadByte(&cl_message);
 
        if (n)
        {
                MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
-               MSG_WriteString(&cls.netcon->message, va("soundlist %i %i", cl.qw_servercount, n));
+               MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "soundlist %i %i", cl.qw_servercount, n));
                return;
        }
 
@@ -948,16 +965,16 @@ static void QW_CL_ProcessUserInfo(int slot)
 static void QW_CL_UpdateUserInfo(void)
 {
        int slot;
-       slot = MSG_ReadByte();
+       slot = MSG_ReadByte(&cl_message);
        if (slot >= cl.maxclients)
        {
                Con_Printf("svc_updateuserinfo >= cl.maxclients\n");
-               MSG_ReadLong();
-               MSG_ReadString();
+               MSG_ReadLong(&cl_message);
+               MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
                return;
        }
-       cl.scores[slot].qw_userid = MSG_ReadLong();
-       strlcpy(cl.scores[slot].qw_userinfo, MSG_ReadString(), sizeof(cl.scores[slot].qw_userinfo));
+       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);
 }
@@ -967,9 +984,9 @@ static void QW_CL_SetInfo(void)
        int slot;
        char key[2048];
        char value[2048];
-       slot = MSG_ReadByte();
-       strlcpy(key, MSG_ReadString(), sizeof(key));
-       strlcpy(value, MSG_ReadString(), sizeof(value));
+       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");
@@ -985,8 +1002,8 @@ static void QW_CL_ServerInfo(void)
        char key[2048];
        char value[2048];
        char temp[32];
-       strlcpy(key, MSG_ReadString(), sizeof(key));
-       strlcpy(value, MSG_ReadString(), sizeof(value));
+       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));
@@ -996,13 +1013,13 @@ static void QW_CL_ServerInfo(void)
 static void QW_CL_ParseNails(void)
 {
        int i, j;
-       int numnails = MSG_ReadByte();
+       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();
+                       bits[j] = MSG_ReadByte(&cl_message);
                if (cl.qw_num_nails > 255)
                        continue;
                v = cl.qw_nails[cl.qw_num_nails++];
@@ -1038,8 +1055,9 @@ static void CL_UpdateItemsAndWeapon(void)
 #define LOADPROGRESSWEIGHT_WORLDMODEL      30.0
 #define LOADPROGRESSWEIGHT_WORLDMODEL_INIT  2.0
 
-void CL_BeginDownloads(qboolean aborteddownload)
+static void CL_BeginDownloads(qboolean aborteddownload)
 {
+       char vabuf[1024];
        // quakeworld works differently
        if (cls.protocol == PROTOCOL_QUAKEWORLD)
                return;
@@ -1072,13 +1090,13 @@ void CL_BeginDownloads(qboolean aborteddownload)
                 && csqc_progcrc.integer >= 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("dlcache/%s.%i.%i", csqc_progname.string, csqc_progsize.integer, csqc_progcrc.integer)))
+                && !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("download %s deflate", csqc_progname.string));
+                               Cmd_ForwardStringToServer(va(vabuf, sizeof(vabuf), "download %s deflate", csqc_progname.string));
                        else
-                               Cmd_ForwardStringToServer(va("download %s", csqc_progname.string));
+                               Cmd_ForwardStringToServer(va(vabuf, sizeof(vabuf), "download %s", csqc_progname.string));
                        return;
                }
        }
@@ -1246,7 +1264,7 @@ void CL_BeginDownloads(qboolean aborteddownload)
                                // 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("download %s", cl.model_name[cl.downloadmodel_current]));
+                                       Cmd_ForwardStringToServer(va(vabuf, sizeof(vabuf), "download %s", cl.model_name[cl.downloadmodel_current]));
                                        // we'll try loading again when the download finishes
                                        return;
                                }
@@ -1258,7 +1276,7 @@ void CL_BeginDownloads(qboolean aborteddownload)
                                Mod_FreeQ3Shaders();
                        }
 
-                       cl.model_precache[cl.downloadmodel_current] = Mod_ForName(cl.model_name[cl.downloadmodel_current], false, false, cl.model_name[cl.downloadmodel_current][0] == '*' ? cl.model_name[1] : NULL);
+                       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
@@ -1299,7 +1317,7 @@ void CL_BeginDownloads(qboolean aborteddownload)
                                Con_Printf("Sound %s not found\n", soundname);
                                if (cl_serverextension_download.integer && cls.netcon && !sv.active)
                                {
-                                       Cmd_ForwardStringToServer(va("download %s", soundname));
+                                       Cmd_ForwardStringToServer(va(vabuf, sizeof(vabuf), "download %s", soundname));
                                        // we'll try loading again when the download finishes
                                        return;
                                }
@@ -1325,7 +1343,7 @@ void CL_BeginDownloads(qboolean aborteddownload)
        }
 }
 
-void CL_BeginDownloads_f(void)
+static void CL_BeginDownloads_f(void)
 {
        // prevent cl_begindownloads from being issued multiple times in one match
        // to prevent accidentally cancelled downloads
@@ -1335,7 +1353,7 @@ void CL_BeginDownloads_f(void)
                CL_BeginDownloads(false);
 }
 
-void CL_StopDownload(int size, int crc)
+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)
        {
@@ -1420,12 +1438,12 @@ void CL_StopDownload(int size, int crc)
        cls.qw_downloadpercent = 0;
 }
 
-void CL_ParseDownload(void)
+static void CL_ParseDownload(void)
 {
        int i, start, size;
        static unsigned char data[NET_MAXMESSAGE];
-       start = MSG_ReadLong();
-       size = (unsigned short)MSG_ReadShort();
+       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++)
@@ -1438,7 +1456,7 @@ void CL_ParseDownload(void)
                }
        }
 
-       MSG_ReadBytes(size, data);
+       MSG_ReadBytes(&cl_message, size, data);
 
        if (!cls.qw_downloadname[0])
        {
@@ -1459,7 +1477,7 @@ void CL_ParseDownload(void)
        cls.qw_downloadspeedcount += size;
 }
 
-void CL_DownloadBegin_f(void)
+static void CL_DownloadBegin_f(void)
 {
        int size = atoi(Cmd_Argv(1));
 
@@ -1492,7 +1510,7 @@ void CL_DownloadBegin_f(void)
        Cmd_ForwardStringToServer("sv_startdownload");
 }
 
-void CL_StopDownload_f(void)
+static void CL_StopDownload_f(void)
 {
        Curl_CancelAll();
        if (cls.qw_downloadname[0])
@@ -1503,7 +1521,7 @@ void CL_StopDownload_f(void)
        CL_BeginDownloads(true);
 }
 
-void CL_DownloadFinished_f(void)
+static void CL_DownloadFinished_f(void)
 {
        if (Cmd_Argc() < 3)
        {
@@ -1516,29 +1534,30 @@ void CL_DownloadFinished_f(void)
 
 static void CL_SendPlayerInfo(void)
 {
+       char vabuf[1024];
        MSG_WriteByte (&cls.netcon->message, clc_stringcmd);
-       MSG_WriteString (&cls.netcon->message, va("name \"%s\"", cl_name.string));
+       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("color %i %i", cl_color.integer >> 4, cl_color.integer & 15));
+       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("rate %i", cl_rate.integer));
+       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("pmodel %i", cl_pmodel.integer));
+               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("playermodel %s", cl_playermodel.string));
+               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("playerskin %s", cl_playerskin.string));
+               MSG_WriteString (&cls.netcon->message, va(vabuf, sizeof(vabuf), "playerskin %s", cl_playerskin.string));
        }
 }
 
@@ -1615,12 +1634,13 @@ static void CL_SignonReply (void)
 CL_ParseServerInfo
 ==================
 */
-void CL_ParseServerInfo (void)
+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();
@@ -1649,7 +1669,7 @@ void CL_ParseServerInfo (void)
        CL_ClearState ();
 
 // parse protocol version number
-       i = MSG_ReadLong ();
+       i = MSG_ReadLong(&cl_message);
        protocol = Protocol_EnumForNumber(i);
        if (protocol == PROTOCOL_UNKNOWN)
        {
@@ -1668,9 +1688,9 @@ void CL_ParseServerInfo (void)
        {
                char gamedir[1][MAX_QPATH];
 
-               cl.qw_servercount = MSG_ReadLong();
+               cl.qw_servercount = MSG_ReadLong(&cl_message);
 
-               str = MSG_ReadString();
+               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]));
 
@@ -1682,27 +1702,27 @@ void CL_ParseServerInfo (void)
                cl.maxclients = 32;
 
                // parse player number
-               i = MSG_ReadByte();
+               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 ();
+               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.movevars_stopspeed          = MSG_ReadFloat();
-               cl.movevars_maxspeed           = MSG_ReadFloat();
-               cl.movevars_spectatormaxspeed  = MSG_ReadFloat();
-               cl.movevars_accelerate         = MSG_ReadFloat();
-               cl.movevars_airaccelerate      = MSG_ReadFloat();
-               cl.movevars_wateraccelerate    = MSG_ReadFloat();
-               cl.movevars_friction           = MSG_ReadFloat();
-               cl.movevars_waterfriction      = MSG_ReadFloat();
-               cl.movevars_entgravity         = MSG_ReadFloat();
+               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;
@@ -1723,7 +1743,7 @@ void CL_ParseServerInfo (void)
                if (cls.netcon)
                {
                        MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
-                       MSG_WriteString(&cls.netcon->message, va("soundlist %i %i", cl.qw_servercount, 0));
+                       MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "soundlist %i %i", cl.qw_servercount, 0));
                }
 
                cl.loadbegun = false;
@@ -1750,7 +1770,7 @@ void CL_ParseServerInfo (void)
        else
        {
        // parse maxclients
-               cl.maxclients = MSG_ReadByte ();
+               cl.maxclients = MSG_ReadByte(&cl_message);
                if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD)
                {
                        Host_Error("Bad maxclients (%u) from server", cl.maxclients);
@@ -1759,14 +1779,14 @@ void CL_ParseServerInfo (void)
                cl.scores = (scoreboard_t *)Mem_Alloc(cls.levelmempool, cl.maxclients*sizeof(*cl.scores));
 
        // parse gametype
-               cl.gametype = MSG_ReadByte ();
+               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 ();
+               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
@@ -1779,7 +1799,7 @@ void CL_ParseServerInfo (void)
                // parse model precache list
                for (nummodels=1 ; ; nummodels++)
                {
-                       str = MSG_ReadString();
+                       str = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
                        if (!str[0])
                                break;
                        if (nummodels==MAX_MODELS)
@@ -1791,7 +1811,7 @@ void CL_ParseServerInfo (void)
                // parse sound precache list
                for (numsounds=1 ; ; numsounds++)
                {
-                       str = MSG_ReadString();
+                       str = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
                        if (!str[0])
                                break;
                        if (numsounds==MAX_SOUNDS)
@@ -1894,6 +1914,7 @@ void CL_ParseServerInfo (void)
                                Con_Print ("ERROR: couldn't open.\n");
                }
        }
+       cl.islocalgame = NetConn_IsLocalGame();
 }
 
 void CL_ValidateState(entity_state_t *s)
@@ -2042,7 +2063,7 @@ void CL_MoveLerpEntityStates(entity_t *ent)
 CL_ParseBaseline
 ==================
 */
-void CL_ParseBaseline (entity_t *ent, int large)
+static void CL_ParseBaseline (entity_t *ent, int large)
 {
        int i;
 
@@ -2051,25 +2072,25 @@ void CL_ParseBaseline (entity_t *ent, int large)
        ent->state_baseline.active = true;
        if (large)
        {
-               ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort ();
-               ent->state_baseline.frame = (unsigned short) MSG_ReadShort ();
+               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 ();
-               ent->state_baseline.frame = MSG_ReadByte ();
+               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 ();
-               ent->state_baseline.frame = MSG_ReadByte ();
+               ent->state_baseline.modelindex = MSG_ReadByte(&cl_message);
+               ent->state_baseline.frame = MSG_ReadByte(&cl_message);
        }
-       ent->state_baseline.colormap = MSG_ReadByte();
-       ent->state_baseline.skin = MSG_ReadByte();
+       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(cls.protocol);
-               ent->state_baseline.angles[i] = MSG_ReadAngle(cls.protocol);
+               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;
 }
@@ -2082,7 +2103,7 @@ CL_ParseClientdata
 Server information pertaining to this client only
 ==================
 */
-void CL_ParseClientdata (void)
+static void CL_ParseClientdata (void)
 {
        int i, bits;
 
@@ -2109,89 +2130,89 @@ void CL_ParseClientdata (void)
        cl.mvelocity[0][2] = 0;
        cl.mviewzoom[0] = 1;
 
-       bits = (unsigned short) MSG_ReadShort ();
+       bits = (unsigned short) MSG_ReadShort(&cl_message);
        if (bits & SU_EXTEND1)
-               bits |= (MSG_ReadByte() << 16);
+               bits |= (MSG_ReadByte(&cl_message) << 16);
        if (bits & SU_EXTEND2)
-               bits |= (MSG_ReadByte() << 24);
+               bits |= (MSG_ReadByte(&cl_message) << 24);
 
        if (bits & SU_VIEWHEIGHT)
-               cl.stats[STAT_VIEWHEIGHT] = MSG_ReadChar ();
+               cl.stats[STAT_VIEWHEIGHT] = MSG_ReadChar(&cl_message);
 
        if (bits & SU_IDEALPITCH)
-               cl.idealpitch = MSG_ReadChar ();
+               cl.idealpitch = MSG_ReadChar(&cl_message);
 
        for (i = 0;i < 3;i++)
        {
                if (bits & (SU_PUNCH1<<i) )
                {
                        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)
-                               cl.mpunchangle[0][i] = MSG_ReadChar();
+                               cl.mpunchangle[0][i] = MSG_ReadChar(&cl_message);
                        else
-                               cl.mpunchangle[0][i] = MSG_ReadAngle16i();
+                               cl.mpunchangle[0][i] = MSG_ReadAngle16i(&cl_message);
                }
                if (bits & (SU_PUNCHVEC1<<i))
                {
                        if (cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4)
-                               cl.mpunchvector[0][i] = MSG_ReadCoord16i();
+                               cl.mpunchvector[0][i] = MSG_ReadCoord16i(&cl_message);
                        else
-                               cl.mpunchvector[0][i] = MSG_ReadCoord32f();
+                               cl.mpunchvector[0][i] = MSG_ReadCoord32f(&cl_message);
                }
                if (bits & (SU_VELOCITY1<<i) )
                {
                        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)
-                               cl.mvelocity[0][i] = MSG_ReadChar()*16;
+                               cl.mvelocity[0][i] = MSG_ReadChar(&cl_message)*16;
                        else
-                               cl.mvelocity[0][i] = MSG_ReadCoord32f();
+                               cl.mvelocity[0][i] = MSG_ReadCoord32f(&cl_message);
                }
        }
 
        // LordHavoc: hipnotic demos don't have this bit set but should
        if (bits & SU_ITEMS || 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_ITEMS] = MSG_ReadLong ();
+               cl.stats[STAT_ITEMS] = MSG_ReadLong(&cl_message);
 
        cl.onground = (bits & SU_ONGROUND) != 0;
        cl.inwater = (bits & SU_INWATER) != 0;
 
        if (cls.protocol == PROTOCOL_DARKPLACES5)
        {
-               cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadShort() : 0;
-               cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadShort() : 0;
-               cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadShort() : 0;
-               cl.stats[STAT_HEALTH] = MSG_ReadShort();
-               cl.stats[STAT_AMMO] = MSG_ReadShort();
-               cl.stats[STAT_SHELLS] = MSG_ReadShort();
-               cl.stats[STAT_NAILS] = MSG_ReadShort();
-               cl.stats[STAT_ROCKETS] = MSG_ReadShort();
-               cl.stats[STAT_CELLS] = MSG_ReadShort();
-               cl.stats[STAT_ACTIVEWEAPON] = (unsigned short) MSG_ReadShort ();
+               cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadShort(&cl_message) : 0;
+               cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadShort(&cl_message) : 0;
+               cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadShort(&cl_message) : 0;
+               cl.stats[STAT_HEALTH] = MSG_ReadShort(&cl_message);
+               cl.stats[STAT_AMMO] = MSG_ReadShort(&cl_message);
+               cl.stats[STAT_SHELLS] = MSG_ReadShort(&cl_message);
+               cl.stats[STAT_NAILS] = MSG_ReadShort(&cl_message);
+               cl.stats[STAT_ROCKETS] = MSG_ReadShort(&cl_message);
+               cl.stats[STAT_CELLS] = MSG_ReadShort(&cl_message);
+               cl.stats[STAT_ACTIVEWEAPON] = (unsigned short) MSG_ReadShort(&cl_message);
        }
        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_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)
        {
-               cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
-               cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
+               cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte(&cl_message) : 0;
+               cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte(&cl_message) : 0;
                if (cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3)
-                       cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? (unsigned short)MSG_ReadShort() : 0;
+                       cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? (unsigned short)MSG_ReadShort(&cl_message) : 0;
                else
-                       cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
-               cl.stats[STAT_HEALTH] = MSG_ReadShort();
-               cl.stats[STAT_AMMO] = MSG_ReadByte();
-               cl.stats[STAT_SHELLS] = MSG_ReadByte();
-               cl.stats[STAT_NAILS] = MSG_ReadByte();
-               cl.stats[STAT_ROCKETS] = MSG_ReadByte();
-               cl.stats[STAT_CELLS] = MSG_ReadByte();
+                       cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte(&cl_message) : 0;
+               cl.stats[STAT_HEALTH] = MSG_ReadShort(&cl_message);
+               cl.stats[STAT_AMMO] = MSG_ReadByte(&cl_message);
+               cl.stats[STAT_SHELLS] = MSG_ReadByte(&cl_message);
+               cl.stats[STAT_NAILS] = MSG_ReadByte(&cl_message);
+               cl.stats[STAT_ROCKETS] = MSG_ReadByte(&cl_message);
+               cl.stats[STAT_CELLS] = MSG_ReadByte(&cl_message);
                if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
-                       cl.stats[STAT_ACTIVEWEAPON] = (1<<MSG_ReadByte ());
+                       cl.stats[STAT_ACTIVEWEAPON] = (1<<MSG_ReadByte(&cl_message));
                else
-                       cl.stats[STAT_ACTIVEWEAPON] = MSG_ReadByte ();
+                       cl.stats[STAT_ACTIVEWEAPON] = MSG_ReadByte(&cl_message);
        }
 
        if (bits & SU_VIEWZOOM)
        {
                if (cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4)
-                       cl.stats[STAT_VIEWZOOM] = MSG_ReadByte();
+                       cl.stats[STAT_VIEWZOOM] = MSG_ReadByte(&cl_message);
                else
-                       cl.stats[STAT_VIEWZOOM] = (unsigned short) MSG_ReadShort();
+                       cl.stats[STAT_VIEWZOOM] = (unsigned short) MSG_ReadShort(&cl_message);
        }
 
        // viewzoom interpolation
@@ -2203,7 +2224,7 @@ void CL_ParseClientdata (void)
 CL_ParseStatic
 =====================
 */
-void CL_ParseStatic (int large)
+static void CL_ParseStatic (int large)
 {
        entity_t *ent;
 
@@ -2243,46 +2264,46 @@ void CL_ParseStatic (int large)
 CL_ParseStaticSound
 ===================
 */
-void CL_ParseStaticSound (int large)
+static void CL_ParseStaticSound (int large)
 {
        vec3_t          org;
        int                     sound_num, vol, atten;
 
-       MSG_ReadVector(org, cls.protocol);
+       MSG_ReadVector(&cl_message, org, cls.protocol);
        if (large || cls.protocol == PROTOCOL_NEHAHRABJP2)
-               sound_num = (unsigned short) MSG_ReadShort ();
+               sound_num = (unsigned short) MSG_ReadShort(&cl_message);
        else
-               sound_num = MSG_ReadByte ();
-       vol = MSG_ReadByte ();
-       atten = MSG_ReadByte ();
+               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);
 }
 
-void CL_ParseEffect (void)
+static void CL_ParseEffect (void)
 {
        vec3_t          org;
        int                     modelindex, startframe, framecount, framerate;
 
-       MSG_ReadVector(org, cls.protocol);
-       modelindex = MSG_ReadByte ();
-       startframe = MSG_ReadByte ();
-       framecount = MSG_ReadByte ();
-       framerate = MSG_ReadByte ();
+       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);
 }
 
-void CL_ParseEffect2 (void)
+static void CL_ParseEffect2 (void)
 {
        vec3_t          org;
        int                     modelindex, startframe, framecount, framerate;
 
-       MSG_ReadVector(org, cls.protocol);
-       modelindex = (unsigned short) MSG_ReadShort ();
-       startframe = (unsigned short) MSG_ReadShort ();
-       framecount = MSG_ReadByte ();
-       framerate = MSG_ReadByte ();
+       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);
 }
@@ -2326,14 +2347,14 @@ void CL_NewBeam (int ent, vec3_t start, vec3_t end, dp_model_t *m, int lightning
                Con_Print("beam list overflow!\n");
 }
 
-void CL_ParseBeam (dp_model_t *m, int lightning)
+static void CL_ParseBeam (dp_model_t *m, int lightning)
 {
        int ent;
        vec3_t start, end;
 
-       ent = (unsigned short) MSG_ReadShort ();
-       MSG_ReadVector(start, cls.protocol);
-       MSG_ReadVector(end, cls.protocol);
+       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)
        {
@@ -2344,7 +2365,7 @@ void CL_ParseBeam (dp_model_t *m, int lightning)
        CL_NewBeam(ent, start, end, m, lightning);
 }
 
-void CL_ParseTempEntity(void)
+static void CL_ParseTempEntity(void)
 {
        int type;
        vec3_t pos, pos2;
@@ -2359,12 +2380,12 @@ void CL_ParseTempEntity(void)
 
        if (cls.protocol == PROTOCOL_QUAKEWORLD)
        {
-               type = MSG_ReadByte();
+               type = MSG_ReadByte(&cl_message);
                switch (type)
                {
                case QW_TE_WIZSPIKE:
                        // spike hitting wall
-                       MSG_ReadVector(pos, cls.protocol);
+                       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);
@@ -2372,7 +2393,7 @@ void CL_ParseTempEntity(void)
 
                case QW_TE_KNIGHTSPIKE:
                        // spike hitting wall
-                       MSG_ReadVector(pos, cls.protocol);
+                       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);
@@ -2380,7 +2401,7 @@ void CL_ParseTempEntity(void)
 
                case QW_TE_SPIKE:
                        // spike hitting wall
-                       MSG_ReadVector(pos, cls.protocol);
+                       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)
@@ -2398,7 +2419,7 @@ void CL_ParseTempEntity(void)
                        break;
                case QW_TE_SUPERSPIKE:
                        // super spike hitting wall
-                       MSG_ReadVector(pos, cls.protocol);
+                       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)
@@ -2417,7 +2438,7 @@ void CL_ParseTempEntity(void)
 
                case QW_TE_EXPLOSION:
                        // rocket explosion
-                       MSG_ReadVector(pos, cls.protocol);
+                       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);
@@ -2426,7 +2447,7 @@ void CL_ParseTempEntity(void)
 
                case QW_TE_TAREXPLOSION:
                        // tarbaby explosion
-                       MSG_ReadVector(pos, cls.protocol);
+                       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);
@@ -2448,19 +2469,19 @@ void CL_ParseTempEntity(void)
                        break;
 
                case QW_TE_LAVASPLASH:
-                       MSG_ReadVector(pos, cls.protocol);
+                       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(pos, cls.protocol);
+                       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();
-                       MSG_ReadVector(pos, cls.protocol);
+                       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);
@@ -2483,14 +2504,14 @@ void CL_ParseTempEntity(void)
                        break;
 
                case QW_TE_BLOOD:
-                       count = MSG_ReadByte();
-                       MSG_ReadVector(pos, cls.protocol);
+                       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(pos, cls.protocol);
+                       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;
@@ -2501,12 +2522,12 @@ void CL_ParseTempEntity(void)
        }
        else
        {
-               type = MSG_ReadByte();
+               type = MSG_ReadByte(&cl_message);
                switch (type)
                {
                case TE_WIZSPIKE:
                        // spike hitting wall
-                       MSG_ReadVector(pos, cls.protocol);
+                       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);
@@ -2514,7 +2535,7 @@ void CL_ParseTempEntity(void)
 
                case TE_KNIGHTSPIKE:
                        // spike hitting wall
-                       MSG_ReadVector(pos, cls.protocol);
+                       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);
@@ -2522,7 +2543,7 @@ void CL_ParseTempEntity(void)
 
                case TE_SPIKE:
                        // spike hitting wall
-                       MSG_ReadVector(pos, cls.protocol);
+                       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)
@@ -2540,7 +2561,7 @@ void CL_ParseTempEntity(void)
                        break;
                case TE_SPIKEQUAD:
                        // quad spike hitting wall
-                       MSG_ReadVector(pos, cls.protocol);
+                       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)
@@ -2558,7 +2579,7 @@ void CL_ParseTempEntity(void)
                        break;
                case TE_SUPERSPIKE:
                        // super spike hitting wall
-                       MSG_ReadVector(pos, cls.protocol);
+                       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)
@@ -2576,7 +2597,7 @@ void CL_ParseTempEntity(void)
                        break;
                case TE_SUPERSPIKEQUAD:
                        // quad super spike hitting wall
-                       MSG_ReadVector(pos, cls.protocol);
+                       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)
@@ -2595,36 +2616,36 @@ void CL_ParseTempEntity(void)
                        // LordHavoc: added for improved blood splatters
                case TE_BLOOD:
                        // blood puff
-                       MSG_ReadVector(pos, cls.protocol);
+                       MSG_ReadVector(&cl_message, pos, cls.protocol);
                        CL_FindNonSolidLocation(pos, pos, 4);
-                       dir[0] = MSG_ReadChar();
-                       dir[1] = MSG_ReadChar();
-                       dir[2] = MSG_ReadChar();
-                       count = MSG_ReadByte();
+                       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(pos, cls.protocol);
+                       MSG_ReadVector(&cl_message, pos, cls.protocol);
                        CL_FindNonSolidLocation(pos, pos, 4);
-                       dir[0] = MSG_ReadChar();
-                       dir[1] = MSG_ReadChar();
-                       dir[2] = MSG_ReadChar();
-                       count = MSG_ReadByte();
+                       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(pos, cls.protocol);
+                       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(pos, cls.protocol); // mins
-                       MSG_ReadVector(pos2, cls.protocol); // maxs
-                       velspeed = MSG_ReadCoord(cls.protocol); // speed
-                       count = (unsigned short) MSG_ReadShort(); // number of particles
+                       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;
@@ -2636,39 +2657,39 @@ void CL_ParseTempEntity(void)
 
                case TE_PARTICLECUBE:
                        // general purpose particle effect
-                       MSG_ReadVector(pos, cls.protocol); // mins
-                       MSG_ReadVector(pos2, cls.protocol); // maxs
-                       MSG_ReadVector(dir, cls.protocol); // dir
-                       count = (unsigned short) MSG_ReadShort(); // number of particles
-                       colorStart = MSG_ReadByte(); // color
-                       colorLength = MSG_ReadByte(); // gravity (1 or 0)
-                       velspeed = MSG_ReadCoord(cls.protocol); // randomvel
+                       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(pos, cls.protocol); // mins
-                       MSG_ReadVector(pos2, cls.protocol); // maxs
-                       MSG_ReadVector(dir, cls.protocol); // dir
-                       count = (unsigned short) MSG_ReadShort(); // number of particles
-                       colorStart = MSG_ReadByte(); // color
+                       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(pos, cls.protocol); // mins
-                       MSG_ReadVector(pos2, cls.protocol); // maxs
-                       MSG_ReadVector(dir, cls.protocol); // dir
-                       count = (unsigned short) MSG_ReadShort(); // number of particles
-                       colorStart = MSG_ReadByte(); // color
+                       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(pos, cls.protocol);
+                       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)
@@ -2690,7 +2711,7 @@ void CL_ParseTempEntity(void)
 
                case TE_GUNSHOTQUAD:
                        // quad bullet hitting wall
-                       MSG_ReadVector(pos, cls.protocol);
+                       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)
@@ -2712,7 +2733,7 @@ void CL_ParseTempEntity(void)
 
                case TE_EXPLOSION:
                        // rocket explosion
-                       MSG_ReadVector(pos, cls.protocol);
+                       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);
@@ -2720,7 +2741,7 @@ void CL_ParseTempEntity(void)
 
                case TE_EXPLOSIONQUAD:
                        // quad rocket explosion
-                       MSG_ReadVector(pos, cls.protocol);
+                       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);
@@ -2728,11 +2749,11 @@ void CL_ParseTempEntity(void)
 
                case TE_EXPLOSION3:
                        // Nehahra movie colored lighting explosion
-                       MSG_ReadVector(pos, cls.protocol);
+                       MSG_ReadVector(&cl_message, pos, cls.protocol);
                        CL_FindNonSolidLocation(pos, pos, 10);
-                       color[0] = MSG_ReadCoord(cls.protocol) * (2.0f / 1.0f);
-                       color[1] = MSG_ReadCoord(cls.protocol) * (2.0f / 1.0f);
-                       color[2] = MSG_ReadCoord(cls.protocol) * (2.0f / 1.0f);
+                       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);
@@ -2741,12 +2762,12 @@ void CL_ParseTempEntity(void)
 
                case TE_EXPLOSIONRGB:
                        // colored lighting explosion
-                       MSG_ReadVector(pos, cls.protocol);
+                       MSG_ReadVector(&cl_message, pos, cls.protocol);
                        CL_FindNonSolidLocation(pos, pos, 10);
                        CL_ParticleExplosion(pos);
-                       color[0] = MSG_ReadByte() * (2.0f / 255.0f);
-                       color[1] = MSG_ReadByte() * (2.0f / 255.0f);
-                       color[2] = MSG_ReadByte() * (2.0f / 255.0f);
+                       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);
@@ -2754,34 +2775,34 @@ void CL_ParseTempEntity(void)
 
                case TE_TAREXPLOSION:
                        // tarbaby explosion
-                       MSG_ReadVector(pos, cls.protocol);
+                       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(pos, cls.protocol);
+                       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(pos, cls.protocol);
+                       MSG_ReadVector(&cl_message, pos, cls.protocol);
                        CL_FindNonSolidLocation(pos, pos, 4);
-                       radius = (MSG_ReadByte() + 1) * 8;
-                       velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
-                       color[0] = MSG_ReadByte() * (2.0f / 255.0f);
-                       color[1] = MSG_ReadByte() * (2.0f / 255.0f);
-                       color[2] = MSG_ReadByte() * (2.0f / 255.0f);
+                       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(pos, cls.protocol);
-                       MSG_ReadVector(dir, cls.protocol);
-                       count = MSG_ReadByte();
+                       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;
 
@@ -2809,25 +2830,25 @@ void CL_ParseTempEntity(void)
 
        // LordHavoc: for compatibility with the Nehahra movie...
                case TE_LIGHTNING4NEH:
-                       CL_ParseBeam(Mod_ForName(MSG_ReadString(), true, false, NULL), false);
+                       CL_ParseBeam(Mod_ForName(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), true, false, NULL), false);
                        break;
 
                case TE_LAVASPLASH:
-                       MSG_ReadVector(pos, cls.protocol);
+                       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(pos, cls.protocol);
+                       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(pos, cls.protocol);
+                       MSG_ReadVector(&cl_message, pos, cls.protocol);
                        CL_FindNonSolidLocation(pos, pos, 10);
-                       colorStart = MSG_ReadByte();
-                       colorLength = MSG_ReadByte();
+                       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);
@@ -2839,31 +2860,31 @@ void CL_ParseTempEntity(void)
                        break;
 
                case TE_TEI_G3:
-                       MSG_ReadVector(pos, cls.protocol);
-                       MSG_ReadVector(pos2, cls.protocol);
-                       MSG_ReadVector(dir, cls.protocol);
+                       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(pos, cls.protocol);
-                       MSG_ReadVector(dir, cls.protocol);
-                       count = MSG_ReadByte();
+                       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(pos, cls.protocol);
+                       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(pos, cls.protocol);
-                       MSG_ReadVector(dir, cls.protocol);
-                       count = MSG_ReadByte();
+                       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;
@@ -2874,39 +2895,39 @@ void CL_ParseTempEntity(void)
        }
 }
 
-void CL_ParseTrailParticles(void)
+static void CL_ParseTrailParticles(void)
 {
        int entityindex;
        int effectindex;
        vec3_t start, end;
-       entityindex = (unsigned short)MSG_ReadShort();
+       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();
-       MSG_ReadVector(start, cls.protocol);
-       MSG_ReadVector(end, cls.protocol);
+       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);
 }
 
-void CL_ParsePointParticles(void)
+static void CL_ParsePointParticles(void)
 {
        int effectindex, count;
        vec3_t origin, velocity;
-       effectindex = (unsigned short)MSG_ReadShort();
-       MSG_ReadVector(origin, cls.protocol);
-       MSG_ReadVector(velocity, cls.protocol);
-       count = (unsigned short)MSG_ReadShort();
+       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);
 }
 
-void CL_ParsePointParticles1(void)
+static void CL_ParsePointParticles1(void)
 {
        int effectindex;
        vec3_t origin;
-       effectindex = (unsigned short)MSG_ReadShort();
-       MSG_ReadVector(origin, cls.protocol);
+       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);
 }
 
@@ -3060,7 +3081,7 @@ static void CL_IPLog_List_f(void)
 }
 
 // look for anything interesting like player IP addresses or ping reports
-qboolean CL_ExaminePrintString(const char *text)
+static qboolean CL_ExaminePrintString(const char *text)
 {
        int len;
        const char *t;
@@ -3205,7 +3226,6 @@ qboolean CL_ExaminePrintString(const char *text)
 
 extern cvar_t slowmo;
 extern cvar_t cl_lerpexcess;
-extern void CSQC_UpdateNetworkTimes(double newtime, double oldtime);
 static void CL_NetworkTimeReceived(double newtime)
 {
        double timehigh;
@@ -3304,14 +3324,7 @@ static void CL_NetworkTimeReceived(double newtime)
        }
 }
 
-#define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf("%3i:%s(%i)\n", msg_readcount-1, x, cmd);
-
-//[515]: csqc
-qboolean CL_VM_Parse_TempEntity (void);
-void CL_VM_Parse_StuffCmd (const char *msg);
-void CL_VM_Parse_CenterPrint (const char *msg);
-void CSQC_AddPrintText (const char *msg);
-void CSQC_ReadEntities (void);
+#define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf("%3i:%s(%i)\n", cl_message.readcount-1, x, cmd);
 
 /*
 =====================
@@ -3319,7 +3332,6 @@ CL_ParseServerMessage
 =====================
 */
 int parsingerror = false;
-extern void CL_UpdateMoveVars(void);
 void CL_ParseServerMessage(void)
 {
        int                     cmd;
@@ -3330,12 +3342,13 @@ void CL_ParseServerMessage(void)
        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 (&net_message);
+       //      CL_WriteDemoMessage (&cl_message);
 
        cl.last_received_message = realtime;
 
@@ -3345,7 +3358,7 @@ void CL_ParseServerMessage(void)
 // if recording demos, copy the message out
 //
        if (cl_shownet.integer == 1)
-               Con_Printf("%f %i\n", realtime, net_message.cursize);
+               Con_Printf("%f %i\n", realtime, cl_message.cursize);
        else if (cl_shownet.integer == 2)
                Con_Print("------------------\n");
 
@@ -3372,10 +3385,10 @@ void CL_ParseServerMessage(void)
 
                while (1)
                {
-                       if (msg_badread)
+                       if (cl_message.badread)
                                Host_Error ("CL_ParseServerMessage: Bad QW server message");
 
-                       cmd = MSG_ReadByte ();
+                       cmd = MSG_ReadByte(&cl_message);
 
                        if (cmd == -1)
                        {
@@ -3436,23 +3449,23 @@ void CL_ParseServerMessage(void)
                                return;
 
                        case qw_svc_print:
-                               i = MSG_ReadByte();
-                               temp = MSG_ReadString();
+                               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("\1%s", temp));    //[515]: csqc
+                                               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 ());     //[515]: csqc
+                               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 ());        //[515]: csqc
+                               CL_VM_Parse_StuffCmd(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));        //[515]: csqc
                                break;
 
                        case qw_svc_damage:
@@ -3467,7 +3480,7 @@ void CL_ParseServerMessage(void)
 
                        case qw_svc_setangle:
                                for (i=0 ; i<3 ; i++)
-                                       cl.viewangles[i] = MSG_ReadAngle (cls.protocol);
+                                       cl.viewangles[i] = MSG_ReadAngle(&cl_message, cls.protocol);
                                if (!cls.demoplayback)
                                {
                                        cl.fixangle[0] = true;
@@ -3479,13 +3492,13 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case qw_svc_lightstyle:
-                               i = MSG_ReadByte ();
+                               i = MSG_ReadByte(&cl_message);
                                if (i >= cl.max_lightstyle)
                                {
                                        Con_Printf ("svc_lightstyle >= MAX_LIGHTSTYLES");
                                        break;
                                }
-                               strlcpy (cl.lightstyle[i].map,  MSG_ReadString(), sizeof (cl.lightstyle[i].map));
+                               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;
@@ -3495,41 +3508,41 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case qw_svc_stopsound:
-                               i = (unsigned short) MSG_ReadShort();
+                               i = (unsigned short) MSG_ReadShort(&cl_message);
                                S_StopSound(i>>3, i&7);
                                break;
 
                        case qw_svc_updatefrags:
-                               i = MSG_ReadByte();
+                               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.scores[i].frags = (signed short) MSG_ReadShort(&cl_message);
                                break;
 
                        case qw_svc_updateping:
-                               i = MSG_ReadByte();
+                               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.scores[i].qw_ping = MSG_ReadShort(&cl_message);
                                break;
 
                        case qw_svc_updatepl:
-                               i = MSG_ReadByte();
+                               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.scores[i].qw_packetloss = MSG_ReadByte(&cl_message);
                                break;
 
                        case qw_svc_updateentertime:
-                               i = MSG_ReadByte();
+                               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.scores[i].qw_entertime = cl.time - MSG_ReadFloat(&cl_message);
                                break;
 
                        case qw_svc_spawnbaseline:
-                               i = (unsigned short) MSG_ReadShort();
+                               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)
@@ -3553,17 +3566,17 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case qw_svc_updatestat:
-                               i = MSG_ReadByte ();
+                               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.stats[i] = MSG_ReadByte(&cl_message);
                                break;
 
                        case qw_svc_updatestatlong:
-                               i = MSG_ReadByte ();
+                               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.stats[i] = MSG_ReadLong(&cl_message);
                                break;
 
                        case qw_svc_spawnstaticsound:
@@ -3571,7 +3584,7 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case qw_svc_cdtrack:
-                               cl.cdtrack = cl.looptrack = MSG_ReadByte ();
+                               cl.cdtrack = cl.looptrack = MSG_ReadByte(&cl_message);
                                if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
                                        CDAudio_Play ((unsigned char)cls.forcetrack, true);
                                else
@@ -3582,20 +3595,20 @@ void CL_ParseServerMessage(void)
                                if(!cl.intermission)
                                        cl.completed_time = cl.time;
                                cl.intermission = 1;
-                               MSG_ReadVector(cl.qw_intermission_origin, cls.protocol);
+                               MSG_ReadVector(&cl_message, cl.qw_intermission_origin, cls.protocol);
                                for (i = 0;i < 3;i++)
-                                       cl.qw_intermission_angles[i] = MSG_ReadAngle(cls.protocol);
+                                       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 ());
+                               SCR_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));
                                break;
 
                        case qw_svc_sellscreen:
-                               Cmd_ExecuteString ("help", src_command);
+                               Cmd_ExecuteString ("help", src_command, true);
                                break;
 
                        case qw_svc_smallkick:
@@ -3606,7 +3619,7 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case qw_svc_muzzleflash:
-                               i = (unsigned short) MSG_ReadShort();
+                               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);
@@ -3648,7 +3661,7 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case qw_svc_chokecount:
-                               i = MSG_ReadByte();
+                               i = 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;
@@ -3683,17 +3696,17 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case qw_svc_maxspeed:
-                               cl.movevars_maxspeed = MSG_ReadFloat();
+                               cl.movevars_maxspeed = MSG_ReadFloat(&cl_message);
                                break;
 
                        case qw_svc_entgravity:
-                               cl.movevars_entgravity = MSG_ReadFloat();
+                               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 () != 0;
+                               cl.paused = MSG_ReadByte(&cl_message) != 0;
                                if (cl.paused)
                                        CDAudio_Pause ();
                                else
@@ -3715,10 +3728,10 @@ void CL_ParseServerMessage(void)
        {
                while (1)
                {
-                       if (msg_badread)
+                       if (cl_message.badread)
                                Host_Error ("CL_ParseServerMessage: Bad server message");
 
-                       cmd = MSG_ReadByte ();
+                       cmd = MSG_ReadByte(&cl_message);
 
                        if (cmd == -1)
                        {
@@ -3790,7 +3803,7 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case svc_time:
-                               CL_NetworkTimeReceived(MSG_ReadFloat());
+                               CL_NetworkTimeReceived(MSG_ReadFloat(&cl_message));
                                break;
 
                        case svc_clientdata:
@@ -3798,7 +3811,7 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case svc_version:
-                               i = MSG_ReadLong ();
+                               i = MSG_ReadLong(&cl_message);
                                protocol = Protocol_EnumForNumber(i);
                                if (protocol == PROTOCOL_UNKNOWN)
                                        Host_Error("CL_ParseServerMessage: Server is unrecognized protocol number (%i)", i);
@@ -3817,17 +3830,17 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case svc_print:
-                               temp = MSG_ReadString();
+                               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 ());     //[515]: csqc
+                               CL_VM_Parse_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));     //[515]: csqc
                                break;
 
                        case svc_stufftext:
-                               temp = MSG_ReadString();
+                               temp = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
                                /* if(utf8_enable.integer)
                                {
                                        strip_pqc = true;
@@ -3875,7 +3888,7 @@ void CL_ParseServerMessage(void)
 
                        case svc_setangle:
                                for (i=0 ; i<3 ; i++)
-                                       cl.viewangles[i] = MSG_ReadAngle (cls.protocol);
+                                       cl.viewangles[i] = MSG_ReadAngle(&cl_message, cls.protocol);
                                if (!cls.demoplayback)
                                {
                                        cl.fixangle[0] = true;
@@ -3887,7 +3900,7 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case svc_setview:
-                               cl.viewentity = (unsigned short)MSG_ReadShort ();
+                               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)
@@ -3901,13 +3914,13 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case svc_lightstyle:
-                               i = MSG_ReadByte ();
+                               i = MSG_ReadByte(&cl_message);
                                if (i >= cl.max_lightstyle)
                                {
                                        Con_Printf ("svc_lightstyle >= MAX_LIGHTSTYLES");
                                        break;
                                }
-                               strlcpy (cl.lightstyle[i].map,  MSG_ReadString(), sizeof (cl.lightstyle[i].map));
+                               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;
@@ -3924,8 +3937,8 @@ void CL_ParseServerMessage(void)
                                }
                                else
                                {
-                                       int i = (unsigned short)MSG_ReadShort();
-                                       char *s = MSG_ReadString();
+                                       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)
@@ -3955,29 +3968,29 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case svc_stopsound:
-                               i = (unsigned short) MSG_ReadShort();
+                               i = (unsigned short) MSG_ReadShort(&cl_message);
                                S_StopSound(i>>3, i&7);
                                break;
 
                        case svc_updatename:
-                               i = MSG_ReadByte ();
+                               i = MSG_ReadByte(&cl_message);
                                if (i >= cl.maxclients)
                                        Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
-                               strlcpy (cl.scores[i].name, MSG_ReadString (), sizeof (cl.scores[i].name));
+                               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 ();
+                               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.scores[i].frags = (signed short) MSG_ReadShort(&cl_message);
                                break;
 
                        case svc_updatecolors:
-                               i = MSG_ReadByte ();
+                               i = MSG_ReadByte(&cl_message);
                                if (i >= cl.maxclients)
                                        Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
-                               cl.scores[i].colors = MSG_ReadByte ();
+                               cl.scores[i].colors = MSG_ReadByte(&cl_message);
                                break;
 
                        case svc_particle:
@@ -3993,7 +4006,7 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case svc_spawnbaseline:
-                               i = (unsigned short) MSG_ReadShort ();
+                               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)
@@ -4001,7 +4014,7 @@ void CL_ParseServerMessage(void)
                                CL_ParseBaseline (cl.entities + i, false);
                                break;
                        case svc_spawnbaseline2:
-                               i = (unsigned short) MSG_ReadShort ();
+                               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)
@@ -4020,7 +4033,7 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case svc_setpause:
-                               cl.paused = MSG_ReadByte () != 0;
+                               cl.paused = MSG_ReadByte(&cl_message) != 0;
                                if (cl.paused)
                                        CDAudio_Pause ();
                                else
@@ -4029,7 +4042,7 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case svc_signonnum:
-                               i = MSG_ReadByte ();
+                               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)
@@ -4047,17 +4060,17 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case svc_updatestat:
-                               i = MSG_ReadByte ();
+                               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.stats[i] = MSG_ReadLong(&cl_message);
                                break;
 
                        case svc_updatestatubyte:
-                               i = MSG_ReadByte ();
+                               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.stats[i] = MSG_ReadByte(&cl_message);
                                break;
 
                        case svc_spawnstaticsound:
@@ -4069,8 +4082,8 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case svc_cdtrack:
-                               cl.cdtrack = MSG_ReadByte ();
-                               cl.looptrack = MSG_ReadByte ();
+                               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
@@ -4089,7 +4102,7 @@ void CL_ParseServerMessage(void)
                                        cl.completed_time = cl.time;
                                cl.intermission = 2;
                                CL_VM_UpdateIntermissionState(cl.intermission);
-                               SCR_CenterPrint(MSG_ReadString ());
+                               SCR_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));
                                break;
 
                        case svc_cutscene:
@@ -4097,26 +4110,26 @@ void CL_ParseServerMessage(void)
                                        cl.completed_time = cl.time;
                                cl.intermission = 3;
                                CL_VM_UpdateIntermissionState(cl.intermission);
-                               SCR_CenterPrint(MSG_ReadString ());
+                               SCR_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));
                                break;
 
                        case svc_sellscreen:
-                               Cmd_ExecuteString ("help", src_command);
+                               Cmd_ExecuteString ("help", src_command, true);
                                break;
                        case svc_hidelmp:
                                if (gamemode == GAME_TENEBRAE)
                                {
                                        // repeating particle effect
-                                       MSG_ReadCoord(cls.protocol);
-                                       MSG_ReadCoord(cls.protocol);
-                                       MSG_ReadCoord(cls.protocol);
-                                       MSG_ReadCoord(cls.protocol);
-                                       MSG_ReadCoord(cls.protocol);
-                                       MSG_ReadCoord(cls.protocol);
-                                       (void) MSG_ReadByte();
-                                       MSG_ReadLong();
-                                       MSG_ReadLong();
-                                       MSG_ReadString();
+                                       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();
@@ -4125,17 +4138,17 @@ void CL_ParseServerMessage(void)
                                if (gamemode == GAME_TENEBRAE)
                                {
                                        // particle effect
-                                       MSG_ReadCoord(cls.protocol);
-                                       MSG_ReadCoord(cls.protocol);
-                                       MSG_ReadCoord(cls.protocol);
-                                       (void) MSG_ReadByte();
-                                       MSG_ReadString();
+                                       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());
+                               R_SetSkyBox(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));
                                break;
                        case svc_entities:
                                if (cls.signon == SIGNONS - 1)
@@ -4187,7 +4200,7 @@ void CL_ParseServerMessage(void)
        // implemented
        if (cls.demorecording)
        {
-               CL_WriteDemoMessage (&net_message);
+               CL_WriteDemoMessage (&cl_message);
 //             R_TimeReport("WriteDemo");
        }
 }
@@ -4197,7 +4210,7 @@ void CL_Parse_DumpPacket(void)
        if (!parsingerror)
                return;
        Con_Print("Packet dump:\n");
-       SZ_HexDumpToConsole(&net_message);
+       SZ_HexDumpToConsole(&cl_message);
        parsingerror = false;
 }
 
index 6c28e575f05ef38feab933ddd18b9c1d98d49033..01e9701c2f44e93f2ae6f7876a421e81fc6a27ae 100644 (file)
@@ -101,7 +101,9 @@ typedef struct particleeffectinfo_s
        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;
@@ -248,7 +250,9 @@ particleeffectinfo_t baselineparticleeffectinfo =
        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;
@@ -302,7 +306,7 @@ cvar_t cl_decals_bias = {CVAR_SAVE, "cl_decals_bias", "0.125", "distance to bias
 cvar_t cl_decals_max = {CVAR_SAVE, "cl_decals_max", "4096", "maximum number of decals allowed to exist in the world at once"};
 
 
-void CL_Particles_ParseEffectInfo(const char *textstart, const char *textend, const char *filename)
+static void CL_Particles_ParseEffectInfo(const char *textstart, const char *textend, const char *filename)
 {
        int arrayindex;
        int argc;
@@ -317,7 +321,7 @@ void CL_Particles_ParseEffectInfo(const char *textstart, const char *textend, co
                        argv[arrayindex][0] = 0;
                for (;;)
                {
-                       if (!COM_ParseToken_Simple(&text, true, false))
+                       if (!COM_ParseToken_Simple(&text, true, false, true))
                                return;
                        if (!strcmp(com_token, "\n"))
                                break;
@@ -422,7 +426,9 @@ void CL_Particles_ParseEffectInfo(const char *textstart, const char *textend, co
                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);}
@@ -509,7 +515,7 @@ static const char *standardeffectnames[EFFECT_TOTAL] =
        "SVC_PARTICLE"
 };
 
-void CL_Particles_LoadEffectInfo(void)
+static void CL_Particles_LoadEffectInfo(void)
 {
        int i;
        int filepass;
@@ -651,9 +657,9 @@ particle_t *CL_NewParticle(const vec3_t sortorigin, unsigned short ptypeindex, i
        part->color[2] = ((((pcolor1 >>  0) & 0xFF) * l1 + ((pcolor2 >>  0) & 0xFF) * l2) >> 8) & 0xFF;
        if (vid.sRGB3D)
        {
-               part->color[0] = (unsigned char)(Image_LinearFloatFromsRGB(part->color[0]) * 256.0f);
-               part->color[1] = (unsigned char)(Image_LinearFloatFromsRGB(part->color[1]) * 256.0f);
-               part->color[2] = (unsigned char)(Image_LinearFloatFromsRGB(part->color[2]) * 256.0f);
+               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;
@@ -891,7 +897,7 @@ void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size,
 
 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);
-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)
+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;
@@ -1417,6 +1423,7 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o
 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);
@@ -1432,6 +1439,11 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins
                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;
@@ -1485,7 +1497,7 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins
                                                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("cubemaps/%i", info->lightcubemapnum) : NULL, info->lightshadow, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+                                               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, 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++;
                                        }
                                }
@@ -1508,9 +1520,22 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins
                                        staintex = min(staintex, info->staintex[1] - 1);
                                }
                                if (info->particletype == pt_decal)
-                                       CL_SpawnDecalParticleForPoint(center, 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]);
+                               {
+                                       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)
-                                       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], originmins[1], originmins[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);
+                               {
+                                       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)
@@ -1531,6 +1556,11 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins
                                                info->particleaccumulator += traillen / info->trailspacing * cl_particles_quality.value * pcount;
                                                trailstep = info->trailspacing / cl_particles_quality.value / max(0.001, pcount);
                                                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
                                        {
@@ -1540,6 +1570,12 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins
                                                        ((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--)
@@ -1561,7 +1597,7 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins
                                                        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], lhrandom(velocitymins[1], velocitymaxs[1]) * info->velocitymultiplier + info->velocityoffset[1] + info->velocityjitter[1] * rvec[1], lhrandom(velocitymins[2], velocitymaxs[2]) * info->velocitymultiplier + info->velocityoffset[2] + info->velocityjitter[2] * rvec[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);
+                                               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;
@@ -1687,11 +1723,11 @@ void CL_ParseParticleEffect (void)
        vec3_t org, dir;
        int i, count, msgcount, color;
 
-       MSG_ReadVector(org, cls.protocol);
+       MSG_ReadVector(&cl_message, org, cls.protocol);
        for (i=0 ; i<3 ; i++)
-               dir[i] = MSG_ReadChar () * (1.0 / 16.0);
-       msgcount = MSG_ReadByte ();
-       color = MSG_ReadByte ();
+               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;
@@ -1930,7 +1966,7 @@ static unsigned char shadebubble(float dx, float dy, vec3_t light)
 }
 
 int particlefontwidth, particlefontheight, particlefontcellwidth, particlefontcellheight, particlefontrows, particlefontcols;
-void CL_Particle_PixelCoordsForTexnum(int texnum, int *basex, int *basey, int *width, int *height)
+static void CL_Particle_PixelCoordsForTexnum(int texnum, int *basex, int *basey, int *width, int *height)
 {
        *basex = (texnum % particlefontcols) * particlefontcellwidth;
        *basey = ((texnum / particlefontcols) % particlefontrows) * particlefontcellheight;
@@ -1948,7 +1984,7 @@ static void setuptex(int texnum, unsigned char *data, unsigned char *particletex
                memcpy(particletexturedata + ((basey + y) * PARTICLEFONTSIZE + basex) * 4, data + y * PARTICLETEXTURESIZE * 4, PARTICLETEXTURESIZE * 4);
 }
 
-void particletextureblotch(unsigned char *data, float radius, float red, float green, float blue, float alpha)
+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;
@@ -1977,7 +2013,8 @@ void particletextureblotch(unsigned char *data, float radius, float red, float g
        }
 }
 
-void particletextureclamp(unsigned char *data, int minr, int ming, int minb, int maxr, int maxg, int maxb)
+#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)
@@ -1987,8 +2024,9 @@ void particletextureclamp(unsigned char *data, int minr, int ming, int minb, int
                data[2] = bound(minr, data[2], maxr);
        }
 }
+#endif
 
-void particletextureinvert(unsigned char *data)
+static void particletextureinvert(unsigned char *data)
 {
        int i;
        for (i = 0;i < PARTICLETEXTURESIZE*PARTICLETEXTURESIZE;i++, data += 4)
@@ -2259,7 +2297,7 @@ static void R_InitParticleTexture (void)
                bufptr = buf;
                for(;;)
                {
-                       if(!COM_ParseToken_Simple(&bufptr, true, false))
+                       if(!COM_ParseToken_Simple(&bufptr, true, false, true))
                                break;
                        if(!strcmp(com_token, "\n"))
                                continue; // empty line
@@ -2271,22 +2309,22 @@ static void R_InitParticleTexture (void)
                        s2 = 1;
                        t2 = 1;
 
-                       if (COM_ParseToken_Simple(&bufptr, true, false) && strcmp(com_token, "\n"))
+                       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) && strcmp(com_token, "\n"))
+                               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) && strcmp(com_token, "\n"))
+                                       if (COM_ParseToken_Simple(&bufptr, true, false, true) && strcmp(com_token, "\n"))
                                        {
                                                s2 = atof(com_token);
-                                               if (COM_ParseToken_Simple(&bufptr, true, false) && strcmp(com_token, "\n"))
+                                               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) && strcmp(com_token, "\n"))
+                                                       if (COM_ParseToken_Simple(&bufptr, true, false, true) && strcmp(com_token, "\n"))
                                                                strlcpy(texturename, com_token, sizeof(texturename));
                                                }
                                        }
@@ -2304,7 +2342,7 @@ static void R_InitParticleTexture (void)
                                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);
+                       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
@@ -2368,7 +2406,7 @@ void R_Particles_Init (void)
        R_RegisterModule("R_Particles", r_part_start, r_part_shutdown, r_part_newmap, NULL, NULL);
 }
 
-void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
+static void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
 {
        int surfacelistindex;
        const decal_t *d;
@@ -2436,7 +2474,7 @@ void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rtlight_t
        // 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);
+       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);
 }
@@ -2495,7 +2533,7 @@ void R_DrawDecals (void)
                        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(decal->org, R_DrawDecal_TransparentCallback, NULL, i, NULL);
+                       R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, decal->org, R_DrawDecal_TransparentCallback, NULL, i, NULL);
                continue;
 killdecal:
                decal->typeindex = 0;
@@ -2519,7 +2557,7 @@ killdecal:
        r_refdef.stats.totaldecals = cl.num_decals;
 }
 
-void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
+static void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
 {
        int surfacelistindex;
        int batchstart, batchcount;
@@ -2746,7 +2784,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh
                if (texture != particletexture[p->texnum].texture)
                {
                        texture = particletexture[p->texnum].texture;
-                       R_SetupShader_Generic(texture, NULL, GL_MODULATE, 1, false);
+                       R_SetupShader_Generic(texture, NULL, GL_MODULATE, 1, false, false, false);
                }
 
                if (p->blendmode == PBLEND_INVMOD)
@@ -2974,7 +3012,7 @@ void R_DrawParticles (void)
                {
                case pt_beam:
                        // beams have no culling
-                       R_MeshQueue_AddTransparent(p->sortorigin, R_DrawParticle_TransparentCallback, NULL, i, NULL);
+                       R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, p->sortorigin, R_DrawParticle_TransparentCallback, NULL, i, NULL);
                        break;
                default:
                        if(cl_particles_visculling.integer)
@@ -2988,7 +3026,7 @@ void R_DrawParticles (void)
                                        }
                        // 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(p->sortorigin, R_DrawParticle_TransparentCallback, NULL, i, NULL);
+                               R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, p->sortorigin, R_DrawParticle_TransparentCallback, NULL, i, NULL);
                        break;
                }
 
index f9c2086aae1978294f9f39b1f64c1a050929b947..7724b5ce28c0a54a8e62a87a6ee61049062476da 100644 (file)
@@ -51,6 +51,7 @@ cvar_t scr_screenshot_png = {CVAR_SAVE, "scr_screenshot_png","0", "save png inst
 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_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)"};
@@ -71,10 +72,6 @@ cvar_t r_stereo_redblue = {0, "r_stereo_redblue", "0", "red/blue anaglyph stereo
 cvar_t r_stereo_redcyan = {0, "r_stereo_redcyan", "0", "red/cyan anaglyph stereo glasses, the kind given away at drive-in movies like Creature From The Black Lagoon In 3D"};
 cvar_t r_stereo_redgreen = {0, "r_stereo_redgreen", "0", "red/green anaglyph stereo glasses (for those who don't mind yellow)"};
 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_zoomwindow = {CVAR_SAVE, "scr_zoomwindow", "0", "displays a zoomed in overlay window"};
-cvar_t scr_zoomwindow_viewsizex = {CVAR_SAVE, "scr_zoomwindow_viewsizex", "20", "horizontal viewsize of zoom window"};
-cvar_t scr_zoomwindow_viewsizey = {CVAR_SAVE, "scr_zoomwindow_viewsizey", "20", "vertical viewsize of zoom window"};
-cvar_t scr_zoomwindow_fov = {CVAR_SAVE, "scr_zoomwindow_fov", "20", "fov of zoom window"};
 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"};
@@ -146,7 +143,7 @@ void SCR_CenterPrint(const char *str)
 }
 
 
-void SCR_DrawCenterString (void)
+static void SCR_DrawCenterString (void)
 {
        char    *start;
        int             x, y;
@@ -203,7 +200,7 @@ void SCR_DrawCenterString (void)
        } while (1);
 }
 
-void SCR_CheckDrawCenterString (void)
+static void SCR_CheckDrawCenterString (void)
 {
        if (scr_center_lines > scr_erase_lines)
                scr_erase_lines = scr_center_lines;
@@ -223,7 +220,7 @@ void SCR_CheckDrawCenterString (void)
        SCR_DrawCenterString ();
 }
 
-void SCR_DrawNetGraph_DrawGraph (int graphx, int graphy, int graphwidth, int graphheight, float graphscale, const char *label, float textsize, int packetcounter, netgraphitem_t *netgraph)
+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;
@@ -311,11 +308,12 @@ void SCR_DrawNetGraph_DrawGraph (int graphx, int graphy, int graphwidth, int gra
 SCR_DrawNetGraph
 ==============
 */
-void SCR_DrawNetGraph (void)
+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;
@@ -351,7 +349,7 @@ void SCR_DrawNetGraph (void)
                                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("%s", svs.clients[i].name), textsize, c->outgoing_packetcounter, c->outgoing_netgraph);
+                       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++;
                }
@@ -363,7 +361,7 @@ void SCR_DrawNetGraph (void)
 SCR_DrawTurtle
 ==============
 */
-void SCR_DrawTurtle (void)
+static void SCR_DrawTurtle (void)
 {
        static int      count;
 
@@ -391,7 +389,7 @@ void SCR_DrawTurtle (void)
 SCR_DrawNet
 ==============
 */
-void SCR_DrawNet (void)
+static void SCR_DrawNet (void)
 {
        if (cls.state != ca_connected)
                return;
@@ -408,7 +406,7 @@ void SCR_DrawNet (void)
 DrawPause
 ==============
 */
-void SCR_DrawPause (void)
+static void SCR_DrawPause (void)
 {
        cachepic_t      *pic;
 
@@ -430,7 +428,7 @@ void SCR_DrawPause (void)
 SCR_DrawBrand
 ==============
 */
-void SCR_DrawBrand (void)
+static void SCR_DrawBrand (void)
 {
        cachepic_t      *pic;
        float           x, y;
@@ -552,9 +550,10 @@ static int SCR_DrawCurlDownload(int offset)
        float size = scr_infobar_height.value;
        Curl_downloadinfo_t *downinfo;
        char temp[256];
+       char addinfobuf[128];
        const char *addinfo;
 
-       downinfo = Curl_GetDownloadInfo(&nDownloads, &addinfo);
+       downinfo = Curl_GetDownloadInfo(&nDownloads, &addinfo, addinfobuf, sizeof(addinfobuf));
        if(!downinfo)
                return 0;
 
@@ -609,6 +608,7 @@ static int SCR_InfobarHeight(void)
        Curl_downloadinfo_t *downinfo;
        const char *addinfo;
        int nDownloads;
+       char addinfobuf[128];
 
        if (cl.time > cl.oldtime)
                scr_infobartime_off -= cl.time - cl.oldtime;
@@ -617,7 +617,7 @@ static int SCR_InfobarHeight(void)
        if(cls.qw_downloadname[0])
                offset += 1;
 
-       downinfo = Curl_GetDownloadInfo(&nDownloads, &addinfo);
+       downinfo = Curl_GetDownloadInfo(&nDownloads, &addinfo, addinfobuf, sizeof(addinfobuf));
        if(downinfo)
        {
                offset += (nDownloads + (addinfo ? 1 : 0));
@@ -633,7 +633,7 @@ static int SCR_InfobarHeight(void)
 SCR_InfoBar_f
 ==============
 */
-void SCR_InfoBar_f(void)
+static void SCR_InfoBar_f(void)
 {
        if(Cmd_Argc() == 3)
        {
@@ -652,7 +652,7 @@ void SCR_InfoBar_f(void)
 SCR_SetUpToDrawConsole
 ==================
 */
-void SCR_SetUpToDrawConsole (void)
+static void SCR_SetUpToDrawConsole (void)
 {
        // lines of console to display
        float conlines;
@@ -739,7 +739,7 @@ void R_TimeReport(const char *desc)
                GL_Finish();
        CHECKGLERROR
        r_timereport_temp = r_timereport_current;
-       r_timereport_current = Sys_DoubleTime();
+       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);
@@ -759,7 +759,7 @@ void R_TimeReport(const char *desc)
        speedstringcount += length;
 }
 
-void R_TimeReport_BeginFrame(void)
+static void R_TimeReport_BeginFrame(void)
 {
        speedstringcount = 0;
        r_speeds_timestring[0] = 0;
@@ -769,7 +769,7 @@ void R_TimeReport_BeginFrame(void)
        if (r_speeds.integer >= 2)
        {
                r_timereport_active = true;
-               r_timereport_start = r_timereport_current = Sys_DoubleTime();
+               r_timereport_start = r_timereport_current = Sys_DirtyTime();
        }
 }
 
@@ -783,7 +783,7 @@ static int R_CountLeafTriangles(const dp_model_t *model, const mleaf_t *leaf)
 
 extern cvar_t r_viewscale;
 extern float viewscalefpsadjusted;
-void R_TimeReport_EndFrame(void)
+static void R_TimeReport_EndFrame(void)
 {
        int i, j, lines, y;
        cl_locnode_t *loc;
@@ -798,7 +798,7 @@ void R_TimeReport_EndFrame(void)
                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),
-"%6.0fus rendertime %3.0f%% viewscale %s%s %.3f cl.time\n"
+"%6.0fus rendertime %3.0f%% viewscale %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"
@@ -810,7 +810,7 @@ void R_TimeReport_EndFrame(void)
 "%6i draws%8i vertices%8i triangles bloompixels%8i copied%8i drawn\n"
 "updated%5i indexbuffers%8i bytes%5i vertexbuffers%8i bytes\n"
 "%s"
-, r_refdef.lastdrawscreentime * 1000000.0, r_viewscale.value * sqrt(viewscalefpsadjusted) * 100.0f, loc ? "Location: " : "", loc ? loc->name : "", cl.time
+, r_refdef.lastdrawscreentime * 1000000.0, r_viewscale.value * sqrt(viewscalefpsadjusted) * 100.0f, loc ? "Location: " : "", loc ? loc->name : "", cl.time, r_refdef.view.colorscale
 , r_refdef.stats.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.world_surfaces, r_refdef.stats.world_triangles, r_refdef.stats.entities, r_refdef.stats.entities_surfaces, r_refdef.stats.entities_triangles
@@ -832,7 +832,7 @@ void R_TimeReport_EndFrame(void)
                if (r_speeds.integer >= 2)
                {
                        r_timereport_active = true;
-                       r_timereport_start = r_timereport_current = Sys_DoubleTime();
+                       r_timereport_start = r_timereport_current = Sys_DirtyTime();
                }
        }
 
@@ -870,7 +870,7 @@ SCR_SizeUp_f
 Keybinding command
 =================
 */
-void SCR_SizeUp_f (void)
+static void SCR_SizeUp_f (void)
 {
        Cvar_SetValue ("viewsize",scr_viewsize.value+10);
 }
@@ -883,7 +883,7 @@ SCR_SizeDown_f
 Keybinding command
 =================
 */
-void SCR_SizeDown_f (void)
+static void SCR_SizeDown_f (void)
 {
        Cvar_SetValue ("viewsize",scr_viewsize.value-10);
 }
@@ -935,6 +935,7 @@ void CL_Screen_Init(void)
        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_printfps);
        Cvar_RegisterVariable (&cl_capturevideo_width);
@@ -954,10 +955,6 @@ void CL_Screen_Init(void)
        Cvar_RegisterVariable(&r_stereo_redcyan);
        Cvar_RegisterVariable(&r_stereo_redgreen);
        Cvar_RegisterVariable(&r_stereo_angle);
-       Cvar_RegisterVariable(&scr_zoomwindow);
-       Cvar_RegisterVariable(&scr_zoomwindow_viewsizex);
-       Cvar_RegisterVariable(&scr_zoomwindow_viewsizey);
-       Cvar_RegisterVariable(&scr_zoomwindow_fov);
        Cvar_RegisterVariable(&scr_stipple);
        Cvar_RegisterVariable(&scr_refresh);
        Cvar_RegisterVariable(&shownetgraph);
@@ -966,6 +963,10 @@ void CL_Screen_Init(void)
        Cvar_RegisterVariable(&vid_touchscreen_outlinealpha);
        Cvar_RegisterVariable(&vid_touchscreen_overlayalpha);
 
+       // 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");
@@ -992,6 +993,7 @@ void SCR_ScreenShot_f (void)
        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)
        {
@@ -1019,14 +1021,41 @@ void SCR_ScreenShot_f (void)
                        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));
+                       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));
+                       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 );
@@ -1035,15 +1064,19 @@ void SCR_ScreenShot_f (void)
 
                // find a file name to save it to
                for (;shotnumber < 1000000;shotnumber++)
-                       if (!FS_SysFileExists(va("%s/screenshots/%s%06d.tga", fs_gamedir, prefix_name, shotnumber)) && !FS_SysFileExists(va("%s/screenshots/%s%06d.jpg", fs_gamedir, prefix_name, shotnumber)) && !FS_SysFileExists(va("%s/screenshots/%s%06d.png", fs_gamedir, prefix_name, 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\n");
+                       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);
@@ -1066,11 +1099,9 @@ void SCR_ScreenShot_f (void)
 
        Mem_Free (buffer1);
        Mem_Free (buffer2);
-
-       shotnumber++;
 }
 
-void SCR_CaptureVideo_BeginVideo(void)
+static void SCR_CaptureVideo_BeginVideo(void)
 {
        double r, g, b;
        unsigned int i;
@@ -1105,7 +1136,7 @@ void SCR_CaptureVideo_BeginVideo(void)
        cls.capturevideo.soundchannels = S_GetSoundChannels();
        cls.capturevideo.startrealtime = realtime;
        cls.capturevideo.frame = cls.capturevideo.lastfpsframe = 0;
-       cls.capturevideo.starttime = cls.capturevideo.lastfpstime = Sys_DoubleTime();
+       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);
@@ -1263,7 +1294,7 @@ static void SCR_ScaleDownBGRA(unsigned char *in, int inw, int inh, unsigned char
        }
 }
 
-void SCR_CaptureVideo_VideoFrame(int newframestepframenum)
+static void SCR_CaptureVideo_VideoFrame(int newframestepframenum)
 {
        int x = 0, y = 0;
        int width = cls.capturevideo.width, height = cls.capturevideo.height;
@@ -1284,7 +1315,7 @@ void SCR_CaptureVideo_VideoFrame(int newframestepframenum)
        if(cl_capturevideo_printfps.integer)
        {
                char buf[80];
-               double t = Sys_DoubleTime();
+               double t = realtime;
                if(t > cls.capturevideo.lastfpstime + 1)
                {
                        double fps1 = (cls.capturevideo.frame - cls.capturevideo.lastfpsframe) / (t - cls.capturevideo.lastfpstime + 0.0000001);
@@ -1303,7 +1334,7 @@ void SCR_CaptureVideo_SoundFrame(const portable_sampleframe_t *paintbuffer, size
        cls.capturevideo.soundframe(paintbuffer, length);
 }
 
-void SCR_CaptureVideo(void)
+static void SCR_CaptureVideo(void)
 {
        int newframenum;
        if (cl_capturevideo.integer)
@@ -1418,6 +1449,8 @@ static void R_Envmap_f (void)
 
        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);
@@ -1446,7 +1479,7 @@ void SHOWLMP_decodehide(void)
 {
        int i;
        char *lmplabel;
-       lmplabel = MSG_ReadString();
+       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)
                {
@@ -1460,17 +1493,17 @@ void SHOWLMP_decodeshow(void)
        int k;
        char lmplabel[256], picname[256];
        float x, y;
-       strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
-       strlcpy (picname, MSG_ReadString(), sizeof (picname));
+       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();
-               y = MSG_ReadByte();
+               x = MSG_ReadByte(&cl_message);
+               y = MSG_ReadByte(&cl_message);
        }
        else
        {
-               x = MSG_ReadShort();
-               y = MSG_ReadShort();
+               x = MSG_ReadShort(&cl_message);
+               y = MSG_ReadShort(&cl_message);
        }
        if (!cl.showlmps || cl.num_showlmps >= cl.max_showlmps)
        {
@@ -1608,17 +1641,15 @@ static void SCR_DrawTouchscreenOverlay(void)
        }
 }
 
-extern void R_UpdateFogColor(void);
 void R_ClearScreen(qboolean fogcolor)
 {
        float clearcolor[4];
        // clear to black
        Vector4Clear(clearcolor);
-       if (fogcolor)
+       if (fogcolor && r_fog_clear.integer)
        {
-               R_UpdateFogColor();
-               if (r_fog_clear.integer)
-                       VectorCopy(r_refdef.fogcolor, clearcolor);
+               R_UpdateFog();
+               VectorCopy(r_refdef.fogcolor, clearcolor);
        }
        // clear depth is 1.0
        // LordHavoc: we use a stencil centered around 128 instead of 0,
@@ -1628,14 +1659,9 @@ void R_ClearScreen(qboolean fogcolor)
        GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | (vid.stencil ? GL_STENCIL_BUFFER_BIT : 0), clearcolor, 1.0f, 128);
 }
 
-qboolean CL_VM_UpdateView (void);
-void SCR_DrawConsole (void);
-void R_Shadow_EditLights_DrawSelectedLightProperties(void);
-
 int r_stereo_side;
 
-extern void Sbar_ShowFPS(void);
-void SCR_DrawScreen (void)
+static void SCR_DrawScreen (void)
 {
        Draw_Frame();
 
@@ -1709,31 +1735,11 @@ void SCR_DrawScreen (void)
 
                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_RenderView();
-
-               if (scr_zoomwindow.integer)
-               {
-                       float sizex = bound(10, scr_zoomwindow_viewsizex.value, 100) / 100.0;
-                       float sizey = bound(10, scr_zoomwindow_viewsizey.value, 100) / 100.0;
-                       r_refdef.view.width = (int)(vid.width * sizex);
-                       r_refdef.view.height = (int)(vid.height * sizey);
-                       r_refdef.view.depth = 1;
-                       r_refdef.view.x = (int)((vid.width - r_refdef.view.width)/2);
-                       r_refdef.view.y = 0;
-                       r_refdef.view.z = 0;
-
-                       r_refdef.view.useperspective = true;
-                       r_refdef.view.frustum_y = tan(scr_zoomwindow_fov.value * M_PI / 360.0) * (3.0/4.0) * cl.viewzoom;
-                       r_refdef.view.frustum_x = r_refdef.view.frustum_y * vid_pixelheight.value * (float)r_refdef.view.width / (float)r_refdef.view.height;
-
-                       r_refdef.view.frustum_x *= r_refdef.frustumscale_x;
-                       r_refdef.view.frustum_y *= r_refdef.frustumscale_y;
-
-                       if(!CL_VM_UpdateView())
-                               R_RenderView();
-               }
        }
 
        if (!r_stereo_sidebyside.integer && !r_stereo_horizontal.integer && !r_stereo_vertical.integer)
@@ -2006,7 +2012,7 @@ static void SCR_DrawLoadingStack(void)
                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(NULL, NULL, GL_MODULATE, 1, true);
+               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
@@ -2023,13 +2029,14 @@ 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_ResetRenderTargets();
+       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
@@ -2039,7 +2046,7 @@ static void SCR_DrawLoadingScreen_SharedSetup (qboolean clear)
        R_Mesh_Start();
        R_EntityMatrix(&identitymatrix);
        // draw the loading plaque
-       loadingscreenpic = Draw_CachePic_Flags (loadingscreenpic_number ? va("gfx/loading%d", loadingscreenpic_number+1) : "gfx/loading", loadingscreenpic_number ? CACHEPICFLAG_NOTPERSISTENT : 0);
+       loadingscreenpic = Draw_CachePic_Flags (loadingscreenpic_number ? va(vabuf, sizeof(vabuf), "gfx/loading%d", loadingscreenpic_number+1) : "gfx/loading", loadingscreenpic_number ? CACHEPICFLAG_NOTPERSISTENT : 0);
 
        w = loadingscreenpic->width;
        h = loadingscreenpic->height;
@@ -2105,11 +2112,11 @@ static void SCR_DrawLoadingScreen (qboolean clear)
        if(loadingscreentexture)
        {
                R_Mesh_PrepareVertices_Generic_Arrays(4, loadingscreentexture_vertex3f, NULL, loadingscreentexture_texcoord2f);
-               R_SetupShader_Generic(loadingscreentexture, NULL, GL_MODULATE, 1, true);
+               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);
+       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();
 }
@@ -2151,6 +2158,10 @@ void SCR_UpdateLoadingScreen (qboolean clear)
        }
        loadingscreencleared = clear;
 
+#ifdef USE_GLES2
+       SCR_DrawLoadingScreen_SharedSetup(clear);
+       SCR_DrawLoadingScreen(clear);
+#else
        if (qglDrawBuffer)
                qglDrawBuffer(GL_BACK);
        SCR_DrawLoadingScreen_SharedSetup(clear);
@@ -2167,6 +2178,7 @@ void SCR_UpdateLoadingScreen (qboolean clear)
                        qglDrawBuffer(GL_BACK);
                SCR_DrawLoadingScreen(clear);
        }
+#endif
        SCR_DrawLoadingScreen_SharedFinish(clear);
 
        // this goes into the event loop, and should prevent unresponsive cursor on vista
@@ -2198,7 +2210,6 @@ extern cvar_t cl_minfps_qualityscale;
 extern cvar_t r_viewscale_fpsscaling;
 static double cl_updatescreen_rendertime = 0;
 static double cl_updatescreen_quality = 1;
-extern void Sbar_ShowFPS_Update(void);
 void CL_UpdateScreen(void)
 {
        vec3_t vieworigin;
@@ -2234,7 +2245,7 @@ void CL_UpdateScreen(void)
                return;
        }
 
-       rendertime1 = Sys_DoubleTime();
+       rendertime1 = Sys_DirtyTime();
 
        conwidth = bound(160, vid_conwidth.value, 32768);
        conheight = bound(90, vid_conheight.value, 24576);
@@ -2277,6 +2288,7 @@ void CL_UpdateScreen(void)
 
        SCR_SetUpToDrawConsole();
 
+#ifndef USE_GLES2
        if (qglDrawBuffer)
        {
                CHECKGLERROR
@@ -2291,9 +2303,10 @@ void CL_UpdateScreen(void)
                        qglDisable(GL_DITHER);CHECKGLERROR
                }
        }
+#endif
 
        R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, vid.width, vid.height, 0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100, NULL);
-       R_Mesh_ResetRenderTargets();
+       R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
        R_SetViewport(&viewport);
        GL_ScissorTest(false);
        GL_ColorMask(1,1,1,1);
@@ -2305,6 +2318,7 @@ void CL_UpdateScreen(void)
        f = pow((float)cl_updatescreen_quality, cl_minfps_qualitypower.value) * cl_minfps_qualityscale.value;
        r_refdef.view.quality = bound(cl_minfps_qualitymin.value, f, cl_minfps_qualitymax.value);
 
+#ifndef USE_GLES2
        if (qglPolygonStipple)
        {
                if(scr_stipple.integer)
@@ -2331,10 +2345,12 @@ void CL_UpdateScreen(void)
                        qglDisable(GL_POLYGON_STIPPLE);CHECKGLERROR
                }
        }
+#endif
 
        if (r_viewscale_fpsscaling.integer)
                GL_Finish();
-       drawscreenstart = Sys_DoubleTime();
+       drawscreenstart = Sys_DirtyTime();
+#ifndef USE_GLES2
        if (R_Stereo_Active())
        {
                r_stereo_side = 0;
@@ -2352,6 +2368,7 @@ void CL_UpdateScreen(void)
                SCR_DrawScreen();
 
                r_stereo_side = 1;
+               r_refdef.view.clear = true;
 
                if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
                {
@@ -2366,10 +2383,11 @@ void CL_UpdateScreen(void)
                SCR_DrawScreen();
        }
        else
+#endif
                SCR_DrawScreen();
        if (r_viewscale_fpsscaling.integer)
                GL_Finish();
-       r_refdef.lastdrawscreentime = Sys_DoubleTime() - drawscreenstart;
+       r_refdef.lastdrawscreentime = Sys_DirtyTime() - drawscreenstart;
 
        SCR_CaptureVideo();
 
@@ -2377,7 +2395,7 @@ void CL_UpdateScreen(void)
                qglFlush(); // FIXME: should we really be using qglFlush here?
 
        // quality adjustment according to render time
-       cl_updatescreen_rendertime += ((Sys_DoubleTime() - rendertime1) - cl_updatescreen_rendertime) * bound(0, cl_minfps_fade.value, 1);
+       cl_updatescreen_rendertime += ((Sys_DirtyTime() - rendertime1) - cl_updatescreen_rendertime) * bound(0, cl_minfps_fade.value, 1);
        if (cl_minfps.value > 0 && cl_updatescreen_rendertime > 0 && !cls.timedemo && (!cls.capturevideo.active || !cls.capturevideo.realtime))
                cl_updatescreen_quality = 1 / (cl_updatescreen_rendertime * cl_minfps.value);
        else
index 4e37eb7548dc46ab6220bacb921991c93e34ff79..08db0588845caa8a6cea0d8e7ef9a9d367a14129 100644 (file)
@@ -418,7 +418,7 @@ typedef struct
 }
 cl_video_subtitle_info_t;
 
-float CL_DrawVideo_WordWidthFunc(void *passthrough, const char *w, size_t *length, float maxWidth)
+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;
 
@@ -432,7 +432,7 @@ float CL_DrawVideo_WordWidthFunc(void *passthrough, const char *w, size_t *lengt
                return 0;
 }
 
-int CL_DrawVideo_DisplaySubtitleLine(void *passthrough, const char *line, size_t length, float width, qboolean isContinuation)
+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;
 
@@ -521,6 +521,7 @@ void CL_DrawVideo(void)
        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)
        {
@@ -538,13 +539,16 @@ void CL_DrawVideo(void)
                }
                qglPolygonStipple(stipple);CHECKGLERROR
        }
+#endif
 
        // draw video
        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);
 
+#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)
@@ -573,12 +577,13 @@ void CL_DrawVideo(void)
 
 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( CLDYNTEXTUREPREFIX "%s", filename ), 0, subtitlesfile ) )
+       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);
index a652dbc221734955ef5480e630fb9ecd1f5da783..da65ef298e96bbb42da1da2f99c20571cb149532 100644 (file)
@@ -41,7 +41,7 @@ unsigned int jam_getwidth(void *stream);
 unsigned int jam_getheight(void *stream);
 double jam_getframerate(void *stream);
 int jam_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow);
-void *jam_open(clvideo_t *video, char *filename, const char **errorstring)
+static void *jam_open(clvideo_t *video, char *filename, const char **errorstring)
 {
        unsigned char jamHead[16];
        char *wavename;
@@ -176,7 +176,7 @@ double jam_getframerate(void *stream)
 
 
 // decode JAM frame
-void jam_decodeframe(unsigned char *inbuf, unsigned char *outbuf, unsigned char *prevbuf, int outsize, int frametype)
+static void jam_decodeframe(unsigned char *inbuf, unsigned char *outbuf, unsigned char *prevbuf, int outsize, int frametype)
 {
        unsigned char *srcptr, *destptr, *prevptr;
        int bytesleft;
index 57d50dd1bcfa3dce58ccd243943370dcd9f9a494..f28e5adb78cdfef974f843555895af22ac927d90 100644 (file)
@@ -580,7 +580,7 @@ typedef struct capturevideostate_s
        const char *formatextension;
        qfile_t *videofile;
                // always use this:
-               //   cls.capturevideo.videofile = FS_OpenRealFile(va("%s.%s", cls.capturevideo.basename, cls.capturevideo.formatextension), "wb", false);
+               //   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);
@@ -632,6 +632,7 @@ typedef struct client_static_s
        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;
@@ -1409,7 +1410,7 @@ extern int cl_ignoremousemoves;
 
 
 float CL_KeyState (kbutton_t *key);
-const char *Key_KeynumToString (int keynum);
+const char *Key_KeynumToString (int keynum, char *buf, size_t buflength);
 int Key_StringToKeynum (const char *str);
 
 //
@@ -1661,16 +1662,18 @@ typedef struct r_refdef_view_s
        // which color components to allow (for anaglyph glasses)
        int colormask[4];
 
-       // global RGB color multiplier for rendering, this is required by HDR
+       // 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 (HDR, mirrors, portals, cameras,
+       // view render, all secondary renders (mirrors, portals, cameras,
        // distortion effects, etc) omit such debugging information
        qboolean showdebug;
 
@@ -1835,8 +1838,60 @@ 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
+{
+       // 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(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);
+void V_CalcRefdef(void);
+void CL_Locs_Reload_f(void);
+
 #endif
 
index 5b0b804360474f9f11edcb170be92772be8ce12f..f07cf854b2535918929c3508540ee4441f649fa4 100644 (file)
 extern cvar_t v_flipped;
 extern cvar_t r_equalize_entities_fullbright;
 
-sfx_t *S_FindName(const char *name);
-int Sbar_GetSortedPlayerIndex (int index);
-void Sbar_SortFrags (void);
-void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius);
-void CSQC_RelinkAllEntities (int drawmask);
-void CSQC_RelinkCSQCEntities (void);
+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 (void)
+static void VM_CL_makevectors (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_CL_makevectors);
        AngleVectors (PRVM_G_VECTOR(OFS_PARM0), PRVM_clientglobalvector(v_forward), PRVM_clientglobalvector(v_right), PRVM_clientglobalvector(v_up));
 }
 
 // #2 void(entity e, vector o) setorigin
-void VM_CL_setorigin (void)
+static void VM_CL_setorigin (prvm_prog_t *prog)
 {
        prvm_edict_t    *e;
        float   *org;
@@ -47,26 +43,28 @@ void VM_CL_setorigin (void)
        e = PRVM_G_EDICT(OFS_PARM0);
        if (e == prog->edicts)
        {
-               VM_Warning("setorigin: can not modify world entity\n");
+               VM_Warning(prog, "setorigin: can not modify world entity\n");
                return;
        }
        if (e->priv.required->free)
        {
-               VM_Warning("setorigin: can not modify free entity\n");
+               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 SetMinMaxSize (prvm_edict_t *e, float *min, float *max)
+static void SetMinMaxSize (prvm_prog_t *prog, prvm_edict_t *e, float *min, float *max)
 {
        int             i;
 
        for (i=0 ; i<3 ; i++)
                if (min[i] > max[i])
-                       PRVM_ERROR("SetMinMaxSize: backwards mins/maxs");
+                       prog->error_cmd("SetMinMaxSize: backwards mins/maxs");
 
        // set derived values
        VectorCopy (min, PRVM_clientedictvector(e, mins));
@@ -77,7 +75,7 @@ static void SetMinMaxSize (prvm_edict_t *e, float *min, float *max)
 }
 
 // #3 void(entity e, string m) setmodel
-void VM_CL_setmodel (void)
+static void VM_CL_setmodel (prvm_prog_t *prog)
 {
        prvm_edict_t    *e;
        const char              *m;
@@ -97,7 +95,7 @@ void VM_CL_setmodel (void)
                if (!strcmp(cl.csqc_model_precache[i]->name, m))
                {
                        mod = cl.csqc_model_precache[i];
-                       PRVM_clientedictstring(e, model) = PRVM_SetEngineString(mod->name);
+                       PRVM_clientedictstring(e, model) = PRVM_SetEngineString(prog, mod->name);
                        PRVM_clientedictfloat(e, modelindex) = -(i+1);
                        break;
                }
@@ -109,7 +107,7 @@ void VM_CL_setmodel (void)
                        mod = cl.model_precache[i];
                        if (mod && !strcmp(mod->name, m))
                        {
-                               PRVM_clientedictstring(e, model) = PRVM_SetEngineString(mod->name);
+                               PRVM_clientedictstring(e, model) = PRVM_SetEngineString(prog, mod->name);
                                PRVM_clientedictfloat(e, modelindex) = i;
                                break;
                        }
@@ -122,13 +120,13 @@ void VM_CL_setmodel (void)
        }
        else
        {
-               SetMinMaxSize (e, vec3_origin, vec3_origin);
-               VM_Warning ("setmodel: model '%s' not precached\n", m);
+               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 (void)
+static void VM_CL_setsize (prvm_prog_t *prog)
 {
        prvm_edict_t    *e;
        float                   *min, *max;
@@ -137,24 +135,24 @@ static void VM_CL_setsize (void)
        e = PRVM_G_EDICT(OFS_PARM0);
        if (e == prog->edicts)
        {
-               VM_Warning("setsize: can not modify world entity\n");
+               VM_Warning(prog, "setsize: can not modify world entity\n");
                return;
        }
        if (e->priv.server->free)
        {
-               VM_Warning("setsize: can not modify free entity\n");
+               VM_Warning(prog, "setsize: can not modify free entity\n");
                return;
        }
        min = PRVM_G_VECTOR(OFS_PARM1);
        max = PRVM_G_VECTOR(OFS_PARM2);
 
-       SetMinMaxSize( e, min, max );
+       SetMinMaxSize( prog, e, min, max );
 
        CL_LinkEdict(e);
 }
 
 // #8 void(entity e, float chan, string samp, float volume, float atten) sound
-static void VM_CL_sound (void)
+static void VM_CL_sound (prvm_prog_t *prog)
 {
        const char                      *sample;
        int                                     channel;
@@ -175,13 +173,13 @@ static void VM_CL_sound (void)
 
        if (volume < 0 || volume > 1)
        {
-               VM_Warning("VM_CL_sound: volume must be in range 0-1\n");
+               VM_Warning(prog, "VM_CL_sound: volume must be in range 0-1\n");
                return;
        }
 
        if (attenuation < 0 || attenuation > 4)
        {
-               VM_Warning("VM_CL_sound: attenuation must be in range 0-4\n");
+               VM_Warning(prog, "VM_CL_sound: attenuation must be in range 0-4\n");
                return;
        }
 
@@ -200,16 +198,16 @@ static void VM_CL_sound (void)
 
        if (!IS_CHAN(channel))
        {
-               VM_Warning("VM_CL_sound: channel must be in range 0-127\n");
+               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(MAX_EDICTS + PRVM_NUM_FOR_EDICT(entity), channel, S_FindName(sample), org, volume, attenuation);
+       S_StartSound_StartPosition_Flags(MAX_EDICTS + PRVM_NUM_FOR_EDICT(entity), channel, S_FindName(sample), org, volume, attenuation, 0, 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(void)
+static void VM_CL_pointsound(prvm_prog_t *prog)
 {
        const char                      *sample;
        float                           volume;
@@ -225,13 +223,13 @@ static void VM_CL_pointsound(void)
 
        if (volume < 0 || volume > 1)
        {
-               VM_Warning("VM_CL_pointsound: volume must be in range 0-1\n");
+               VM_Warning(prog, "VM_CL_pointsound: volume must be in range 0-1\n");
                return;
        }
 
        if (attenuation < 0 || attenuation > 4)
        {
-               VM_Warning("VM_CL_pointsound: attenuation must be in range 0-4\n");
+               VM_Warning(prog, "VM_CL_pointsound: attenuation must be in range 0-4\n");
                return;
        }
 
@@ -240,16 +238,16 @@ static void VM_CL_pointsound(void)
 }
 
 // #14 entity() spawn
-static void VM_CL_spawn (void)
+static void VM_CL_spawn (prvm_prog_t *prog)
 {
        prvm_edict_t *ed;
-       ed = PRVM_ED_Alloc();
+       ed = PRVM_ED_Alloc(prog);
        VM_RETURN_EDICT(ed);
 }
 
-void CL_VM_SetTraceGlobals(const trace_t *trace, int svent)
+static void CL_VM_SetTraceGlobals(prvm_prog_t *prog, const trace_t *trace, int svent)
 {
-       VM_SetTraceGlobals(trace);
+       VM_SetTraceGlobals(prog, trace);
        PRVM_clientglobalfloat(trace_networkentity) = svent;
 }
 
@@ -257,7 +255,7 @@ void CL_VM_SetTraceGlobals(const trace_t *trace, int svent)
 #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 (void)
+static void VM_CL_traceline (prvm_prog_t *prog)
 {
        float   *v1, *v2;
        trace_t trace;
@@ -276,11 +274,11 @@ static void VM_CL_traceline (void)
        ent = PRVM_G_EDICT(OFS_PARM3);
 
        if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v2[1]) || IS_NAN(v2[2]))
-               PRVM_ERROR("%s: NAN errors detected in traceline('%f %f %f', '%f %f %f', %i, entity %i)\n", PRVM_NAME, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
+               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(&trace, svent);
+       CL_VM_SetTraceGlobals(prog, &trace, svent);
 //     R_TimeReport("traceline");
 }
 
@@ -296,7 +294,7 @@ 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 (void)
+static void VM_CL_tracebox (prvm_prog_t *prog)
 {
        float   *v1, *v2, *m1, *m2;
        trace_t trace;
@@ -316,15 +314,15 @@ static void VM_CL_tracebox (void)
        ent = PRVM_G_EDICT(OFS_PARM5);
 
        if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v2[1]) || IS_NAN(v2[2]))
-               PRVM_ERROR("%s: NAN errors detected in tracebox('%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', %i, entity %i)\n", PRVM_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));
+               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(&trace, svent);
+       CL_VM_SetTraceGlobals(prog, &trace, svent);
 //     R_TimeReport("tracebox");
 }
 
-trace_t CL_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore, int *svent)
+static trace_t CL_Trace_Toss (prvm_prog_t *prog, prvm_edict_t *tossent, prvm_edict_t *ignore, int *svent)
 {
        int i;
        float gravity;
@@ -366,7 +364,7 @@ trace_t CL_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore, int *svent)
        return trace;
 }
 
-static void VM_CL_tracetoss (void)
+static void VM_CL_tracetoss (prvm_prog_t *prog)
 {
        trace_t trace;
        prvm_edict_t    *ent;
@@ -380,19 +378,19 @@ static void VM_CL_tracetoss (void)
        ent = PRVM_G_EDICT(OFS_PARM0);
        if (ent == prog->edicts)
        {
-               VM_Warning("tracetoss: can not use world entity\n");
+               VM_Warning(prog, "tracetoss: can not use world entity\n");
                return;
        }
        ignore = PRVM_G_EDICT(OFS_PARM1);
 
-       trace = CL_Trace_Toss (ent, ignore, &svent);
+       trace = CL_Trace_Toss (prog, ent, ignore, &svent);
 
-       CL_VM_SetTraceGlobals(&trace, svent);
+       CL_VM_SetTraceGlobals(prog, &trace, svent);
 }
 
 
 // #20 void(string s) precache_model
-void VM_CL_precache_model (void)
+static void VM_CL_precache_model (prvm_prog_t *prog)
 {
        const char      *name;
        int                     i;
@@ -422,13 +420,13 @@ void VM_CL_precache_model (void)
                                return;
                        }
                }
-               VM_Warning("VM_CL_precache_model: no free models\n");
+               VM_Warning(prog, "VM_CL_precache_model: no free models\n");
                return;
        }
-       VM_Warning("VM_CL_precache_model: model \"%s\" not found\n", name);
+       VM_Warning(prog, "VM_CL_precache_model: model \"%s\" not found\n", name);
 }
 
-int CSQC_EntitiesInBox (vec3_t mins, vec3_t maxs, int maxlist, prvm_edict_t **list)
+static int CSQC_EntitiesInBox (prvm_prog_t *prog, vec3_t mins, vec3_t maxs, int maxlist, prvm_edict_t **list)
 {
        prvm_edict_t    *ent;
        int                             i, k;
@@ -445,7 +443,7 @@ int CSQC_EntitiesInBox (vec3_t mins, vec3_t maxs, int maxlist, prvm_edict_t **li
 }
 
 // #22 entity(vector org, float rad) findradius
-static void VM_CL_findradius (void)
+static void VM_CL_findradius (prvm_prog_t *prog)
 {
        prvm_edict_t    *ent, *chain;
        vec_t                   radius, radius2;
@@ -461,7 +459,7 @@ static void VM_CL_findradius (void)
        else
                chainfield = prog->fieldoffsets.chain;
        if(chainfield < 0)
-               PRVM_ERROR("VM_findchain: %s doesnt have the specified chain field !", PRVM_NAME);
+               prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
 
        chain = (prvm_edict_t *)prog->edicts;
 
@@ -475,7 +473,7 @@ static void VM_CL_findradius (void)
        maxs[0] = org[0] + (radius + 1);
        maxs[1] = org[1] + (radius + 1);
        maxs[2] = org[2] + (radius + 1);
-       numtouchedicts = CSQC_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
+       numtouchedicts = CSQC_EntitiesInBox(prog, mins, maxs, MAX_EDICTS, touchedicts);
        if (numtouchedicts > MAX_EDICTS)
        {
                // this never happens   //[515]: for what then ?
@@ -512,7 +510,7 @@ static void VM_CL_findradius (void)
 }
 
 // #34 float() droptofloor
-static void VM_CL_droptofloor (void)
+static void VM_CL_droptofloor (prvm_prog_t *prog)
 {
        prvm_edict_t            *ent;
        vec3_t                          end;
@@ -526,12 +524,12 @@ static void VM_CL_droptofloor (void)
        ent = PRVM_PROG_TO_EDICT(PRVM_clientglobaledict(self));
        if (ent == prog->edicts)
        {
-               VM_Warning("droptofloor: can not modify world entity\n");
+               VM_Warning(prog, "droptofloor: can not modify world entity\n");
                return;
        }
        if (ent->priv.server->free)
        {
-               VM_Warning("droptofloor: can not modify free entity\n");
+               VM_Warning(prog, "droptofloor: can not modify free entity\n");
                return;
        }
 
@@ -552,7 +550,7 @@ static void VM_CL_droptofloor (void)
 }
 
 // #35 void(float style, string value) lightstyle
-static void VM_CL_lightstyle (void)
+static void VM_CL_lightstyle (prvm_prog_t *prog)
 {
        int                     i;
        const char      *c;
@@ -563,7 +561,7 @@ static void VM_CL_lightstyle (void)
        c = PRVM_G_STRING(OFS_PARM1);
        if (i >= cl.max_lightstyle)
        {
-               VM_Warning("VM_CL_lightstyle >= MAX_LIGHTSTYLES\n");
+               VM_Warning(prog, "VM_CL_lightstyle >= MAX_LIGHTSTYLES\n");
                return;
        }
        strlcpy (cl.lightstyle[i].map, c, sizeof (cl.lightstyle[i].map));
@@ -572,7 +570,7 @@ static void VM_CL_lightstyle (void)
 }
 
 // #40 float(entity e) checkbottom
-static void VM_CL_checkbottom (void)
+static void VM_CL_checkbottom (prvm_prog_t *prog)
 {
        static int              cs_yes, cs_no;
        prvm_edict_t    *ent;
@@ -643,14 +641,14 @@ realcheck:
 }
 
 // #41 float(vector v) pointcontents
-static void VM_CL_pointcontents (void)
+static void VM_CL_pointcontents (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_CL_pointcontents);
        PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, CL_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
 }
 
 // #48 void(vector o, vector d, float color, float count) particle
-static void VM_CL_particle (void)
+static void VM_CL_particle (prvm_prog_t *prog)
 {
        float   *org, *dir;
        int             count;
@@ -665,7 +663,7 @@ static void VM_CL_particle (void)
 }
 
 // #74 void(vector pos, string samp, float vol, float atten) ambientsound
-static void VM_CL_ambientsound (void)
+static void VM_CL_ambientsound (prvm_prog_t *prog)
 {
        float   *f;
        sfx_t   *s;
@@ -676,12 +674,12 @@ static void VM_CL_ambientsound (void)
 }
 
 // #92 vector(vector org[, float lpflag]) getlight (DP_QC_GETLIGHT)
-static void VM_CL_getlight (void)
+static void VM_CL_getlight (prvm_prog_t *prog)
 {
        vec3_t ambientcolor, diffusecolor, diffusenormal;
        vec_t *p;
 
-       VM_SAFEPARMCOUNTRANGE(1, 2, VM_CL_getlight);
+       VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_getlight);
 
        p = PRVM_G_VECTOR(OFS_PARM0);
        VectorClear(ambientcolor);
@@ -692,11 +690,16 @@ static void VM_CL_getlight (void)
        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
-extern qboolean CSQC_AddRenderEdict (prvm_edict_t *ed, int edictnum);//csprogs.c
 
 void CSQC_R_RecalcView (void)
 {
@@ -708,31 +711,15 @@ void CSQC_R_RecalcView (void)
        Matrix4x4_Concat(&viewmodelmatrix_withbob, &r_refdef.view.matrix, &cl.csqc_viewmodelmatrixfromengine);
 }
 
-void CL_RelinkLightFlashes(void);
 //#300 void() clearscene (EXT_CSQC)
-void VM_CL_R_ClearScene (void)
+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;
-       // FIXME: restore these to the values from VM_CL_UpdateView
-       r_refdef.view.x = 0;
-       r_refdef.view.y = 0;
-       r_refdef.view.z = 0;
-       r_refdef.view.width = vid.width;
-       r_refdef.view.height = vid.height;
-       r_refdef.view.depth = 1;
-       // FIXME: restore frustum_x/frustum_y
-       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 = scr_fov.value * (3.0 / 4.0) * (float)r_refdef.view.width / (float)r_refdef.view.height / vid_pixelheight.value;
-       r_refdef.view.ortho_y = scr_fov.value * (3.0 / 4.0);
-       r_refdef.view.clear = true;
-       r_refdef.view.isoverlay = false;
+       // 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;
@@ -742,11 +729,9 @@ void VM_CL_R_ClearScene (void)
 }
 
 //#301 void(float mask) addentities (EXT_CSQC)
-extern void CSQC_Predraw (prvm_edict_t *ed);//csprogs.c
-extern void CSQC_Think (prvm_edict_t *ed);//csprogs.c
-void VM_CL_R_AddEntities (void)
+static void VM_CL_R_AddEntities (prvm_prog_t *prog)
 {
-       double t = Sys_DoubleTime();
+       double t = Sys_DirtyTime();
        int                     i, drawmask;
        prvm_edict_t *ed;
        VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities);
@@ -775,23 +760,27 @@ void VM_CL_R_AddEntities (void)
        }
 
        // callprofile fixing hack: do not include this time in what is counted for CSQC_UpdateView
-       prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= Sys_DoubleTime() - t;
+       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)
-void VM_CL_R_AddEntity (void)
+static void VM_CL_R_AddEntity (prvm_prog_t *prog)
 {
-       double t = Sys_DoubleTime();
+       double t = Sys_DirtyTime();
        VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
        CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0), 0);
-       prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= Sys_DoubleTime() - t;
+       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
-void VM_CL_R_SetView (void)
+static void VM_CL_R_SetView (prvm_prog_t *prog)
 {
        int             c;
        float   *f;
@@ -825,7 +814,7 @@ void VM_CL_R_SetView (void)
                        PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.height;
                        break;
                case VF_VIEWPORT:
-                       VM_Warning("VM_CL_R_GetView : VF_VIEWPORT can't be retrieved, use VF_MIN/VF_SIZE instead\n");
+                       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);
@@ -887,9 +876,44 @@ void VM_CL_R_SetView (void)
                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;
                default:
                        PRVM_G_FLOAT(OFS_RETURN) = 0;
-                       VM_Warning("VM_CL_R_GetView : unknown parm %i\n", c);
+                       VM_Warning(prog, "VM_CL_R_GetView : unknown parm %i\n", c);
                        return;
                }
                return;
@@ -1002,18 +1026,53 @@ void VM_CL_R_SetView (void)
        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;
        default:
                PRVM_G_FLOAT(OFS_RETURN) = 0;
-               VM_Warning("VM_CL_R_SetView : unknown parm %i\n", c);
+               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)
-void VM_CL_R_AddDynamicLight (void)
+static void VM_CL_R_AddDynamicLight (prvm_prog_t *prog)
 {
-       double t = Sys_DoubleTime();
+       double t = Sys_DirtyTime();
        vec_t *org;
        float radius = 300;
        vec_t *col;
@@ -1060,13 +1119,14 @@ void VM_CL_R_AddDynamicLight (void)
 
        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++;
-       prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= Sys_DoubleTime() - t;
+       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 (void)
+static void VM_CL_unproject (prvm_prog_t *prog)
 {
        float   *f;
        vec3_t  temp;
@@ -1083,7 +1143,7 @@ static void VM_CL_unproject (void)
 }
 
 //#311 vector (vector v) cs_project (EXT_CSQC)
-static void VM_CL_project (void)
+static void VM_CL_project (prvm_prog_t *prog)
 {
        float   *f;
        vec3_t  v;
@@ -1105,7 +1165,7 @@ static void VM_CL_project (void)
 }
 
 //#330 float(float stnum) getstatf (EXT_CSQC)
-static void VM_CL_getstatf (void)
+static void VM_CL_getstatf (prvm_prog_t *prog)
 {
        int i;
        union
@@ -1117,7 +1177,7 @@ static void VM_CL_getstatf (void)
        i = (int)PRVM_G_FLOAT(OFS_PARM0);
        if(i < 0 || i >= MAX_CL_STATS)
        {
-               VM_Warning("VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n");
+               VM_Warning(prog, "VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n");
                return;
        }
        dat.l = cl.stats[i];
@@ -1125,7 +1185,7 @@ static void VM_CL_getstatf (void)
 }
 
 //#331 float(float stnum) getstati (EXT_CSQC)
-static void VM_CL_getstati (void)
+static void VM_CL_getstati (prvm_prog_t *prog)
 {
        int i, index;
        int firstbit, bitcount;
@@ -1149,7 +1209,7 @@ static void VM_CL_getstati (void)
 
        if(index < 0 || index >= MAX_CL_STATS)
        {
-               VM_Warning("VM_CL_getstati: index>=MAX_CL_STATS or index<0\n");
+               VM_Warning(prog, "VM_CL_getstati: index>=MAX_CL_STATS or index<0\n");
                return;
        }
        i = cl.stats[index];
@@ -1159,7 +1219,7 @@ static void VM_CL_getstati (void)
 }
 
 //#332 string(float firststnum) getstats (EXT_CSQC)
-static void VM_CL_getstats (void)
+static void VM_CL_getstats (prvm_prog_t *prog)
 {
        int i;
        char t[17];
@@ -1168,15 +1228,15 @@ static void VM_CL_getstats (void)
        if(i < 0 || i > MAX_CL_STATS-4)
        {
                PRVM_G_INT(OFS_RETURN) = OFS_NULL;
-               VM_Warning("VM_CL_getstats: index>MAX_CL_STATS-4 or index<0\n");
+               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(t);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, t);
 }
 
 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
-static void VM_CL_setmodelindex (void)
+static void VM_CL_setmodelindex (prvm_prog_t *prog)
 {
        int                             i;
        prvm_edict_t    *t;
@@ -1197,23 +1257,23 @@ static void VM_CL_setmodelindex (void)
        model = CL_GetModelByIndex(i);
        if (!model)
        {
-               VM_Warning("VM_CL_setmodelindex: null model\n");
+               VM_Warning(prog, "VM_CL_setmodelindex: null model\n");
                return;
        }
-       PRVM_clientedictstring(t, model) = PRVM_SetEngineString(model->name);
+       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 (t, model->normalmins, model->normalmaxs);
+               SetMinMaxSize (prog, t, model->normalmins, model->normalmaxs);
        }
        else
-               SetMinMaxSize (t, vec3_origin, vec3_origin);
+               SetMinMaxSize (prog, t, vec3_origin, vec3_origin);
 }
 
 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
-static void VM_CL_modelnameforindex (void)
+static void VM_CL_modelnameforindex (prvm_prog_t *prog)
 {
        dp_model_t *model;
 
@@ -1221,11 +1281,11 @@ static void VM_CL_modelnameforindex (void)
 
        PRVM_G_INT(OFS_RETURN) = OFS_NULL;
        model = CL_GetModelByIndex((int)PRVM_G_FLOAT(OFS_PARM0));
-       PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(model->name) : 0;
+       PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(prog, model->name) : 0;
 }
 
 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
-static void VM_CL_particleeffectnum (void)
+static void VM_CL_particleeffectnum (prvm_prog_t *prog)
 {
        int                     i;
        VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum);
@@ -1236,7 +1296,7 @@ static void VM_CL_particleeffectnum (void)
 }
 
 // #336 void(entity ent, float effectnum, vector start, vector end[, float color]) trailparticles (EXT_CSQC)
-static void VM_CL_trailparticles (void)
+static void VM_CL_trailparticles (prvm_prog_t *prog)
 {
        int                             i;
        float                   *start, *end;
@@ -1254,7 +1314,7 @@ static void VM_CL_trailparticles (void)
 }
 
 //#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC)
-static void VM_CL_pointparticles (void)
+static void VM_CL_pointparticles (prvm_prog_t *prog)
 {
        int                     i;
        float n;
@@ -1270,7 +1330,7 @@ static void VM_CL_pointparticles (void)
 }
 
 //#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 (void)
+static void VM_CL_boxparticles (prvm_prog_t *prog)
 {
        int effectnum;
        // prvm_edict_t *own;
@@ -1309,7 +1369,7 @@ static void VM_CL_boxparticles (void)
 }
 
 //#531 void(float pause) setpause
-static void VM_CL_setpause(void) 
+static void VM_CL_setpause(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_CL_setpause);
        if ((int)PRVM_G_FLOAT(OFS_PARM0) != 0)
@@ -1318,16 +1378,16 @@ static void VM_CL_setpause(void)
                cl.csqc_paused = false;
 }
 
-//#343 void(float usecursor) setcursormode (EXT_CSQC)
-static void VM_CL_setcursormode (void)
+//#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 (EXT_CSQC)
-static void VM_CL_getmousepos(void)
+//#344 vector() getmousepos (DP_CSQC)
+static void VM_CL_getmousepos(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0,VM_CL_getmousepos);
 
@@ -1340,7 +1400,7 @@ static void VM_CL_getmousepos(void)
 }
 
 //#345 float(float framenum) getinputstate (EXT_CSQC)
-static void VM_CL_getinputstate (void)
+static void VM_CL_getinputstate (prvm_prog_t *prog)
 {
        int i, frame;
        VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
@@ -1356,6 +1416,7 @@ static void VM_CL_getinputstate (void)
                        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));
@@ -1372,19 +1433,51 @@ static void VM_CL_getinputstate (void)
 }
 
 //#346 void(float sens) setsensitivityscaler (EXT_CSQC)
-static void VM_CL_setsensitivityscale (void)
+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)
-static void VM_CL_runplayerphysics (void)
+#define PMF_JUMP_HELD 1
+#define PMF_LADDER 2 // not used by DP
+#define PMF_DUCKED 4 // FIXME FTEQW doesn't have this for Q1 like movement
+static void VM_CL_runplayerphysics (prvm_prog_t *prog)
 {
+       cl_clientmovement_state_t s;
+       prvm_edict_t *ent;
+
+       VM_SAFEPARMCOUNT(1, VM_CL_runplayerphysics);
+
+       ent = PRVM_G_EDICT(OFS_PARM0);
+       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
+       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.canjump = ((int)PRVM_clientedictfloat(ent, pmove_flags) & PMF_JUMP_HELD) == 0;
+       s.cmd.jump = (s.cmd.buttons & 2) != 0;
+       s.cmd.crouch = (s.cmd.buttons & 16) != 0;
+
+       CL_ClientMovement_PlayerMove(&s);
+
+       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);
 }
 
 //#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
-static void VM_CL_getplayerkey (void)
+static void VM_CL_getplayerkey (prvm_prog_t *prog)
 {
        int                     i;
        char            t[128];
@@ -1449,11 +1542,11 @@ static void VM_CL_getplayerkey (void)
                }
        if(!t[0])
                return;
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
+       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 (void)
+static void VM_CL_setlistener (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(4, VM_CL_setlistener);
        Matrix4x4_FromVectors(&cl.csqc_listenermatrix, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), PRVM_G_VECTOR(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0));
@@ -1461,7 +1554,7 @@ static void VM_CL_setlistener (void)
 }
 
 //#352 void(string cmdname) registercommand (EXT_CSQC)
-static void VM_CL_registercmd (void)
+static void VM_CL_registercmd (prvm_prog_t *prog)
 {
        char *t;
        VM_SAFEPARMCOUNT(1, VM_CL_registercmd);
@@ -1480,64 +1573,64 @@ static void VM_CL_registercmd (void)
 }
 
 //#360 float() readbyte (EXT_CSQC)
-static void VM_CL_ReadByte (void)
+static void VM_CL_ReadByte (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0, VM_CL_ReadByte);
-       PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte();
+       PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte(&cl_message);
 }
 
 //#361 float() readchar (EXT_CSQC)
-static void VM_CL_ReadChar (void)
+static void VM_CL_ReadChar (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0, VM_CL_ReadChar);
-       PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar();
+       PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar(&cl_message);
 }
 
 //#362 float() readshort (EXT_CSQC)
-static void VM_CL_ReadShort (void)
+static void VM_CL_ReadShort (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0, VM_CL_ReadShort);
-       PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort();
+       PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort(&cl_message);
 }
 
 //#363 float() readlong (EXT_CSQC)
-static void VM_CL_ReadLong (void)
+static void VM_CL_ReadLong (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0, VM_CL_ReadLong);
-       PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong();
+       PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong(&cl_message);
 }
 
 //#364 float() readcoord (EXT_CSQC)
-static void VM_CL_ReadCoord (void)
+static void VM_CL_ReadCoord (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord);
-       PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(cls.protocol);
+       PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(&cl_message, cls.protocol);
 }
 
 //#365 float() readangle (EXT_CSQC)
-static void VM_CL_ReadAngle (void)
+static void VM_CL_ReadAngle (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle);
-       PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(cls.protocol);
+       PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(&cl_message, cls.protocol);
 }
 
 //#366 string() readstring (EXT_CSQC)
-static void VM_CL_ReadString (void)
+static void VM_CL_ReadString (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0, VM_CL_ReadString);
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(MSG_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 (void)
+static void VM_CL_ReadFloat (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0, VM_CL_ReadFloat);
-       PRVM_G_FLOAT(OFS_RETURN) = MSG_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 (void)
+static void VM_CL_ReadPicture (prvm_prog_t *prog)
 {
        const char *name;
        unsigned char *data;
@@ -1548,8 +1641,8 @@ static void VM_CL_ReadPicture (void)
 
        VM_SAFEPARMCOUNT(0, VM_CL_ReadPicture);
 
-       name = MSG_ReadString();
-       size = MSG_ReadShort();
+       name = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
+       size = MSG_ReadShort(&cl_message);
 
        // check if a texture of that name exists
        // if yes, it is used and the data is discarded
@@ -1566,14 +1659,14 @@ static void VM_CL_ReadPicture (void)
                        // texture found and loaded
                        // skip over the jpeg as we don't need it
                        for(i = 0; i < size; ++i)
-                               (void) MSG_ReadByte();
+                               (void) MSG_ReadByte(&cl_message);
                }
                else
                {
                        // texture not found
                        // use the attached jpeg as texture
                        buf = (unsigned char *) Mem_Alloc(tempmempool, size);
-                       MSG_ReadBytes(size, buf);
+                       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);
@@ -1581,12 +1674,12 @@ static void VM_CL_ReadPicture (void)
                }
        }
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(name);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, name);
 }
 
 //////////////////////////////////////////////////////////
 
-static void VM_CL_makestatic (void)
+static void VM_CL_makestatic (prvm_prog_t *prog)
 {
        prvm_edict_t *ent;
 
@@ -1595,12 +1688,12 @@ static void VM_CL_makestatic (void)
        ent = PRVM_G_EDICT(OFS_PARM0);
        if (ent == prog->edicts)
        {
-               VM_Warning("makestatic: can not modify world entity\n");
+               VM_Warning(prog, "makestatic: can not modify world entity\n");
                return;
        }
        if (ent->priv.server->free)
        {
-               VM_Warning("makestatic: can not modify free entity\n");
+               VM_Warning(prog, "makestatic: can not modify free entity\n");
                return;
        }
 
@@ -1669,7 +1762,7 @@ static void VM_CL_makestatic (void)
                Con_Printf("Too many static entities");
 
 // throw the entity away now
-       PRVM_ED_Free (ent);
+       PRVM_ED_Free(prog, ent);
 }
 
 //=================================================================//
@@ -1683,30 +1776,30 @@ copies data from one entity to another
 copyentity(src, dst)
 =================
 */
-static void VM_CL_copyentity (void)
+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("copyentity: can not read world entity\n");
+               VM_Warning(prog, "copyentity: can not read world entity\n");
                return;
        }
        if (in->priv.server->free)
        {
-               VM_Warning("copyentity: can not read free entity\n");
+               VM_Warning(prog, "copyentity: can not read free entity\n");
                return;
        }
        out = PRVM_G_EDICT(OFS_PARM1);
        if (out == prog->edicts)
        {
-               VM_Warning("copyentity: can not modify world entity\n");
+               VM_Warning(prog, "copyentity: can not modify world entity\n");
                return;
        }
        if (out->priv.server->free)
        {
-               VM_Warning("copyentity: can not modify free entity\n");
+               VM_Warning(prog, "copyentity: can not modify free entity\n");
                return;
        }
        memcpy(out->fields.vp, in->fields.vp, prog->entityfields * 4);
@@ -1716,14 +1809,14 @@ static void VM_CL_copyentity (void)
 //=================================================================//
 
 // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
-static void VM_CL_effect (void)
+static void VM_CL_effect (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(5, VM_CL_effect);
        CL_Effect(PRVM_G_VECTOR(OFS_PARM0), (int)PRVM_G_FLOAT(OFS_PARM1), (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), PRVM_G_FLOAT(OFS_PARM4));
 }
 
 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
-static void VM_CL_te_blood (void)
+static void VM_CL_te_blood (prvm_prog_t *prog)
 {
        float   *pos;
        vec3_t  pos2;
@@ -1736,7 +1829,7 @@ static void VM_CL_te_blood (void)
 }
 
 // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
-static void VM_CL_te_bloodshower (void)
+static void VM_CL_te_bloodshower (prvm_prog_t *prog)
 {
        vec_t speed;
        vec3_t vel1, vel2;
@@ -1754,7 +1847,7 @@ static void VM_CL_te_bloodshower (void)
 }
 
 // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
-static void VM_CL_te_explosionrgb (void)
+static void VM_CL_te_explosionrgb (prvm_prog_t *prog)
 {
        float           *pos;
        vec3_t          pos2;
@@ -1768,28 +1861,28 @@ static void VM_CL_te_explosionrgb (void)
 }
 
 // #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 (void)
+static void VM_CL_te_particlecube (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube);
        CL_ParticleCube(PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), (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 (void)
+static void VM_CL_te_particlerain (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain);
        CL_ParticleRain(PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), (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 (void)
+static void VM_CL_te_particlesnow (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow);
        CL_ParticleRain(PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), (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 (void)
+static void VM_CL_te_spark (prvm_prog_t *prog)
 {
        float           *pos;
        vec3_t          pos2;
@@ -1802,7 +1895,7 @@ static void VM_CL_te_spark (void)
 
 extern cvar_t cl_sound_ric_gunshot;
 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
-static void VM_CL_te_gunshotquad (void)
+static void VM_CL_te_gunshotquad (prvm_prog_t *prog)
 {
        float           *pos;
        vec3_t          pos2;
@@ -1826,7 +1919,7 @@ static void VM_CL_te_gunshotquad (void)
 }
 
 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
-static void VM_CL_te_spikequad (void)
+static void VM_CL_te_spikequad (prvm_prog_t *prog)
 {
        float           *pos;
        vec3_t          pos2;
@@ -1847,7 +1940,7 @@ static void VM_CL_te_spikequad (void)
 }
 
 // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
-static void VM_CL_te_superspikequad (void)
+static void VM_CL_te_superspikequad (prvm_prog_t *prog)
 {
        float           *pos;
        vec3_t          pos2;
@@ -1868,7 +1961,7 @@ static void VM_CL_te_superspikequad (void)
 }
 
 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
-static void VM_CL_te_explosionquad (void)
+static void VM_CL_te_explosionquad (prvm_prog_t *prog)
 {
        float           *pos;
        vec3_t          pos2;
@@ -1881,7 +1974,7 @@ static void VM_CL_te_explosionquad (void)
 }
 
 // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
-static void VM_CL_te_smallflash (void)
+static void VM_CL_te_smallflash (prvm_prog_t *prog)
 {
        float           *pos;
        vec3_t          pos2;
@@ -1893,7 +1986,7 @@ static void VM_CL_te_smallflash (void)
 }
 
 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
-static void VM_CL_te_customflash (void)
+static void VM_CL_te_customflash (prvm_prog_t *prog)
 {
        float           *pos;
        vec3_t          pos2;
@@ -1907,7 +2000,7 @@ static void VM_CL_te_customflash (void)
 }
 
 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
-static void VM_CL_te_gunshot (void)
+static void VM_CL_te_gunshot (prvm_prog_t *prog)
 {
        float           *pos;
        vec3_t          pos2;
@@ -1931,7 +2024,7 @@ static void VM_CL_te_gunshot (void)
 }
 
 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
-static void VM_CL_te_spike (void)
+static void VM_CL_te_spike (prvm_prog_t *prog)
 {
        float           *pos;
        vec3_t          pos2;
@@ -1952,7 +2045,7 @@ static void VM_CL_te_spike (void)
 }
 
 // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
-static void VM_CL_te_superspike (void)
+static void VM_CL_te_superspike (prvm_prog_t *prog)
 {
        float           *pos;
        vec3_t          pos2;
@@ -1973,7 +2066,7 @@ static void VM_CL_te_superspike (void)
 }
 
 // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
-static void VM_CL_te_explosion (void)
+static void VM_CL_te_explosion (prvm_prog_t *prog)
 {
        float           *pos;
        vec3_t          pos2;
@@ -1986,7 +2079,7 @@ static void VM_CL_te_explosion (void)
 }
 
 // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
-static void VM_CL_te_tarexplosion (void)
+static void VM_CL_te_tarexplosion (prvm_prog_t *prog)
 {
        float           *pos;
        vec3_t          pos2;
@@ -1999,7 +2092,7 @@ static void VM_CL_te_tarexplosion (void)
 }
 
 // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
-static void VM_CL_te_wizspike (void)
+static void VM_CL_te_wizspike (prvm_prog_t *prog)
 {
        float           *pos;
        vec3_t          pos2;
@@ -2012,7 +2105,7 @@ static void VM_CL_te_wizspike (void)
 }
 
 // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
-static void VM_CL_te_knightspike (void)
+static void VM_CL_te_knightspike (prvm_prog_t *prog)
 {
        float           *pos;
        vec3_t          pos2;
@@ -2025,21 +2118,21 @@ static void VM_CL_te_knightspike (void)
 }
 
 // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
-static void VM_CL_te_lavasplash (void)
+static void VM_CL_te_lavasplash (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
        CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
 }
 
 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
-static void VM_CL_te_teleport (void)
+static void VM_CL_te_teleport (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
        CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), 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 (void)
+static void VM_CL_te_explosion2 (prvm_prog_t *prog)
 {
        float           *pos;
        vec3_t          pos2, color;
@@ -2064,35 +2157,35 @@ static void VM_CL_te_explosion2 (void)
 
 
 // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
-static void VM_CL_te_lightning1 (void)
+static void VM_CL_te_lightning1 (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1);
        CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt, true);
 }
 
 // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
-static void VM_CL_te_lightning2 (void)
+static void VM_CL_te_lightning2 (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2);
        CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt2, true);
 }
 
 // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
-static void VM_CL_te_lightning3 (void)
+static void VM_CL_te_lightning3 (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3);
        CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt3, false);
 }
 
 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
-static void VM_CL_te_beam (void)
+static void VM_CL_te_beam (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_CL_te_beam);
        CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_beam, false);
 }
 
 // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
-static void VM_CL_te_plasmaburn (void)
+static void VM_CL_te_plasmaburn (prvm_prog_t *prog)
 {
        float           *pos;
        vec3_t          pos2;
@@ -2104,7 +2197,7 @@ static void VM_CL_te_plasmaburn (void)
 }
 
 // #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET)
-static void VM_CL_te_flamejet (void)
+static void VM_CL_te_flamejet (prvm_prog_t *prog)
 {
        float *pos;
        vec3_t pos2;
@@ -2118,7 +2211,7 @@ static void VM_CL_te_flamejet (void)
 
 
 // #443 void(entity e, entity tagentity, string tagname) setattachment
-void VM_CL_setattachment (void)
+static void VM_CL_setattachment (prvm_prog_t *prog)
 {
        prvm_edict_t *e;
        prvm_edict_t *tagentity;
@@ -2134,12 +2227,12 @@ void VM_CL_setattachment (void)
 
        if (e == prog->edicts)
        {
-               VM_Warning("setattachment: can not modify world entity\n");
+               VM_Warning(prog, "setattachment: can not modify world entity\n");
                return;
        }
        if (e->priv.server->free)
        {
-               VM_Warning("setattachment: can not modify free entity\n");
+               VM_Warning(prog, "setattachment: can not modify free entity\n");
                return;
        }
 
@@ -2168,7 +2261,7 @@ void VM_CL_setattachment (void)
 /////////////////////////////////////////
 // DP_MD3_TAGINFO extension coded by VorteX
 
-int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
+static int CL_GetTagIndex (prvm_prog_t *prog, prvm_edict_t *e, const char *tagname)
 {
        dp_model_t *model = CL_GetModelFromEdict(e);
        if (model)
@@ -2177,7 +2270,7 @@ int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
                return -1;
 }
 
-int CL_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
+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;
@@ -2201,7 +2294,7 @@ int CL_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, cons
        return 1;
 }
 
-int CL_GetPitchSign(prvm_edict_t *ent)
+int CL_GetPitchSign(prvm_prog_t *prog, prvm_edict_t *ent)
 {
        dp_model_t *model;
        if ((model = CL_GetModelFromEdict(ent)) && model->type == mod_alias)
@@ -2209,7 +2302,7 @@ int CL_GetPitchSign(prvm_edict_t *ent)
        return 1;
 }
 
-void CL_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
+void CL_GetEntityMatrix (prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
 {
        float scale;
        float pitchsign = 1;
@@ -2234,21 +2327,21 @@ void CL_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatri
        }
        else
        {
-               pitchsign = CL_GetPitchSign(ent);
+               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);
        }
 }
 
-int CL_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
+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(ent->priv.server->framegroupblend, ent);
+               VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
                VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
-               VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
+               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;
@@ -2265,7 +2358,7 @@ int CL_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out
 extern cvar_t cl_bob;
 extern cvar_t cl_bobcycle;
 extern cvar_t cl_bobup;
-int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
+int CL_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
 {
        int ret;
        int attachloop;
@@ -2291,10 +2384,10 @@ int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
                        return 5;
                // apply transformation by child's tagindex on parent entity and then
                // by parent entity itself
-               ret = CL_GetEntityLocalTagMatrix(ent, tagindex - 1, &attachmatrix);
+               ret = CL_GetEntityLocalTagMatrix(prog, ent, tagindex - 1, &attachmatrix);
                if(ret && attachloop == 0)
                        return ret;
-               CL_GetEntityMatrix(ent, &entitymatrix, false);
+               CL_GetEntityMatrix(prog, ent, &entitymatrix, false);
                Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
                Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
                // next iteration we process the parent entity
@@ -2313,7 +2406,7 @@ int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
        {
                Matrix4x4_Copy(&tagmatrix, out);
 
-               CL_GetEntityMatrix(prog->edicts, &entitymatrix, true);
+               CL_GetEntityMatrix(prog, prog->edicts, &entitymatrix, true);
                Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
 
                /*
@@ -2343,7 +2436,7 @@ int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
 }
 
 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
-void VM_CL_gettagindex (void)
+static void VM_CL_gettagindex (prvm_prog_t *prog)
 {
        prvm_edict_t *ent;
        const char *tag_name;
@@ -2355,12 +2448,12 @@ void VM_CL_gettagindex (void)
        tag_name = PRVM_G_STRING(OFS_PARM1);
        if (ent == prog->edicts)
        {
-               VM_Warning("VM_CL_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
+               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("VM_CL_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
+               VM_Warning(prog, "VM_CL_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
                return;
        }
 
@@ -2369,7 +2462,7 @@ void VM_CL_gettagindex (void)
                Con_DPrintf("VM_CL_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
        else
        {
-               tag_index = CL_GetTagIndex(ent, tag_name);
+               tag_index = CL_GetTagIndex(prog, ent, tag_name);
                if (tag_index == 0)
                        Con_DPrintf("VM_CL_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
        }
@@ -2377,7 +2470,7 @@ void VM_CL_gettagindex (void)
 }
 
 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
-void VM_CL_gettaginfo (void)
+static void VM_CL_gettaginfo (prvm_prog_t *prog)
 {
        prvm_edict_t *e;
        int tagindex;
@@ -2393,18 +2486,18 @@ void VM_CL_gettaginfo (void)
 
        e = PRVM_G_EDICT(OFS_PARM0);
        tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
-       returncode = CL_GetTagMatrix(&tag_matrix, e, tagindex);
+       returncode = CL_GetTagMatrix(prog, &tag_matrix, e, tagindex);
        Matrix4x4_ToVectors(&tag_matrix, PRVM_clientglobalvector(v_forward), le, PRVM_clientglobalvector(v_up), PRVM_G_VECTOR(OFS_RETURN));
        VectorScale(le, -1, PRVM_clientglobalvector(v_right));
        model = CL_GetModelFromEdict(e);
-       VM_GenerateFrameGroupBlend(e->priv.server->framegroupblend, e);
+       VM_GenerateFrameGroupBlend(prog, e->priv.server->framegroupblend, e);
        VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model);
-       VM_UpdateEdictSkeleton(e, model, e->priv.server->frameblend);
-       CL_GetExtendedTagInfo(e, tagindex, &parentindex, &tagname, &tag_localmatrix);
+       VM_UpdateEdictSkeleton(prog, e, model, e->priv.server->frameblend);
+       CL_GetExtendedTagInfo(prog, e, tagindex, &parentindex, &tagname, &tag_localmatrix);
        Matrix4x4_ToVectors(&tag_localmatrix, fo, le, up, trans);
 
        PRVM_clientglobalfloat(gettaginfo_parent) = parentindex;
-       PRVM_clientglobalstring(gettaginfo_name) = tagname ? PRVM_SetTempString(tagname) : 0;
+       PRVM_clientglobalstring(gettaginfo_name) = tagname ? PRVM_SetTempString(prog, tagname) : 0;
        VectorCopy(trans, PRVM_clientglobalvector(gettaginfo_offset));
        VectorCopy(fo, PRVM_clientglobalvector(gettaginfo_forward));
        VectorScale(le, -1, PRVM_clientglobalvector(gettaginfo_right));
@@ -2413,10 +2506,10 @@ void VM_CL_gettaginfo (void)
        switch(returncode)
        {
                case 1:
-                       VM_Warning("gettagindex: can't affect world entity\n");
+                       VM_Warning(prog, "gettagindex: can't affect world entity\n");
                        break;
                case 2:
-                       VM_Warning("gettagindex: can't affect free entity\n");
+                       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));
@@ -2513,7 +2606,7 @@ typedef struct vmparticlespawner_s
 vmparticlespawner_t vmpartspawner;
 
 // TODO: automatic max_themes grow
-static void VM_InitParticleSpawner (int maxthemes)
+static void VM_InitParticleSpawner (prvm_prog_t *prog, int maxthemes)
 {
        // bound max themes to not be an insane value
        if (maxthemes < 4)
@@ -2598,7 +2691,7 @@ static void VM_ResetParticleTheme (vmparticletheme_t *theme)
 }
 
 // particle theme -> QC globals
-void VM_CL_ParticleThemeToGlobals(vmparticletheme_t *theme)
+static void VM_CL_ParticleThemeToGlobals(vmparticletheme_t *theme)
 {
        *vmpartspawner.particle_type = theme->typeindex;
        *vmpartspawner.particle_blendmode = theme->blendmode;
@@ -2639,7 +2732,7 @@ void VM_CL_ParticleThemeToGlobals(vmparticletheme_t *theme)
 }
 
 // QC globals ->  particle theme
-void VM_CL_ParticleThemeFromGlobals(vmparticletheme_t *theme)
+static void VM_CL_ParticleThemeFromGlobals(vmparticletheme_t *theme)
 {
        theme->typeindex = (unsigned short)*vmpartspawner.particle_type;
        theme->blendmode = (pblend_t)(int)*vmpartspawner.particle_blendmode;
@@ -2673,48 +2766,48 @@ void VM_CL_ParticleThemeFromGlobals(vmparticletheme_t *theme)
 
 // init particle spawner interface
 // # float(float max_themes) initparticlespawner
-void VM_CL_InitParticleSpawner (void)
+static void VM_CL_InitParticleSpawner (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_InitParticleSpawner);
-       VM_InitParticleSpawner((int)PRVM_G_FLOAT(OFS_PARM0));
+       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
-void VM_CL_ResetParticle (void)
+static void VM_CL_ResetParticle (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0, VM_CL_ResetParticle);
        if (vmpartspawner.verified == false)
        {
-               VM_Warning("VM_CL_ResetParticle: particle spawner not initialized\n");
+               VM_Warning(prog, "VM_CL_ResetParticle: particle spawner not initialized\n");
                return;
        }
        VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]);
 }
 
 // void(float themenum) particletheme
-void VM_CL_ParticleTheme (void)
+static void VM_CL_ParticleTheme (prvm_prog_t *prog)
 {
        int themenum;
 
        VM_SAFEPARMCOUNT(1, VM_CL_ParticleTheme);
        if (vmpartspawner.verified == false)
        {
-               VM_Warning("VM_CL_ParticleTheme: particle spawner not initialized\n");
+               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("VM_CL_ParticleTheme: bad theme number %i\n", themenum);
+               VM_Warning(prog, "VM_CL_ParticleTheme: bad theme number %i\n", themenum);
                VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]);
                return;
        }
        if (vmpartspawner.themes[themenum].initialized == false)
        {
-               VM_Warning("VM_CL_ParticleTheme: theme #%i not exists\n", themenum);
+               VM_Warning(prog, "VM_CL_ParticleTheme: theme #%i not exists\n", themenum);
                VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]);
                return;
        }
@@ -2724,14 +2817,14 @@ void VM_CL_ParticleTheme (void)
 
 // float() saveparticletheme
 // void(float themenum) updateparticletheme
-void VM_CL_ParticleThemeSave (void)
+static void VM_CL_ParticleThemeSave (prvm_prog_t *prog)
 {
        int themenum;
 
        VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_ParticleThemeSave);
        if (vmpartspawner.verified == false)
        {
-               VM_Warning("VM_CL_ParticleThemeSave: particle spawner not initialized\n");
+               VM_Warning(prog, "VM_CL_ParticleThemeSave: particle spawner not initialized\n");
                return;
        }
        // allocate new theme, save it and return
@@ -2743,9 +2836,9 @@ void VM_CL_ParticleThemeSave (void)
                if (themenum >= vmpartspawner.max_themes)
                {
                        if (vmpartspawner.max_themes == 2048)
-                               VM_Warning("VM_CL_ParticleThemeSave: no free theme slots\n");
+                               VM_Warning(prog, "VM_CL_ParticleThemeSave: no free theme slots\n");
                        else
-                               VM_Warning("VM_CL_ParticleThemeSave: no free theme slots, try initparticlespawner() with highter max_themes\n");
+                               VM_Warning(prog, "VM_CL_ParticleThemeSave: no free theme slots, try initparticlespawner() with highter max_themes\n");
                        PRVM_G_FLOAT(OFS_RETURN) = -1;
                        return;
                }
@@ -2758,7 +2851,7 @@ void VM_CL_ParticleThemeSave (void)
        themenum = (int)PRVM_G_FLOAT(OFS_PARM0);
        if (themenum < 0 || themenum >= vmpartspawner.max_themes)
        {
-               VM_Warning("VM_CL_ParticleThemeSave: bad theme number %i\n", themenum);
+               VM_Warning(prog, "VM_CL_ParticleThemeSave: bad theme number %i\n", themenum);
                return;
        }
        vmpartspawner.themes[themenum].initialized = true;
@@ -2766,26 +2859,26 @@ void VM_CL_ParticleThemeSave (void)
 }
 
 // void(float themenum) freeparticletheme
-void VM_CL_ParticleThemeFree (void)
+static void VM_CL_ParticleThemeFree (prvm_prog_t *prog)
 {
        int themenum;
 
        VM_SAFEPARMCOUNT(1, VM_CL_ParticleThemeFree);
        if (vmpartspawner.verified == false)
        {
-               VM_Warning("VM_CL_ParticleThemeFree: particle spawner not initialized\n");
+               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("VM_CL_ParticleThemeFree: bad theme number %i\n", themenum);
+               VM_Warning(prog, "VM_CL_ParticleThemeFree: bad theme number %i\n", themenum);
                return;
        }
        if (vmpartspawner.themes[themenum].initialized == false)
        {
-               VM_Warning("VM_CL_ParticleThemeFree: theme #%i already freed\n", themenum);
+               VM_Warning(prog, "VM_CL_ParticleThemeFree: theme #%i already freed\n", themenum);
                VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]);
                return;
        }
@@ -2796,7 +2889,7 @@ void VM_CL_ParticleThemeFree (void)
 
 // float(vector org, vector dir, [float theme]) particle
 // returns 0 if failed, 1 if succesful
-void VM_CL_SpawnParticle (void)
+static void VM_CL_SpawnParticle (prvm_prog_t *prog)
 {
        float *org, *dir;
        vmparticletheme_t *theme;
@@ -2806,7 +2899,7 @@ void VM_CL_SpawnParticle (void)
        VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_SpawnParticle2);
        if (vmpartspawner.verified == false)
        {
-               VM_Warning("VM_CL_SpawnParticle: particle spawner not initialized\n");
+               VM_Warning(prog, "VM_CL_SpawnParticle: particle spawner not initialized\n");
                PRVM_G_FLOAT(OFS_RETURN) = 0; 
                return;
        }
@@ -2831,7 +2924,7 @@ void VM_CL_SpawnParticle (void)
                themenum = (int)PRVM_G_FLOAT(OFS_PARM2);
                if (themenum <= 0 || themenum >= vmpartspawner.max_themes)
                {
-                       VM_Warning("VM_CL_SpawnParticle: bad theme number %i\n", themenum);
+                       VM_Warning(prog, "VM_CL_SpawnParticle: bad theme number %i\n", themenum);
                        PRVM_G_FLOAT(OFS_RETURN) = 0; 
                        return;
                }
@@ -2852,7 +2945,7 @@ void VM_CL_SpawnParticle (void)
 
 // float(vector org, vector dir, float spawndelay, float collisiondelay, [float theme]) delayedparticle
 // returns 0 if failed, 1 if success
-void VM_CL_SpawnParticleDelayed (void)
+static void VM_CL_SpawnParticleDelayed (prvm_prog_t *prog)
 {
        float *org, *dir;
        vmparticletheme_t *theme;
@@ -2862,7 +2955,7 @@ void VM_CL_SpawnParticleDelayed (void)
        VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_SpawnParticle2);
        if (vmpartspawner.verified == false)
        {
-               VM_Warning("VM_CL_SpawnParticle: particle spawner not initialized\n");
+               VM_Warning(prog, "VM_CL_SpawnParticle: particle spawner not initialized\n");
                PRVM_G_FLOAT(OFS_RETURN) = 0; 
                return;
        }
@@ -2875,7 +2968,7 @@ void VM_CL_SpawnParticleDelayed (void)
                themenum = (int)PRVM_G_FLOAT(OFS_PARM4);
                if (themenum <= 0 || themenum >= vmpartspawner.max_themes)
                {
-                       VM_Warning("VM_CL_SpawnParticle: bad theme number %i\n", themenum);
+                       VM_Warning(prog, "VM_CL_SpawnParticle: bad theme number %i\n", themenum);
                        PRVM_G_FLOAT(OFS_RETURN) = 0;  
                        return;
                }
@@ -2900,7 +2993,7 @@ void VM_CL_SpawnParticleDelayed (void)
 // vector(float entitynum, float whatfld) getentityvec;
 // querying engine-drawn entity
 // VorteX: currently it's only tested with whatfld = 1..7
-void VM_CL_GetEntity (void)
+static void VM_CL_GetEntity (prvm_prog_t *prog)
 {
        int entnum, fieldnum;
        float org[3], v1[3], v2[3];
@@ -2978,68 +3071,39 @@ void VM_CL_GetEntity (void)
 //QC POLYGON functions
 //====================
 
-#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;
-       double          progstarttime;
-
-       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;
-
-// FIXME: make VM_CL_R_Polygon functions use Debug_Polygon functions?
-vmpolygons_t vmpolygons[PRVM_MAXPROGS];
-
 //#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
-void VM_CL_R_RenderScene (void)
+static void VM_CL_R_RenderScene (prvm_prog_t *prog)
 {
-       double t = Sys_DoubleTime();
-       vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
+       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;
-       polys->progstarttime = prog->starttime;
 
        // callprofile fixing hack: do not include this time in what is counted for CSQC_UpdateView
-       prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= Sys_DoubleTime() - t;
+       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)
@@ -3090,9 +3154,7 @@ static void VM_InitPolygons (vmpolygons_t* polys)
 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
 {
        int surfacelistindex;
-       vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
-       if(polys->progstarttime != prog->starttime) // from other progs? won't draw these (this can cause crashes!)
-               return;
+       vmpolygons_t *polys = (vmpolygons_t *)ent;
 //     R_Mesh_ResetTextureState();
        R_EntityMatrix(&identitymatrix);
        GL_CullFace(GL_NONE);
@@ -3106,7 +3168,7 @@ static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t
                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);
+               R_SetupShader_Generic(tex, NULL, GL_MODULATE, 1, false, false, false);
                numtriangles = 0;
                for (;surfacelistindex < numsurfaces;surfacelistindex++)
                {
@@ -3119,7 +3181,7 @@ static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t
        }
 }
 
-void VMPolygons_Store(vmpolygons_t *polys)
+static void VMPolygons_Store(vmpolygons_t *polys)
 {
        qboolean hasalpha;
        int i;
@@ -3181,10 +3243,10 @@ void VMPolygons_Store(vmpolygons_t *polys)
 
 // 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 (void)
+void VM_CL_AddPolygonsToMeshQueue (prvm_prog_t *prog)
 {
        int i;
-       vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
+       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
@@ -3197,7 +3259,7 @@ void VM_CL_AddPolygonsToMeshQueue (void)
        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(center, VM_DrawPolygonCallback, NULL, i, NULL);
+               R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, center, VM_DrawPolygonCallback, (entity_render_t *)polys, i, NULL);
        }
 
        /*polys->num_triangles = 0; // now done after rendering the scene,
@@ -3205,11 +3267,11 @@ void VM_CL_AddPolygonsToMeshQueue (void)
 }
 
 //void(string texturename, float flag[, float is2d]) R_BeginPolygon
-void VM_CL_R_PolygonBegin (void)
+static void VM_CL_R_PolygonBegin (prvm_prog_t *prog)
 {
        const char              *picname;
        skinframe_t     *sf;
-       vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
+       vmpolygons_t *polys = &prog->vmpolygons;
        int tf;
 
        // TODO instead of using skinframes here (which provides the benefit of
@@ -3220,15 +3282,9 @@ void VM_CL_R_PolygonBegin (void)
 
        if (!polys->initialized)
                VM_InitPolygons(polys);
-       if(polys->progstarttime != prog->starttime)
-       {
-               // from another progs? then reset the polys first (fixes crashes on map change, because that can make skinframe textures invalid)
-               polys->num_vertices = polys->num_triangles = 0;
-               polys->progstarttime = prog->starttime;
-       }
        if (polys->begin_active)
        {
-               VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonBegin after first\n");
+               VM_Warning(prog, "VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonBegin after first\n");
                return;
        }
        picname = PRVM_G_STRING(OFS_PARM0);
@@ -3262,21 +3318,21 @@ void VM_CL_R_PolygonBegin (void)
 }
 
 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
-void VM_CL_R_PolygonVertex (void)
+static void VM_CL_R_PolygonVertex (prvm_prog_t *prog)
 {
-       vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
+       vmpolygons_t *polys = &prog->vmpolygons;
 
        VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
 
        if (!polys->begin_active)
        {
-               VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
+               VM_Warning(prog, "VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
                return;
        }
 
        if (polys->begin_vertices >= VMPOLYGONS_MAXPOINTS)
        {
-               VM_Warning("VM_CL_R_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS);
+               VM_Warning(prog, "VM_CL_R_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS);
                return;
        }
 
@@ -3293,21 +3349,21 @@ void VM_CL_R_PolygonVertex (void)
 }
 
 //void() R_EndPolygon
-void VM_CL_R_PolygonEnd (void)
+static void VM_CL_R_PolygonEnd (prvm_prog_t *prog)
 {
-       vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
+       vmpolygons_t *polys = &prog->vmpolygons;
 
        VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
        if (!polys->begin_active)
        {
-               VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
+               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("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", polys->begin_vertices);
+               VM_Warning(prog, "VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", polys->begin_vertices);
 }
 
 static vmpolygons_t debugPolys;
@@ -3376,8 +3432,9 @@ is not a staircase.
 
 =============
 */
-qboolean CL_CheckBottom (prvm_edict_t *ent)
+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;
@@ -3444,8 +3501,9 @@ 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 CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
+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;
        trace_t         trace;
@@ -3474,7 +3532,7 @@ qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean
                        }
                        trace = CL_TraceBox(PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, mins), PRVM_clientedictvector(ent, maxs), neworg, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
                        if (settrace)
-                               CL_VM_SetTraceGlobals(&trace, svent);
+                               CL_VM_SetTraceGlobals(prog, &trace, svent);
 
                        if (trace.fraction == 1)
                        {
@@ -3502,14 +3560,14 @@ qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean
 
        trace = CL_TraceBox(neworg, PRVM_clientedictvector(ent, mins), PRVM_clientedictvector(ent, maxs), end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
        if (settrace)
-               CL_VM_SetTraceGlobals(&trace, svent);
+               CL_VM_SetTraceGlobals(prog, &trace, svent);
 
        if (trace.startsolid)
        {
                neworg[2] -= sv_stepheight.value;
                trace = CL_TraceBox(neworg, PRVM_clientedictvector(ent, mins), PRVM_clientedictvector(ent, maxs), end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
                if (settrace)
-                       CL_VM_SetTraceGlobals(&trace, svent);
+                       CL_VM_SetTraceGlobals(prog, &trace, svent);
                if (trace.startsolid)
                        return false;
        }
@@ -3562,7 +3620,7 @@ VM_CL_walkmove
 float(float yaw, float dist[, settrace]) walkmove
 ===============
 */
-static void VM_CL_walkmove (void)
+static void VM_CL_walkmove (prvm_prog_t *prog)
 {
        prvm_edict_t    *ent;
        float   yaw, dist;
@@ -3579,12 +3637,12 @@ static void VM_CL_walkmove (void)
        ent = PRVM_PROG_TO_EDICT(PRVM_clientglobaledict(self));
        if (ent == prog->edicts)
        {
-               VM_Warning("walkmove: can not modify world entity\n");
+               VM_Warning(prog, "walkmove: can not modify world entity\n");
                return;
        }
        if (ent->priv.server->free)
        {
-               VM_Warning("walkmove: can not modify free entity\n");
+               VM_Warning(prog, "walkmove: can not modify free entity\n");
                return;
        }
        yaw = PRVM_G_FLOAT(OFS_PARM0);
@@ -3619,12 +3677,12 @@ VM_CL_serverkey
 string(string key) serverkey
 ===============
 */
-void VM_CL_serverkey(void)
+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(string);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
 }
 
 /*
@@ -3637,7 +3695,7 @@ Should be fast but can be inexact.
 float checkpvs(vector viewpos, entity viewee) = #240;
 =================
 */
-static void VM_CL_checkpvs (void)
+static void VM_CL_checkpvs (prvm_prog_t *prog)
 {
        vec3_t viewpos;
        prvm_edict_t *viewee;
@@ -3655,7 +3713,7 @@ static void VM_CL_checkpvs (void)
 
        if(viewee->priv.required->free)
        {
-               VM_Warning("checkpvs: can not check free entity\n");
+               VM_Warning(prog, "checkpvs: can not check free entity\n");
                PRVM_G_FLOAT(OFS_RETURN) = 4;
                return;
        }
@@ -3698,7 +3756,7 @@ static void VM_CL_checkpvs (void)
 }
 
 // #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(void)
+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);
@@ -3722,7 +3780,7 @@ static void VM_CL_skel_create(void)
 }
 
 // #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(void)
+static void VM_CL_skel_build(prvm_prog_t *prog)
 {
        int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
        skeleton_t *skeleton;
@@ -3746,7 +3804,7 @@ static void VM_CL_skel_build(void)
        firstbone = max(0, firstbone);
        lastbone = min(lastbone, model->num_bones - 1);
        lastbone = min(lastbone, skeleton->model->num_bones - 1);
-       VM_GenerateFrameGroupBlend(framegroupblend, ed);
+       VM_GenerateFrameGroupBlend(prog, framegroupblend, ed);
        VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model);
        blendfrac = 1.0f - retainfrac;
        for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
@@ -3766,7 +3824,7 @@ static void VM_CL_skel_build(void)
 }
 
 // #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(void)
+static void VM_CL_skel_get_numbones(prvm_prog_t *prog)
 {
        int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
        skeleton_t *skeleton;
@@ -3777,7 +3835,7 @@ static void VM_CL_skel_get_numbones(void)
 }
 
 // #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(void)
+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;
@@ -3787,11 +3845,11 @@ static void VM_CL_skel_get_bonename(void)
                return;
        if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
                return;
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(skeleton->model->data_bones[bonenum].name);
+       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(void)
+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;
@@ -3805,7 +3863,7 @@ static void VM_CL_skel_get_boneparent(void)
 }
 
 // #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(void)
+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);
@@ -3817,7 +3875,7 @@ static void VM_CL_skel_find_bone(void)
 }
 
 // #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(void)
+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;
@@ -3841,7 +3899,7 @@ static void VM_CL_skel_get_bonerel(void)
 }
 
 // #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(void)
+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;
@@ -3872,7 +3930,7 @@ static void VM_CL_skel_get_boneabs(void)
 }
 
 // #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(void)
+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;
@@ -3892,7 +3950,7 @@ static void VM_CL_skel_set_bone(void)
 }
 
 // #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(void)
+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;
@@ -3914,7 +3972,7 @@ static void VM_CL_skel_mul_bone(void)
 }
 
 // #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(void)
+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;
@@ -3941,7 +3999,7 @@ static void VM_CL_skel_mul_bones(void)
 }
 
 // #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(void)
+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;
@@ -3962,7 +4020,7 @@ static void VM_CL_skel_copybones(void)
 }
 
 // #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(void)
+static void VM_CL_skel_delete(prvm_prog_t *prog)
 {
        int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
        skeleton_t *skeleton;
@@ -3973,7 +4031,7 @@ static void VM_CL_skel_delete(void)
 }
 
 // #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(void)
+static void VM_CL_frameforname(prvm_prog_t *prog)
 {
        int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
        dp_model_t *model = CL_GetModelByIndex(modelindex);
@@ -3993,7 +4051,7 @@ static void VM_CL_frameforname(void)
 }
 
 // #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(void)
+static void VM_CL_frameduration(prvm_prog_t *prog)
 {
        int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
        dp_model_t *model = CL_GetModelByIndex(modelindex);
@@ -4005,7 +4063,7 @@ static void VM_CL_frameduration(void)
                PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
 }
 
-void VM_CL_RotateMoves(void)
+static void VM_CL_RotateMoves(prvm_prog_t *prog)
 {
        /*
         * Obscure builtin used by GAME_XONOTIC.
@@ -4044,7 +4102,7 @@ void VM_CL_RotateMoves(void)
 }
 
 // #358 void(string cubemapname) loadcubemap
-static void VM_CL_loadcubemap(void)
+static void VM_CL_loadcubemap(prvm_prog_t *prog)
 {
        const char *name;
 
@@ -4375,7 +4433,7 @@ VM_CL_R_AddDynamicLight,          // #305 void(vector org, float radius, vector lightcol
 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
-NULL /* R_LoadWorldModel in menu VM, should stay unassigned in client*/, // #309
+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
@@ -4387,8 +4445,8 @@ VM_precache_pic,                          // #317 string(string name, float trywad) precache_pic (EXT_
 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)
-VM_drawpic,                                            // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (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
@@ -4409,8 +4467,8 @@ 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 (EXT_CSQC)
-VM_CL_getmousepos,                             // #344 vector() getmousepos (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)
@@ -4706,14 +4764,15 @@ NULL,                                                   // #635
 NULL,                                                  // #636
 NULL,                                                  // #637
 VM_CL_RotateMoves,                                     // #638
-NULL,                                                  // #639
+VM_digest_hex,                                         // #639
+NULL,                                                  // #640
 };
 
 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
 
-void VM_Polygons_Reset(void)
+void VM_Polygons_Reset(prvm_prog_t *prog)
 {
-       vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
+       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)
@@ -4723,17 +4782,15 @@ void VM_Polygons_Reset(void)
        }
 }
 
-void VM_CL_Cmd_Init(void)
+void CLVM_init_cmd(prvm_prog_t *prog)
 {
-       VM_Cmd_Init();
-       VM_Polygons_Reset();
+       VM_Cmd_Init(prog);
+       VM_Polygons_Reset(prog);
 }
 
-void VM_CL_Cmd_Reset(void)
+void CLVM_reset_cmd(prvm_prog_t *prog)
 {
        World_End(&cl.world);
-       VM_Cmd_Reset();
-       VM_Polygons_Reset();
+       VM_Cmd_Reset(prog);
+       VM_Polygons_Reset(prog);
 }
-
-
index 8835dae65d4c0accc6ee6c7c93343d96150caa0d..259991ff3f0ebf2416a1e2c0458f6ce0d09e45a0 100644 (file)
@@ -1,10 +1,6 @@
 #ifndef __CLVM_CMDS_H__
 #define __CLVM_CMDS_H__
 
-int CL_GetPitchSign(prvm_edict_t *ent);
-int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex);
-void CL_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix);
-
 /* These are VM built-ins that originate in the client-side programs support
    but are reused by the other programs (usually the menu). */
 
@@ -23,8 +19,6 @@ void VM_CL_R_LoadWorldModel (void);
 void VM_CL_R_PolygonBegin (void);
 void VM_CL_R_PolygonVertex (void);
 void VM_CL_R_PolygonEnd (void);
-/* VMs exposing the polygon calls must call this on Init/Reset */
-void VM_Polygons_Reset(void);
 
 void VM_CL_setattachment(void);
 void VM_CL_gettagindex(void);
index bbaca649369e1e5be7b88e3251d019894db88ce0..0a42ca4a093d2ad9d59882ea45e6a78d52114efc 100644 (file)
@@ -20,6 +20,7 @@ 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
 {
@@ -59,7 +60,7 @@ typedef struct cmddeferred_s
 {
        struct cmddeferred_s *next;
        char *value;
-       double time;
+       double delay;
 } cmddeferred_t;
 
 static cmddeferred_t *cmd_deferred_list = NULL;
@@ -75,13 +76,12 @@ static void Cmd_Defer_f (void)
 {
        if(Cmd_Argc() == 1)
        {
-               double time = Sys_DoubleTime();
                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->time-time, next->value);
+                       Con_Printf("-> In %9.2f: %s\n", next->delay, next->value);
                        next = next->next;
                }
        } else if(Cmd_Argc() == 2 && !strcasecmp("clear", Cmd_Argv(1)))
@@ -99,7 +99,7 @@ static void Cmd_Defer_f (void)
                cmddeferred_t *defcmd = (cmddeferred_t*)Mem_Alloc(tempmempool, sizeof(*defcmd));
                size_t len = strlen(value);
 
-               defcmd->time = Sys_DoubleTime() + atof(Cmd_Argv(1));
+               defcmd->delay = atof(Cmd_Argv(1));
                defcmd->value = (char*)Mem_Alloc(tempmempool, len+1);
                memcpy(defcmd->value, value, len+1);
                defcmd->next = NULL;
@@ -175,6 +175,10 @@ static void Cmd_Centerprint_f (void)
 
 static sizebuf_t       cmd_text;
 static unsigned char           cmd_text_buf[CMDBUFSIZE];
+void *cmd_text_mutex = NULL;
+
+#define Cbuf_LockThreadMutex() (cmd_text_mutex ? Thread_LockMutex(cmd_text_mutex),1 : 0)
+#define Cbuf_UnlockThreadMutex() (cmd_text_mutex ? Thread_UnlockMutex(cmd_text_mutex),1 : 0)
 
 /*
 ============
@@ -187,15 +191,14 @@ void Cbuf_AddText (const char *text)
 {
        int             l;
 
-       l = (int)strlen (text);
+       l = (int)strlen(text);
 
+       Cbuf_LockThreadMutex();
        if (cmd_text.cursize + l >= cmd_text.maxsize)
-       {
                Con_Print("Cbuf_AddText: overflow\n");
-               return;
-       }
-
-       SZ_Write (&cmd_text, (const unsigned char *)text, (int)strlen (text));
+       else
+               SZ_Write(&cmd_text, (const unsigned char *)text, l);
+       Cbuf_UnlockThreadMutex();
 }
 
 
@@ -210,29 +213,19 @@ FIXME: actually change the command buffer to do less copying
 */
 void Cbuf_InsertText (const char *text)
 {
-       char    *temp;
-       int             templen;
-
-       // copy off any commands still remaining in the exec buffer
-       templen = cmd_text.cursize;
-       if (templen)
-       {
-               temp = (char *)Mem_Alloc (tempmempool, templen);
-               memcpy (temp, cmd_text.data, templen);
-               SZ_Clear (&cmd_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
-               temp = NULL;
-
-       // add the entire text of the file
-       Cbuf_AddText (text);
-
-       // add the copied off data
-       if (temp != NULL)
        {
-               SZ_Write (&cmd_text, (const unsigned char *)temp, templen);
-               Mem_Free (temp);
+               // 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();
 }
 
 /*
@@ -240,15 +233,22 @@ void Cbuf_InsertText (const char *text)
 Cbuf_Execute_Deferred --blub
 ============
 */
-void Cbuf_Execute_Deferred (void)
+static void Cbuf_Execute_Deferred (void)
 {
+       static double oldrealtime = 0;
        cmddeferred_t *cmd, *prev;
-       double time = Sys_DoubleTime();
+       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)
        {
-               if(cmd->time <= time)
+               cmd->delay -= eat;
+               if(cmd->delay <= 0)
                {
                        Cbuf_AddText(cmd->value);
                        Cbuf_AddText(";\n");
@@ -289,7 +289,6 @@ void Cbuf_Execute (void)
        // LordHavoc: making sure the tokenizebuffer doesn't get filled up by repeated crashes
        cmd_tokenizebufferpos = 0;
 
-       Cbuf_Execute_Deferred();
        while (cmd_text.cursize)
        {
 // find a \n or ; line break
@@ -362,11 +361,11 @@ void Cbuf_Execute (void)
                )
                {
                        Cmd_PreprocessString( line, preprocessed, sizeof(preprocessed), NULL );
-                       Cmd_ExecuteString (preprocessed, src_command);
+                       Cmd_ExecuteString (preprocessed, src_command, false);
                }
                else
                {
-                       Cmd_ExecuteString (line, src_command);
+                       Cmd_ExecuteString (line, src_command, false);
                }
 
                if (cmd_wait)
@@ -378,6 +377,17 @@ void Cbuf_Execute (void)
        }
 }
 
+void Cbuf_Frame(void)
+{
+       Cbuf_Execute_Deferred();
+       if (cmd_text.cursize)
+       {
+               SV_LockThreadMutex();
+               Cbuf_Execute();
+               SV_UnlockThreadMutex();
+       }
+}
+
 /*
 ==============================================================================
 
@@ -397,7 +407,7 @@ quake -nosound +cmd amlev1
 ===============
 */
 qboolean host_stuffcmdsrun = false;
-void Cmd_StuffCmds_f (void)
+static void Cmd_StuffCmds_f (void)
 {
        int             i, j, l;
        // this is for all commandline options combined (and is bounds checked)
@@ -453,6 +463,7 @@ void Cmd_StuffCmds_f (void)
 static void Cmd_Exec(const char *filename)
 {
        char *f;
+       qboolean isdefaultcfg = strlen(filename) >= 11 && !strcmp(filename + strlen(filename) - 11, "default.cfg");
 
        if (!strcmp(filename, "config.cfg"))
        {
@@ -472,7 +483,7 @@ static void Cmd_Exec(const char *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 (strlen(filename) >= 11 && !strcmp(filename + strlen(filename) - 11, "default.cfg"))
+       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)
@@ -481,23 +492,29 @@ static void Cmd_Exec(const char *filename)
        Cbuf_InsertText (f);
        Mem_Free(f);
 
-       // 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
-       if (gamemode == GAME_NEHAHRA)
-               Cbuf_InsertText("\nsv_gameplayfix_upwardvelocityclearsongroundflag 0\nsv_gameplayfix_blowupfallenzombies 0\n\n");
-       // 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.
-       if (gamemode == GAME_HIPNOTIC)
-               Cbuf_InsertText("\nsv_gameplayfix_blowupfallenzombies 0\nsys_ticrate 0.02\nsv_gameplayfix_slidemoveprojectiles 0\n\n");
-       // rogue mission pack has a guardian boss that does not wake up if findradius returns one of the entities around its spawn area
-       if (gamemode == GAME_ROGUE)
-               Cbuf_InsertText("\nsv_gameplayfix_findradiusdistancetobox 0\n\n");
-       if (gamemode == GAME_NEXUIZ)
-               Cbuf_InsertText("\nsv_gameplayfix_q2airaccelerate 1\nsv_gameplayfix_stepmultipletimes 1\n\n");
-       if (gamemode == GAME_TENEBRAE)
-               Cbuf_InsertText("\nr_shadow_gloss 2\nr_shadow_bumpscale_basetexture 4\n\n");
+       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
+               if (gamemode == GAME_NEHAHRA)
+                       Cbuf_InsertText("\nsv_gameplayfix_upwardvelocityclearsongroundflag 0\nsv_gameplayfix_blowupfallenzombies 0\n\n");
+               // 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.
+               if (gamemode == GAME_HIPNOTIC)
+                       Cbuf_InsertText("\nsv_gameplayfix_blowupfallenzombies 0\nsys_ticrate 0.02\nsv_gameplayfix_slidemoveprojectiles 0\n\n");
+               // rogue mission pack has a guardian boss that does not wake up if findradius returns one of the entities around its spawn area
+               if (gamemode == GAME_ROGUE)
+                       Cbuf_InsertText("\nsv_gameplayfix_findradiusdistancetobox 0\n\n");
+               if (gamemode == GAME_NEXUIZ)
+                       Cbuf_InsertText("\nsv_gameplayfix_q2airaccelerate 1\nsv_gameplayfix_stepmultipletimes 1\n\n");
+               if (gamemode == GAME_TENEBRAE)
+                       Cbuf_InsertText("\nr_shadow_gloss 2\nr_shadow_bumpscale_basetexture 4\n\n");
+               // Steel Storm: Burning Retribution csqc misinterprets CSQC_InputEvent if type is a value other than 0 or 1
+               if (gamemode == GAME_STEELSTORM)
+                       Cbuf_InsertText("\ncl_csqc_generatemousemoveevents 0\n\n");
+       }
 }
 
 /*
@@ -778,6 +795,7 @@ static const char *Cmd_GetDirectCvarValue(const char *varname, cmdalias_t *alias
        cvar_t *cvar;
        long argno;
        char *endptr;
+       char vabuf[1024];
 
        if(is_multiple)
                *is_multiple = false;
@@ -795,7 +813,7 @@ static const char *Cmd_GetDirectCvarValue(const char *varname, cmdalias_t *alias
                }
                else if(!strcmp(varname, "#"))
                {
-                       return va("%d", Cmd_Argc());
+                       return va(vabuf, sizeof(vabuf), "%d", Cmd_Argc());
                }
                else if(varname[strlen(varname) - 1] == '-')
                {
@@ -900,8 +918,8 @@ fail:
 
 static const char *Cmd_GetCvarValue(const char *var, size_t varlen, cmdalias_t *alias)
 {
-       static char varname[MAX_INPUTLINE];
-       static char varval[MAX_INPUTLINE];
+       static char varname[MAX_INPUTLINE]; // cmd_mutex
+       static char varval[MAX_INPUTLINE]; // cmd_mutex
        const char *varstr;
        char *varfunc;
 static char asis[] = "asis"; // just to suppress const char warnings
@@ -1090,8 +1108,8 @@ Called for aliases and fills in the alias into the cbuffer
 */
 static void Cmd_ExecuteAlias (cmdalias_t *alias)
 {
-       static char buffer[ MAX_INPUTLINE ];
-       static char buffer2[ MAX_INPUTLINE ];
+       static char buffer[ MAX_INPUTLINE ]; // cmd_mutex
+       static char buffer2[ MAX_INPUTLINE ]; // cmd_mutex
        Cmd_PreprocessString( alias->value, buffer, sizeof(buffer) - 2, alias );
        // insert at start of command buffer, so that aliases execute in order
        // (fixes bug introduced by Black on 20050705)
@@ -1161,6 +1179,7 @@ static void Cmd_Apropos_f(void)
        const char *partial;
        int count;
        qboolean ispattern;
+       char vabuf[1024];
 
        if (Cmd_Argc() > 1)
                partial = Cmd_Args();
@@ -1172,7 +1191,7 @@ static void Cmd_Apropos_f(void)
 
        ispattern = partial && (strchr(partial, '*') || strchr(partial, '?'));
        if(!ispattern)
-               partial = va("*%s*", partial);
+               partial = va(vabuf, sizeof(vabuf), "*%s*", partial);
 
        count = 0;
        for (cvar = cvar_vars; cvar; cvar = cvar->next)
@@ -1215,6 +1234,9 @@ void Cmd_Init (void)
        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)
@@ -1262,6 +1284,14 @@ 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);
 }
 
@@ -1630,7 +1660,6 @@ void Cmd_ClearCsqcFuncs (void)
                cmd->csqcfunc = false;
 }
 
-qboolean CL_VM_ConsoleCommand (const char *cmd);
 /*
 ============
 Cmd_ExecuteString
@@ -1639,7 +1668,7 @@ 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)
+void Cmd_ExecuteString (const char *text, cmd_source_t src, qboolean lockmutex)
 {
        int oldpos;
        int found;
@@ -1654,10 +1683,7 @@ void Cmd_ExecuteString (const char *text, cmd_source_t src)
 
 // execute the command line
        if (!Cmd_Argc())
-       {
-               cmd_tokenizebufferpos = oldpos;
-               return;         // no tokens
-       }
+               goto done; // no tokens
 
 // check functions
        for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
@@ -1665,7 +1691,7 @@ void Cmd_ExecuteString (const char *text, cmd_source_t src)
                if (!strcasecmp (cmd_argv[0],cmd->name))
                {
                        if (cmd->csqcfunc && CL_VM_ConsoleCommand (text))       //[515]: csqc
-                               return;
+                               goto done;
                        switch (src)
                        {
                        case src_command:
@@ -1689,8 +1715,7 @@ void Cmd_ExecuteString (const char *text, cmd_source_t src)
                                if (cmd->clientfunction)
                                {
                                        cmd->clientfunction ();
-                                       cmd_tokenizebufferpos = oldpos;
-                                       return;
+                                       goto done;
                                }
                                break;
                        }
@@ -1703,8 +1728,7 @@ command_found:
        if (cmd_source == src_client)
        {
                Con_Printf("player \"%s\" tried to %s\n", host_client->name, text);
-               cmd_tokenizebufferpos = oldpos;
-               return;
+               goto done;
        }
 
 // check alias
@@ -1713,21 +1737,18 @@ command_found:
                if (!strcasecmp (cmd_argv[0], a->name))
                {
                        Cmd_ExecuteAlias(a);
-                       cmd_tokenizebufferpos = oldpos;
-                       return;
+                       goto done;
                }
        }
 
        if(found) // if the command was hooked and found, all is good
-       {
-               cmd_tokenizebufferpos = oldpos;
-               return;
-       }
+               goto done;
 
 // check cvars
        if (!Cvar_Command () && host_framecount > 0)
                Con_Printf("Unknown command \"%s\"\n", Cmd_Argv(0));
 
+done:
        cmd_tokenizebufferpos = oldpos;
 }
 
@@ -1869,6 +1890,7 @@ 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
@@ -1877,7 +1899,7 @@ void Cmd_ForwardToServer (void)
        else
        {
                // we need to keep the command name, so send Cmd_Argv(0), a space and then Cmd_Args()
-               s = va("%s %s", Cmd_Argv(0), Cmd_Argc() > 1 ? 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)
index cb96abaada65098ccce99692c2eeb6cc5efe2362..c8bf80ca4b6a1647040d8d716805c2b362b4b22d 100644 (file)
@@ -61,6 +61,8 @@ void Cbuf_InsertText (const char *text);
  * \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);
 
 //===========================================================================
 
@@ -142,7 +144,7 @@ int Cmd_CheckParm (const char *parm);
 
 /// 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);
+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)
@@ -165,5 +167,7 @@ void Cmd_Print(const char *text);
 /// 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
 
index cf0d527f360a424e6d7707382fe12400ee25b081..f0251fb64a6966675e66cb73f40a1b4d50a508d3 100644 (file)
@@ -53,7 +53,7 @@ void Collision_Init (void)
 
 
 
-void Collision_PrintBrushAsQHull(colbrushf_t *brush, const char *name)
+static void Collision_PrintBrushAsQHull(colbrushf_t *brush, const char *name)
 {
        int i;
        Con_Printf("3 %s\n%i\n", name, brush->numpoints);
@@ -65,7 +65,7 @@ void Collision_PrintBrushAsQHull(colbrushf_t *brush, const char *name)
                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);
 }
 
-void Collision_ValidateBrush(colbrushf_t *brush)
+static void Collision_ValidateBrush(colbrushf_t *brush)
 {
        int j, k, pointsoffplanes, pointonplanes, pointswithinsufficientplanes, printbrush;
        float d;
@@ -124,7 +124,7 @@ void Collision_ValidateBrush(colbrushf_t *brush)
                Collision_PrintBrushAsQHull(brush, "unnamed");
 }
 
-float nearestplanedist_float(const float *normal, const colpointf_t *points, int numpoints)
+static float nearestplanedist_float(const float *normal, const colpointf_t *points, int numpoints)
 {
        float dist, bestdist;
        if (!numpoints)
@@ -140,7 +140,7 @@ float nearestplanedist_float(const float *normal, const colpointf_t *points, int
        return bestdist;
 }
 
-float furthestplanedist_float(const float *normal, const colpointf_t *points, int numpoints)
+static float furthestplanedist_float(const float *normal, const colpointf_t *points, int numpoints)
 {
        float dist, bestdist;
        if (!numpoints)
@@ -156,7 +156,7 @@ float furthestplanedist_float(const float *normal, const colpointf_t *points, in
        return bestdist;
 }
 
-void Collision_CalcEdgeDirsForPolygonBrushFloat(colbrushf_t *brush)
+static void Collision_CalcEdgeDirsForPolygonBrushFloat(colbrushf_t *brush)
 {
        int i, j;
        for (i = 0, j = brush->numpoints - 1;i < brush->numpoints;j = i, i++)
@@ -1032,7 +1032,7 @@ void Collision_TracePointBrushFloat(trace_t *trace, const vec3_t point, const co
        }
 }
 
-void Collision_SnapCopyPoints(int numpoints, const colpointf_t *in, colpointf_t *out, float fractionprecision, float invfractionprecision)
+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++)
@@ -1247,28 +1247,6 @@ void Collision_BrushForBox(colboxbrushf_t *boxbrush, const vec3_t mins, const ve
        //Collision_ValidateBrush(&boxbrush->brush);
 }
 
-void Collision_ClipTrace_BrushBox(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 supercontents, int q3surfaceflags, texture_t *texture)
-{
-       colboxbrushf_t boxbrush, thisbrush_start, thisbrush_end;
-       vec3_t startmins, startmaxs, endmins, endmaxs;
-
-       // create brushes for the collision
-       VectorAdd(start, mins, startmins);
-       VectorAdd(start, maxs, startmaxs);
-       VectorAdd(end, mins, endmins);
-       VectorAdd(end, maxs, endmaxs);
-       Collision_BrushForBox(&boxbrush, cmins, cmaxs, supercontents, q3surfaceflags, texture);
-       Collision_BrushForBox(&thisbrush_start, startmins, startmaxs, 0, 0, NULL);
-       Collision_BrushForBox(&thisbrush_end, endmins, endmaxs, 0, 0, NULL);
-
-       memset(trace, 0, sizeof(trace_t));
-       trace->hitsupercontentsmask = hitsupercontentsmask;
-       trace->fraction = 1;
-       trace->realfraction = 1;
-       trace->allsolid = true;
-       Collision_TraceBrushBrushFloat(trace, &thisbrush_start.brush, &thisbrush_end.brush, &boxbrush.brush, &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;
 
@@ -1278,7 +1256,7 @@ void Collision_ClipTrace_BrushBox(trace_t *trace, const vec3_t cmins, const vec3
 // 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], deviationdist, impactdist, linelength;
+       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);
@@ -1300,13 +1278,12 @@ float Collision_ClipTrace_Line_Sphere(double *linestart, double *lineend, double
        // of the line from the sphereorigin (deviation, how off-center it is)
        VectorMA(linestart, impactdist, dir, v);
        VectorSubtract(v, sphereorigin, v);
-       deviationdist = VectorLength2(v);
-       // if outside the radius, it's a miss for sure
-       // (we do this comparison using squared radius to avoid a sqrt)
-       if (deviationdist > sphereradius*sphereradius)
+       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 -= sphereradius - deviationdist/sphereradius;
+       impactdist -= sqrt(deviationdist2);
        if (impactdist >= linelength)
                return 1; // miss (not close enough)
        if (impactdist < 0)
@@ -1538,55 +1515,6 @@ void Collision_TraceLineTriangleFloat(trace_t *trace, const vec3_t linestart, co
 #endif
 }
 
-typedef struct colbspnode_s
-{
-       mplane_t plane;
-       struct colbspnode_s *children[2];
-       // the node is reallocated or split if max is reached
-       int numcolbrushf;
-       int maxcolbrushf;
-       colbrushf_t **colbrushflist;
-       //int numcolbrushd;
-       //int maxcolbrushd;
-       //colbrushd_t **colbrushdlist;
-}
-colbspnode_t;
-
-typedef struct colbsp_s
-{
-       mempool_t *mempool;
-       colbspnode_t *nodes;
-}
-colbsp_t;
-
-colbsp_t *Collision_CreateCollisionBSP(mempool_t *mempool)
-{
-       colbsp_t *bsp;
-       bsp = (colbsp_t *)Mem_Alloc(mempool, sizeof(colbsp_t));
-       bsp->mempool = mempool;
-       bsp->nodes = (colbspnode_t *)Mem_Alloc(bsp->mempool, sizeof(colbspnode_t));
-       return bsp;
-}
-
-void Collision_FreeCollisionBSPNode(colbspnode_t *node)
-{
-       if (node->children[0])
-               Collision_FreeCollisionBSPNode(node->children[0]);
-       if (node->children[1])
-               Collision_FreeCollisionBSPNode(node->children[1]);
-       while (--node->numcolbrushf)
-               Mem_Free(node->colbrushflist[node->numcolbrushf]);
-       //while (--node->numcolbrushd)
-       //      Mem_Free(node->colbrushdlist[node->numcolbrushd]);
-       Mem_Free(node);
-}
-
-void Collision_FreeCollisionBSP(colbsp_t *bsp)
-{
-       Collision_FreeCollisionBSPNode(bsp->nodes);
-       Mem_Free(bsp);
-}
-
 void Collision_BoundingBoxOfBrushTraceSegment(const colbrushf_t *start, const colbrushf_t *end, vec3_t mins, vec3_t maxs, float startfrac, float endfrac)
 {
        int i;
@@ -1615,7 +1543,7 @@ void Collision_BoundingBoxOfBrushTraceSegment(const colbrushf_t *start, const co
 
 //===========================================
 
-void Collision_TranslateBrush(const vec3_t shift, colbrushf_t *brush)
+static void Collision_TranslateBrush(const vec3_t shift, colbrushf_t *brush)
 {
        int i;
        // now we can transform the data
@@ -1631,7 +1559,7 @@ void Collision_TranslateBrush(const vec3_t shift, colbrushf_t *brush)
        VectorAdd(brush->maxs, shift, brush->maxs);
 }
 
-void Collision_TransformBrush(const matrix4x4_t *matrix, colbrushf_t *brush)
+static void Collision_TransformBrush(const matrix4x4_t *matrix, colbrushf_t *brush)
 {
        int i;
        vec3_t v;
@@ -1671,17 +1599,8 @@ typedef struct collision_cachedtrace_parameters_s
        dp_model_t *model;
        vec3_t end;
        vec3_t start;
-       vec3_t mins;
-       vec3_t maxs;
-//     const frameblend_t *frameblend;
-//     const skeleton_t *skeleton;
-//     matrix4x4_t inversematrix;
        int hitsupercontentsmask;
-       int type; // which type of query produced this cache entry
        matrix4x4_t matrix;
-       vec3_t bodymins;
-       vec3_t bodymaxs;
-       int bodysupercontents;
 }
 collision_cachedtrace_parameters_t;
 
@@ -1742,7 +1661,7 @@ void Collision_Cache_Init(mempool_t *mempool)
        Collision_Cache_Reset(true);
 }
 
-void Collision_Cache_RebuildHash(void)
+static void Collision_Cache_RebuildHash(void)
 {
        int index;
        int range = collision_cachedtrace_lastused + 1;
@@ -1810,7 +1729,7 @@ static unsigned int Collision_Cache_HashIndexForArray(unsigned int *array, unsig
        return hashindex;
 }
 
-static collision_cachedtrace_t *Collision_Cache_Lookup(int type, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask)
+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;
@@ -1823,28 +1742,18 @@ static collision_cachedtrace_t *Collision_Cache_Lookup(int type, dp_model_t *mod
        collision_cachedtrace_t *cached = collision_cachedtrace_array + index;
        collision_cachedtrace_parameters_t params;
        // all non-cached traces use the same index
-       if ((frameblend && frameblend[0].lerp != 1) || (skeleton && skeleton->relativetransforms))
-               r_refdef.stats.collisioncache_animated++;
-       else if (!collision_cache.integer)
+       if (!collision_cache.integer)
                r_refdef.stats.collisioncache_traced++;
        else
        {
                // cached trace lookup
                memset(&params, 0, sizeof(params));
-               params.type = type;
                params.model = model;
-               VectorCopy(bodymins, params.bodymins);
-               VectorCopy(bodymaxs, params.bodymaxs);
-               params.bodysupercontents = bodysupercontents;
                VectorCopy(start, params.start);
-               VectorCopy(mins,  params.mins);
-               VectorCopy(maxs,  params.maxs);
                VectorCopy(end,   params.end);
                params.hitsupercontentsmask = hitsupercontentsmask;
                params.matrix = *matrix;
-               //params.inversematrix = *inversematrix;
                fullhashindex = Collision_Cache_HashIndexForArray((unsigned int *)&params, sizeof(params) / sizeof(unsigned int));
-               //fullhashindex = Collision_Cache_HashIndexForArray((unsigned int *)&params, 10);
                hashindex = (int)(fullhashindex % (unsigned int)collision_cachedtrace_hashsize);
                for (index = hash[hashindex];index;index = arraynext[index])
                {
@@ -1859,20 +1768,6 @@ static collision_cachedtrace_t *Collision_Cache_Lookup(int type, dp_model_t *mod
                         || cached->p.start[0] != params.start[0]
                         || cached->p.start[1] != params.start[1]
                         || cached->p.start[2] != params.start[2]
-                        || cached->p.mins[0] != params.mins[0]
-                        || cached->p.mins[1] != params.mins[1]
-                        || cached->p.mins[2] != params.mins[2]
-                        || cached->p.maxs[0] != params.maxs[0]
-                        || cached->p.maxs[1] != params.maxs[1]
-                        || cached->p.maxs[2] != params.maxs[2]
-                        || cached->p.type != params.type
-                        || cached->p.bodysupercontents != params.bodysupercontents
-                        || cached->p.bodymins[0] != params.bodymins[0]
-                        || cached->p.bodymins[1] != params.bodymins[1]
-                        || cached->p.bodymins[2] != params.bodymins[2]
-                        || cached->p.bodymaxs[0] != params.bodymaxs[0]
-                        || cached->p.bodymaxs[1] != params.bodymaxs[1]
-                        || cached->p.bodymaxs[2] != params.bodymaxs[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]
@@ -1938,16 +1833,38 @@ static collision_cachedtrace_t *Collision_Cache_Lookup(int type, dp_model_t *mod
        return cached;
 }
 
-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)
+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)
 {
-       float starttransformed[3], endtransformed[3];
-       collision_cachedtrace_t *cached = Collision_Cache_Lookup(3, model, frameblend, skeleton, bodymins, bodymaxs, bodysupercontents, matrix, inversematrix, start, mins, maxs, end, 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;
 
@@ -1987,19 +1904,10 @@ void Collision_ClipToGenericEntity(trace_t *trace, dp_model_t *model, const fram
        // 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);
-
-       cached->result = *trace;
 }
 
 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)
 {
-       collision_cachedtrace_t *cached = Collision_Cache_Lookup(3, model, NULL, NULL, vec3_origin, vec3_origin, 0, &identitymatrix, &identitymatrix, start, mins, maxs, end, hitsupercontents);
-       if (cached->valid)
-       {
-               *trace = cached->result;
-               return;
-       }
-
        memset(trace, 0, sizeof(*trace));
        trace->fraction = trace->realfraction = 1;
        // ->TraceBox: TraceBrush not needed here, as worldmodel is never rotated
@@ -2008,20 +1916,11 @@ void Collision_ClipToWorld(trace_t *trace, dp_model_t *model, const vec3_t start
        trace->fraction = bound(0, trace->fraction, 1);
        trace->realfraction = bound(0, trace->realfraction, 1);
        VectorLerp(start, trace->fraction, end, trace->endpos);
-
-       cached->result = *trace;
 }
 
 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];
-       collision_cachedtrace_t *cached = Collision_Cache_Lookup(2, model, frameblend, skeleton, bodymins, bodymaxs, bodysupercontents, matrix, inversematrix, start, vec3_origin, vec3_origin, end, hitsupercontentsmask);
-       if (cached->valid)
-       {
-               *trace = cached->result;
-               return;
-       }
-
        memset(trace, 0, sizeof(*trace));
        trace->fraction = trace->realfraction = 1;
 
@@ -2044,19 +1943,10 @@ void Collision_ClipLineToGenericEntity(trace_t *trace, dp_model_t *model, const
        // 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);
-
-       cached->result = *trace;
 }
 
 void Collision_ClipLineToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t end, int hitsupercontents, qboolean hitsurfaces)
 {
-       collision_cachedtrace_t *cached = Collision_Cache_Lookup(2, model, NULL, NULL, vec3_origin, vec3_origin, 0, &identitymatrix, &identitymatrix, start, vec3_origin, vec3_origin, end, hitsupercontents);
-       if (cached->valid)
-       {
-               *trace = cached->result;
-               return;
-       }
-
        memset(trace, 0, sizeof(*trace));
        trace->fraction = trace->realfraction = 1;
        if (model && model->TraceLineAgainstSurfaces && hitsurfaces)
@@ -2066,20 +1956,11 @@ void Collision_ClipLineToWorld(trace_t *trace, dp_model_t *model, const vec3_t s
        trace->fraction = bound(0, trace->fraction, 1);
        trace->realfraction = bound(0, trace->realfraction, 1);
        VectorLerp(start, trace->fraction, end, trace->endpos);
-
-       cached->result = *trace;
 }
 
 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];
-       collision_cachedtrace_t *cached = Collision_Cache_Lookup(1, model, frameblend, skeleton, bodymins, bodymaxs, bodysupercontents, matrix, inversematrix, start, vec3_origin, vec3_origin, start, hitsupercontentsmask);
-       if (cached->valid)
-       {
-               *trace = cached->result;
-               return;
-       }
-
        memset(trace, 0, sizeof(*trace));
        trace->fraction = trace->realfraction = 1;
 
@@ -2097,26 +1978,15 @@ void Collision_ClipPointToGenericEntity(trace_t *trace, dp_model_t *model, const
        // 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);
-
-       cached->result = *trace;
 }
 
 void Collision_ClipPointToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, int hitsupercontents)
 {
-       collision_cachedtrace_t *cached = Collision_Cache_Lookup(1, model, NULL, NULL, vec3_origin, vec3_origin, 0, &identitymatrix, &identitymatrix, start, vec3_origin, vec3_origin, start, hitsupercontents);
-       if (cached->valid)
-       {
-               *trace = cached->result;
-               return;
-       }
-
        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);
-
-       cached->result = *trace;
 }
 
 void Collision_CombineTraces(trace_t *cliptrace, const trace_t *trace, void *touch, qboolean isbmodel)
index 919e9dcd9084ec597ef552cc6806935f7cbaff9b..5e0a4ba02367bf030266fcdf267df4bd79786457 100644 (file)
@@ -160,6 +160,9 @@ void Collision_ClipPointToGenericEntity(trace_t *trace, dp_model_t *model, const
 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
index 69a7a5d8d2c43718d701d08d5e30411ba24321c4..ada40e20ca8dbd2dd601e094949cd0e94864185f 100644 (file)
@@ -404,170 +404,167 @@ void MSG_WriteAngle (sizebuf_t *sb, float f, protocolversion_t protocol)
 //
 // reading functions
 //
-int msg_readcount;
-qboolean msg_badread;
 
-void MSG_BeginReading (void)
+void MSG_BeginReading(sizebuf_t *sb)
 {
-       msg_readcount = 0;
-       msg_badread = false;
+       sb->readcount = 0;
+       sb->badread = false;
 }
 
-int MSG_ReadLittleShort (void)
+int MSG_ReadLittleShort(sizebuf_t *sb)
 {
-       if (msg_readcount+2 > net_message.cursize)
+       if (sb->readcount+2 > sb->cursize)
        {
-               msg_badread = true;
+               sb->badread = true;
                return -1;
        }
-       msg_readcount += 2;
-       return (short)(net_message.data[msg_readcount-2] | (net_message.data[msg_readcount-1]<<8));
+       sb->readcount += 2;
+       return (short)(sb->data[sb->readcount-2] | (sb->data[sb->readcount-1]<<8));
 }
 
-int MSG_ReadBigShort (void)
+int MSG_ReadBigShort (sizebuf_t *sb)
 {
-       if (msg_readcount+2 > net_message.cursize)
+       if (sb->readcount+2 > sb->cursize)
        {
-               msg_badread = true;
+               sb->badread = true;
                return -1;
        }
-       msg_readcount += 2;
-       return (short)((net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1]);
+       sb->readcount += 2;
+       return (short)((sb->data[sb->readcount-2]<<8) + sb->data[sb->readcount-1]);
 }
 
-int MSG_ReadLittleLong (void)
+int MSG_ReadLittleLong (sizebuf_t *sb)
 {
-       if (msg_readcount+4 > net_message.cursize)
+       if (sb->readcount+4 > sb->cursize)
        {
-               msg_badread = true;
+               sb->badread = true;
                return -1;
        }
-       msg_readcount += 4;
-       return net_message.data[msg_readcount-4] | (net_message.data[msg_readcount-3]<<8) | (net_message.data[msg_readcount-2]<<16) | (net_message.data[msg_readcount-1]<<24);
+       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 (void)
+int MSG_ReadBigLong (sizebuf_t *sb)
 {
-       if (msg_readcount+4 > net_message.cursize)
+       if (sb->readcount+4 > sb->cursize)
        {
-               msg_badread = true;
+               sb->badread = true;
                return -1;
        }
-       msg_readcount += 4;
-       return (net_message.data[msg_readcount-4]<<24) + (net_message.data[msg_readcount-3]<<16) + (net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-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 (void)
+float MSG_ReadLittleFloat (sizebuf_t *sb)
 {
        union
        {
                float f;
                int l;
        } dat;
-       if (msg_readcount+4 > net_message.cursize)
+       if (sb->readcount+4 > sb->cursize)
        {
-               msg_badread = true;
+               sb->badread = true;
                return -1;
        }
-       msg_readcount += 4;
-       dat.l = net_message.data[msg_readcount-4] | (net_message.data[msg_readcount-3]<<8) | (net_message.data[msg_readcount-2]<<16) | (net_message.data[msg_readcount-1]<<24);
+       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 (void)
+float MSG_ReadBigFloat (sizebuf_t *sb)
 {
        union
        {
                float f;
                int l;
        } dat;
-       if (msg_readcount+4 > net_message.cursize)
+       if (sb->readcount+4 > sb->cursize)
        {
-               msg_badread = true;
+               sb->badread = true;
                return -1;
        }
-       msg_readcount += 4;
-       dat.l = (net_message.data[msg_readcount-4]<<24) | (net_message.data[msg_readcount-3]<<16) | (net_message.data[msg_readcount-2]<<8) | net_message.data[msg_readcount-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 (void)
+char *MSG_ReadString (sizebuf_t *sb, char *string, size_t maxstring)
 {
-       static char string[MAX_INPUTLINE];
-       const int maxstring = sizeof(string);
-       int l = 0,c;
-       // read string into buffer, but only store as many characters as will fit
-       while ((c = MSG_ReadByte()) > 0)
+       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 (int numbytes, unsigned char *out)
+int MSG_ReadBytes (sizebuf_t *sb, int numbytes, unsigned char *out)
 {
        int l, c;
-       for (l = 0;l < numbytes && (c = MSG_ReadByte()) != -1;l++)
+       for (l = 0;l < numbytes && (c = MSG_ReadByte(sb)) != -1;l++)
                out[l] = c;
        return l;
 }
 
-float MSG_ReadCoord13i (void)
+float MSG_ReadCoord13i (sizebuf_t *sb)
 {
-       return MSG_ReadLittleShort() * (1.0/8.0);
+       return MSG_ReadLittleShort(sb) * (1.0/8.0);
 }
 
-float MSG_ReadCoord16i (void)
+float MSG_ReadCoord16i (sizebuf_t *sb)
 {
-       return (signed short) MSG_ReadLittleShort();
+       return (signed short) MSG_ReadLittleShort(sb);
 }
 
-float MSG_ReadCoord32f (void)
+float MSG_ReadCoord32f (sizebuf_t *sb)
 {
-       return MSG_ReadLittleFloat();
+       return MSG_ReadLittleFloat(sb);
 }
 
-float MSG_ReadCoord (protocolversion_t protocol)
+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();
+               return MSG_ReadCoord13i(sb);
        else if (protocol == PROTOCOL_DARKPLACES1)
-               return MSG_ReadCoord32f();
+               return MSG_ReadCoord32f(sb);
        else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
-               return MSG_ReadCoord16i();
+               return MSG_ReadCoord16i(sb);
        else
-               return MSG_ReadCoord32f();
+               return MSG_ReadCoord32f(sb);
 }
 
-void MSG_ReadVector (float *v, protocolversion_t protocol)
+void MSG_ReadVector (sizebuf_t *sb, float *v, protocolversion_t protocol)
 {
-       v[0] = MSG_ReadCoord(protocol);
-       v[1] = MSG_ReadCoord(protocol);
-       v[2] = MSG_ReadCoord(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 (void)
+float MSG_ReadAngle8i (sizebuf_t *sb)
 {
-       return (signed char) MSG_ReadByte () * (360.0/256.0);
+       return (signed char) MSG_ReadByte (sb) * (360.0/256.0);
 }
 
-float MSG_ReadAngle16i (void)
+float MSG_ReadAngle16i (sizebuf_t *sb)
 {
-       return (signed short)MSG_ReadShort () * (360.0/65536.0);
+       return (signed short)MSG_ReadShort (sb) * (360.0/65536.0);
 }
 
-float MSG_ReadAngle32f (void)
+float MSG_ReadAngle32f (sizebuf_t *sb)
 {
-       return MSG_ReadFloat ();
+       return MSG_ReadFloat (sb);
 }
 
-float MSG_ReadAngle (protocolversion_t protocol)
+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 ();
+               return MSG_ReadAngle8i (sb);
        else
-               return MSG_ReadAngle16i ();
+               return MSG_ReadAngle16i (sb);
 }
 
 
@@ -992,7 +989,7 @@ COM_ParseToken_Simple
 Parse a token out of a string
 ==============
 */
-int COM_ParseToken_Simple(const char **datapointer, qboolean returnnewline, qboolean parsebackslash)
+int COM_ParseToken_Simple(const char **datapointer, qboolean returnnewline, qboolean parsebackslash, qboolean parsecomments)
 {
        int len;
        int c;
@@ -1027,14 +1024,14 @@ skipwhite:
        if (data[0] == '\r' && data[1] == '\n')
                data++;
 
-       if (data[0] == '/' && data[1] == '/')
+       if (parsecomments && data[0] == '/' && data[1] == '/')
        {
                // comment
                while (*data && *data != '\n' && *data != '\r')
                        data++;
                goto skipwhite;
        }
-       else if (data[0] == '/' && data[1] == '*')
+       else if (parsecomments && data[0] == '/' && data[1] == '*')
        {
                // comment
                data++;
@@ -1453,7 +1450,7 @@ static const gamemode_info_t gamemode_info [GAME_COUNT] =
 { GAME_BATTLEMECH,             GAME_BATTLEMECH,                "battlemech",           "-battlemech",          "Battlemech",                   "base",         NULL,                   "battlemech",   "battlemech"            }, // COMMANDLINEOPTION: Game: -battlemech runs the multiplayer topdown deathmatch game BattleMech
 { GAME_ZYMOTIC,                        GAME_ZYMOTIC,                   "zymotic",                      "-zymotic",                     "Zymotic",                              "basezym",      NULL,                   "zymotic",              "zymotic"                       }, // COMMANDLINEOPTION: Game: -zymotic runs the singleplayer game Zymotic
 { GAME_SETHERAL,               GAME_SETHERAL,                  "setheral",                     "-setheral",            "Setheral",                             "data",         NULL,                   "setheral",             "setheral"                      }, // COMMANDLINEOPTION: Game: -setheral runs the multiplayer game Setheral
-{ GAME_SOM,                            GAME_NORMAL,                    "som",                          "-som",                         "Son of Man",                   "id1",          "sonofman",             "som",                  "darkplaces"            }, // COMMANDLINEOPTION: Game: -som runs the multiplayer game Son Of Man
+{ GAME_SOM,                            GAME_NORMAL,                    "sonofman",                     "-som",                         "Son of Man",                   "id1",          "sonofman",             "som",                  "darkplaces"            }, // COMMANDLINEOPTION: Game: -som runs the multiplayer game Son Of Man
 { GAME_TENEBRAE,               GAME_NORMAL,                    "tenebrae",                     "-tenebrae",            "DarkPlaces-Tenebrae",  "id1",          "tenebrae",             "dp",                   "darkplaces"            }, // COMMANDLINEOPTION: Game: -tenebrae runs the graphics test mod known as Tenebrae (some features not implemented)
 { GAME_NEOTERIC,               GAME_NORMAL,                    "neoteric",                     "-neoteric",            "Neoteric",                             "id1",          "neobase",              "neo",                  "darkplaces"            }, // COMMANDLINEOPTION: Game: -neoteric runs the game Neoteric
 { GAME_OPENQUARTZ,             GAME_NORMAL,                    "openquartz",           "-openquartz",          "OpenQuartz",                   "id1",          NULL,                   "openquartz",   "darkplaces"            }, // COMMANDLINEOPTION: Game: -openquartz runs the game OpenQuartz, a standalone GPL replacement of the quake content
@@ -1478,10 +1475,9 @@ void COM_InitGameType (void)
        int i;
        int index = 0;
 
-       FS_StripExtension (com_argv[0], name, sizeof (name));
-       COM_ToLowerString (name, name, sizeof (name));
-
-       // check executable filename for keywords
+       // check executable filename for keywords, but do it SMARTLY - only check the last path element
+       FS_StripExtension(FS_FileWithoutPath(com_argv[0]), name, sizeof (name));
+       COM_ToLowerString(name, name, sizeof (name));
        for (i = 1;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
                if (gamemode_info[i].prog_name && gamemode_info[i].prog_name[0] && strstr (name, gamemode_info[i].prog_name))
                {
@@ -1617,25 +1613,18 @@ void COM_Init_Commands (void)
 ============
 va
 
-does a varargs printf into a temp buffer, so I don't need to have
-varargs versions of all text functions.
-FIXME: make this buffer size safe someday
+varargs print into provided buffer, returns buffer (so that it can be called in-line, unlike dpsnprintf)
 ============
 */
-char *va(const char *format, ...)
+char *va(char *buf, size_t buflen, const char *format, ...)
 {
        va_list argptr;
-       // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
-       static char string[8][1024], *s;
-       static int stringindex = 0;
 
-       s = string[stringindex];
-       stringindex = (stringindex + 1) & 7;
        va_start (argptr, format);
-       dpvsnprintf (s, sizeof (string[0]), format,argptr);
+       dpvsnprintf (buf, buflen, format,argptr);
        va_end (argptr);
 
-       return s;
+       return buf;
 }
 
 
@@ -1693,6 +1682,7 @@ void COM_ToLowerString (const char *in, char *out, size_t size_out)
 
        if(utf8_enable.integer)
        {
+               *out = 0;
                while(*in && size_out > 1)
                {
                        int n;
@@ -1725,6 +1715,7 @@ void COM_ToUpperString (const char *in, char *out, size_t size_out)
 
        if(utf8_enable.integer)
        {
+               *out = 0;
                while(*in && size_out > 1)
                {
                        int n;
@@ -1975,69 +1966,7 @@ COM_StringDecolorize(const char *in, size_t size_in, char *out, size_t size_out,
 #undef APPEND
 }
 
-// written by Elric, thanks Elric!
-char *SearchInfostring(const char *infostring, const char *key)
-{
-       static char value [MAX_INPUTLINE];
-       char crt_key [MAX_INPUTLINE];
-       size_t value_ind, key_ind;
-       char c;
-
-       if (*infostring++ != '\\')
-               return NULL;
-
-       value_ind = 0;
-       for (;;)
-       {
-               key_ind = 0;
-
-               // Get the key name
-               for (;;)
-               {
-                       c = *infostring++;
-
-                       if (c == '\0')
-                               return NULL;
-                       if (c == '\\' || key_ind == sizeof (crt_key) - 1)
-                       {
-                               crt_key[key_ind] = '\0';
-                               break;
-                       }
-
-                       crt_key[key_ind++] = c;
-               }
-
-               // If it's the key we are looking for, save it in "value"
-               if (!strcmp(crt_key, key))
-               {
-                       for (;;)
-                       {
-                               c = *infostring++;
-
-                               if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
-                               {
-                                       value[value_ind] = '\0';
-                                       return value;
-                               }
-
-                               value[value_ind++] = c;
-                       }
-               }
-
-               // Else, skip the value
-               for (;;)
-               {
-                       c = *infostring++;
-
-                       if (c == '\0')
-                               return NULL;
-                       if (c == '\\')
-                               break;
-               }
-       }
-}
-
-void InfoString_GetValue(const char *buffer, const char *key, char *value, size_t valuelength)
+char *InfoString_GetValue(const char *buffer, const char *key, char *value, size_t valuelength)
 {
        int pos = 0, j;
        size_t keylength;
@@ -2047,23 +1976,23 @@ void InfoString_GetValue(const char *buffer, const char *key, char *value, size_
        if (valuelength < 1 || !value)
        {
                Con_Printf("InfoString_GetValue: no room in value\n");
-               return;
+               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;
+               return NULL;
        }
        if (strchr(key, '\"'))
        {
                Con_Printf("InfoString_SetValue: key name \"%s\" contains \" which is not allowed in an infostring\n", key);
-               return;
+               return NULL;
        }
        if (!key[0])
        {
                Con_Printf("InfoString_GetValue: can not look up a key with no name\n");
-               return;
+               return NULL;
        }
        while (buffer[pos] == '\\')
        {
@@ -2074,12 +2003,13 @@ void InfoString_GetValue(const char *buffer, const char *key, char *value, size_
                        for (j = 0;buffer[pos+j] && buffer[pos+j] != '\\' && j < (int)valuelength - 1;j++)
                                value[j] = buffer[pos+j];
                        value[j] = 0;
-                       return;
+                       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)
@@ -2128,7 +2058,7 @@ void InfoString_SetValue(char *buffer, size_t bufferlength, const char *key, con
        if (value && value[0])
        {
                // set the key/value and append the remaining text
-               char tempbuffer[4096];
+               char tempbuffer[MAX_INPUTLINE];
                strlcpy(tempbuffer, buffer + pos2, sizeof(tempbuffer));
                dpsnprintf(buffer + pos, bufferlength - pos, "\\%s\\%s%s", key, value, tempbuffer);
        }
@@ -2142,8 +2072,8 @@ void InfoString_SetValue(char *buffer, size_t bufferlength, const char *key, con
 void InfoString_Print(char *buffer)
 {
        int i;
-       char key[2048];
-       char value[2048];
+       char key[MAX_INPUTLINE];
+       char value[MAX_INPUTLINE];
        while (*buffer)
        {
                if (*buffer != '\\')
index bd715ed65eeb2cc9259b33bfabb116c5db959b6a..e91be28379d9830d08f76523874c35dfb02c63bd 100644 (file)
@@ -46,6 +46,8 @@ typedef struct sizebuf_s
        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);
@@ -64,6 +66,8 @@ unsigned char COM_BlockSequenceCRCByteQW(unsigned char *base, int length, int se
 unsigned Com_BlockChecksum (void *buffer, int length);
 void Com_BlockFullChecksum (void *buffer, int len, unsigned char *outbuf);
 
+void COM_Init_Commands(void);
+
 
 //============================================================================
 //                                                     Endianess handling
@@ -160,34 +164,31 @@ void MSG_WriteCoord (sizebuf_t *sb, float f, protocolversion_t protocol);
 void MSG_WriteVector (sizebuf_t *sb, float *v, protocolversion_t protocol);
 void MSG_WriteAngle (sizebuf_t *sb, float f, protocolversion_t protocol);
 
-extern int                     msg_readcount;
-extern qboolean        msg_badread;            // set if a read goes beyond end of message
-
-void MSG_BeginReading (void);
-int MSG_ReadLittleShort (void);
-int MSG_ReadBigShort (void);
-int MSG_ReadLittleLong (void);
-int MSG_ReadBigLong (void);
-float MSG_ReadLittleFloat (void);
-float MSG_ReadBigFloat (void);
-char *MSG_ReadString (void);
-int MSG_ReadBytes (int numbytes, unsigned char *out);
-
-#define MSG_ReadChar() (msg_readcount >= net_message.cursize ? (msg_badread = true, -1) : (signed char)net_message.data[msg_readcount++])
-#define MSG_ReadByte() (msg_readcount >= net_message.cursize ? (msg_badread = true, -1) : (unsigned char)net_message.data[msg_readcount++])
+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 (void);
-float MSG_ReadAngle16i (void);
-float MSG_ReadAngle32f (void);
-float MSG_ReadCoord13i (void);
-float MSG_ReadCoord16i (void);
-float MSG_ReadCoord32f (void);
-float MSG_ReadCoord (protocolversion_t protocol);
-void MSG_ReadVector (float *v, protocolversion_t protocol);
-float MSG_ReadAngle (protocolversion_t protocol);
+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, float *v, protocolversion_t protocol);
+float MSG_ReadAngle (sizebuf_t *sb, protocolversion_t protocol);
 //@}
 //============================================================================
 
@@ -197,7 +198,7 @@ int COM_Wordwrap(const char *string, size_t length, float continuationSize, floa
 
 extern char com_token[MAX_INPUTLINE];
 
-int COM_ParseToken_Simple(const char **datapointer, qboolean returnnewline, qboolean parsebackslash);
+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);
@@ -211,8 +212,8 @@ void COM_Init (void);
 void COM_Shutdown (void);
 void COM_InitGameType (void);
 
-char   *va(const char *format, ...) DP_FUNC_PRINTF(1);
-// does a varargs printf into a temp buffer
+char *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
@@ -332,9 +333,7 @@ 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 *SearchInfostring(const char *infostring, const char *key);
-
-void InfoString_GetValue(const char *buffer, const char *key, char *value, size_t valuelength);
+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);
 
index bb9c277d7a7848429e6fd7f305c79d5166af2a4c..14175b07ad4c37cd84ea4e0202c438c43365c098 100644 (file)
@@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include <time.h>
 
 #include "quakedef.h"
+#include "thread.h"
 
 // for u8_encodech
 #include "ft2.h"
@@ -35,6 +36,7 @@ float con_cursorspeed = 4;
 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)
@@ -287,27 +289,9 @@ int ConBuffer_FindPrevLine(conbuffer_t *buf, int mask_must, int mask_mustnot, in
        return -1;
 }
 
-int Con_FindNextLine(conbuffer_t *buf, int mask_must, int mask_mustnot, int start)
-{
-       int i;
-       for(i = start + 1; i < buf->lines_count; ++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];
+       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);
@@ -338,23 +322,13 @@ size_t logq_size = 0;
 
 void Log_ConPrint (const char *msg);
 //@}
-/*
-====================
-Log_DestBuffer_Init
-====================
-*/
 static void Log_DestBuffer_Init(void)
 {
        memcpy(log_dest_buffer, "\377\377\377\377n", 5); // QW rcon print
        log_dest_buffer_pos = 5;
 }
 
-/*
-====================
-Log_DestBuffer_Flush
-====================
-*/
-void Log_DestBuffer_Flush(void)
+static void Log_DestBuffer_Flush_NoLock(void)
 {
        lhnetaddress_t log_dest_addr;
        lhnetsocket_t *log_dest_socket;
@@ -390,12 +364,21 @@ void Log_DestBuffer_Flush(void)
 
 /*
 ====================
-Log_Timestamp
+Log_DestBuffer_Flush
 ====================
 */
-const char* Log_Timestamp (const char *desc)
+void Log_DestBuffer_Flush(void)
 {
-       static char timestamp [128];
+       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;
@@ -422,13 +405,7 @@ const char* Log_Timestamp (const char *desc)
        return timestamp;
 }
 
-
-/*
-====================
-Log_Open
-====================
-*/
-void Log_Open (void)
+static void Log_Open (void)
 {
        if (logfile != NULL || log_file.string[0] == '\0')
                return;
@@ -441,7 +418,6 @@ void Log_Open (void)
        }
 }
 
-
 /*
 ====================
 Log_Close
@@ -490,7 +466,7 @@ void Log_Start (void)
                                        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();
+                                       Log_DestBuffer_Flush_NoLock();
                                        pos += n;
                                }
                        }
@@ -596,6 +572,10 @@ 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;
        Con_ClearNotify();
@@ -619,12 +599,15 @@ void Con_ClearNotify (void)
 Con_MessageMode_f
 ================
 */
-void Con_MessageMode_f (void)
+static void Con_MessageMode_f (void)
 {
        key_dest = key_message;
        chat_mode = 0; // "say"
-       chat_bufferlen = 0;
-       chat_buffer[0] = 0;
+       if(Cmd_Argc() > 1)
+       {
+               dpsnprintf(chat_buffer, sizeof(chat_buffer), "%s ", Cmd_Args());
+               chat_bufferlen = strlen(chat_buffer);
+       }
 }
 
 
@@ -633,12 +616,15 @@ void Con_MessageMode_f (void)
 Con_MessageMode2_f
 ================
 */
-void Con_MessageMode2_f (void)
+static void Con_MessageMode2_f (void)
 {
        key_dest = key_message;
        chat_mode = 1; // "say_team"
-       chat_bufferlen = 0;
-       chat_buffer[0] = 0;
+       if(Cmd_Argc() > 1)
+       {
+               dpsnprintf(chat_buffer, sizeof(chat_buffer), "%s ", Cmd_Args());
+               chat_bufferlen = strlen(chat_buffer);
+       }
 }
 
 /*
@@ -646,7 +632,7 @@ void Con_MessageMode2_f (void)
 Con_CommandMode_f
 ================
 */
-void Con_CommandMode_f (void)
+static void Con_CommandMode_f (void)
 {
        key_dest = key_message;
        if(Cmd_Argc() > 1)
@@ -701,7 +687,7 @@ static void Con_Maps_f (void)
                GetMapList("", NULL, 0);
 }
 
-void Con_ConDump_f (void)
+static void Con_ConDump_f (void)
 {
        int i;
        qfile_t *file;
@@ -716,17 +702,21 @@ void Con_ConDump_f (void)
                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);
 }
 
 /*
@@ -738,6 +728,8 @@ 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;
@@ -794,7 +786,10 @@ void Con_Init (void)
 
 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;
 }
 
 /*
@@ -806,14 +801,14 @@ All console printing must go through this in order to be displayed
 If no console is visible, the notify window will pop up.
 ================
 */
-void Con_PrintToHistory(const char *txt, int mask)
+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];
+       static char buf[CON_TEXTSIZE]; // con_mutex
        static int bufpos = 0;
 
        if(!con.text) // FIXME uses a non-abstracted property of con
@@ -908,7 +903,7 @@ void Con_Rcon_Redirect_Init(lhnetsocket_t *sock, lhnetaddress_t *dest, qboolean
        rcon_redirect_bufferpos = 5;
 }
 
-void Con_Rcon_Redirect_Flush(void)
+static void Con_Rcon_Redirect_Flush(void)
 {
        rcon_redirect_buffer[rcon_redirect_bufferpos] = 0;
        if (rcon_redirect_proquakeprotocol)
@@ -941,7 +936,7 @@ Con_Rcon_AddChar
 ================
 */
 /// Adds a character to the rcon buffer.
-void Con_Rcon_AddChar(int c)
+static void Con_Rcon_AddChar(int c)
 {
        if(log_dest_buffer_appending)
                return;
@@ -962,7 +957,7 @@ void Con_Rcon_AddChar(int c)
                        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();
+                       Log_DestBuffer_Flush_NoLock();
        }
        else
                log_dest_buffer_pos = 0;
@@ -1047,6 +1042,9 @@ void Con_MaskPrint(int additionalmask, const char *msg)
        static int index = 0;
        static char line[MAX_INPUTLINE];
 
+       if (con_mutex)
+               Thread_LockMutex(con_mutex);
+
        for (;*msg;msg++)
        {
                Con_Rcon_AddChar(*msg);
@@ -1313,6 +1311,9 @@ void Con_MaskPrint(int additionalmask, const char *msg)
                        mask = 0;
                }
        }
+
+       if (con_mutex)
+               Thread_UnlockMutex(con_mutex);
 }
 
 /*
@@ -1411,7 +1412,7 @@ Modified by EvilTypeGuy eviltypeguy@qeradiant.com
 ================
 */
 extern cvar_t r_font_disable_freetype;
-void Con_DrawInput (void)
+static void Con_DrawInput (void)
 {
        int             y;
        int             i;
@@ -1450,7 +1451,8 @@ void Con_DrawInput (void)
                                int ofs = u8_bytelen(text + key_linepos, 1);
                                size_t len;
                                const char *curbuf;
-                               curbuf = u8_encodech(0xE000 + 11 + 130 * key_insert, &len);
+                               char charbuf16[16];
+                               curbuf = u8_encodech(0xE000 + 11 + 130 * key_insert, &len, charbuf16);
 
                                if (curbuf)
                                {
@@ -1488,7 +1490,8 @@ void Con_DrawInput (void)
                        {
                                size_t len;
                                const char *curbuf;
-                               curbuf = u8_encodech(0xE000 + 11 + 130 * key_insert, &len);
+                               char charbuf16[16];
+                               curbuf = u8_encodech(0xE000 + 11 + 130 * key_insert, &len, charbuf16);
                                memcpy(text, curbuf, len);
                                text[len] = 0;
                        }
@@ -1516,7 +1519,7 @@ typedef struct
 }
 con_text_info_t;
 
-float Con_WordWidthFunc(void *passthrough, const char *w, size_t *length, float maxWidth)
+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)
@@ -1530,13 +1533,13 @@ float Con_WordWidthFunc(void *passthrough, const char *w, size_t *length, float
                return DrawQ_TextWidth(w, *length, ti->fontsize, ti->fontsize, false, ti->font);
        else
        {
-               printf("Con_WordWidthFunc: can't get here (maxWidth should never be %f)\n", maxWidth);
+               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;
        }
 }
 
-int Con_CountLineFunc(void *passthrough, const char *line, size_t length, float width, qboolean isContinuation)
+static int Con_CountLineFunc(void *passthrough, const char *line, size_t length, float width, qboolean isContinuation)
 {
        (void) passthrough;
        (void) line;
@@ -1546,7 +1549,7 @@ int Con_CountLineFunc(void *passthrough, const char *line, size_t length, float
        return 1;
 }
 
-int Con_DisplayLineFunc(void *passthrough, const char *line, size_t length, float width, qboolean isContinuation)
+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;
 
@@ -1567,7 +1570,7 @@ int Con_DisplayLineFunc(void *passthrough, const char *line, size_t length, floa
        return 1;
 }
 
-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)
+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;
@@ -1658,6 +1661,7 @@ void Con_DrawNotify (void)
        int numChatlines;
        int chatpos;
 
+       if (con_mutex) Thread_LockMutex(con_mutex);
        ConBuffer_FixTimes(&con);
 
        numChatlines = con_chat.integer;
@@ -1732,7 +1736,8 @@ void Con_DrawNotify (void)
                //static char *cursor[2] = { "\xee\x80\x8a", "\xee\x80\x8b" }; // { off, on }
                int colorindex = -1;
                const char *cursor;
-               cursor = u8_encodech(0xE00A + ((int)(realtime * con_cursorspeed)&1), NULL);
+               char charbuf16[16];
+               cursor = u8_encodech(0xE00A + ((int)(realtime * con_cursorspeed)&1), NULL, charbuf16);
 
                // LordHavoc: speedup, and other improvements
                if (chat_mode < 0)
@@ -1748,6 +1753,7 @@ void Con_DrawNotify (void)
                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);
 }
 
 /*
@@ -1757,7 +1763,7 @@ Con_LineHeight
 Returns the height of a given console line; calculates it if necessary.
 ================
 */
-int Con_LineHeight(int lineno)
+static int Con_LineHeight(int lineno)
 {
        con_lineinfo_t *li = &CON_LINES(lineno);
        if(li->height == -1)
@@ -1781,7 +1787,7 @@ If alpha is 0, the line is not drawn, but still wrapped and its height
 returned.
 ================
 */
-int Con_DrawConsoleLine(int mask_must, int mask_mustnot, float y, int lineno, float ymin, float ymax)
+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;
@@ -1866,6 +1872,8 @@ void Con_DrawConsole (int lines)
        if (lines <= 0)
                return;
 
+       if (con_mutex) Thread_LockMutex(con_mutex);
+
        if (con_backscroll < 0)
                con_backscroll = 0;
 
@@ -1972,6 +1980,7 @@ void Con_DrawConsole (int lines)
        Con_DrawInput ();
 
        r_draw2d_force = false;
+       if (con_mutex) Thread_UnlockMutex(con_mutex);
 }
 
 /*
@@ -2070,7 +2079,7 @@ qboolean GetMapList (const char *s, char *completedname, int completednamebuffer
                                for (;;)
                                {
                                        int l;
-                                       if (!COM_ParseToken_Simple(&data, false, false))
+                                       if (!COM_ParseToken_Simple(&data, false, false, true))
                                                break;
                                        if (com_token[0] == '{')
                                                continue;
@@ -2081,7 +2090,7 @@ qboolean GetMapList (const char *s, char *completedname, int completednamebuffer
                                        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))
+                                       if (!COM_ParseToken_Simple(&data, false, false, true))
                                                break;
                                        if (developer_extra.integer)
                                                Con_DPrintf("key: %s %s\n", keyname, com_token);
@@ -2174,7 +2183,7 @@ void Con_DisplayList(const char **list)
        SanitizeString strips color tags from the string in
        and writes the result on string out
 */
-void SanitizeString(char *in, char *out)
+static void SanitizeString(char *in, char *out)
 {
        while(*in)
        {
@@ -2229,7 +2238,7 @@ static int Nicks_offset[MAX_SCOREBOARD]; // when nicks use a space, we need this
 static int Nicks_matchpos;
 
 // co against <<:BLASTER:>> is true!?
-int Nicks_strncasecmp_nospaces(char *a, char *b, unsigned int a_len)
+static int Nicks_strncasecmp_nospaces(char *a, char *b, unsigned int a_len)
 {
        while(a_len)
        {
@@ -2255,7 +2264,7 @@ int Nicks_strncasecmp_nospaces(char *a, char *b, unsigned int a_len)
        }
        return 0;
 }
-int Nicks_strncasecmp(char *a, char *b, unsigned int a_len)
+static int Nicks_strncasecmp(char *a, char *b, unsigned int a_len)
 {
        char space_char;
        if(!(con_nickcompletion_flags.integer & NICKS_ALPHANUMERICS_ONLY))
@@ -2306,7 +2315,7 @@ int Nicks_strncasecmp(char *a, char *b, unsigned int a_len)
 
    Count the number of possible nicks to complete
  */
-int Nicks_CompleteCountPossible(char *line, int pos, char *s, qboolean isCon)
+static int Nicks_CompleteCountPossible(char *line, int pos, char *s, qboolean isCon)
 {
        char name[128];
        int i, p;
@@ -2373,14 +2382,14 @@ int Nicks_CompleteCountPossible(char *line, int pos, char *s, qboolean isCon)
        return count;
 }
 
-void Cmd_CompleteNicksPrint(int count)
+static void Cmd_CompleteNicksPrint(int count)
 {
        int i;
        for(i = 0; i < count; ++i)
                Con_Printf("%s\n", Nicks_list[i]);
 }
 
-void Nicks_CutMatchesNormal(int count)
+static void Nicks_CutMatchesNormal(int count)
 {
        // cut match 0 down to the longest possible completion
        int i;
@@ -2403,7 +2412,7 @@ void Nicks_CutMatchesNormal(int count)
        //Con_Printf("List0: %s\n", Nicks_sanlist[0]);
 }
 
-unsigned int Nicks_strcleanlen(const char *s)
+static unsigned int Nicks_strcleanlen(const char *s)
 {
        unsigned int l = 0;
        while(*s)
@@ -2418,7 +2427,7 @@ unsigned int Nicks_strcleanlen(const char *s)
        return l;
 }
 
-void Nicks_CutMatchesAlphaNumeric(int count)
+static void Nicks_CutMatchesAlphaNumeric(int count)
 {
        // cut match 0 down to the longest possible completion
        int i;
@@ -2477,7 +2486,7 @@ void Nicks_CutMatchesAlphaNumeric(int count)
        }
 }
 
-void Nicks_CutMatchesNoSpaces(int count)
+static void Nicks_CutMatchesNoSpaces(int count)
 {
        // cut match 0 down to the longest possible completion
        int i;
@@ -2533,7 +2542,7 @@ void Nicks_CutMatchesNoSpaces(int count)
        }
 }
 
-void Nicks_CutMatches(int count)
+static void Nicks_CutMatches(int count)
 {
        if(con_nickcompletion_flags.integer & NICKS_ALPHANUMERICS_ONLY)
                Nicks_CutMatchesAlphaNumeric(count);
@@ -2543,7 +2552,7 @@ void Nicks_CutMatches(int count)
                Nicks_CutMatchesNormal(count);
 }
 
-const char **Nicks_CompleteBuildList(int count)
+static const char **Nicks_CompleteBuildList(int count)
 {
        const char **buf;
        int bpos = 0;
@@ -2563,7 +2572,7 @@ const char **Nicks_CompleteBuildList(int count)
        Nicks_AddLastColor
        Restores the previous used color, after the autocompleted name.
 */
-int Nicks_AddLastColor(char *buffer, int pos)
+static int Nicks_AddLastColor(char *buffer, int pos)
 {
        qboolean quote_added = false;
        int match;
@@ -2684,6 +2693,7 @@ void Con_CompleteCommandLine (void)
        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;
@@ -2704,7 +2714,7 @@ void Con_CompleteCommandLine (void)
        {
                strlcpy(command, key_line + 1, min(sizeof(command), (unsigned int)(space - key_line)));
 
-               patterns = Cvar_VariableString(va("con_completion_%s", command)); // TODO maybe use a better place for this?
+               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
 
@@ -2756,7 +2766,7 @@ void Con_CompleteCommandLine (void)
 
                                stringlistinit(&resultbuf);
                                stringlistinit(&dirbuf);
-                               while(COM_ParseToken_Simple(&patterns, false, false))
+                               while(COM_ParseToken_Simple(&patterns, false, false, true))
                                {
                                        fssearch_t *search;
                                        if(strchr(com_token, '/'))
index 8b2d7680579a2d26b982bd96a43a08e68fb763dc..860c501eebfe3b89a0901842426e89ef72326915 100644 (file)
@@ -63,6 +63,8 @@ void Con_DrawNotify (void);
 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
index 6a40df4c7233b4c259c9e1c14ed839cc3caa486e..09c164e2293240baf404a1138bc3759ae86ea4d6 100644 (file)
@@ -2,6 +2,7 @@
 #include "quakedef.h"
 #include "crypto.h"
 #include "common.h"
+#include "thread.h"
 
 #include "hmac.h"
 #include "libcurl.h"
@@ -144,6 +145,8 @@ static size_t Crypto_UnParsePack(char *buf, size_t len, unsigned long header, co
 #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
 
 #else
 
@@ -156,6 +159,13 @@ static size_t Crypto_UnParsePack(char *buf, size_t len, unsigned long header, co
 #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);
@@ -193,6 +203,8 @@ 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 dllfunction_t d0_blind_id_funcs[] =
 {
        {"d0_blind_id_new", (void **) &qd0_blind_id_new},
@@ -230,6 +242,8 @@ static dllfunction_t d0_blind_id_funcs[] =
        {"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},
        {NULL, NULL}
 };
 // end of d0_blind_id interface
@@ -340,14 +354,15 @@ 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)
+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(*fs_userdir)
-               f = FS_SysOpen(va("%s%s", fs_userdir, path), "rb", false);
-       if(!f)
-               f = FS_SysOpen(va("%s%s", fs_basedir, path), "rb", false);
+       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);
@@ -748,11 +763,20 @@ static void Crypto_BuildChallengeAppend(void)
        challenge_append_length = p - challenge_append;
 }
 
-static void Crypto_LoadKeys(void)
+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
@@ -767,14 +791,14 @@ static void Crypto_LoadKeys(void)
                memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i]));
                memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i]));
                pubkeys_havepriv[i] = false;
-               len = Crypto_LoadFile(va("key_%d.d0pk", i), buf, sizeof(buf));
+               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("key_%d.d0si", i), buf, sizeof(buf));
+                               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))
@@ -782,9 +806,9 @@ static void Crypto_LoadKeys(void)
                                                len2 = FP64_SIZE;
                                                if(qd0_blind_id_fingerprint64_public_id(pubkeys[i], pubkeys_priv_fp64[i], &len2)) // keeps final NUL
                                                {
-                                                       Con_Printf("Loaded private ID key_%d.d0si for key_%d.d0pk (fingerprint: %s)\n", i, i, pubkeys_priv_fp64[i]);
+                                                       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]);
                                                        pubkeys_havepriv[i] = true;
-                                                       strlcat(crypto_idstring_buf, va(" %s@%s", pubkeys_priv_fp64[i], pubkeys_fp64[i]), sizeof(crypto_idstring_buf));
+                                                       strlcat(crypto_idstring_buf, va(vabuf, sizeof(vabuf), " %s@%s", pubkeys_priv_fp64[i], pubkeys_fp64[i]), sizeof(crypto_idstring_buf));
                                                }
                                                else
                                                {
@@ -853,6 +877,7 @@ static void Crypto_LoadKeys(void)
 static void Crypto_UnloadKeys(void)
 {
        int i;
+
        keygen_i = -1;
        for(i = 0; i < MAX_PUBKEYS; ++i)
        {
@@ -867,6 +892,45 @@ static void Crypto_UnloadKeys(void)
        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;
@@ -892,13 +956,21 @@ void Crypto_Shutdown(void)
 
                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();
@@ -910,10 +982,16 @@ void Crypto_Init(void)
        Crypto_Rijndael_OpenLibrary(); // if this fails, it's uncritical
 
        Crypto_InitHostKeys();
-       Crypto_LoadKeys();
 }
 // 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)
 {
@@ -926,11 +1004,15 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch
        d0_blind_id_t *ctx, *ctx2;
        D0_BOOL status;
        size_t len2;
+       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;
        }
 
@@ -938,12 +1020,14 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch
        {
                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))
@@ -958,12 +1042,14 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch
                        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;
        }
 
@@ -973,6 +1059,7 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch
        {
                Con_Printf("d0_blind_id_new failed\n");
                keygen_i = -1;
+               SV_UnlockThreadMutex();
                return;
        }
        ctx2 = qd0_blind_id_new();
@@ -981,6 +1068,7 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch
                Con_Printf("d0_blind_id_new failed\n");
                qd0_blind_id_free(ctx);
                keygen_i = -1;
+               SV_UnlockThreadMutex();
                return;
        }
        if(!qd0_blind_id_copy(ctx, pubkeys[keygen_i]))
@@ -989,6 +1077,7 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch
                qd0_blind_id_free(ctx);
                qd0_blind_id_free(ctx2);
                keygen_i = -1;
+               SV_UnlockThreadMutex();
                return;
        }
        if(!qd0_blind_id_copy(ctx2, pubkeys[keygen_i]))
@@ -997,6 +1086,7 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch
                qd0_blind_id_free(ctx);
                qd0_blind_id_free(ctx2);
                keygen_i = -1;
+               SV_UnlockThreadMutex();
                return;
        }
        bufsize = sizeof(buf);
@@ -1006,6 +1096,7 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch
                qd0_blind_id_free(ctx);
                qd0_blind_id_free(ctx2);
                keygen_i = -1;
+               SV_UnlockThreadMutex();
                return;
        }
        buf2size = sizeof(buf2);
@@ -1015,6 +1106,7 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch
                qd0_blind_id_free(ctx);
                qd0_blind_id_free(ctx2);
                keygen_i = -1;
+               SV_UnlockThreadMutex();
                return;
        }
        bufsize = sizeof(buf);
@@ -1024,6 +1116,7 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch
                qd0_blind_id_free(ctx);
                qd0_blind_id_free(ctx2);
                keygen_i = -1;
+               SV_UnlockThreadMutex();
                return;
        }
        buf2size = sizeof(buf2);
@@ -1033,6 +1126,7 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch
                qd0_blind_id_free(ctx);
                qd0_blind_id_free(ctx2);
                keygen_i = -1;
+               SV_UnlockThreadMutex();
                return;
        }
        qd0_blind_id_free(ctx);
@@ -1043,9 +1137,9 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch
        len2 = FP64_SIZE;
        if(qd0_blind_id_fingerprint64_public_id(pubkeys[keygen_i], pubkeys_priv_fp64[keygen_i], &len2)) // keeps final NUL
        {
-               Con_Printf("Received private ID key_%d.d0pk (fingerprint: %s)\n", keygen_i, pubkeys_priv_fp64[keygen_i]);
+               Con_Printf("Received 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(" %s@%s", pubkeys_priv_fp64[keygen_i], pubkeys_fp64[keygen_i]), sizeof(crypto_idstring_buf));
+               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();
        }
@@ -1056,36 +1150,32 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch
        {
                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;
        }
 
-       if(*fs_userdir)
-       {
-               FS_CreatePath(va("%skey_%d.d0si", fs_userdir, keygen_i));
-               f = FS_SysOpen(va("%skey_%d.d0si", fs_userdir, keygen_i), "wb", false);
-       }
-       if(!f)
-       {
-               FS_CreatePath(va("%skey_%d.d0si", fs_basedir, keygen_i));
-               f = FS_SysOpen(va("%skey_%d.d0si", fs_basedir, keygen_i), "wb", false);
-       }
+       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\n", keygen_i);
+               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);
 
-       Con_Printf("Saved to key_%d.d0si\n", 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)
@@ -1106,20 +1196,25 @@ static void Crypto_KeyGen_f(void)
                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(pubkeys_havepriv[i])
        {
                Con_Printf("there is already a private key for %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;
@@ -1127,6 +1222,7 @@ static void Crypto_KeyGen_f(void)
        {
                Con_Printf("d0_blind_id_start failed\n");
                keygen_i = -1;
+               SV_UnlockThreadMutex();
                return;
        }
        p[0] = buf;
@@ -1135,6 +1231,7 @@ static void Crypto_KeyGen_f(void)
        {
                Con_Printf("d0_blind_id_generate_private_id_request failed\n");
                keygen_i = -1;
+               SV_UnlockThreadMutex();
                return;
        }
        buf2pos = strlen(Cmd_Argv(2));
@@ -1143,12 +1240,14 @@ static void Crypto_KeyGen_f(void)
        {
                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;
@@ -1157,9 +1256,11 @@ static void Crypto_KeyGen_f(void)
        {
                Con_Printf("curl failed\n");
                keygen_i = -1;
+               SV_UnlockThreadMutex();
                return;
        }
        Con_Printf("key generation in progress\n");
+       SV_UnlockThreadMutex();
 }
 // end
 
@@ -1185,7 +1286,7 @@ static void Crypto_Keys_f(void)
                {
                        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 (fingerprint: %s)\n", i, pubkeys_priv_fp64[i]);
+                               Con_Printf("    private ID key_%d.d0si%s (public key fingerprint: %s)\n", i, sessionid.string, pubkeys_priv_fp64[i]);
                }
        }
 }
@@ -1522,6 +1623,8 @@ static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_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
@@ -1532,7 +1635,7 @@ static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in,
                int i;
                // sorry, we have to verify the challenge here to not reflect network spam
 
-               if (!(s = SearchInfostring(string + 4, "challenge")))
+               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++)
@@ -1552,9 +1655,9 @@ static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in,
                const char *cnt, *s, *p;
                int id;
                int clientid = -1, serverid = -1;
-               cnt = SearchInfostring(string + 4, "id");
+               cnt = InfoString_GetValue(string + 4, "id", infostringvalue, sizeof(infostringvalue));
                id = (cnt ? atoi(cnt) : -1);
-               cnt = SearchInfostring(string + 4, "cnt");
+               cnt = InfoString_GetValue(string + 4, "cnt", infostringvalue, sizeof(infostringvalue));
                if(!cnt)
                        return CRYPTO_DISCARD; // pre-challenge: rather be silent
                GetUntilNul(&data_in, &len_in);
@@ -1563,7 +1666,7 @@ static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in,
                if(!strcmp(cnt, "0"))
                {
                        int i;
-                       if (!(s = SearchInfostring(string + 4, "challenge")))
+                       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++)
@@ -1574,7 +1677,7 @@ static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in,
                        if (i == MAX_CHALLENGES) // challenge mismatch is silent
                                return CRYPTO_DISCARD; // pre-challenge: rather be silent
 
-                       if (!(s = SearchInfostring(string + 4, "aeslevel")))
+                       if (!(s = InfoString_GetValue(string + 4, "aeslevel", infostringvalue, sizeof(infostringvalue))))
                                aeslevel = 0; // not supported
                        else
                                aeslevel = bound(0, atoi(s), 3);
@@ -1660,7 +1763,7 @@ static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in,
                                        CLEAR_CDATA;
                                        return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
                                }
-                               PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\1\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes));
+                               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;
@@ -1685,7 +1788,7 @@ static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in,
                                        CLEAR_CDATA;
                                        return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
                                }
-                               PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\5\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes));
+                               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;
@@ -1710,11 +1813,11 @@ static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in,
                                return CRYPTO_NOMATCH; // pre-challenge, rather be silent
                        if(id >= 0)
                                if(CDATA->cdata_id != id)
-                                       return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_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("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
+                               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("d0pk\\cnt\\3\\id\\%d", CDATA->cdata_id));
+                       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;
@@ -1752,10 +1855,10 @@ static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in,
                                return CRYPTO_NOMATCH; // pre-challenge, rather be silent
                        if(id >= 0)
                                if(CDATA->cdata_id != id)
-                                       return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_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("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
-                       PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\5\\id\\%d", CDATA->cdata_id));
+                               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;
@@ -1778,9 +1881,9 @@ static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in,
                                return CRYPTO_NOMATCH; // pre-challenge, rather be silent
                        if(id >= 0)
                                if(CDATA->cdata_id != id)
-                                       return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_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("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
+                               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))
                        {
@@ -1830,11 +1933,12 @@ int Crypto_ServerParsePacket(const char *data_in, size_t len_in, char *data_out,
        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 = SearchInfostring(data_in + 4, "cnt");
+                       cnt = InfoString_GetValue(data_in + 4, "cnt", infostringvalue, sizeof(infostringvalue));
                        if(cnt)
                                if(!strcmp(cnt, "0"))
                                        do_reject = true;
@@ -1863,12 +1967,12 @@ int Crypto_ServerParsePacket(const char *data_in, size_t len_in, char *data_out,
                        *len_out = 0;
                        return CRYPTO_DISCARD;
                }
-               t = Sys_DoubleTime();
+               t = Sys_DirtyTime();
        }
        ret = Crypto_ServerParsePacket_Internal(data_in, len_in, data_out, len_out, peeraddress);
        if(do_time)
        {
-               t = Sys_DoubleTime() - t;
+               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;
@@ -1900,6 +2004,8 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out,
        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
@@ -1935,7 +2041,7 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out,
        }
        else if (len_in >= 13 && !memcmp(string, "infoResponse\x0A", 13))
        {
-               s = SearchInfostring(string + 13, "d0_blind_id");
+               s = InfoString_GetValue(string + 13, "d0_blind_id", infostringvalue, sizeof(infostringvalue));
                if(s)
                        Crypto_StoreHostKey(peeraddress, s, true);
                return CRYPTO_NOMATCH;
@@ -1950,7 +2056,7 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out,
                        save = *p;
                        * (char *) p = 0; // cut off the string there
                }
-               s = SearchInfostring(string + 15, "d0_blind_id");
+               s = InfoString_GetValue(string + 15, "d0_blind_id", infostringvalue, sizeof(infostringvalue));
                if(s)
                        Crypto_StoreHostKey(peeraddress, s, true);
                if(p)
@@ -2110,7 +2216,7 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out,
 
                        // build outgoing message
                        // append regular stuff
-                       PutWithNul(&data_out_p, len_out, va("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, 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] : "");
 
@@ -2180,9 +2286,9 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out,
        {
                const char *cnt;
                int id;
-               cnt = SearchInfostring(string + 4, "id");
+               cnt = InfoString_GetValue(string + 4, "id", infostringvalue, sizeof(infostringvalue));
                id = (cnt ? atoi(cnt) : -1);
-               cnt = SearchInfostring(string + 4, "cnt");
+               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);
@@ -2193,13 +2299,13 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out,
                {
                        if(id >= 0)
                                if(CDATA->cdata_id != id)
-                                       return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_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("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
+                               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 = SearchInfostring(string + 4, "aes")))
+                       if((s = InfoString_GetValue(string + 4, "aes", infostringvalue, sizeof(infostringvalue))))
                                aes = atoi(s);
                        else
                                aes = false;
@@ -2223,7 +2329,7 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out,
                        }
                        crypto->use_aes = aes != 0;
 
-                       PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\2\\id\\%d", CDATA->cdata_id));
+                       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;
@@ -2242,9 +2348,9 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out,
 
                        if(id >= 0)
                                if(CDATA->cdata_id != id)
-                                       return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_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("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
+                               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"
 
@@ -2278,12 +2384,12 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out,
                        }
 
                        // cache the server key
-                       Crypto_StoreHostKey(&cls.connect_address, va("%d %s@%s", crypto->use_aes ? 1 : 0, crypto->server_idfp, pubkeys_fp64[CDATA->s]), false);
+                       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("d0pk\\cnt\\4\\id\\%d", CDATA->cdata_id));
+                               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;
@@ -2319,15 +2425,15 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out,
 
                        if(id >= 0)
                                if(CDATA->cdata_id != id)
-                                       return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_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("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
+                               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 = SearchInfostring(string + 4, "aes")))
+                               if((s = InfoString_GetValue(string + 4, "aes", infostringvalue, sizeof(infostringvalue))))
                                        aes = atoi(s);
                                else
                                        aes = false;
@@ -2350,7 +2456,7 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out,
                                crypto->use_aes = aes != 0;
                        }
 
-                       PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\6\\id\\%d", CDATA->cdata_id));
+                       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;
index 507c0a06242157b85be327806279e8711c72d938..7edfcd98a389af04ed25559a62de798ebb2fa851 100644 (file)
@@ -31,7 +31,10 @@ 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)
index 55bf6bf1716a7f8a6d0a552f625bbbde8699e084..47573d3cf8cc446661775e2d4d0cb6d4238f8eb7 100644 (file)
 //[515]: omg !!! optimize it ! a lot of hacks here and there also :P
 
 #define CSQC_RETURNVAL prog->globals.generic[OFS_RETURN]
-#define CSQC_BEGIN             csqc_tmpprog=prog;prog=0;PRVM_SetProg(PRVM_CLIENTPROG);
-#define CSQC_END               prog=csqc_tmpprog;
-
-static prvm_prog_t *csqc_tmpprog;
+#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();
+               VM_ClearTraceGlobals(prog);
                PRVM_clientglobalfloat(trace_networkentity) = 0;
        CSQC_END
 }
@@ -196,28 +195,9 @@ prvm_required_field_t cl_reqglobals[] =
 #undef PRVM_DECLARE_function
 };
 
-void CL_VM_Error (const char *format, ...) DP_FUNC_PRINTF(1);
-void CL_VM_Error (const char *format, ...)     //[515]: hope it will be never executed =)
-{
-       char errorstring[4096];
-       va_list argptr;
-
-       va_start (argptr, format);
-       dpvsnprintf (errorstring, sizeof(errorstring), format, argptr);
-       va_end (argptr);
-//     Con_Printf( "CL_VM_Error: %s\n", errorstring );
-
-       PRVM_Crash();
-       cl.csqc_loaded = false;
-
-       Cvar_SetValueQuick(&csqc_progcrc, -1);
-       Cvar_SetValueQuick(&csqc_progsize, -1);
-
-//     Host_AbortCurrentFrame();       //[515]: hmmm... if server says it needs csqc then client MUST disconnect
-       Host_Error("CL_VM_Error: %s", errorstring);
-}
 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
@@ -230,6 +210,7 @@ void CL_VM_UpdateDmgGlobals (int dmg_take, int dmg_save, vec3_t dmg_origin)
 
 void CSQC_UpdateNetworkTimes(double newtime, double oldtime)
 {
+       prvm_prog_t *prog = CLVM_prog;
        if(!cl.csqc_loaded)
                return;
        CSQC_BEGIN
@@ -240,9 +221,9 @@ void CSQC_UpdateNetworkTimes(double newtime, double oldtime)
 }
 
 //[515]: set globals before calling R_UpdateView, WEIRD CRAP
-void CSQC_R_RecalcView (void);
 static void CSQC_SetGlobals (void)
 {
+       prvm_prog_t *prog = CLVM_prog;
        CSQC_BEGIN
                PRVM_clientglobalfloat(time) = cl.time;
                PRVM_clientglobalfloat(frametime) = max(0, cl.time - cl.oldtime);
@@ -274,17 +255,19 @@ static void CSQC_SetGlobals (void)
 
 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);
-       PRVM_ExecuteProgram(PRVM_clientedictfunction(ed, predraw), "CSQC_Predraw: NULL function\n");
+       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))
@@ -292,7 +275,7 @@ void CSQC_Think (prvm_edict_t *ed)
                PRVM_clientedictfloat(ed, nextthink) = 0;
                b = PRVM_clientglobaledict(self);
                PRVM_clientglobaledict(self) = PRVM_EDICT_TO_PROG(ed);
-               PRVM_ExecuteProgram(PRVM_clientedictfunction(ed, think), "CSQC_Think: NULL function\n");
+               prog->ExecuteProgram(prog, PRVM_clientedictfunction(ed, think), "CSQC_Think: NULL function\n");
                PRVM_clientglobaledict(self) = b;
        }
 }
@@ -301,6 +284,7 @@ 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;
@@ -320,6 +304,7 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed, int edictnum)
                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);
@@ -357,12 +342,12 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed, int edictnum)
                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(&entrender->matrix, ed, 0);
+       CL_GetTagMatrix(prog, &entrender->matrix, ed, 0);
 
        // set up the animation data
-       VM_GenerateFrameGroupBlend(ed->priv.server->framegroupblend, ed);
+       VM_GenerateFrameGroupBlend(prog, ed->priv.server->framegroupblend, ed);
        VM_FrameBlendFromFrameGroupBlend(ed->priv.server->frameblend, ed->priv.server->framegroupblend, model);
-       VM_UpdateEdictSkeleton(ed, model, ed->priv.server->frameblend);
+       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);
 
@@ -370,13 +355,22 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed, int edictnum)
        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);
+               if(PRVM_clientedictvector(ed, modellight_diffuse)) VectorCopy(PRVM_clientedictvector(ed, modellight_diffuse), entrender->modellight_diffuse);
+               if(PRVM_clientedictvector(ed, modellight_dir))     VectorCopy(PRVM_clientedictvector(ed, modellight_dir), 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_NOCULL)             entrender->flags |= RENDER_NOCULL;
-               if(renderflags & RF_DEPTHHACK)  entrender->flags |= RENDER_NODEPTHTEST;
-               if(renderflags & RF_ADDITIVE)           entrender->flags |= RENDER_ADDITIVE;
+               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;
        }
 
        c = (int)PRVM_clientedictfloat(ed, colormap);
@@ -427,8 +421,13 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed, int edictnum)
        return true;
 }
 
-qboolean CL_VM_InputEvent (qboolean down, int key, int ascii)
+// 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)
@@ -441,18 +440,21 @@ qboolean CL_VM_InputEvent (qboolean down, int key, int ascii)
                {
                        PRVM_clientglobalfloat(time) = cl.time;
                        PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity];
-                       PRVM_G_FLOAT(OFS_PARM0) = !down; // 0 is down, 1 is up
-                       PRVM_G_FLOAT(OFS_PARM1) = key;
-                       PRVM_G_FLOAT(OFS_PARM2) = ascii;
-                       PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_InputEvent), "QC function CSQC_InputEvent is missing");
+                       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 (void)
 {
+       prvm_prog_t *prog = CLVM_prog;
        vec3_t emptyvector;
        emptyvector[0] = 0;
        emptyvector[1] = 0;
@@ -462,6 +464,9 @@ qboolean CL_VM_UpdateView (void)
                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];
@@ -473,18 +478,21 @@ qboolean CL_VM_UpdateView (void)
                // pass in width and height as parameters (EXT_CSQC_1)
                PRVM_G_FLOAT(OFS_PARM0) = vid.width;
                PRVM_G_FLOAT(OFS_PARM1) = vid.height;
-               PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_UpdateView), "QC function CSQC_UpdateView is missing");
+               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;
 }
 
-extern sizebuf_t vm_tempstringsbuf;
 qboolean CL_VM_ConsoleCommand (const char *cmd)
 {
+       prvm_prog_t *prog = CLVM_prog;
        int restorevm_tempstringsbuf_cursize;
        qboolean r = false;
        if(!cl.csqc_loaded)
@@ -494,10 +502,10 @@ qboolean CL_VM_ConsoleCommand (const char *cmd)
        {
                PRVM_clientglobalfloat(time) = cl.time;
                PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity];
-               restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
-               PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(cmd);
-               PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_ConsoleCommand), "QC function CSQC_ConsoleCommand is missing");
-               vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
+               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
@@ -506,6 +514,7 @@ qboolean CL_VM_ConsoleCommand (const char *cmd)
 
 qboolean CL_VM_Parse_TempEntity (void)
 {
+       prvm_prog_t *prog = CLVM_prog;
        int                     t;
        qboolean        r = false;
        if(!cl.csqc_loaded)
@@ -513,15 +522,15 @@ qboolean CL_VM_Parse_TempEntity (void)
        CSQC_BEGIN
        if(PRVM_clientfunction(CSQC_Parse_TempEntity))
        {
-               t = msg_readcount;
+               t = cl_message.readcount;
                PRVM_clientglobalfloat(time) = cl.time;
                PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity];
-               PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Parse_TempEntity), "QC function CSQC_Parse_TempEntity is missing");
+               prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Parse_TempEntity), "QC function CSQC_Parse_TempEntity is missing");
                r = CSQC_RETURNVAL != 0;
                if(!r)
                {
-                       msg_readcount = t;
-                       msg_badread = false;
+                       cl_message.readcount = t;
+                       cl_message.badread = false;
                }
        }
        CSQC_END
@@ -530,6 +539,7 @@ qboolean CL_VM_Parse_TempEntity (void)
 
 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')
@@ -543,7 +553,7 @@ void CL_VM_Parse_StuffCmd (const char *msg)
                int sizeflags = csqc_progcrc.flags;
                csqc_progcrc.flags &= ~CVAR_READONLY;
                csqc_progsize.flags &= ~CVAR_READONLY;
-               Cmd_ExecuteString (msg, src_command);
+               Cmd_ExecuteString (msg, src_command, true);
                csqc_progcrc.flags = crcflags;
                csqc_progsize.flags = sizeflags;
                return;
@@ -576,7 +586,7 @@ void CL_VM_Parse_StuffCmd (const char *msg)
                                l = sizeof(buf) - 1;
                        strlcpy(buf, p, l + 1); // strlcpy needs a + 1 as it includes the newline!
 
-                       Cmd_ExecuteString(buf, src_command);
+                       Cmd_ExecuteString(buf, src_command, true);
 
                        p += l;
                        if(*p == '\n')
@@ -584,7 +594,7 @@ void CL_VM_Parse_StuffCmd (const char *msg)
                        else
                                break; // end of string or overflow
                }
-               Cmd_ExecuteString("curl --clear_autodownload", src_command); // don't inhibit CSQC loading
+               Cmd_ExecuteString("curl --clear_autodownload", src_command, true); // don't inhibit CSQC loading
                return;
        }
 
@@ -598,10 +608,10 @@ void CL_VM_Parse_StuffCmd (const char *msg)
        {
                PRVM_clientglobalfloat(time) = cl.time;
                PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity];
-               restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
-               PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(msg);
-               PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Parse_StuffCmd), "QC function CSQC_Parse_StuffCmd is missing");
-               vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
+               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);
@@ -610,17 +620,19 @@ void CL_VM_Parse_StuffCmd (const char *msg)
 
 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 = vm_tempstringsbuf.cursize;
-       PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(msg);
-       PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Parse_Print), "QC function CSQC_Parse_Print is missing");
-       vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
+       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)
        {
@@ -654,6 +666,7 @@ void CSQC_AddPrintText (const char *msg)
 
 void CL_VM_Parse_CenterPrint (const char *msg)
 {
+       prvm_prog_t *prog = CLVM_prog;
        int restorevm_tempstringsbuf_cursize;
        if(!cl.csqc_loaded)
        {
@@ -665,10 +678,10 @@ void CL_VM_Parse_CenterPrint (const char *msg)
        {
                PRVM_clientglobalfloat(time) = cl.time;
                PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity];
-               restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
-               PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(msg);
-               PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Parse_CenterPrint), "QC function CSQC_Parse_CenterPrint is missing");
-               vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
+               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);
@@ -677,6 +690,7 @@ void CL_VM_Parse_CenterPrint (const char *msg)
 
 void CL_VM_UpdateIntermissionState (int intermission)
 {
+       prvm_prog_t *prog = CLVM_prog;
        if(cl.csqc_loaded)
        {
                CSQC_BEGIN
@@ -686,6 +700,7 @@ void CL_VM_UpdateIntermissionState (int intermission)
 }
 void CL_VM_UpdateShowingScoresState (int showingscores)
 {
+       prvm_prog_t *prog = CLVM_prog;
        if(cl.csqc_loaded)
        {
                CSQC_BEGIN
@@ -693,8 +708,9 @@ void CL_VM_UpdateShowingScoresState (int showingscores)
                CSQC_END
        }
 }
-qboolean CL_VM_Event_Sound(int sound_num, float volume, int channel, float attenuation, int ent, vec3_t pos)
+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)
        {
@@ -705,13 +721,13 @@ qboolean CL_VM_Event_Sound(int sound_num, float volume, int channel, float atten
                        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(cl.sound_name[sound_num] );
+                       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) = 0; // pitch shift not supported yet
-                       PRVM_G_FLOAT(OFS_PARM7) = 0; // flags - none can come in at this point yet
-                       PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Event_Sound), "QC function CSQC_Event_Sound is missing");
+                       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
@@ -719,8 +735,9 @@ qboolean CL_VM_Event_Sound(int sound_num, float volume, int channel, float atten
 
        return r;
 }
-void CL_VM_UpdateCoopDeathmatchGlobals (int gametype)
+static void CL_VM_UpdateCoopDeathmatchGlobals (int gametype)
 {
+       prvm_prog_t *prog = CLVM_prog;
        // Avoid global names for clean(er) coding
        int localcoop;
        int localdeathmatch;
@@ -751,8 +768,10 @@ void CL_VM_UpdateCoopDeathmatchGlobals (int gametype)
                CSQC_END
        }
 }
-float CL_VM_Event (float event)                //[515]: needed ? I'd say "YES", but don't know for what :D
+#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;
@@ -762,15 +781,17 @@ float CL_VM_Event (float event)           //[515]: needed ? I'd say "YES", but don't know
                PRVM_clientglobalfloat(time) = cl.time;
                PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity];
                PRVM_G_FLOAT(OFS_PARM0) = event;
-               PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Event), "QC function CSQC_Event is missing");
+               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)
        {
@@ -783,8 +804,8 @@ void CSQC_ReadEntities (void)
                oldself = PRVM_clientglobaledict(self);
                while(1)
                {
-                       entnum = MSG_ReadShort();
-                       if(!entnum || msg_badread)
+                       entnum = MSG_ReadShort(&cl_message);
+                       if(!entnum || cl_message.badread)
                                break;
                        realentnum = entnum & 0x7FFF;
                        PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[realentnum];
@@ -792,7 +813,7 @@ void CSQC_ReadEntities (void)
                        {
                                if(PRVM_clientglobaledict(self))
                                {
-                                       PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Ent_Remove), "QC function CSQC_Ent_Remove is missing");
+                                       prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Ent_Remove), "QC function CSQC_Ent_Remove is missing");
                                        cl.csqc_server2csqcentitynumber[realentnum] = 0;
                                }
                                else
@@ -811,7 +832,7 @@ void CSQC_ReadEntities (void)
                                        if(!PRVM_clientfunction(CSQC_Ent_Spawn))
                                        {
                                                prvm_edict_t    *ed;
-                                               ed = PRVM_ED_Alloc();
+                                               ed = PRVM_ED_Alloc(prog);
                                                PRVM_clientedictfloat(ed, entnum) = realentnum;
                                                PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[realentnum] = PRVM_EDICT_TO_PROG(ed);
                                        }
@@ -822,15 +843,15 @@ void CSQC_ReadEntities (void)
                                                PRVM_G_FLOAT(OFS_PARM0) = (float) realentnum;
                                                // make sure no one gets wrong ideas
                                                PRVM_clientglobaledict(self) = 0;
-                                               PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Ent_Spawn), "QC function CSQC_Ent_Spawn is missing");
+                                               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;
-                                       PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Ent_Update), "QC function CSQC_Ent_Update is missing");
+                                       prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Ent_Update), "QC function CSQC_Ent_Update is missing");
                                }
                                else {
                                        PRVM_G_FLOAT(OFS_PARM0) = 0;
-                                       PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Ent_Update), "QC function CSQC_Ent_Update is missing");
+                                       prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Ent_Update), "QC function CSQC_Ent_Update is missing");
                                }
                        }
                }
@@ -838,13 +859,13 @@ void CSQC_ReadEntities (void)
        CSQC_END
 }
 
-void CL_VM_CB_BeginIncreaseEdicts(void)
+static void CLVM_begin_increase_edicts(prvm_prog_t *prog)
 {
        // links don't survive the transition, so unlink everything
        World_UnlinkAll(&cl.world);
 }
 
-void CL_VM_CB_EndIncreaseEdicts(void)
+static void CLVM_end_increase_edicts(prvm_prog_t *prog)
 {
        int i;
        prvm_edict_t *ent;
@@ -855,7 +876,7 @@ void CL_VM_CB_EndIncreaseEdicts(void)
                        CL_LinkEdict(ent);
 }
 
-void CL_VM_CB_InitEdict(prvm_edict_t *e)
+static void CLVM_init_edict(prvm_prog_t *prog, prvm_edict_t *e)
 {
        int edictnum = PRVM_NUM_FOR_EDICT(e);
        entity_render_t *entrender;
@@ -866,21 +887,19 @@ void CL_VM_CB_InitEdict(prvm_edict_t *e)
        entrender->shadertime = cl.time;
 }
 
-extern void R_DecalSystem_Reset(decalsystem_t *decalsystem);
-
-void CL_VM_CB_FreeEdict(prvm_edict_t *ed)
+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.vp, 0, prog->entityfields * 4);
-       VM_RemoveEdictSkeleton(ed);
+       VM_RemoveEdictSkeleton(prog, ed);
        World_Physics_RemoveFromEntity(&cl.world, ed);
        World_Physics_RemoveJointFromEntity(&cl.world, ed);
 }
 
-void CL_VM_CB_CountEdicts(void)
+static void CLVM_count_edicts(prvm_prog_t *prog)
 {
        int             i;
        prvm_edict_t    *ent;
@@ -904,19 +923,18 @@ void CL_VM_CB_CountEdicts(void)
        Con_Printf("touch     :%3i\n", solid);
 }
 
-qboolean CL_VM_CB_LoadEdict(prvm_edict_t *ent)
+static qboolean CLVM_load_edict(prvm_prog_t *prog, prvm_edict_t *ent)
 {
        return true;
 }
 
-void Cmd_ClearCsqcFuncs (void);
-
 // 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
@@ -925,7 +943,7 @@ qboolean MakeDownloadPacket(const char *filename, unsigned char *data, size_t le
        if(cnt == 0)
        {
                MSG_WriteByte(buf, svc_stufftext);
-               MSG_WriteString(buf, va("\ncl_downloadbegin %lu %s\n", (unsigned long)len, filename));
+               MSG_WriteString(buf, va(vabuf, sizeof(vabuf), "\ncl_downloadbegin %lu %s\n", (unsigned long)len, filename));
                return true;
        }
        else if(cnt >= 1 && cnt <= npackets)
@@ -945,19 +963,22 @@ qboolean MakeDownloadPacket(const char *filename, unsigned char *data, size_t le
        else if(cnt == npackets + 1)
        {
                MSG_WriteByte(buf, svc_stufftext);
-               MSG_WriteString(buf, va("\ncl_downloadfinished %lu %d\n", (unsigned long)len, crc));
+               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)
 {
-       const char* csprogsfn;
-       unsigned char *csprogsdata;
-       fs_offset_t csprogsdatasize;
+       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
@@ -972,8 +993,11 @@ void CL_VM_Init (void)
 
        // see if the requested csprogs.dat file matches the requested crc
        csprogsdatacrc = -1;
-       csprogsfn = va("dlcache/%s.%i.%i", csqc_progname.string, requiredsize, requiredcrc);
-       csprogsdata = FS_LoadFile(csprogsfn, tempmempool, true, &csprogsdatasize);
+       if (!cls.demoplayback || csqc_usedemoprogs.integer)
+       {
+               csprogsfn = va(vabuf, sizeof(vabuf), "dlcache/%s.%i.%i", csqc_progname.string, requiredsize, requiredcrc);
+               csprogsdata = FS_LoadFile(csprogsfn, tempmempool, true, &csprogsdatasize);
+       }
        if (!csprogsdata)
        {
                csprogsfn = csqc_progname.string;
@@ -1014,13 +1038,12 @@ void CL_VM_Init (void)
                return;
        }
 
-       PRVM_Begin;
-       PRVM_InitProg(PRVM_CLIENTPROG);
+       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 = CL_NAME;
+       prog->name = "client";
        prog->num_edicts = 1;
        prog->max_edicts = 512;
        prog->limit_edicts = CL_MAX_EDICTS;
@@ -1030,22 +1053,24 @@ void CL_VM_Init (void)
        prog->extensionstring = vm_sv_extensions;
        prog->builtins = vm_cl_builtins;
        prog->numbuiltins = vm_cl_numbuiltins;
-       prog->begin_increase_edicts = CL_VM_CB_BeginIncreaseEdicts;
-       prog->end_increase_edicts = CL_VM_CB_EndIncreaseEdicts;
-       prog->init_edict = CL_VM_CB_InitEdict;
-       prog->free_edict = CL_VM_CB_FreeEdict;
-       prog->count_edicts = CL_VM_CB_CountEdicts;
-       prog->load_edict = CL_VM_CB_LoadEdict;
-       prog->init_cmd = VM_CL_Cmd_Init;
-       prog->reset_cmd = VM_CL_Cmd_Reset;
-       prog->error_cmd = CL_VM_Error;
-       prog->ExecuteProgram = CLVM_ExecuteProgram;
-
-       PRVM_LoadProgs(csprogsfn, cl_numrequiredfunc, cl_required_func, CL_REQFIELDS, cl_reqfields, CL_REQGLOBALS, cl_reqglobals);
+
+       // 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, cl_numrequiredfunc, cl_required_func, CL_REQFIELDS, cl_reqfields, CL_REQGLOBALS, cl_reqglobals);
 
        if (!prog->loaded)
        {
-               CL_VM_Error("CSQC %s ^2failed to load\n", csprogsfn);
+               Host_Error("CSQC %s ^2failed to load\n", csprogsfn);
                if(!sv.active)
                        CL_Disconnect();
                Mem_Free(csprogsdata);
@@ -1086,18 +1111,17 @@ void CL_VM_Init (void)
        PRVM_clientglobalfloat(time) = cl.time;
        PRVM_clientglobaledict(self) = 0;
 
-       PRVM_clientglobalstring(mapname) = PRVM_SetEngineString(cl.worldname);
+       PRVM_clientglobalstring(mapname) = PRVM_SetEngineString(prog, cl.worldname);
        PRVM_clientglobalfloat(player_localentnum) = cl.playerentity;
 
        // set map description (use world entity 0)
-       PRVM_clientedictstring(prog->edicts, message) = PRVM_SetEngineString(cl.worldmessage);
+       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
-       PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Init), "QC function CSQC_Init is missing");
+       prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Init), "QC function CSQC_Init is missing");
 
-       PRVM_End;
        cl.csqc_loaded = true;
 
        cl.csqc_vidvars.drawcrosshair = false;
@@ -1109,6 +1133,7 @@ void CL_VM_Init (void)
 
 void CL_VM_ShutDown (void)
 {
+       prvm_prog_t *prog = CLVM_prog;
        Cmd_ClearCsqcFuncs();
        //Cvar_SetValueQuick(&csqc_progcrc, -1);
        //Cvar_SetValueQuick(&csqc_progsize, -1);
@@ -1118,8 +1143,8 @@ void CL_VM_ShutDown (void)
                PRVM_clientglobalfloat(time) = cl.time;
                PRVM_clientglobaledict(self) = 0;
                if (PRVM_clientfunction(CSQC_Shutdown))
-                       PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Shutdown), "QC function CSQC_Shutdown is missing");
-               PRVM_ResetProg();
+                       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;
@@ -1127,6 +1152,7 @@ void CL_VM_ShutDown (void)
 
 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;
@@ -1142,7 +1168,7 @@ qboolean CL_VM_GetEntitySoundOrigin(int entnum, vec3_t out)
        {
                mod = CL_GetModelFromEdict(ed);
                VectorCopy(PRVM_clientedictvector(ed, origin), out);
-               if(CL_GetTagMatrix (&matrix, ed, 0) == 0)
+               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);
@@ -1156,6 +1182,7 @@ qboolean CL_VM_GetEntitySoundOrigin(int entnum, vec3_t out)
 
 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;
@@ -1180,7 +1207,7 @@ qboolean CL_VM_TransformView(int entnum, matrix4x4_t *viewmatrix, mplane_t *clip
                                VectorScale(left, -1, PRVM_clientglobalvector(v_right));
                                VectorCopy(up, PRVM_clientglobalvector(v_up));
                                VectorCopy(origin, PRVM_clientglobalvector(trace_endpos));
-                               PRVM_ExecuteProgram(PRVM_clientedictfunction(ed, camera_transform), "QC function e.camera_transform is missing");
+                               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);
index bb0a3fb80dd92dccf66cfe601c828f4652c908a8..2aba12b389140b9ad5de7595b191ebdcf324a677 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef CSPROGS_H
 #define CSPROGS_H
 
-#define CL_NAME "client"
-
 // LordHavoc: changed to match MAX_EDICTS
 #define CL_MAX_EDICTS MAX_EDICTS
 
 #define VF_PERSPECTIVE         200 //(float)
 #define VF_CLEARSCREEN         201 //(float)
 
+#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)
+
+#define VF_MAINVIEW            212 //(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
@@ -48,8 +59,9 @@
 #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_NOCULL                              128 // do not cull this entity using r_cullentities, for large outdoor entities (asteroids on the sky. etc)
+#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_FULLBRIGHT                  256
 #define RF_NOSHADOW                            512
@@ -66,4 +78,35 @@ 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);
+
 #endif
index 17d1b9424d0c24c97f2610f180190875d9e2b3f2..cf7569dba482a202a641553ed5a31fa59dc220c0 100644 (file)
@@ -156,7 +156,7 @@ static int Q3PatchTesselation(float largestsquared3xcurvearea, float tolerance)
                // maps [4..8[ to 4
 }
 
-float Squared3xCurveArea(const float *a, const float *control, const float *b, int components)
+static float Squared3xCurveArea(const float *a, const float *control, const float *b, int components)
 {
 #if 0
        // mimicing the old behaviour with the new code...
index 3dee0406d0351cc2ac9c39707dbca97ffb91e982..4e9e20dab8a2cee0e256e820fe6d784c2680d450 100644 (file)
@@ -70,7 +70,7 @@ cvar_t *Cvar_FindVarAfter (const char *prev_var_name, int neededflags)
        return var;
 }
 
-cvar_t *Cvar_FindVarLink (const char *var_name, cvar_t **parent, cvar_t ***link, cvar_t **prev_alpha)
+static cvar_t *Cvar_FindVarLink (const char *var_name, cvar_t **parent, cvar_t ***link, cvar_t **prev_alpha)
 {
        int hashindex;
        cvar_t *var;
@@ -266,17 +266,18 @@ void Cvar_CompleteCvarPrint (const char *partial)
 static void Cvar_UpdateAutoCvar(cvar_t *var)
 {
        int i;
-       if(!prog)
-               Host_Error("Cvar_UpdateAutoCvar: no prog set");
-       i = PRVM_GetProgNr();
-       if(var->globaldefindex_progid[i] == prog->id)
+       int j;
+       const char *s;
+       vec3_t v;
+       prvm_prog_t *prog;
+       for (i = 0;i < PRVM_PROG_MAX;i++)
        {
-               // MUST BE SYNCED WITH prvm_edict.c PRVM_LoadProgs
-               int j;
-               const char *s;
-               vec3_t v;
-               switch(prog->globaldefs[var->globaldefindex[i]].type & ~DEF_SAVEGLOBAL)
+               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;
@@ -298,9 +299,10 @@ static void Cvar_UpdateAutoCvar(cvar_t *var)
                                VectorCopy(v, PRVM_GLOBALFIELDVECTOR(prog->globaldefs[var->globaldefindex[i]].ofs));
                                break;
                        case ev_string:
-                               PRVM_ChangeEngineString(var->globaldefindex_stringno[i], var->string);
+                               PRVM_ChangeEngineString(prog, var->globaldefindex_stringno[i], var->string);
                                PRVM_GLOBALFIELDSTRING(prog->globaldefs[var->globaldefindex[i]].ofs) = var->globaldefindex_stringno[i];
                                break;
+                       }
                }
        }
 }
@@ -318,12 +320,12 @@ void Cvar_UpdateAllAutoCvars(void)
 Cvar_Set
 ============
 */
-void Cvar_SetQuick_Internal (cvar_t *var, const char *value)
+extern cvar_t sv_disablenotify;
+static void Cvar_SetQuick_Internal (cvar_t *var, const char *value)
 {
        qboolean changed;
        size_t valuelen;
-       prvm_prog_t *tmpprog;
-       int i;
+       char vabuf[1024];
 
        changed = strcmp(var->string, value) != 0;
        // LordHavoc: don't reallocate when there is no change
@@ -341,7 +343,7 @@ void Cvar_SetQuick_Internal (cvar_t *var, const char *value)
        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)
+       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?
@@ -369,16 +371,16 @@ void Cvar_SetQuick_Internal (cvar_t *var, const char *value)
                if (!strcmp(var->name, "_cl_color"))
                {
                        int top = (var->integer >> 4) & 15, bottom = var->integer & 15;
-                       CL_SetInfo("topcolor", va("%i", top), true, false, false, false);
-                       CL_SetInfo("bottomcolor", va("%i", bottom), true, false, false, false);
+                       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("color %i %i", top, bottom));
+                               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("%i", var->integer), true, false, false, false);
+                       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"))
@@ -397,16 +399,7 @@ void Cvar_SetQuick_Internal (cvar_t *var, const char *value)
                        NetConn_UpdateFavorites();
        }
 
-       tmpprog = prog;
-       for(i = 0; i < PRVM_MAXPROGS; ++i)
-       {
-               if(PRVM_ProgLoaded(i))
-               {
-                       PRVM_SetProg(i);
-                       Cvar_UpdateAutoCvar(var);
-               }
-       }
-       prog = tmpprog;
+       Cvar_UpdateAutoCvar(var);
 }
 
 void Cvar_SetQuick (cvar_t *var, const char *value)
@@ -830,7 +823,7 @@ void Cvar_WriteVariables (qfile_t *f)
 
        // 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_DEFAULTSET)))
+               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);
index c63910820765c5e7517a3261855fb2fff924cfbd..35bdc6f127c2fc657c74172f42a4dac58cbbf92e 100644 (file)
-[Project]\r
-FileName=darkplaces-dedicated.dev\r
-Name=DarkPlaces\r
-UnitCount=165\r
-Type=1\r
-Ver=1\r
-ObjFiles=\r
-Includes=\r
-Libs=\r
-PrivateResource=darkplaces-dedicated_private.rc\r
-ResourceIncludes=\r
-MakeIncludes=\r
-Compiler=-Wall -O2 -fno-strict-aliasing -ffast-math -funroll-loops -D_FILE_OFFSET_BITS=64 -D__KERNEL_STRICT_NAMES_@@_\r
-CppCompiler=\r
-Linker=-lwinmm -lws2_32_@@_\r
-IsCpp=0\r
-Icon=darkplaces.ico\r
-ExeOutput=\r
-ObjectOutput=\r
-OverrideOutput=1\r
-OverrideOutputName=darkplaces-dedicated.exe\r
-HostApplication=\r
-Folders="Header Files","Source Files"\r
-CommandLine=\r
-UseCustomMakefile=0\r
-CustomMakefile=\r
-IncludeVersionInfo=1\r
-SupportXPThemes=0\r
-CompilerSet=0\r
-CompilerSettings=0000000000000000000100\r
-\r
-[Unit1]\r
-FileName=dpvsimpledecode.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit2]\r
-FileName=cdaudio.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit3]\r
-FileName=cl_collision.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit4]\r
-FileName=cl_screen.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit5]\r
-FileName=cl_video.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit6]\r
-FileName=client.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit7]\r
-FileName=clprogdefs.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit8]\r
-FileName=cmd.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit9]\r
-FileName=collision.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit10]\r
-FileName=common.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit11]\r
-FileName=console.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit12]\r
-FileName=curves.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit13]\r
-FileName=cvar.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit16]\r
-FileName=fs.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit17]\r
-FileName=gl_backend.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit18]\r
-FileName=polygon.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit19]\r
-FileName=glquake.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit20]\r
-FileName=image.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit21]\r
-FileName=input.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit22]\r
-FileName=jpeg.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit23]\r
-FileName=keys.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit24]\r
-FileName=lhnet.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit25]\r
-FileName=mathlib.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit26]\r
-FileName=matrixlib.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit27]\r
-FileName=menu.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit28]\r
-FileName=meshqueue.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit29]\r
-FileName=model_alias.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit30]\r
-FileName=model_brush.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit31]\r
-FileName=model_shared.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit32]\r
-FileName=model_sprite.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit33]\r
-FileName=model_zymotic.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit34]\r
-FileName=modelgen.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit35]\r
-FileName=mprogdefs.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit36]\r
-FileName=netconn.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit37]\r
-FileName=palette.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit38]\r
-FileName=portals.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit39]\r
-FileName=pr_comp.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit40]\r
-FileName=progdefs.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit41]\r
-FileName=progs.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit42]\r
-FileName=progsvm.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit43]\r
-FileName=protocol.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit44]\r
-FileName=prvm_execprogram.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit45]\r
-FileName=qtypes.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit46]\r
-FileName=quakedef.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit47]\r
-FileName=r_lerpanim.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit48]\r
-FileName=r_modules.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit49]\r
-FileName=r_shadow.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit50]\r
-FileName=r_textures.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit51]\r
-FileName=render.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit52]\r
-FileName=resource.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit53]\r
-FileName=sbar.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit54]\r
-FileName=screen.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit55]\r
-FileName=server.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit56]\r
-FileName=sound.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit57]\r
-FileName=spritegn.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit58]\r
-FileName=sys.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit59]\r
-FileName=vid.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit60]\r
-FileName=wad.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit62]\r
-FileName=zone.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit63]\r
-FileName=zone.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit64]\r
-FileName=cd_shared.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit65]\r
-FileName=cd_null.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit66]\r
-FileName=cl_collision.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit67]\r
-FileName=cl_demo.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit68]\r
-FileName=cl_input.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit69]\r
-FileName=cl_main.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit70]\r
-FileName=cl_parse.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit71]\r
-FileName=cl_particles.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit72]\r
-FileName=cl_screen.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit73]\r
-FileName=cl_video.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit74]\r
-FileName=cmd.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit75]\r
-FileName=collision.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit76]\r
-FileName=common.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit77]\r
-FileName=console.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit78]\r
-FileName=polygon.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit79]\r
-FileName=curves.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit80]\r
-FileName=cvar.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit81]\r
-FileName=dpvsimpledecode.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit82]\r
-FileName=filematch.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit83]\r
-FileName=fractalnoise.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit84]\r
-FileName=fs.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit85]\r
-FileName=gl_backend.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit86]\r
-FileName=gl_draw.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit87]\r
-FileName=gl_rmain.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit88]\r
-FileName=gl_rsurf.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit89]\r
-FileName=gl_textures.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit91]\r
-FileName=host_cmd.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit92]\r
-FileName=image.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit93]\r
-FileName=jpeg.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit94]\r
-FileName=keys.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit95]\r
-FileName=lhnet.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit96]\r
-FileName=mathlib.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit97]\r
-FileName=matrixlib.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit98]\r
-FileName=menu.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit99]\r
-FileName=meshqueue.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit100]\r
-FileName=model_alias.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit101]\r
-FileName=model_brush.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit102]\r
-FileName=model_shared.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit103]\r
-FileName=model_sprite.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit104]\r
-FileName=netconn.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit105]\r
-FileName=palette.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit106]\r
-FileName=portals.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit107]\r
-FileName=protocol.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit108]\r
-FileName=prvm_cmds.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit109]\r
-FileName=prvm_edict.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit110]\r
-FileName=prvm_exec.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit111]\r
-FileName=builddate.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit113]\r
-FileName=r_lerpanim.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit114]\r
-FileName=r_lightning.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit115]\r
-FileName=r_modules.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit116]\r
-FileName=r_shadow.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit118]\r
-FileName=r_sprites.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit119]\r
-FileName=sbar.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit120]\r
-FileName=snd_null.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit121]\r
-FileName=sv_main.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit122]\r
-FileName=sv_move.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit123]\r
-FileName=sv_phys.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit124]\r
-FileName=sv_user.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit125]\r
-FileName=sys_shared.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit126]\r
-FileName=sys_linux.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit127]\r
-FileName=vid_shared.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit128]\r
-FileName=vid_null.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit133]\r
-FileName=image_png.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit134]\r
-FileName=lhfont.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit135]\r
-FileName=mdfour.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit136]\r
-FileName=model_dpmodel.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit137]\r
-FileName=model_psk.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit139]\r
-FileName=csprogs.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit140]\r
-FileName=mdfour.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit141]\r
-FileName=image_png.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit143]\r
-FileName=wad.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit145]\r
-FileName=cl_dyntexture.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit148]\r
-FileName=cl_gecko.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit149]\r
-FileName=clvm_cmds.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit150]\r
-FileName=libcurl.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit151]\r
-FileName=libcurl.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit152]\r
-FileName=sv_demo.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit153]\r
-FileName=sv_demo.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit154]\r
-FileName=svbsp.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit155]\r
-FileName=svbsp.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit156]\r
-FileName=timing.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit157]\r
-FileName=hmac.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit112]\r
-FileName=r_explosion.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[VersionInfo]\r
-Major=1\r
-Minor=0\r
-Release=0\r
-Build=0\r
-LanguageID=1033\r
-CharsetID=1252\r
-CompanyName=Forest Hale Digital Services\r
-FileVersion=1.0\r
-FileDescription=DarkPlaces Game Engine\r
-InternalName=darkplaces.exe\r
-LegalCopyright=id Software, Forest Hale, and contributors\r
-LegalTrademarks=\r
-OriginalFilename=darkplaces.exe\r
-ProductName=DarkPlaces\r
-ProductVersion=1.0\r
-AutoIncBuildNr=0\r
-\r
-[Unit90]\r
-FileName=host.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit138]\r
-FileName=clvm_cmds.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit14]\r
-FileName=bspfile.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit15]\r
-FileName=draw.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit61]\r
-FileName=world.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit117]\r
-FileName=r_sky.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit158]\r
-FileName=hmac.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit159]\r
-FileName=cap_avi.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit160]\r
-FileName=cap_avi.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit161]\r
-FileName=cap_ogg.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit162]\r
-FileName=cap_ogg.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit163]\r
-FileName=utf8lib.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit164]\r
-FileName=ft2.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit165]\r
-FileName=bih.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit129]\r
-FileName=svvm_cmds.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit130]\r
-FileName=mvm_cmds.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit131]\r
-FileName=prvm_cmds.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit132]\r
-FileName=csprogs.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit144]\r
-FileName=world.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit146]\r
-FileName=cl_dyntexture.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit147]\r
-FileName=cl_gecko.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit142]\r
-FileName=view.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
+[Project]
+FileName=darkplaces-dedicated.dev
+Name=DarkPlaces
+UnitCount=165
+Type=1
+Ver=1
+ObjFiles=
+Includes=
+Libs=
+PrivateResource=darkplaces-dedicated_private.rc
+ResourceIncludes=
+MakeIncludes=
+Compiler=-Wall -O2 -fno-strict-aliasing -ffast-math -funroll-loops -D_FILE_OFFSET_BITS=64 -D__KERNEL_STRICT_NAMES_@@_
+CppCompiler=
+Linker=-lwinmm -lws2_32_@@_
+IsCpp=0
+Icon=darkplaces.ico
+ExeOutput=
+ObjectOutput=
+OverrideOutput=1
+OverrideOutputName=darkplaces-dedicated.exe
+HostApplication=
+Folders="Header Files","Source Files"
+CommandLine=
+UseCustomMakefile=0
+CustomMakefile=
+IncludeVersionInfo=1
+SupportXPThemes=0
+CompilerSet=0
+CompilerSettings=0000000000000000000100
+
+[Unit1]
+FileName=dpvsimpledecode.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit2]
+FileName=cdaudio.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit3]
+FileName=cl_collision.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit4]
+FileName=cl_screen.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit5]
+FileName=cl_video.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit6]
+FileName=client.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit7]
+FileName=clprogdefs.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit8]
+FileName=cmd.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit9]
+FileName=collision.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit10]
+FileName=common.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit11]
+FileName=console.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit12]
+FileName=curves.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit13]
+FileName=cvar.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit16]
+FileName=fs.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit17]
+FileName=gl_backend.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit18]
+FileName=polygon.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit19]
+FileName=glquake.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit20]
+FileName=image.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit21]
+FileName=input.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit22]
+FileName=jpeg.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit23]
+FileName=keys.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit24]
+FileName=lhnet.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit25]
+FileName=mathlib.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit26]
+FileName=matrixlib.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit27]
+FileName=menu.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit28]
+FileName=meshqueue.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit29]
+FileName=model_alias.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit30]
+FileName=model_brush.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit31]
+FileName=model_shared.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit32]
+FileName=model_sprite.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit33]
+FileName=model_zymotic.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit34]
+FileName=modelgen.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit35]
+FileName=mprogdefs.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit36]
+FileName=netconn.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit37]
+FileName=palette.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit38]
+FileName=portals.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit39]
+FileName=pr_comp.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit40]
+FileName=progdefs.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit41]
+FileName=progs.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit42]
+FileName=progsvm.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit43]
+FileName=protocol.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit44]
+FileName=prvm_execprogram.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit45]
+FileName=qtypes.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit46]
+FileName=quakedef.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit47]
+FileName=r_lerpanim.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit48]
+FileName=r_modules.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit49]
+FileName=r_shadow.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit50]
+FileName=r_textures.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit51]
+FileName=render.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit52]
+FileName=resource.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit53]
+FileName=sbar.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit54]
+FileName=screen.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit55]
+FileName=server.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit56]
+FileName=sound.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit57]
+FileName=spritegn.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit58]
+FileName=sys.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit59]
+FileName=vid.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit60]
+FileName=wad.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit62]
+FileName=zone.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit63]
+FileName=zone.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit64]
+FileName=cd_shared.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit65]
+FileName=cd_null.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit66]
+FileName=cl_collision.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit67]
+FileName=cl_demo.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit68]
+FileName=cl_input.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit69]
+FileName=cl_main.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit70]
+FileName=cl_parse.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit71]
+FileName=cl_particles.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit72]
+FileName=cl_screen.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit73]
+FileName=cl_video.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit74]
+FileName=cmd.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit75]
+FileName=collision.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit76]
+FileName=common.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit77]
+FileName=console.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit78]
+FileName=polygon.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit79]
+FileName=curves.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit80]
+FileName=cvar.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit81]
+FileName=dpvsimpledecode.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit82]
+FileName=filematch.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit83]
+FileName=fractalnoise.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit84]
+FileName=fs.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit85]
+FileName=gl_backend.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit86]
+FileName=gl_draw.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit87]
+FileName=gl_rmain.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit88]
+FileName=gl_rsurf.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit89]
+FileName=gl_textures.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit91]
+FileName=host_cmd.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit92]
+FileName=image.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit93]
+FileName=jpeg.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit94]
+FileName=keys.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit95]
+FileName=lhnet.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit96]
+FileName=mathlib.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit97]
+FileName=matrixlib.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit98]
+FileName=menu.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit99]
+FileName=meshqueue.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit100]
+FileName=model_alias.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit101]
+FileName=model_brush.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit102]
+FileName=model_shared.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit103]
+FileName=model_sprite.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit104]
+FileName=netconn.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit105]
+FileName=palette.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit106]
+FileName=portals.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit107]
+FileName=protocol.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit108]
+FileName=prvm_cmds.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit109]
+FileName=prvm_edict.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit110]
+FileName=prvm_exec.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit111]
+FileName=builddate.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit113]
+FileName=r_lerpanim.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit114]
+FileName=r_lightning.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit115]
+FileName=r_modules.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit116]
+FileName=r_shadow.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit118]
+FileName=r_sprites.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit119]
+FileName=sbar.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit120]
+FileName=snd_null.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit121]
+FileName=sv_main.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit122]
+FileName=sv_move.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit123]
+FileName=sv_phys.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit124]
+FileName=sv_user.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit125]
+FileName=sys_shared.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit126]
+FileName=sys_linux.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit127]
+FileName=vid_shared.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit128]
+FileName=vid_null.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit133]
+FileName=image_png.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit134]
+FileName=lhfont.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit135]
+FileName=mdfour.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit136]
+FileName=model_dpmodel.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit137]
+FileName=model_psk.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit139]
+FileName=csprogs.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit140]
+FileName=mdfour.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit141]
+FileName=image_png.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit143]
+FileName=wad.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit145]
+FileName=cl_dyntexture.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit148]
+FileName=cl_gecko.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit149]
+FileName=clvm_cmds.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit150]
+FileName=libcurl.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit151]
+FileName=libcurl.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit152]
+FileName=sv_demo.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit153]
+FileName=sv_demo.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit154]
+FileName=svbsp.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit155]
+FileName=svbsp.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit156]
+FileName=timing.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit157]
+FileName=hmac.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit112]
+FileName=r_explosion.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[VersionInfo]
+Major=1
+Minor=0
+Release=0
+Build=0
+LanguageID=1033
+CharsetID=1252
+CompanyName=Forest Hale Digital Services
+FileVersion=1.0
+FileDescription=DarkPlaces Game Engine
+InternalName=darkplaces.exe
+LegalCopyright=id Software, Forest Hale, and contributors
+LegalTrademarks=
+OriginalFilename=darkplaces.exe
+ProductName=DarkPlaces
+ProductVersion=1.0
+AutoIncBuildNr=0
+
+[Unit90]
+FileName=host.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit138]
+FileName=clvm_cmds.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit14]
+FileName=bspfile.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit15]
+FileName=draw.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit61]
+FileName=world.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit117]
+FileName=r_sky.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit158]
+FileName=hmac.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit159]
+FileName=cap_avi.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit160]
+FileName=cap_avi.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit161]
+FileName=cap_ogg.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit162]
+FileName=cap_ogg.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit163]
+FileName=utf8lib.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit164]
+FileName=ft2.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit165]
+FileName=bih.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit129]
+FileName=svvm_cmds.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit130]
+FileName=mvm_cmds.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit131]
+FileName=prvm_cmds.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit132]
+FileName=csprogs.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit144]
+FileName=world.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit146]
+FileName=cl_dyntexture.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit147]
+FileName=cl_gecko.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit142]
+FileName=view.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
index 3910650f62c9863f93a0f4e8a690c3c4e907a3f1..b96bdd594a03f4a4456c684e61b22d8658da8e79 100644 (file)
                                RelativePath=".\cl_dyntexture.c"\r
                                >\r
                        </File>\r
-                       <File\r
-                               RelativePath=".\cl_gecko.c"\r
-                               >\r
-                       </File>\r
                        <File\r
                                RelativePath=".\cl_input.c"\r
                                >\r
index 123c8384e1918649bd76f685ab06f12c4bf99a5b..aeebb0d8d6b99361952369d15db8d7cde1d2ced4 100644 (file)
                                RelativePath=".\cl_dyntexture.c"\r
                                >\r
                        </File>\r
-                       <File\r
-                               RelativePath=".\cl_gecko.c"\r
-                               >\r
-                       </File>\r
                        <File\r
                                RelativePath=".\cl_input.c"\r
                                >\r
index fd905ff23088966780285a4b215296bc40fc1887..00a9beadb8ab6d3007a08c53bddec6372d46f0d5 100644 (file)
                                RelativePath=".\cl_dyntexture.c"\r
                                >\r
                        </File>\r
-                       <File\r
-                               RelativePath=".\cl_gecko.c"\r
-                               >\r
-                       </File>\r
                        <File\r
                                RelativePath=".\cl_input.c"\r
                                >\r
index 87ca69eab15617c89d31b16033667ab33f4f4fa5..0b68b7cea69e501875a2abbfbeb1c934b681b42a 100644 (file)
-[Project]\r
-FileName=darkplaces.dev\r
-Name=DarkPlaces\r
-UnitCount=175\r
-Type=0\r
-Ver=1\r
-ObjFiles=\r
-Includes=\r
-Libs=\r
-PrivateResource=darkplaces_private.rc\r
-ResourceIncludes=\r
-MakeIncludes=\r
-Compiler=-Wall -O2 -fno-strict-aliasing -ffast-math -funroll-loops -D_FILE_OFFSET_BITS=64 -D__KERNEL_STRICT_NAMES_@@_\r
-CppCompiler=\r
-Linker=-lwinmm -lws2_32 -luser32 -lgdi32 -ldxguid -ldinput -lcomctl32 -Wl,--large-address-aware_@@_\r
-IsCpp=0\r
-Icon=darkplaces.ico\r
-ExeOutput=\r
-ObjectOutput=\r
-OverrideOutput=1\r
-OverrideOutputName=darkplaces.exe\r
-HostApplication=\r
-Folders="Header Files","Source Files"\r
-CommandLine=\r
-UseCustomMakefile=0\r
-CustomMakefile=\r
-IncludeVersionInfo=1\r
-SupportXPThemes=0\r
-CompilerSet=0\r
-CompilerSettings=0000000000000000000100\r
-\r
-[Unit1]\r
-FileName=dpvsimpledecode.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit2]\r
-FileName=cdaudio.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit3]\r
-FileName=cl_collision.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit4]\r
-FileName=cl_screen.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit5]\r
-FileName=cl_video.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit6]\r
-FileName=client.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit7]\r
-FileName=clprogdefs.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit8]\r
-FileName=cmd.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit9]\r
-FileName=collision.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit10]\r
-FileName=common.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit11]\r
-FileName=conproc.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit12]\r
-FileName=console.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit13]\r
-FileName=snd_main.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit14]\r
-FileName=curves.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit15]\r
-FileName=cvar.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit16]\r
-FileName=bspfile.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit17]\r
-FileName=draw.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit18]\r
-FileName=fs.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit19]\r
-FileName=gl_backend.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit20]\r
-FileName=polygon.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit21]\r
-FileName=glquake.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit22]\r
-FileName=image.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit23]\r
-FileName=input.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit24]\r
-FileName=jpeg.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit25]\r
-FileName=keys.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit26]\r
-FileName=lhnet.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit27]\r
-FileName=mathlib.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit28]\r
-FileName=matrixlib.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit29]\r
-FileName=menu.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit30]\r
-FileName=meshqueue.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit31]\r
-FileName=model_alias.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit32]\r
-FileName=model_brush.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit33]\r
-FileName=model_shared.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit34]\r
-FileName=model_sprite.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit35]\r
-FileName=model_zymotic.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit36]\r
-FileName=modelgen.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit37]\r
-FileName=mprogdefs.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit38]\r
-FileName=netconn.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit39]\r
-FileName=palette.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit40]\r
-FileName=portals.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit41]\r
-FileName=pr_comp.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit42]\r
-FileName=progdefs.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit43]\r
-FileName=progs.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit44]\r
-FileName=progsvm.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit45]\r
-FileName=protocol.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit46]\r
-FileName=prvm_execprogram.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit47]\r
-FileName=qtypes.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit48]\r
-FileName=quakedef.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit49]\r
-FileName=r_lerpanim.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit50]\r
-FileName=r_modules.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit51]\r
-FileName=r_shadow.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit52]\r
-FileName=r_textures.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit53]\r
-FileName=render.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit54]\r
-FileName=resource.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit55]\r
-FileName=sbar.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit56]\r
-FileName=screen.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit57]\r
-FileName=server.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit58]\r
-FileName=snd_ogg.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit59]\r
-FileName=snd_wav.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit60]\r
-FileName=sound.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit61]\r
-FileName=spritegn.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit62]\r
-FileName=sys.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit63]\r
-FileName=vid.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit64]\r
-FileName=wad.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit65]\r
-FileName=world.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit66]\r
-FileName=zone.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit67]\r
-FileName=zone.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit68]\r
-FileName=cd_shared.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit69]\r
-FileName=cd_win.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit70]\r
-FileName=cl_collision.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit71]\r
-FileName=cl_demo.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit72]\r
-FileName=cl_input.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit73]\r
-FileName=cl_main.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit74]\r
-FileName=cl_parse.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit75]\r
-FileName=cl_particles.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit76]\r
-FileName=cl_screen.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit77]\r
-FileName=cl_video.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit78]\r
-FileName=cmd.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit79]\r
-FileName=collision.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit80]\r
-FileName=common.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit81]\r
-FileName=conproc.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit82]\r
-FileName=console.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit83]\r
-FileName=polygon.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit84]\r
-FileName=curves.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit85]\r
-FileName=cvar.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit86]\r
-FileName=dpvsimpledecode.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit87]\r
-FileName=filematch.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit88]\r
-FileName=fractalnoise.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit89]\r
-FileName=fs.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit90]\r
-FileName=gl_backend.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit91]\r
-FileName=gl_draw.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit92]\r
-FileName=gl_rmain.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit93]\r
-FileName=gl_rsurf.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit94]\r
-FileName=gl_textures.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit95]\r
-FileName=host.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit96]\r
-FileName=host_cmd.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit97]\r
-FileName=image.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit98]\r
-FileName=jpeg.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit99]\r
-FileName=keys.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit100]\r
-FileName=lhnet.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit101]\r
-FileName=mathlib.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit102]\r
-FileName=matrixlib.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit103]\r
-FileName=menu.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit104]\r
-FileName=meshqueue.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit105]\r
-FileName=model_alias.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit106]\r
-FileName=model_brush.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit107]\r
-FileName=model_shared.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit108]\r
-FileName=model_sprite.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit109]\r
-FileName=netconn.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit110]\r
-FileName=palette.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit111]\r
-FileName=portals.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit112]\r
-FileName=protocol.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit113]\r
-FileName=prvm_cmds.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit114]\r
-FileName=prvm_edict.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit115]\r
-FileName=prvm_exec.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit116]\r
-FileName=builddate.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit118]\r
-FileName=r_lerpanim.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit119]\r
-FileName=r_lightning.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit120]\r
-FileName=r_modules.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit121]\r
-FileName=r_shadow.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit123]\r
-FileName=r_sprites.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit124]\r
-FileName=sbar.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit125]\r
-FileName=snd_main.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit126]\r
-FileName=snd_mem.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit127]\r
-FileName=snd_mix.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit128]\r
-FileName=snd_ogg.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit129]\r
-FileName=snd_wav.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit130]\r
-FileName=snd_win.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit131]\r
-FileName=sv_main.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit132]\r
-FileName=sv_move.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit133]\r
-FileName=sv_phys.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit134]\r
-FileName=sv_user.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit135]\r
-FileName=sys_shared.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit136]\r
-FileName=sys_win.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit137]\r
-FileName=vid_shared.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit138]\r
-FileName=vid_wgl.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit139]\r
-FileName=view.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit140]\r
-FileName=wad.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit141]\r
-FileName=world.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit142]\r
-FileName=svvm_cmds.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit143]\r
-FileName=mvm_cmds.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit145]\r
-FileName=csprogs.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit146]\r
-FileName=image_png.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit147]\r
-FileName=lhfont.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit148]\r
-FileName=mdfour.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit149]\r
-FileName=model_dpmodel.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit150]\r
-FileName=model_psk.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit151]\r
-FileName=csprogs.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit152]\r
-FileName=image_png.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit153]\r
-FileName=mdfour.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit154]\r
-FileName=libcurl.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit155]\r
-FileName=libcurl.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit156]\r
-FileName=clvm_cmds.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit157]\r
-FileName=svbsp.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit117]\r
-FileName=r_explosion.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[VersionInfo]\r
-Major=1\r
-Minor=0\r
-Release=0\r
-Build=0\r
-LanguageID=1033\r
-CharsetID=1252\r
-CompanyName=Forest Hale Digital Services\r
-FileVersion=1.0\r
-FileDescription=DarkPlaces Game Engine\r
-InternalName=darkplaces.exe\r
-LegalCopyright=id Software, Forest Hale, and contributors\r
-LegalTrademarks=\r
-OriginalFilename=darkplaces.exe\r
-ProductName=DarkPlaces\r
-ProductVersion=1.0\r
-AutoIncBuildNr=0\r
-\r
-[Unit122]\r
-FileName=r_sky.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit144]\r
-FileName=prvm_cmds.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit158]\r
-FileName=svbsp.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit159]\r
-FileName=sv_demo.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit160]\r
-FileName=sv_demo.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit161]\r
-FileName=snd_modplug.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit162]\r
-FileName=snd_modplug.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit163]\r
-FileName=cl_gecko.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit164]\r
-FileName=cl_gecko.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit165]\r
-FileName=cl_dyntexture.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit166]\r
-FileName=cl_dyntexture.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit167]\r
-FileName=hmac.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit168]\r
-FileName=hmac.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit169]\r
-FileName=cap_avi.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit170]\r
-FileName=cap_avi.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit171]\r
-FileName=cap_ogg.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit172]\r
-FileName=cap_ogg.h\r
-CompileCpp=0\r
-Folder=Header Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit173]\r
-FileName=utf8lib.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit174]\r
-FileName=ft2.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
-[Unit175]\r
-FileName=bih.c\r
-CompileCpp=0\r
-Folder=Source Files\r
-Compile=1\r
-Link=1\r
-Priority=1000\r
-OverrideBuildCmd=0\r
-BuildCmd=\r
-\r
+[Project]
+FileName=darkplaces.dev
+Name=DarkPlaces
+UnitCount=175
+Type=0
+Ver=1
+ObjFiles=
+Includes=
+Libs=
+PrivateResource=darkplaces_private.rc
+ResourceIncludes=
+MakeIncludes=
+Compiler=-Wall -O2 -fno-strict-aliasing -ffast-math -funroll-loops -D_FILE_OFFSET_BITS=64 -D__KERNEL_STRICT_NAMES_@@_
+CppCompiler=
+Linker=-lwinmm -lws2_32 -luser32 -lgdi32 -ldxguid -ldinput -lcomctl32 -Wl,--large-address-aware_@@_
+IsCpp=0
+Icon=darkplaces.ico
+ExeOutput=
+ObjectOutput=
+OverrideOutput=1
+OverrideOutputName=darkplaces.exe
+HostApplication=
+Folders="Header Files","Source Files"
+CommandLine=
+UseCustomMakefile=0
+CustomMakefile=
+IncludeVersionInfo=1
+SupportXPThemes=0
+CompilerSet=0
+CompilerSettings=0000000000000000000100
+
+[Unit1]
+FileName=dpvsimpledecode.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit2]
+FileName=cdaudio.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit3]
+FileName=cl_collision.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit4]
+FileName=cl_screen.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit5]
+FileName=cl_video.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit6]
+FileName=client.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit7]
+FileName=clprogdefs.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit8]
+FileName=cmd.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit9]
+FileName=collision.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit10]
+FileName=common.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit11]
+FileName=conproc.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit12]
+FileName=console.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit13]
+FileName=snd_main.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit14]
+FileName=curves.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit15]
+FileName=cvar.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit16]
+FileName=bspfile.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit17]
+FileName=draw.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit18]
+FileName=fs.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit19]
+FileName=gl_backend.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit20]
+FileName=polygon.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit21]
+FileName=glquake.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit22]
+FileName=image.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit23]
+FileName=input.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit24]
+FileName=jpeg.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit25]
+FileName=keys.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit26]
+FileName=lhnet.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit27]
+FileName=mathlib.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit28]
+FileName=matrixlib.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit29]
+FileName=menu.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit30]
+FileName=meshqueue.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit31]
+FileName=model_alias.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit32]
+FileName=model_brush.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit33]
+FileName=model_shared.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit34]
+FileName=model_sprite.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit35]
+FileName=model_zymotic.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit36]
+FileName=modelgen.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit37]
+FileName=mprogdefs.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit38]
+FileName=netconn.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit39]
+FileName=palette.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit40]
+FileName=portals.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit41]
+FileName=pr_comp.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit42]
+FileName=progdefs.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit43]
+FileName=progs.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit44]
+FileName=progsvm.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit45]
+FileName=protocol.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit46]
+FileName=prvm_execprogram.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit47]
+FileName=qtypes.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit48]
+FileName=quakedef.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit49]
+FileName=r_lerpanim.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit50]
+FileName=r_modules.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit51]
+FileName=r_shadow.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit52]
+FileName=r_textures.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit53]
+FileName=render.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit54]
+FileName=resource.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit55]
+FileName=sbar.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit56]
+FileName=screen.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit57]
+FileName=server.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit58]
+FileName=snd_ogg.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit59]
+FileName=snd_wav.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit60]
+FileName=sound.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit61]
+FileName=spritegn.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit62]
+FileName=sys.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit63]
+FileName=vid.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit64]
+FileName=wad.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit65]
+FileName=world.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit66]
+FileName=zone.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit67]
+FileName=zone.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit68]
+FileName=cd_shared.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit69]
+FileName=cd_win.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit70]
+FileName=cl_collision.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit71]
+FileName=cl_demo.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit72]
+FileName=cl_input.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit73]
+FileName=cl_main.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit74]
+FileName=cl_parse.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit75]
+FileName=cl_particles.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit76]
+FileName=cl_screen.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit77]
+FileName=cl_video.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit78]
+FileName=cmd.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit79]
+FileName=collision.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit80]
+FileName=common.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit81]
+FileName=conproc.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit82]
+FileName=console.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit83]
+FileName=polygon.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit84]
+FileName=curves.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit85]
+FileName=cvar.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit86]
+FileName=dpvsimpledecode.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit87]
+FileName=filematch.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit88]
+FileName=fractalnoise.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit89]
+FileName=fs.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit90]
+FileName=gl_backend.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit91]
+FileName=gl_draw.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit92]
+FileName=gl_rmain.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit93]
+FileName=gl_rsurf.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit94]
+FileName=gl_textures.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit95]
+FileName=host.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit96]
+FileName=host_cmd.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit97]
+FileName=image.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit98]
+FileName=jpeg.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit99]
+FileName=keys.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit100]
+FileName=lhnet.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit101]
+FileName=mathlib.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit102]
+FileName=matrixlib.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit103]
+FileName=menu.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit104]
+FileName=meshqueue.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit105]
+FileName=model_alias.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit106]
+FileName=model_brush.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit107]
+FileName=model_shared.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit108]
+FileName=model_sprite.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit109]
+FileName=netconn.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit110]
+FileName=palette.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit111]
+FileName=portals.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit112]
+FileName=protocol.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit113]
+FileName=prvm_cmds.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit114]
+FileName=prvm_edict.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit115]
+FileName=prvm_exec.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit116]
+FileName=builddate.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit118]
+FileName=r_lerpanim.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit119]
+FileName=r_lightning.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit120]
+FileName=r_modules.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit121]
+FileName=r_shadow.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit123]
+FileName=r_sprites.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit124]
+FileName=sbar.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit125]
+FileName=snd_main.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit126]
+FileName=snd_mem.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit127]
+FileName=snd_mix.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit128]
+FileName=snd_ogg.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit129]
+FileName=snd_wav.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit130]
+FileName=snd_win.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit131]
+FileName=sv_main.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit132]
+FileName=sv_move.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit133]
+FileName=sv_phys.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit134]
+FileName=sv_user.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit135]
+FileName=sys_shared.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit136]
+FileName=sys_win.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit137]
+FileName=vid_shared.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit138]
+FileName=vid_wgl.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit139]
+FileName=view.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit140]
+FileName=wad.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit141]
+FileName=world.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit142]
+FileName=svvm_cmds.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit143]
+FileName=mvm_cmds.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit145]
+FileName=csprogs.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit146]
+FileName=image_png.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit147]
+FileName=lhfont.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit148]
+FileName=mdfour.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit149]
+FileName=model_dpmodel.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit150]
+FileName=model_psk.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit151]
+FileName=csprogs.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit152]
+FileName=image_png.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit153]
+FileName=mdfour.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit154]
+FileName=libcurl.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit155]
+FileName=libcurl.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit156]
+FileName=clvm_cmds.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit157]
+FileName=svbsp.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit117]
+FileName=r_explosion.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[VersionInfo]
+Major=1
+Minor=0
+Release=0
+Build=0
+LanguageID=1033
+CharsetID=1252
+CompanyName=Forest Hale Digital Services
+FileVersion=1.0
+FileDescription=DarkPlaces Game Engine
+InternalName=darkplaces.exe
+LegalCopyright=id Software, Forest Hale, and contributors
+LegalTrademarks=
+OriginalFilename=darkplaces.exe
+ProductName=DarkPlaces
+ProductVersion=1.0
+AutoIncBuildNr=0
+
+[Unit122]
+FileName=r_sky.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit144]
+FileName=prvm_cmds.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit158]
+FileName=svbsp.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit159]
+FileName=sv_demo.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit160]
+FileName=sv_demo.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit161]
+FileName=snd_modplug.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit162]
+FileName=snd_modplug.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit163]
+FileName=cl_gecko.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit164]
+FileName=cl_gecko.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit165]
+FileName=cl_dyntexture.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit166]
+FileName=cl_dyntexture.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit167]
+FileName=hmac.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit168]
+FileName=hmac.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit169]
+FileName=cap_avi.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit170]
+FileName=cap_avi.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit171]
+FileName=cap_ogg.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit172]
+FileName=cap_ogg.h
+CompileCpp=0
+Folder=Header Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit173]
+FileName=utf8lib.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit174]
+FileName=ft2.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit175]
+FileName=bih.c
+CompileCpp=0
+Folder=Source Files
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
index 2100605d5e2ca8f72e8abca72510bec52e465beb..8fa52e44af7920fca8fb490b381e1f7c9650946a 100644 (file)
@@ -145,11 +145,11 @@ void              end_sys_fields;                 // flag for structure dumping
 */
 
 // Additional OPTIONAL Fields and Globals
-float          intermission;
+float          intermission; // indicates intermission state (0 = normal, 1 = scores, 2 = finale text)
 
 vector         view_angles; // same as input_angles
-vector         view_punchangle;
-vector         view_punchvector;
+vector         view_punchangle; // from server
+vector         view_punchvector; // from server
 
 /*
 ==============================================================================
@@ -399,6 +399,9 @@ void(vector v1, vector min, vector max, vector v2, float nomonsters, entity fore
 vector() randomvec = #91;
 vector(vector org) getlight = #92;
 vector(vector org, float lpflags) getlight2 = #92;
+vector getlight_dir;
+vector getlight_ambient;
+vector getlight_diffuse;
 const float LP_LIGHTMAP        = 1;
 const float LP_RTWORLD = 2;
 const float LP_DYNLIGHT = 4;
@@ -445,6 +448,8 @@ void() clearscene = #300;
 void(float mask) addentities = #301;
 void(entity ent) addentity = #302;
 float(float property, ...) setproperty = #303;
+float(float property) getproperty = #309;
+vector(float property) getpropertyvec = #309;
 void() renderscene = #304;
 void(vector org, float radius, vector lightcolours) adddynamiclight = #305;
 void(vector org, float radius, vector lightcolours, float style, string cubemapname, float pflags) adddynamiclight2 = #305;
@@ -734,13 +739,21 @@ float transparent_offset; // should be set before entity is added
 // example: transparent_offset = 1000000; // entity always appear on background of other transparents
 // note: offset is done in view forward axis
 
-// DP_CSQC_ENTITYNOCULL
+// DP_CSQC_ENTITYWORLDOBJECT
 // idea: VorteX
 // darkplaces implementation: VorteX
-const float RF_NOCULL = 128;
+const float RF_WORLDOBJECT = 128;
 // description: when renderflag is set, engine will not use culling methods for this entity, e.g. it will always be drawn
-// useful for large outdoor objects (like asteriods on sky horizont or sky models)
-// also useful when culling is done at CSQC side
+// useful for large outdoor objects (like asteroids on sky horizon or sky models)
+
+// DP_CSQC_ENTITYMODELLIGHT
+// idea: VorteX
+// darkplaces implementation: VorteX
+const float RF_MODELLIGHT = 4096;
+.vector modellight_ambient;
+.vector modellight_diffuse;
+.vector modellight_dir;
+// description: allows CSQC to override directional model lightning on entity
 
 // DP_CSQC_SETPAUSE
 // idea: VorteX
@@ -869,3 +882,14 @@ string(string command, float bindmap) findkeysforcommand = #610;
 float(string url, float id, string content_type, string delim, float buf, float keyid) crypto_uri_postbuf = #513;
 //description:
 //use -1 as buffer handle to justs end delim as postdata
+
+//DP_CSQC_MAINVIEW
+//idea: divVerent
+//darkplaces implementation: divVerent
+//constant definitions:
+const float VF_MAINVIEW         = 212;
+//use setproperty(VF_MAINVIEW, 1); before calling R_RenderView for the render
+//that shall become the "main" view, which is e.g. used by PRYDON_CLIENTCURSOR 
+//this flag is set for the first scene, and not cleared by R_ClearScene
+//this flag is automatically cleared by R_RenderView
+//so when not using this extension, the first view rendered is the main view
index 1aba127a584f1b7a4c46b17dda93a060bdf48e31..8d2148843e9aa27fb9ab84e579a543482ae75c3c 100644 (file)
@@ -520,6 +520,14 @@ void(entity e, entity tagentity, string tagname) setattachment = #443; // attach
 //description:
 //MOVETYPE_BOUNCE but without gravity, and with full reflection (no speed loss like grenades have), in other words - bouncing laser bolts.
 
+//DP_MOVETYPEFLYWORLDONLY
+//idea: Samual
+//darkplaces implementation: Samual
+//movetype definitions:
+float MOVETYPE_FLY_WORLDONLY = 33;
+//description:
+//like MOVETYPE_FLY, but does all traces with MOVE_WORLDONLY, and is ignored by MOVETYPE_PUSH. Should only be combined with SOLID_NOT and SOLID_TRIGGER.
+
 //DP_NULL_MODEL
 //idea: Chris
 //darkplaces implementation: divVerent
@@ -613,6 +621,13 @@ void(entity from, entity to) copyentity = #400;
 //description:
 //copies all data in the entity to another entity.
 
+//DP_QC_CRC16
+//idea: divVerent
+//darkplaces implementation: divVerent
+//Some hash function to build hash tables with. This has to be be the CRC-16-CCITT that is also required for the QuakeWorld download protocol.
+//When caseinsensitive is set, the CRC is calculated of the lower cased string.
+float(float caseinsensitive, string s, ...) crc16 = #494;
+
 //DP_QC_CVAR_DEFSTRING
 //idea: id Software (Doom3), LordHavoc
 //darkplaces implementation: LordHavoc
@@ -649,6 +664,24 @@ float CVAR_TYPEFLAG_ENGINE = 8;
 float CVAR_TYPEFLAG_HASDESCRIPTION = 16;
 float CVAR_TYPEFLAG_READONLY = 32;
 
+//DP_QC_DIGEST
+//idea: motorsep, Spike
+//DarkPlaces implementation: divVerent
+//builtin definitions:
+string(string digest, string data, ...) digest_hex = #639;
+//description:
+//returns a given hex digest of given data
+//the returned digest is always encoded in hexadecimal
+//only the "MD4" digest is always supported!
+//if the given digest is not supported, string_null is returned
+//the digest string is matched case sensitively, use "MD4", not "md4"!
+
+//DP_QC_DIGEST_SHA256
+//idea: motorsep, Spike
+//DarkPlaces implementation: divVerent
+//description:
+//"SHA256" is also an allowed digest type
+
 //DP_QC_EDICT_NUM
 //idea: 515
 //DarkPlaces implementation: LordHavoc
@@ -874,6 +907,31 @@ float GETTIME_CDTRACK = 4;
 //returns the playing time of the current cdtrack when passed to gettime()
 //see DP_END_GETSOUNDTIME for similar functionality but for entity sound channels
 
+//DP_QC_I18N
+//idea: divVerent
+//darkplaces implementation: divVerent
+//description:
+//
+//The engine supports translating by gettext compatible .po files.
+//progs.dat uses progs.dat.<LANGUAGE>.po
+//menu.dat uses menu.dat.<LANGUAGE>.po
+//csprogs.dat uses csprogs.dat.<LANGUAGE>.po
+//
+//To create a string that can be translated, define it as
+//  string dotranslate_FILENOTFOUND = "File not found";
+//Note: if the compiler does constant folding, this will only work if there is
+//no other "File not found" string in the progs!
+//
+//Alternatively, if using the Xonotic patched fteqcc compiler, you can simplify
+//this by using _("File not found") directly in the source code.
+//
+//The language is set by the "prvm_language" cvar: if prvm_language is set to
+//"de", it will read progs.dat.de.po for translating strings in progs.dat.
+//
+//If prvm_language is set to the special name "dump", progs.dat.pot will be
+//written, which is a translation template to be edited by filling out the
+//msgstr entries.
+
 //DP_QC_LOG
 //darkplaces implementation: divVerent
 //builtin definitions:
@@ -1201,12 +1259,14 @@ float(string name, string value) registercvar = #93;
 
 //DP_SND_FAKETRACKS
 //idea: requested
+
 //darkplaces implementation: Elric
 //description:
 //the engine plays sound/cdtracks/track001.wav instead of cd track 1 and so on if found, this allows games and mods to have music tracks without using ambientsound.
 //Note: also plays .ogg with DP_SND_OGGVORBIS extension.
 
 //DP_SND_SOUND7_WIP1
+//DP_SND_SOUND7_WIP2
 //idea: divVerent
 //darkplaces implementation: divVerent
 //builtin definitions:
@@ -1217,8 +1277,9 @@ float SOUNDFLAG_RELIABLE = 1;
 //extensions to sound():
 //- channel may be in the range from -128 to 127; channels -128 to 0 are "auto",
 //  i.e. support multiple sounds at once, but cannot be stopped/restarted
-//- a speed parameter has been reserved for later addition of pitch shifting.
-//  it MUST be set to 0 for now, meaning "no pitch change"
+//- a value 0 in the speed parameter means no change; otherwise, it is a
+//  percentage of playback speed ("pitch shifting"). 100 is normal pitch, 50 is
+//  half speed, 200 is double speed, etc. (DP_SND_SOUND7_WIP2)
 //- the flag SOUNDFLAG_RELIABLE can be specified, which makes the sound send
 //  to MSG_ALL (reliable) instead of MSG_BROADCAST (unreliable, default);
 //  similarily, SOUNDFLAG_RELIABLE_TO_ONE sends to MSG_ONE
@@ -1606,6 +1667,8 @@ const float MOVETYPE_PHYSICS = 32; // need to be set before any physics_* builti
 const float SOLID_PHYSICS_BOX = 32;
 const float SOLID_PHYSICS_SPHERE = 33;
 const float SOLID_PHYSICS_CAPSULE = 34;
+const float SOLID_PHYSICS_TRIMESH = 35;
+const float SOLID_PHYSICS_CYLINDER = 36;
 //SOLID_BSP;
 //joint types:
 const float JOINTTYPE_POINT = 1;
@@ -1628,6 +1691,8 @@ const float JOINTTYPE_FIXED = -1;
 //   note that ODE does not support both in one anyway
 //field definitions:
 .float mass; // ODE mass, standart value is 1
+.vector massofs; // offsets a mass center out of object center, if not set a center of model bounds is used
+.float friction;
 .float bouncefactor;
 .float bouncestop;
 .float jointtype;
@@ -1638,7 +1703,6 @@ void(entity e, vector torque) physics_addtorque = #542; // add relative torque
 //description: provides Open Dynamics Engine support, requires extenal dll to be present or engine compiled with statical link option
 //be sure to checkextension for it to know if library is loaded and ready, also to enable physics set "physics_ode" cvar to 1
 //note: this extension is highly experimental and may be unstable
-//note: use SOLID_BSP on entities to get a trimesh collision models on them
 
 //DP_SV_PRINT
 //idea: id Software (QuakeWorld Server)
@@ -2389,13 +2453,6 @@ string(string search, string replace, string subject) strireplace = #485;
 //description:
 //strreplace replaces all occurrences of 'search' with 'replace' in the string 'subject', and returns the result as a tempstring.
 //strireplace does the same but uses case-insensitive matching of the 'search' term
-//
-//DP_QC_CRC16
-//idea: divVerent
-//darkplaces implementation: divVerent
-//Some hash function to build hash tables with. This has to be be the CRC-16-CCITT that is also required for the QuakeWorld download protocol.
-//When caseinsensitive is set, the CRC is calculated of the lower cased string.
-float(float caseinsensitive, string s, ...) crc16 = #494;
 
 //DP_SV_SHUTDOWN
 //idea: divVerent
index 179a4d0c5fe93cae3b4668e1f4d9221c6a79082c..a79a9d363aee62cc8b45416277d572eca511b601 100644 (file)
@@ -15,13 +15,13 @@ typedef qboolean bool;
 #endif
 
 #define ALIGN_SIZE 16
-#define ATOMIC_SIZE 32
+#define ATOMIC_SIZE 4
 
 #ifdef SSE_POSSIBLE
        #if defined(__APPLE__)
                #include <libkern/OSAtomic.h>
                #define ALIGN(var) var __attribute__((__aligned__(16)))
-               #define ATOMIC(var) var __attribute__((__aligned__(32)))
+               #define ATOMIC(var) var __attribute__((__aligned__(4)))
                #define MEMORY_BARRIER (_mm_sfence())
                #define ATOMIC_COUNTER volatile int32_t 
                #define ATOMIC_INCREMENT(counter) (OSAtomicIncrement32Barrier(&(counter)))
@@ -29,7 +29,7 @@ typedef qboolean bool;
                #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__(32)))
+               #define ATOMIC(var) var __attribute__((__aligned__(4)))
                #define MEMORY_BARRIER (_mm_sfence())
                //(__sync_synchronize())
                #define ATOMIC_COUNTER volatile LONG
@@ -43,7 +43,7 @@ typedef qboolean bool;
                #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__(32)))
+               #define ATOMIC(var) var __attribute__((__aligned__(4)))
                #define MEMORY_BARRIER (_mm_sfence())
                //(__sync_synchronize())
                #define ATOMIC_COUNTER volatile int
@@ -52,7 +52,7 @@ typedef qboolean bool;
                #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(32)) var
+               #define ATOMIC(var) __declspec(align(4)) var
                #define MEMORY_BARRIER (_mm_sfence())
                //(MemoryBarrier())
                #define ATOMIC_COUNTER volatile LONG
@@ -91,11 +91,11 @@ typedef qboolean bool;
        #define _mm_cvtss_f32(val) (__builtin_ia32_vec_ext_v4sf ((__v4sf)(val), 0))
 #endif
 
-#define MM_MALLOC(size) _mm_malloc(size, ATOMIC_SIZE)
+#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, ATOMIC_SIZE);
+       void *ptr = _mm_malloc(nmemb*size, ALIGN_SIZE);
        if (ptr != NULL) memset(ptr, 0, nmemb*size);
        return ptr;
 }
@@ -163,15 +163,15 @@ enum { DPSOFTRAST_OPCODE_Reset = 0 };
 #define DPSOFTRAST_DRAW_MAXCOMMANDPOOL 2097152
 #define DPSOFTRAST_DRAW_MAXCOMMANDSIZE 16384
 
-typedef ATOMIC(struct DPSOFTRAST_State_Command_Pool_s
+typedef ALIGN(struct DPSOFTRAST_State_Command_Pool_s
 {
        int freecommand;
        int usedcommands;
-       ATOMIC(unsigned char commands[DPSOFTRAST_DRAW_MAXCOMMANDPOOL]);
+       ALIGN(unsigned char commands[DPSOFTRAST_DRAW_MAXCOMMANDPOOL]);
 }
 DPSOFTRAST_State_Command_Pool);
 
-typedef ATOMIC(struct DPSOFTRAST_State_Triangle_s
+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];
@@ -236,7 +236,7 @@ typedef enum DPSOFTRAST_BLENDMODE_e
 }
 DPSOFTRAST_BLENDMODE;
 
-typedef ATOMIC(struct DPSOFTRAST_State_Thread_s
+typedef ALIGN(struct DPSOFTRAST_State_Thread_s
 {
        void *thread;
        int index;
@@ -302,7 +302,7 @@ typedef ATOMIC(struct DPSOFTRAST_State_Thread_s
 }
 DPSOFTRAST_State_Thread);
 
-typedef ATOMIC(struct DPSOFTRAST_State_s
+typedef ALIGN(struct DPSOFTRAST_State_s
 {
        int fb_width;
        int fb_height;
@@ -492,7 +492,7 @@ static void DPSOFTRAST_Validate(DPSOFTRAST_State_Thread *thread, int mask)
        }
 }
 
-DPSOFTRAST_Texture *DPSOFTRAST_Texture_GetByIndex(int index)
+static DPSOFTRAST_Texture *DPSOFTRAST_Texture_GetByIndex(int index)
 {
        if (index >= 1 && index < dpsoftrast.texture_end && dpsoftrast.texture[index].bytes)
                return &dpsoftrast.texture[index];
@@ -660,7 +660,7 @@ void DPSOFTRAST_Texture_Free(int index)
        while (dpsoftrast.texture_end > 0 && dpsoftrast.texture[dpsoftrast.texture_end-1].bytes == NULL)
                dpsoftrast.texture_end--;
 }
-void DPSOFTRAST_Texture_CalculateMipmaps(int index)
+static void DPSOFTRAST_Texture_CalculateMipmaps(int index)
 {
        int i, x, y, z, w, layer0, layer1, row0, row1;
        unsigned char *o, *i0, *i1, *i2, *i3;
@@ -1653,7 +1653,7 @@ static void DPSOFTRAST_Fill4f(float *dst, const float *src, int size)
 }
 #endif
 
-void DPSOFTRAST_Vertex_Transform(float *out4f, const float *in4f, int numitems, const float *inmatrix16f)
+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}};
@@ -1701,10 +1701,12 @@ void DPSOFTRAST_Vertex_Transform(float *out4f, const float *in4f, int numitems,
 #endif
 }
 
-void DPSOFTRAST_Vertex_Copy(float *out4f, const float *in4f, int numitems)
+#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) \
@@ -2005,7 +2007,7 @@ static float *DPSOFTRAST_Array_TransformProject(int outarray, int inarray, const
 #endif
 }
 
-void DPSOFTRAST_Draw_Span_Begin(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, float *zf)
+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;
@@ -2032,7 +2034,7 @@ void DPSOFTRAST_Draw_Span_Begin(DPSOFTRAST_State_Thread *thread, const DPSOFTRAS
        }
 }
 
-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)
+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;
@@ -2344,7 +2346,8 @@ static void DPSOFTRAST_Texture2DBGRA8(DPSOFTRAST_Texture *texture, int mip, floa
        }
 }
 
-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)
+#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;
@@ -2540,8 +2543,9 @@ void DPSOFTRAST_Draw_Span_Texture2DVarying(DPSOFTRAST_State_Thread *thread, cons
                }
        }
 }
+#endif
 
-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)
+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;
@@ -2822,19 +2826,20 @@ void DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(DPSOFTRAST_State_Thread *thread,
 #endif
 }
 
-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)
+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);
 }
 
-float DPSOFTRAST_SampleShadowmap(const float *vector)
+static float DPSOFTRAST_SampleShadowmap(const float *vector)
 {
        // TODO: IMPLEMENT
        return 1.0f;
 }
 
-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)
+#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;
@@ -2857,8 +2862,10 @@ void DPSOFTRAST_Draw_Span_MultiplyVarying(const DPSOFTRAST_State_Triangle * REST
                out4f[x*4+3] = in4f[x*4+3] * c[3];
        }
 }
+#endif
 
-void DPSOFTRAST_Draw_Span_Varying(const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, float *out4f, int arrayindex, const float *zf)
+#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;
@@ -2881,8 +2888,10 @@ void DPSOFTRAST_Draw_Span_Varying(const DPSOFTRAST_State_Triangle * RESTRICT tri
                out4f[x*4+3] = c[3];
        }
 }
+#endif
 
-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)
+#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];
@@ -2902,8 +2911,10 @@ void DPSOFTRAST_Draw_Span_AddBloom(const DPSOFTRAST_State_Triangle * RESTRICT tr
                out4f[x*4+3] = ina4f[x*4+3] + c[3];
        }
 }
+#endif
 
-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)
+#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++)
@@ -2914,8 +2925,10 @@ void DPSOFTRAST_Draw_Span_MultiplyBuffers(const DPSOFTRAST_State_Triangle * REST
                out4f[x*4+3] = ina4f[x*4+3] * inb4f[x*4+3];
        }
 }
+#endif
 
-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)
+#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++)
@@ -2926,8 +2939,10 @@ void DPSOFTRAST_Draw_Span_AddBuffers(const DPSOFTRAST_State_Triangle * RESTRICT
                out4f[x*4+3] = ina4f[x*4+3] + inb4f[x*4+3];
        }
 }
+#endif
 
-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)
+#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;
@@ -2941,8 +2956,10 @@ void DPSOFTRAST_Draw_Span_MixBuffers(const DPSOFTRAST_State_Triangle * RESTRICT
                out4f[x*4+3] = ina4f[x*4+3] * a + inb4f[x*4+3] * b;
        }
 }
+#endif
 
-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)
+#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;
@@ -2960,10 +2977,11 @@ void DPSOFTRAST_Draw_Span_MixUniformColor(const DPSOFTRAST_State_Triangle * REST
                out4f[x*4+3] = in4f[x*4+3] * ilerp + localcolor[3] * lerp;
        }
 }
+#endif
 
 
 
-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)
+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;
@@ -3010,7 +3028,7 @@ void DPSOFTRAST_Draw_Span_MultiplyVaryingBGRA8(const DPSOFTRAST_State_Triangle *
 #endif
 }
 
-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)
+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;
@@ -3055,7 +3073,7 @@ void DPSOFTRAST_Draw_Span_VaryingBGRA8(const DPSOFTRAST_State_Triangle * RESTRIC
 #endif
 }
 
-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)
+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;
@@ -3078,7 +3096,7 @@ void DPSOFTRAST_Draw_Span_AddBloomBGRA8(const DPSOFTRAST_State_Triangle * RESTRI
 #endif
 }
 
-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)
+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;
@@ -3099,7 +3117,7 @@ void DPSOFTRAST_Draw_Span_MultiplyBuffersBGRA8(const DPSOFTRAST_State_Triangle *
 #endif
 }
 
-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)
+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;
@@ -3120,7 +3138,8 @@ void DPSOFTRAST_Draw_Span_AddBuffersBGRA8(const DPSOFTRAST_State_Triangle * REST
 #endif
 }
 
-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)
+#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;
@@ -3142,8 +3161,9 @@ void DPSOFTRAST_Draw_Span_TintedAddBuffersBGRA8(const DPSOFTRAST_State_Triangle
        }
 #endif
 }
+#endif
 
-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)
+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;
@@ -3166,7 +3186,7 @@ void DPSOFTRAST_Draw_Span_MixBuffersBGRA8(const DPSOFTRAST_State_Triangle * REST
 #endif
 }
 
-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)
+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;
@@ -3190,7 +3210,7 @@ void DPSOFTRAST_Draw_Span_MixUniformColorBGRA8(const DPSOFTRAST_State_Triangle *
 
 
 
-void DPSOFTRAST_VertexShader_Generic(void)
+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);
@@ -3199,7 +3219,7 @@ void DPSOFTRAST_VertexShader_Generic(void)
                DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD1, DPSOFTRAST_ARRAY_TEXCOORD1);
 }
 
-void DPSOFTRAST_PixelShader_Generic(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span)
+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];
@@ -3237,14 +3257,14 @@ void DPSOFTRAST_PixelShader_Generic(DPSOFTRAST_State_Thread *thread, const DPSOF
 
 
 
-void DPSOFTRAST_VertexShader_PostProcess(void)
+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);
 }
 
-void DPSOFTRAST_PixelShader_PostProcess(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span)
+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];
@@ -3271,12 +3291,12 @@ void DPSOFTRAST_PixelShader_PostProcess(DPSOFTRAST_State_Thread *thread, const D
 
 
 
-void DPSOFTRAST_VertexShader_Depth_Or_Shadow(void)
+static void DPSOFTRAST_VertexShader_Depth_Or_Shadow(void)
 {
        DPSOFTRAST_Array_TransformProject(DPSOFTRAST_ARRAY_POSITION, DPSOFTRAST_ARRAY_POSITION, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1);
 }
 
-void DPSOFTRAST_PixelShader_Depth_Or_Shadow(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span)
+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];
@@ -3288,13 +3308,13 @@ void DPSOFTRAST_PixelShader_Depth_Or_Shadow(DPSOFTRAST_State_Thread *thread, con
 
 
 
-void DPSOFTRAST_VertexShader_FlatColor(void)
+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);
 }
 
-void DPSOFTRAST_PixelShader_FlatColor(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span)
+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;
@@ -3338,14 +3358,14 @@ void DPSOFTRAST_PixelShader_FlatColor(DPSOFTRAST_State_Thread *thread, const DPS
 
 
 
-void DPSOFTRAST_VertexShader_VertexColor(void)
+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);
 }
 
-void DPSOFTRAST_PixelShader_VertexColor(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span)
+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;
@@ -3412,14 +3432,14 @@ void DPSOFTRAST_PixelShader_VertexColor(DPSOFTRAST_State_Thread *thread, const D
 
 
 
-void DPSOFTRAST_VertexShader_Lightmap(void)
+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);
 }
 
-void DPSOFTRAST_PixelShader_Lightmap(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span)
+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;
@@ -3514,38 +3534,38 @@ void DPSOFTRAST_PixelShader_Lightmap(DPSOFTRAST_State_Thread *thread, const DPSO
 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);
 
-void DPSOFTRAST_VertexShader_FakeLight(void)
+static void DPSOFTRAST_VertexShader_FakeLight(void)
 {
        DPSOFTRAST_VertexShader_LightDirection();
 }
 
-void DPSOFTRAST_PixelShader_FakeLight(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span)
+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);
 }
 
 
 
-void DPSOFTRAST_VertexShader_LightDirectionMap_ModelSpace(void)
+static void DPSOFTRAST_VertexShader_LightDirectionMap_ModelSpace(void)
 {
        DPSOFTRAST_VertexShader_LightDirection();
        DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD4, DPSOFTRAST_ARRAY_TEXCOORD4);
 }
 
-void DPSOFTRAST_PixelShader_LightDirectionMap_ModelSpace(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span)
+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);
 }
 
 
 
-void DPSOFTRAST_VertexShader_LightDirectionMap_TangentSpace(void)
+static void DPSOFTRAST_VertexShader_LightDirectionMap_TangentSpace(void)
 {
        DPSOFTRAST_VertexShader_LightDirection();
        DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD4, DPSOFTRAST_ARRAY_TEXCOORD4);
 }
 
-void DPSOFTRAST_PixelShader_LightDirectionMap_TangentSpace(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span)
+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);
 }
@@ -3857,8 +3877,8 @@ void DPSOFTRAST_PixelShader_LightDirection(DPSOFTRAST_State_Thread *thread, cons
 
                                specular = DPSOFTRAST_Vector3Dot(surfacenormal, specularnormal);if (specular < 0.0f) specular = 0.0f;
                        }
+                       specular = pow(specular, 1.0f + SpecularPower * glosstex[3]);
 
-                       specular = pow(specular, 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;
@@ -4046,7 +4066,7 @@ void DPSOFTRAST_PixelShader_LightDirection(DPSOFTRAST_State_Thread *thread, cons
 
 
 
-void DPSOFTRAST_VertexShader_LightSource(void)
+static void DPSOFTRAST_VertexShader_LightSource(void)
 {
        int i;
        int numvertices = dpsoftrast.numvertices;
@@ -4113,7 +4133,7 @@ void DPSOFTRAST_VertexShader_LightSource(void)
        DPSOFTRAST_Array_Transform(DPSOFTRAST_ARRAY_TEXCOORD3, DPSOFTRAST_ARRAY_POSITION, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelToLightM1);
 }
 
-void DPSOFTRAST_PixelShader_LightSource(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span)
+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];
@@ -4266,7 +4286,7 @@ void DPSOFTRAST_PixelShader_LightSource(DPSOFTRAST_State_Thread *thread, const D
 
                                specular = DPSOFTRAST_Vector3Dot(surfacenormal, specularnormal);if (specular < 0.0f) specular = 0.0f;
                        }
-                       specular = pow(specular, SpecularPower * glosstex[3]);
+                       specular = pow(specular, 1.0f + SpecularPower * glosstex[3]);
 
                        if (thread->shader_permutation & SHADERPERMUTATION_CUBEFILTER)
                        {
@@ -4410,14 +4430,14 @@ void DPSOFTRAST_PixelShader_LightSource(DPSOFTRAST_State_Thread *thread, const D
 
 
 
-void DPSOFTRAST_VertexShader_Refraction(void)
+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);
 }
 
-void DPSOFTRAST_PixelShader_Refraction(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span)
+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;
@@ -4499,7 +4519,7 @@ void DPSOFTRAST_PixelShader_Refraction(DPSOFTRAST_State_Thread *thread, const DP
 
 
 
-void DPSOFTRAST_VertexShader_Water(void)
+static void DPSOFTRAST_VertexShader_Water(void)
 {
        int i;
        int numvertices = dpsoftrast.numvertices;
@@ -4549,7 +4569,7 @@ void DPSOFTRAST_VertexShader_Water(void)
 }
 
 
-void DPSOFTRAST_PixelShader_Water(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span)
+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;
@@ -4667,12 +4687,12 @@ void DPSOFTRAST_PixelShader_Water(DPSOFTRAST_State_Thread *thread, const DPSOFTR
 
 
 
-void DPSOFTRAST_VertexShader_ShowDepth(void)
+static void DPSOFTRAST_VertexShader_ShowDepth(void)
 {
        DPSOFTRAST_Array_TransformProject(DPSOFTRAST_ARRAY_POSITION, DPSOFTRAST_ARRAY_POSITION, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1);
 }
 
-void DPSOFTRAST_PixelShader_ShowDepth(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span)
+static void DPSOFTRAST_PixelShader_ShowDepth(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span)
 {
        // TODO: IMPLEMENT
        float buffer_z[DPSOFTRAST_DRAW_MAXSPANLENGTH];
@@ -4684,12 +4704,12 @@ void DPSOFTRAST_PixelShader_ShowDepth(DPSOFTRAST_State_Thread *thread, const DPS
 
 
 
-void DPSOFTRAST_VertexShader_DeferredGeometry(void)
+static void DPSOFTRAST_VertexShader_DeferredGeometry(void)
 {
        DPSOFTRAST_Array_TransformProject(DPSOFTRAST_ARRAY_POSITION, DPSOFTRAST_ARRAY_POSITION, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1);
 }
 
-void DPSOFTRAST_PixelShader_DeferredGeometry(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span)
+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];
@@ -4701,12 +4721,12 @@ void DPSOFTRAST_PixelShader_DeferredGeometry(DPSOFTRAST_State_Thread *thread, co
 
 
 
-void DPSOFTRAST_VertexShader_DeferredLightSource(void)
+static void DPSOFTRAST_VertexShader_DeferredLightSource(void)
 {
        DPSOFTRAST_Array_TransformProject(DPSOFTRAST_ARRAY_POSITION, DPSOFTRAST_ARRAY_POSITION, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1);
 }
 
-void DPSOFTRAST_PixelShader_DeferredLightSource(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span)
+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];
@@ -4739,6 +4759,8 @@ static const DPSOFTRAST_ShaderModeInfo DPSOFTRAST_ShaderModeTable[SHADERMODE_COU
        {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}},
@@ -4813,7 +4835,7 @@ static void DPSOFTRAST_Draw_DepthWrite(const DPSOFTRAST_State_Thread *thread, co
        }
 }
 
-void DPSOFTRAST_Draw_ProcessSpans(DPSOFTRAST_State_Thread *thread)
+static void DPSOFTRAST_Draw_ProcessSpans(DPSOFTRAST_State_Thread *thread)
 {
        int i;
        DPSOFTRAST_State_Triangle *triangle;
@@ -4835,7 +4857,7 @@ void DPSOFTRAST_Draw_ProcessSpans(DPSOFTRAST_State_Thread *thread)
        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;);
+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)
 {
@@ -5405,7 +5427,7 @@ void DPSOFTRAST_DrawTriangles(int firstvertex, int numvertices, int numtriangles
        }
 }
 
-DEFCOMMAND(23, SetRenderTargets, int width; int height;);
+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;
index 3f267a2e669d191e69a69ae12b5f4ed3c2d1e05b..9bd1d010b93e04fd2ee1ec236e2efaec433c1074 100644 (file)
@@ -112,7 +112,7 @@ typedef enum gl20_texunit_e
        GL20TU_SHADOWMAP2D = 15,
        GL20TU_CUBEPROJECTION = 12,
        // rtlight prepass data (screenspace depth and normalmap)
-       GL20TU_SCREENDEPTH = 13,
+//     GL20TU_UNUSED1 = 13,
        GL20TU_SCREENNORMALMAP = 14,
        // lightmap prepass data (screenspace diffuse and specular from lights)
        GL20TU_SCREENDIFFUSE = 11,
@@ -151,6 +151,8 @@ typedef enum shadermode_e
        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)
@@ -195,8 +197,8 @@ typedef enum shaderpermutation_e
        SHADERPERMUTATION_BOUNCEGRID = 1<<28, ///< (lightmap) use Texture_BounceGrid as an additional source of ambient light
        SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL = 1<<29, ///< (lightmap) use 16-component pixels in bouncegrid texture for directional lighting rather than standard 4-component
        SHADERPERMUTATION_TRIPPY = 1<<30, ///< use trippy vertex shader effect
-       SHADERPERMUTATION_LIMIT = 1<<31, ///< size of permutations array
-       SHADERPERMUTATION_COUNT = 31 ///< size of shaderpermutationinfo array
+       SHADERPERMUTATION_DEPTHRGB = 1<<31, ///< read/write depth values in RGB color coded format for older hardware without depth samplers
+       SHADERPERMUTATION_COUNT = 32 ///< size of shaderpermutationinfo array
 }
 shaderpermutation_t;
 
@@ -225,7 +227,6 @@ typedef enum DPSOFTRAST_UNIFORM_e
        DPSOFTRAST_UNIFORM_Texture_Reflection,
        DPSOFTRAST_UNIFORM_Texture_ShadowMap2D,
        DPSOFTRAST_UNIFORM_Texture_CubeProjection,
-       DPSOFTRAST_UNIFORM_Texture_ScreenDepth,
        DPSOFTRAST_UNIFORM_Texture_ScreenNormalMap,
        DPSOFTRAST_UNIFORM_Texture_ScreenDiffuse,
        DPSOFTRAST_UNIFORM_Texture_ScreenSpecular,
@@ -308,6 +309,8 @@ typedef enum DPSOFTRAST_UNIFORM_e
        DPSOFTRAST_UNIFORM_ShadowMapMatrixM4,
        DPSOFTRAST_UNIFORM_BloomColorSubtract,
        DPSOFTRAST_UNIFORM_NormalmapScrollBlend,
+       DPSOFTRAST_UNIFORM_OffsetMapping_LodDistance,
+       DPSOFTRAST_UNIFORM_OffsetMapping_Bias,
        DPSOFTRAST_UNIFORM_TOTAL
 }
 DPSOFTRAST_UNIFORM;
index 2cf5e82f6aa45a0d3c0576aed4a87e9677b94c78..a72bf3645f86b40fea31ae22e021bd3fc67e5833 100644 (file)
@@ -33,7 +33,7 @@ typedef struct hz_bitstream_readblocks_s
 }
 hz_bitstream_readblocks_t;
 
-hz_bitstream_read_t *hz_bitstream_read_open(char *filename)
+static hz_bitstream_read_t *hz_bitstream_read_open(char *filename)
 {
        qfile_t *file;
        hz_bitstream_read_t *stream;
@@ -48,7 +48,7 @@ hz_bitstream_read_t *hz_bitstream_read_open(char *filename)
                return NULL;
 }
 
-void hz_bitstream_read_close(hz_bitstream_read_t *stream)
+static void hz_bitstream_read_close(hz_bitstream_read_t *stream)
 {
        if (stream)
        {
@@ -57,7 +57,7 @@ void hz_bitstream_read_close(hz_bitstream_read_t *stream)
        }
 }
 
-hz_bitstream_readblocks_t *hz_bitstream_read_blocks_new(void)
+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));
@@ -67,7 +67,7 @@ hz_bitstream_readblocks_t *hz_bitstream_read_blocks_new(void)
        return blocks;
 }
 
-void hz_bitstream_read_blocks_free(hz_bitstream_readblocks_t *blocks)
+static void hz_bitstream_read_blocks_free(hz_bitstream_readblocks_t *blocks)
 {
        hz_bitstream_readblock_t *b, *n;
        if (blocks == NULL)
@@ -80,13 +80,13 @@ void hz_bitstream_read_blocks_free(hz_bitstream_readblocks_t *blocks)
        Z_Free(blocks);
 }
 
-void hz_bitstream_read_flushbits(hz_bitstream_readblocks_t *blocks)
+static void hz_bitstream_read_flushbits(hz_bitstream_readblocks_t *blocks)
 {
        blocks->store = 0;
        blocks->count = 0;
 }
 
-int hz_bitstream_read_blocks_read(hz_bitstream_readblocks_t *blocks, hz_bitstream_read_t *stream, unsigned int size)
+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;
@@ -133,7 +133,7 @@ int hz_bitstream_read_blocks_read(hz_bitstream_readblocks_t *blocks, hz_bitstrea
        return HZREADERROR_OK;
 }
 
-unsigned int hz_bitstream_read_blocks_getbyte(hz_bitstream_readblocks_t *blocks)
+static unsigned int hz_bitstream_read_blocks_getbyte(hz_bitstream_readblocks_t *blocks)
 {
        while (blocks->current != NULL && blocks->position >= blocks->current->size)
        {
@@ -145,7 +145,7 @@ unsigned int hz_bitstream_read_blocks_getbyte(hz_bitstream_readblocks_t *blocks)
        return blocks->current->data[blocks->position++];
 }
 
-int hz_bitstream_read_bit(hz_bitstream_readblocks_t *blocks)
+static int hz_bitstream_read_bit(hz_bitstream_readblocks_t *blocks)
 {
        if (!blocks->count)
        {
@@ -157,7 +157,7 @@ int hz_bitstream_read_bit(hz_bitstream_readblocks_t *blocks)
        return (blocks->store >> blocks->count) & 1;
 }
 
-unsigned int hz_bitstream_read_bits(hz_bitstream_readblocks_t *blocks, int size)
+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
@@ -178,18 +178,18 @@ unsigned int hz_bitstream_read_bits(hz_bitstream_readblocks_t *blocks, int size)
        return num;
 }
 
-unsigned int hz_bitstream_read_byte(hz_bitstream_readblocks_t *blocks)
+static unsigned int hz_bitstream_read_byte(hz_bitstream_readblocks_t *blocks)
 {
        return hz_bitstream_read_blocks_getbyte(blocks);
 }
 
-unsigned int hz_bitstream_read_short(hz_bitstream_readblocks_t *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));
 }
 
-unsigned int hz_bitstream_read_int(hz_bitstream_readblocks_t *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)
@@ -197,7 +197,7 @@ unsigned int hz_bitstream_read_int(hz_bitstream_readblocks_t *blocks)
             | (hz_bitstream_read_byte(blocks));
 }
 
-void hz_bitstream_read_bytes(hz_bitstream_readblocks_t *blocks, void *outdata, unsigned int size)
+static void hz_bitstream_read_bytes(hz_bitstream_readblocks_t *blocks, void *outdata, unsigned int size)
 {
        unsigned char *out;
        out = (unsigned char *)outdata;
index 2a5681a987bad7ea5c7fb495273a34b5641161b8..5cb62afa8f84919e53099963aa68b25ac6170be5 100644 (file)
@@ -45,6 +45,8 @@ typedef struct cachepic_s
        qboolean hasalpha;
        // name of pic
        char name[MAX_QPATH];
+       // allow to override/free the texture
+       qboolean allow_free_tex;
 }
 cachepic_t;
 
@@ -94,6 +96,7 @@ DRAWFLAG_NUMFLAGS,
 DRAWFLAG_MASK = 0xFF,   // ONLY R_BeginPolygon()
 DRAWFLAG_MIPMAP = 0x100 // ONLY R_BeginPolygon()
 };
+#define DRAWFLAGS_BLEND (DRAWFLAG_ADDITIVE + DRAWFLAG_MODULATE + DRAWFLAG_2XMODULATE + DRAWFLAG_SCREEN)
 
 typedef struct ft2_settings_s
 {
index d810ff541f1b6e497dc6489150dd1f38415d4c57..93768046d58dbe73e3b2049bb121e55ae920d893 100644 (file)
@@ -37,6 +37,8 @@
 # include <direct.h>
 # include <io.h>
 # include <shlobj.h>
+# include <sys/stat.h>
+# include <share.h>
 #else
 # include <pwd.h>
 # include <sys/stat.h>
@@ -44,6 +46,7 @@
 #endif
 
 #include "quakedef.h"
+#include "thread.h"
 
 #include "fs.h"
 #include "wad.h"
 # define lseek _lseeki64
 #endif
 
-#if _MSC_VER >= 1400
 // suppress deprecated warnings
-# include <sys/stat.h>
-# include <share.h>
+#if _MSC_VER >= 1400
 # define read _read
 # define write _write
 # define close _close
@@ -332,6 +333,7 @@ VARIABLES
 */
 
 mempool_t *fs_mempool;
+void *fs_mutex = NULL;
 
 searchpath_t *fs_searchpaths = NULL;
 const char *const fs_checkgamedir_missing = "missing";
@@ -461,7 +463,7 @@ PK3_CloseLibrary
 Unload the Zlib DLL
 ====================
 */
-void PK3_CloseLibrary (void)
+static void PK3_CloseLibrary (void)
 {
 #ifndef LINK_TO_ZLIB
        Sys_UnloadLibrary (&zlib_dll);
@@ -476,7 +478,7 @@ PK3_OpenLibrary
 Try to load the Zlib DLL
 ====================
 */
-qboolean PK3_OpenLibrary (void)
+static qboolean PK3_OpenLibrary (void)
 {
 #ifdef LINK_TO_ZLIB
        return true;
@@ -532,7 +534,7 @@ PK3_GetEndOfCentralDir
 Extract the end of the central directory from a PK3 package
 ====================
 */
-qboolean PK3_GetEndOfCentralDir (const char *packfile, int packhandle, pk3_endOfCentralDir_t *eocd)
+static qboolean PK3_GetEndOfCentralDir (const char *packfile, int packhandle, pk3_endOfCentralDir_t *eocd)
 {
        fs_offset_t filesize, maxsize;
        unsigned char *buffer, *ptr;
@@ -597,7 +599,7 @@ PK3_BuildFileList
 Extract the file list from a PK3 file
 ====================
 */
-int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd)
+static int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd)
 {
        unsigned char *central_dir, *ptr;
        unsigned int ind;
@@ -717,7 +719,7 @@ FS_LoadPackPK3
 Create a package entry associated with a PK3 file
 ====================
 */
-pack_t *FS_LoadPackPK3FromFD (const char *packfile, int packhandle, qboolean silent)
+static pack_t *FS_LoadPackPK3FromFD (const char *packfile, int packhandle, qboolean silent)
 {
        pk3_endOfCentralDir_t eocd;
        pack_t *pack;
@@ -770,14 +772,10 @@ pack_t *FS_LoadPackPK3FromFD (const char *packfile, int packhandle, qboolean sil
        Con_DPrintf("Added packfile %s (%i files)\n", packfile, real_nb_files);
        return pack;
 }
-pack_t *FS_LoadPackPK3 (const char *packfile)
+static pack_t *FS_LoadPackPK3 (const char *packfile)
 {
        int packhandle;
-#if _MSC_VER >= 1400
-       _sopen_s(&packhandle, packfile, O_RDONLY | O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE);
-#else
-       packhandle = open (packfile, O_RDONLY | O_BINARY);
-#endif
+       packhandle = FS_SysOpenFD (packfile, "rb", false);
        if (packhandle < 0)
                return NULL;
        return FS_LoadPackPK3FromFD(packfile, packhandle, false);
@@ -791,7 +789,7 @@ PK3_GetTrueFileOffset
 Find where the true file data offset is
 ====================
 */
-qboolean PK3_GetTrueFileOffset (packfile_t *pfile, pack_t *pack)
+static qboolean PK3_GetTrueFileOffset (packfile_t *pfile, pack_t *pack)
 {
        unsigned char buffer [ZIP_LOCAL_CHUNK_BASE_SIZE];
        fs_offset_t count;
@@ -910,7 +908,7 @@ FS_Path_f
 
 ============
 */
-void FS_Path_f (void)
+static void FS_Path_f (void)
 {
        searchpath_t *s;
 
@@ -939,7 +937,7 @@ FS_LoadPackPAK
  *Loads the header and directory, adding the files at the beginning
  *of the list so they override previous pack files.
  */
-pack_t *FS_LoadPackPAK (const char *packfile)
+static pack_t *FS_LoadPackPAK (const char *packfile)
 {
        dpackheader_t header;
        int i, numpackfiles;
@@ -947,11 +945,7 @@ pack_t *FS_LoadPackPAK (const char *packfile)
        pack_t *pack;
        dpackfile_t *info;
 
-#if _MSC_VER >= 1400
-       _sopen_s(&packhandle, packfile, O_RDONLY | O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE);
-#else
-       packhandle = open (packfile, O_RDONLY | O_BINARY);
-#endif
+       packhandle = FS_SysOpenFD(packfile, "rb", false);
        if (packhandle < 0)
                return NULL;
        if(read (packhandle, (void *)&header, sizeof(header)) != sizeof(header))
@@ -1024,7 +1018,7 @@ FS_LoadPackVirtual
 Create a package entry associated with a directory file
 ====================
 */
-pack_t *FS_LoadPackVirtual (const char *dirname)
+static pack_t *FS_LoadPackVirtual (const char *dirname)
 {
        pack_t *pack;
        pack = (pack_t *)Mem_Alloc(fs_mempool, sizeof (pack_t));
@@ -1196,7 +1190,7 @@ Sets fs_gamedir, adds the directory to the head of the path,
 then loads and adds pak1.pak pak2.pak ...
 ================
 */
-void FS_AddGameDirectory (const char *dir)
+static void FS_AddGameDirectory (const char *dir)
 {
        int i;
        stringlist_t list;
@@ -1242,13 +1236,14 @@ void FS_AddGameDirectory (const char *dir)
 FS_AddGameHierarchy
 ================
 */
-void FS_AddGameHierarchy (const char *dir)
+static void FS_AddGameHierarchy (const char *dir)
 {
+       char vabuf[1024];
        // Add the common game directory
-       FS_AddGameDirectory (va("%s%s/", fs_basedir, dir));
+       FS_AddGameDirectory (va(vabuf, sizeof(vabuf), "%s%s/", fs_basedir, dir));
 
        if (*fs_userdir)
-               FS_AddGameDirectory(va("%s%s/", fs_userdir, dir));
+               FS_AddGameDirectory(va(vabuf, sizeof(vabuf), "%s%s/", fs_userdir, dir));
 }
 
 
@@ -1302,7 +1297,7 @@ const char *FS_FileWithoutPath (const char *in)
 FS_ClearSearchPath
 ================
 */
-void FS_ClearSearchPath (void)
+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
@@ -1351,6 +1346,7 @@ void FS_Rescan (void)
        qboolean fs_modified = false;
        qboolean reset = false;
        char gamedirbuf[MAX_INPUTLINE];
+       char vabuf[1024];
 
        if (fs_searchpaths)
                reset = true;
@@ -1389,7 +1385,7 @@ void FS_Rescan (void)
                // update the com_modname (used server info)
                strlcpy (com_modname, fs_gamedirs[i], sizeof (com_modname));
                if(i)
-                       strlcat(gamedirbuf, va(" %s", fs_gamedirs[i]), sizeof(gamedirbuf));
+                       strlcat(gamedirbuf, va(vabuf, sizeof(vabuf), " %s", fs_gamedirs[i]), sizeof(gamedirbuf));
                else
                        strlcpy(gamedirbuf, fs_gamedirs[i], sizeof(gamedirbuf));
        }
@@ -1410,7 +1406,7 @@ void FS_Rescan (void)
 
        // If "-condebug" is in the command line, remove the previous log file
        if (COM_CheckParm ("-condebug") != 0)
-               unlink (va("%s/qconsole.log", fs_gamedir));
+               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"))
@@ -1444,7 +1440,7 @@ void FS_Rescan (void)
        W_UnloadAll();
 }
 
-void FS_Rescan_f(void)
+static void FS_Rescan_f(void)
 {
        FS_Rescan();
 }
@@ -1454,10 +1450,7 @@ void FS_Rescan_f(void)
 FS_ChangeGameDirs
 ================
 */
-extern void Host_SaveConfig (void);
-extern void Host_LoadConfig_f (void);
 extern qboolean vid_opened;
-extern void VID_Stop(void);
 qboolean FS_ChangeGameDirs(int numgamedirs, char gamedirs[][MAX_QPATH], qboolean complain, qboolean failmissing)
 {
        int i;
@@ -1530,7 +1523,7 @@ qboolean FS_ChangeGameDirs(int numgamedirs, char gamedirs[][MAX_QPATH], qboolean
 FS_GameDir_f
 ================
 */
-void FS_GameDir_f (void)
+static void FS_GameDir_f (void)
 {
        int i;
        int numgamedirs;
@@ -1568,13 +1561,13 @@ void FS_GameDir_f (void)
        FS_ChangeGameDirs(numgamedirs, gamedirs, true, true);
 }
 
-static const char *FS_SysCheckGameDir(const char *gamedir)
+static const char *FS_SysCheckGameDir(const char *gamedir, char *buf, size_t buflength)
 {
-       static char buf[8192];
        qboolean success;
        qfile_t *f;
        stringlist_t list;
        fs_offset_t n;
+       char vabuf[1024];
 
        stringlistinit(&list);
        listdirectory(&list, gamedir, "");
@@ -1583,10 +1576,10 @@ static const char *FS_SysCheckGameDir(const char *gamedir)
 
        if(success)
        {
-               f = FS_SysOpen(va("%smodinfo.txt", gamedir), "r", false);
+               f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%smodinfo.txt", gamedir), "r", false);
                if(f)
                {
-                       n = FS_Read (f, buf, sizeof(buf) - 1);
+                       n = FS_Read (f, buf, buflength - 1);
                        if(n >= 0)
                                buf[n] = 0;
                        else
@@ -1609,17 +1602,19 @@ 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("%s%s/", fs_userdir, gamedir));
+       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("%s%s/", fs_basedir, gamedir));
+                       ret = FS_SysCheckGameDir(va(vabuf, sizeof(vabuf), "%s%s/", fs_basedir, gamedir), buf, sizeof(buf));
                        if(ret)
                                return ret;
                        return "";
@@ -1627,7 +1622,7 @@ const char *FS_CheckGameDir(const char *gamedir)
                return ret;
        }
 
-       ret = FS_SysCheckGameDir(va("%s%s/", fs_basedir, gamedir));
+       ret = FS_SysCheckGameDir(va(vabuf, sizeof(vabuf), "%s%s/", fs_basedir, gamedir), buf, sizeof(buf));
        if(ret)
                return ret;
        
@@ -1639,14 +1634,15 @@ static void FS_ListGameDirs(void)
        stringlist_t list, list2;
        int i, j;
        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("%s/", fs_basedir), "");
-       listdirectory(&list, va("%s/", fs_userdir), "");
+       listdirectory(&list, va(vabuf, sizeof(vabuf), "%s/", fs_basedir), "");
+       listdirectory(&list, va(vabuf, sizeof(vabuf), "%s/", fs_userdir), "");
        stringlistsort(&list, false);
 
        stringlistinit(&list2);
@@ -1742,7 +1738,7 @@ void FS_Init_SelfPack (void)
        }
 }
 
-int FS_ChooseUserDir(userdirmode_t userdirmode, char *userdir, size_t userdirsize)
+static int FS_ChooseUserDir(userdirmode_t userdirmode, char *userdir, size_t userdirsize)
 {
 #if defined(__IPHONEOS__)
        if (userdirmode == USERDIRMODE_HOME)
@@ -1763,7 +1759,8 @@ int FS_ChooseUserDir(userdirmode_t userdirmode, char *userdir, size_t userdirsiz
        wchar_t *savedgamesdirw;
        char savedgamesdir[MAX_OSPATH];
        int fd;
-       
+       char vabuf[1024];
+
        userdir[0] = 0;
        switch(userdirmode)
        {
@@ -1836,6 +1833,7 @@ int FS_ChooseUserDir(userdirmode_t userdirmode, char *userdir, size_t userdirsiz
 #else
        int fd;
        char *homedir;
+       char vabuf[1024];
        userdir[0] = 0;
        switch(userdirmode)
        {
@@ -1881,19 +1879,31 @@ int FS_ChooseUserDir(userdirmode_t userdirmode, char *userdir, size_t userdirsiz
        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)
-#if _MSC_VER >= 1400
-       _sopen_s(&fd, va("%s%s/config.cfg", userdir, gamedirname1), O_WRONLY | O_CREAT, _SH_DENYNO, _S_IREAD | _S_IWRITE); // note: no O_TRUNC here!
+#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
-       fd = open (va("%s%s/config.cfg", userdir, gamedirname1), O_WRONLY | O_CREAT, 0666); // note: no O_TRUNC here!
+       // 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)
        {
-               close(fd);
                return 1; // good choice - the path exists and is writable
        }
        else
-               return 0; // probably good - failed to write but maybe we need to create path
+       {
+               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
+       }
 }
 
 /*
@@ -1936,10 +1946,11 @@ void FS_Init (void)
                        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("%s/Contents/Resources/%s", fs_basedir, gamedirname1), &statresult) == 0)
+                               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));
@@ -2052,6 +2063,9 @@ void FS_Init (void)
 
        // generate the searchpath
        FS_Rescan();
+
+       if (Thread_HasThreads())
+               fs_mutex = Thread_CreateMutex();
 }
 
 void FS_Init_Commands(void)
@@ -2080,19 +2094,24 @@ void FS_Shutdown (void)
        //  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;
+       int handle = -1;
        int mod, opt;
        unsigned int ind;
+       qboolean dolock = false;
 
        // Parse the mode string
        switch (mode[0])
@@ -2123,6 +2142,9 @@ int FS_SysOpenFD(const char *filepath, const char *mode, qboolean nonblocking)
                        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]);
@@ -2132,11 +2154,29 @@ int FS_SysOpenFD(const char *filepath, const char *mode, qboolean nonblocking)
        if (nonblocking)
                opt |= O_NONBLOCK;
 
-#if _MSC_VER >= 1400
-       _sopen_s(&handle, filepath, mod | opt, _SH_DENYNO, _S_IREAD | _S_IWRITE);
+#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;
 }
 
@@ -2181,7 +2221,7 @@ FS_OpenPackedFile
 Open a packed file using its package file descriptor
 ===========
 */
-qfile_t *FS_OpenPackedFile (pack_t* pack, int pack_ind)
+static qfile_t *FS_OpenPackedFile (pack_t* pack, int pack_ind)
 {
        packfile_t *pfile;
        int dup_handle;
@@ -2436,7 +2476,7 @@ FS_OpenReadFile
 Look for a file in the search paths and open it in read-only mode
 ===========
 */
-qfile_t *FS_OpenReadFile (const char *filename, qboolean quiet, qboolean nonblocking, int symlinkLevels)
+static qfile_t *FS_OpenReadFile (const char *filename, qboolean quiet, qboolean nonblocking, int symlinkLevels)
 {
        searchpath_t *search;
        int pack_ind;
@@ -2580,13 +2620,17 @@ 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;
        }
 
-       return FS_OpenReadFile (filepath, quiet, false, 16);
+       if (fs_mutex) Thread_LockMutex(fs_mutex);
+       result = FS_OpenReadFile (filepath, quiet, false, 16);
+       if (fs_mutex) Thread_UnlockMutex(fs_mutex);
+       return result;
 }
 
 
@@ -3545,7 +3589,7 @@ void FS_FreeSearch(fssearch_t *search)
 }
 
 extern int con_linewidth;
-int FS_ListDirectory(const char *pattern, int oneperline)
+static int FS_ListDirectory(const char *pattern, int oneperline)
 {
        int numfiles;
        int numcolumns;
index 7ffba78eab5c028eaa756bec7be349dcdeb4fdcd..cd1979a2939bb424550931e285cc1d1c8ed69200 100644 (file)
@@ -136,4 +136,9 @@ unsigned char *FS_Inflate(const unsigned char *data, size_t size, size_t *inflat
 
 qboolean FS_HasZlib(void);
 
+void FS_Init_SelfPack(void);
+void FS_Init(void);
+void FS_Shutdown(void);
+void FS_Init_Commands(void);
+
 #endif
index 484a3159779ffe54c10eca6aa5204e25cebbd16a..12e889057c8c821b09c75f4e96de6f032eec761e 100644 (file)
@@ -363,7 +363,7 @@ ft2_font_t *Font_Alloc(void)
        return (ft2_font_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_t));
 }
 
-qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
+static qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment)
 {
        ft2_attachment_t *na;
 
@@ -410,6 +410,7 @@ 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)
@@ -457,10 +458,10 @@ qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt)
 
                if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], &dpfnt->settings, fb))
                {
-                       if(!FS_FileExists(va("%s.tga", dpfnt->fallbacks[i])))
-                       if(!FS_FileExists(va("%s.png", dpfnt->fallbacks[i])))
-                       if(!FS_FileExists(va("%s.jpg", dpfnt->fallbacks[i])))
-                       if(!FS_FileExists(va("%s.pcx", dpfnt->fallbacks[i])))
+                       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;
@@ -612,7 +613,7 @@ static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *setti
        return true;
 }
 
-void Font_Postprocess_Update(ft2_font_t *fnt, int bpp, int w, int h)
+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];
@@ -666,7 +667,7 @@ void Font_Postprocess_Update(ft2_font_t *fnt, int bpp, int w, int h)
        }
 }
 
-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)
+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;
 
@@ -1109,6 +1110,7 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
        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
@@ -1545,9 +1547,11 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
                                data[x*4+0] = data[x*4+2];
                                data[x*4+2] = b;
                        }
-                       Image_WriteTGABGRA(va("%s.tga", map_identifier), w, h, data);
+                       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("dds/%s.dds", map_identifier), r_texture_dds_save.integer < 2, true);
+                               R_SaveTextureDDSFile(tex, va(vabuf, sizeof(vabuf), "dds/%s.dds", map_identifier), r_texture_dds_save.integer < 2, true);
+#endif
                }
        }
 
index 74938dc509636456b57232e62e22db1376b99bb6..8df14f8e1da990268ea13c0e6ca26e9ec5e30ee0 100644 (file)
@@ -8,6 +8,94 @@ 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)"};
@@ -84,8 +172,8 @@ void GL_PrintError(int errornumber, const char *filename, int linenumber)
                Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber);
                break;
 #endif
-#ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT
-       case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
+#ifdef GL_INVALID_FRAMEBUFFER_OPERATION
+       case GL_INVALID_FRAMEBUFFER_OPERATION:
                Con_Printf("GL_INVALID_FRAMEBUFFER_OPERATION at %s:%i\n", filename, linenumber);
                break;
 #endif
@@ -259,7 +347,7 @@ unsigned short polygonelement3s[(POLYGONELEMENTS_MAXPOINTS-2)*3];
 int quadelement3i[QUADELEMENTS_MAXQUADS*6];
 unsigned short quadelement3s[QUADELEMENTS_MAXQUADS*6];
 
-void GL_VBOStats_f(void)
+static void GL_VBOStats_f(void)
 {
        GL_Mesh_ListVBOs(true);
 }
@@ -331,7 +419,7 @@ static void gl_backend_start(void)
        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_EXT, &gl_state.defaultframebufferobject);
+                       qglGetIntegerv(GL_FRAMEBUFFER_BINDING, &gl_state.defaultframebufferobject);
                break;
        case RENDERPATH_D3D9:
 #ifdef SUPPORTD3D
@@ -1091,6 +1179,7 @@ void R_SetViewport(const r_viewport_t *v)
        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
@@ -1098,6 +1187,7 @@ void R_SetViewport(const r_viewport_t *v)
                Matrix4x4_ToArrayFloatGL(&gl_projectionmatrix, m);
                qglLoadMatrixf(m);CHECKGLERROR
                qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
+#endif
                break;
        case RENDERPATH_D3D9:
 #ifdef SUPPORTD3D
@@ -1145,7 +1235,7 @@ static void GL_BindVBO(int bufferobject)
        {
                gl_state.vertexbufferobject = bufferobject;
                CHECKGLERROR
-               qglBindBufferARB(GL_ARRAY_BUFFER_ARB, bufferobject);CHECKGLERROR
+               qglBindBufferARB(GL_ARRAY_BUFFER, bufferobject);CHECKGLERROR
        }
 }
 
@@ -1155,13 +1245,13 @@ static void GL_BindEBO(int bufferobject)
        {
                gl_state.elementbufferobject = bufferobject;
                CHECKGLERROR
-               qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, bufferobject);CHECKGLERROR
+               qglBindBufferARB(GL_ELEMENT_ARRAY_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)
 {
-       int temp;
        switch(vid.renderpath)
        {
        case RENDERPATH_GL11:
@@ -1169,16 +1259,111 @@ int R_Mesh_CreateFramebufferObject(rtexture_t *depthtexture, rtexture_t *colorte
        case RENDERPATH_GL20:
        case RENDERPATH_GLES1:
        case RENDERPATH_GLES2:
-               if (!vid.support.ext_framebuffer_object)
-                       return 0;
-               qglGenFramebuffersEXT(1, (GLuint*)&temp);CHECKGLERROR
-               R_Mesh_SetRenderTargets(temp, NULL, NULL, NULL, NULL, NULL);
-               if (depthtexture) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, depthtexture->gltexturetypeenum, R_GetTexture(depthtexture), 0);CHECKGLERROR
-               if (colortexture) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, colortexture->gltexturetypeenum, R_GetTexture(colortexture), 0);CHECKGLERROR
-               if (colortexture2) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, colortexture2->gltexturetypeenum, R_GetTexture(colortexture2), 0);CHECKGLERROR
-               if (colortexture3) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT2_EXT, colortexture3->gltexturetypeenum, R_GetTexture(colortexture3), 0);CHECKGLERROR
-               if (colortexture4) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT3_EXT, colortexture4->gltexturetypeenum, R_GetTexture(colortexture4), 0);CHECKGLERROR
-               return temp;
+               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
+                       if (depthtexture  && depthtexture->texnum ) qglFramebufferTexture2D(GL_FRAMEBUFFER, depthtexture->glisdepthstencil ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT  , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR
+                       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
+
+                       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
+                       }
+                       status = qglCheckFramebufferStatus(GL_FRAMEBUFFER);CHECKGLERROR
+                       if (status != GL_FRAMEBUFFER_COMPLETE)
+                       {
+                               Con_Printf("R_Mesh_CreateFramebufferObject: glCheckFramebufferStatus returned %i\n", status);
+                               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
+
+                       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
+                       }
+                       status = qglCheckFramebufferStatus(GL_FRAMEBUFFER);CHECKGLERROR
+                       if (status != GL_FRAMEBUFFER_COMPLETE)
+                       {
+                               Con_Printf("R_Mesh_CreateFramebufferObject: glCheckFramebufferStatus returned %i\n", status);
+                               qglDeleteFramebuffers(1, (GLuint*)&temp);
+                               temp = 0;
+                       }
+                       return temp;
+               }
+               return 0;
        case RENDERPATH_D3D9:
        case RENDERPATH_D3D10:
        case RENDERPATH_D3D11:
@@ -1199,7 +1384,7 @@ void R_Mesh_DestroyFramebufferObject(int fbo)
        case RENDERPATH_GLES1:
        case RENDERPATH_GLES2:
                if (fbo)
-                       qglDeleteFramebuffersEXT(1, (GLuint*)&fbo);
+                       qglDeleteFramebuffers(1, (GLuint*)&fbo);
                break;
        case RENDERPATH_D3D9:
        case RENDERPATH_D3D10:
@@ -1213,10 +1398,6 @@ void R_Mesh_DestroyFramebufferObject(int fbo)
 #ifdef SUPPORTD3D
 void R_Mesh_SetRenderTargetsD3D9(IDirect3DSurface9 *depthsurface, IDirect3DSurface9 *colorsurface0, IDirect3DSurface9 *colorsurface1, IDirect3DSurface9 *colorsurface2, IDirect3DSurface9 *colorsurface3)
 {
-// LordHavoc: for some weird reason the redundant SetDepthStencilSurface calls are necessary (otherwise the lights fail depth test, as if they were using the shadowmap depth surface and render target still)
-       if (gl_state.d3drt_depthsurface == depthsurface && gl_state.d3drt_colorsurfaces[0] == colorsurface0 && gl_state.d3drt_colorsurfaces[1] == colorsurface1 && gl_state.d3drt_colorsurfaces[2] == colorsurface2 && gl_state.d3drt_colorsurfaces[3] == colorsurface3)
-               return;
-
        gl_state.framebufferobject = depthsurface != gl_state.d3drt_backbufferdepthsurface || colorsurface0 != gl_state.d3drt_backbuffercolorsurface;
        if (gl_state.d3drt_depthsurface != depthsurface)
        {
@@ -1246,38 +1427,6 @@ void R_Mesh_SetRenderTargetsD3D9(IDirect3DSurface9 *depthsurface, IDirect3DSurfa
 }
 #endif
 
-void R_Mesh_ResetRenderTargets(void)
-{
-       switch(vid.renderpath)
-       {
-       case RENDERPATH_GL11:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL20:
-       case RENDERPATH_GLES1:
-       case RENDERPATH_GLES2:
-               if (gl_state.framebufferobject)
-               {
-                       gl_state.framebufferobject = 0;
-                       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, gl_state.defaultframebufferobject);
-               }
-               break;
-       case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
-               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:
-               DPSOFTRAST_SetRenderTargets(vid.width, vid.height, vid.softdepthpixels, vid.softpixels, NULL, NULL, NULL);
-               break;
-       }
-}
-
 void R_Mesh_SetRenderTargets(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, rtexture_t *colortexture2, rtexture_t *colortexture3, rtexture_t *colortexture4)
 {
        unsigned int i;
@@ -1302,7 +1451,7 @@ void R_Mesh_SetRenderTargets(int fbo, rtexture_t *depthtexture, rtexture_t *colo
                if (gl_state.framebufferobject != fbo)
                {
                        gl_state.framebufferobject = fbo;
-                       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, gl_state.framebufferobject ? gl_state.framebufferobject : gl_state.defaultframebufferobject);
+                       qglBindFramebuffer(GL_FRAMEBUFFER, gl_state.framebufferobject ? gl_state.framebufferobject : gl_state.defaultframebufferobject);
                }
                break;
        case RENDERPATH_D3D9:
@@ -1311,19 +1460,24 @@ void R_Mesh_SetRenderTargets(int fbo, rtexture_t *depthtexture, rtexture_t *colo
                // TODO: optimize: keep surface pointer around in rtexture_t until texture is freed or lost
                if (fbo)
                {
-                       IDirect3DSurface9 *colorsurfaces[4];
-                       for (i = 0;i < 4;i++)
+                       IDirect3DSurface9 *surfaces[5];
+                       for (i = 0;i < 5;i++)
                        {
-                               colorsurfaces[i] = NULL;
+                               surfaces[i] = NULL;
                                if (textures[i])
-                                       IDirect3DTexture9_GetSurfaceLevel((IDirect3DTexture9 *)textures[i]->d3dtexture, 0, &colorsurfaces[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(depthtexture ? (IDirect3DSurface9 *)depthtexture->d3dtexture : NULL, colorsurfaces[0], colorsurfaces[1], colorsurfaces[2], colorsurfaces[3]);
+                       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 < 4;i++)
-                               if (textures[i])
-                                       IDirect3DSurface9_Release(colorsurfaces[i]);
+                       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);
@@ -1382,8 +1536,6 @@ static int d3dstencilopforglfunc(int f)
 }
 #endif
 
-extern cvar_t r_transparent_alphatocoverage;
-
 static void GL_Backend_ResetState(void)
 {
        unsigned int i;
@@ -1432,6 +1584,7 @@ static void GL_Backend_ResetState(void)
        case RENDERPATH_GL11:
        case RENDERPATH_GL13:
        case RENDERPATH_GLES1:
+#ifdef GL_ALPHA_TEST
                CHECKGLERROR
 
                qglColorMask(1, 1, 1, 1);CHECKGLERROR
@@ -1448,14 +1601,14 @@ static void GL_Backend_ResetState(void)
 
                if (vid.support.arb_vertex_buffer_object)
                {
-                       qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
-                       qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+                       qglBindBufferARB(GL_ARRAY_BUFFER, 0);
+                       qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0);
                }
 
                if (vid.support.ext_framebuffer_object)
                {
-                       //qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
-                       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+                       //qglBindRenderbuffer(GL_RENDERBUFFER, 0);
+                       qglBindFramebuffer(GL_FRAMEBUFFER, 0);
                }
 
                qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), NULL);CHECKGLERROR
@@ -1466,7 +1619,7 @@ static void GL_Backend_ResetState(void)
                qglColor4f(1, 1, 1, 1);CHECKGLERROR
 
                if (vid.support.ext_framebuffer_object)
-                       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, gl_state.framebufferobject);
+                       qglBindFramebuffer(GL_FRAMEBUFFER, gl_state.framebufferobject);
 
                gl_state.unit = MAX_TEXTUREUNITS;
                gl_state.clientunit = MAX_TEXTUREUNITS;
@@ -1483,8 +1636,8 @@ static void GL_Backend_ResetState(void)
                        }
                        if (vid.support.arb_texture_cube_map)
                        {
-                               qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
-                               qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
+                               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
@@ -1495,6 +1648,7 @@ static void GL_Backend_ResetState(void)
                        qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
                }
                CHECKGLERROR
+#endif
                break;
        case RENDERPATH_SOFT:
                DPSOFTRAST_ColorMask(1,1,1,1);
@@ -1520,11 +1674,11 @@ static void GL_Backend_ResetState(void)
                qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
                if (vid.support.arb_vertex_buffer_object)
                {
-                       qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
-                       qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+                       qglBindBufferARB(GL_ARRAY_BUFFER, 0);
+                       qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0);
                }
                if (vid.support.ext_framebuffer_object)
-                       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, gl_state.defaultframebufferobject);
+                       qglBindFramebuffer(GL_FRAMEBUFFER, gl_state.defaultframebufferobject);
                qglEnableVertexAttribArray(GLSLATTRIB_POSITION);
                qglVertexAttribPointer(GLSLATTRIB_POSITION, 3, GL_FLOAT, false, sizeof(float[3]), NULL);CHECKGLERROR
                qglDisableVertexAttribArray(GLSLATTRIB_COLOR);
@@ -1542,7 +1696,7 @@ static void GL_Backend_ResetState(void)
                        }
                        if (vid.support.arb_texture_cube_map)
                        {
-                               qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
+                               qglBindTexture(GL_TEXTURE_CUBE_MAP, 0);CHECKGLERROR
                        }
                }
                for (i = 0;i < vid.texarrayunits;i++)
@@ -1571,7 +1725,7 @@ void GL_ActiveTexture(unsigned int num)
                        if (qglActiveTexture)
                        {
                                CHECKGLERROR
-                               qglActiveTexture(GL_TEXTURE0_ARB + gl_state.unit);
+                               qglActiveTexture(GL_TEXTURE0 + gl_state.unit);
                                CHECKGLERROR
                        }
                        break;
@@ -1598,7 +1752,7 @@ void GL_ClientActiveTexture(unsigned int num)
                        if (qglActiveTexture)
                        {
                                CHECKGLERROR
-                               qglClientActiveTexture(GL_TEXTURE0_ARB + gl_state.clientunit);
+                               qglClientActiveTexture(GL_TEXTURE0 + gl_state.clientunit);
                                CHECKGLERROR
                        }
                        break;
@@ -1811,7 +1965,11 @@ void GL_DepthRange(float nearfrac, float farfrac)
                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
@@ -1863,10 +2021,12 @@ void R_SetStencilSeparate(qboolean enable, int writemask, int frontfail, int fro
                        qglStencilMask(writemask);CHECKGLERROR
                        qglStencilOpSeparate(GL_FRONT, frontfail, frontzfail, frontzpass);CHECKGLERROR
                        qglStencilOpSeparate(GL_BACK, backfail, backzfail, backzpass);CHECKGLERROR
-                       qglStencilFuncSeparate(frontcompare, backcompare, comparereference, comparereference);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
@@ -1876,6 +2036,7 @@ void R_SetStencilSeparate(qboolean enable, int writemask, int frontfail, int fro
                        qglStencilMask(writemask);CHECKGLERROR
                        qglStencilOp(backfail, backzfail, backzpass);CHECKGLERROR
                        qglStencilFunc(backcompare, comparereference, comparemask);CHECKGLERROR
+#endif
                }
                break;
        case RENDERPATH_D3D9:
@@ -1927,7 +2088,9 @@ void R_SetStencil(qboolean enable, int writemask, int fail, int zfail, int zpass
                }
                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
@@ -2123,6 +2286,7 @@ void GL_AlphaTest(int state)
                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)
@@ -2133,6 +2297,7 @@ void GL_AlphaTest(int state)
                        {
                                qglDisable(GL_ALPHA_TEST);CHECKGLERROR
                        }
+#endif
                        break;
                case RENDERPATH_D3D9:
                case RENDERPATH_D3D10:
@@ -2162,6 +2327,7 @@ void GL_AlphaToCoverage(qboolean state)
                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)
@@ -2174,6 +2340,7 @@ void GL_AlphaToCoverage(qboolean state)
                                qglDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);CHECKGLERROR
 //                             qglDisable(GL_MULTISAMPLE_ARB);CHECKGLERROR
                        }
+#endif
                        break;
                }
        }
@@ -2346,7 +2513,11 @@ void GL_Clear(int mask, const float *colorvalue, float depthvalue, int stencilva
                }
                if (mask & GL_DEPTH_BUFFER_BIT)
                {
+#ifdef USE_GLES2
+                       qglClearDepthf(depthvalue);CHECKGLERROR
+#else
                        qglClearDepth(depthvalue);CHECKGLERROR
+#endif
                }
                if (mask & GL_STENCIL_BUFFER_BIT)
                {
@@ -2438,7 +2609,7 @@ void GL_ReadPixelsBGRA(int x, int y, int width, int height, unsigned char *outpi
 void R_Mesh_Start(void)
 {
        BACKENDACTIVECHECK
-       R_Mesh_ResetRenderTargets();
+       R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
        R_Mesh_SetUseVBO();
        if (gl_printcheckerror.integer && !gl_paranoid.integer)
        {
@@ -2447,7 +2618,7 @@ void R_Mesh_Start(void)
        }
 }
 
-qboolean GL_Backend_CompileShader(int programobject, GLenum shadertypeenum, const char *shadertype, int numstrings, const char **strings)
+static qboolean GL_Backend_CompileShader(int programobject, GLenum shadertypeenum, const char *shadertype, int numstrings, const char **strings)
 {
        int shaderobject;
        int shadercompiled;
@@ -2459,7 +2630,7 @@ qboolean GL_Backend_CompileShader(int programobject, GLenum shadertypeenum, cons
        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")))
+       if (compilelog[0] && (strstr(compilelog, "error") || strstr(compilelog, "ERROR") || strstr(compilelog, "Error") || strstr(compilelog, "WARNING") || strstr(compilelog, "warning") || strstr(compilelog, "Warning") || developer_extra.integer))
        {
                int i, j, pretextlines = 0;
                for (i = 0;i < numstrings - 1;i++)
@@ -2499,8 +2670,10 @@ unsigned int GL_Backend_CompileProgram(int vertexstrings_count, const char **ver
        qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD5, "Attrib_TexCoord5");
        qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD6, "Attrib_TexCoord6");
        qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD7, "Attrib_TexCoord7");
+#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;
@@ -2518,7 +2691,7 @@ unsigned int GL_Backend_CompileProgram(int vertexstrings_count, const char **ver
        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"))
+               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.
@@ -2544,18 +2717,6 @@ void GL_Backend_FreeProgram(unsigned int prog)
        CHECKGLERROR
 }
 
-void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
-{
-       int i;
-       if (offset)
-       {
-               for (i = 0;i < count;i++)
-                       *out++ = *in++ + offset;
-       }
-       else
-               memcpy(out, in, sizeof(*out) * count);
-}
-
 // 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, size_t element3i_bufferoffset, const unsigned short *element3s, const r_meshbuffer_t *element3s_indexbuffer, size_t element3s_bufferoffset)
@@ -2714,6 +2875,7 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
                        CHECKGLERROR
                        if (gl_mesh_testmanualfeeding.integer)
                        {
+#ifndef USE_GLES2
                                unsigned int i, j, element;
                                const GLfloat *p;
                                qglBegin(GL_TRIANGLES);
@@ -2814,13 +2976,13 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
                                                                        if (vid.texarrayunits > 1)
                                                                        {
                                                                                if (gl_state.units[j].pointer_texcoord_components == 4)
-                                                                                       qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]);
+                                                                                       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_ARB + j, p[0], p[1], p[2]);
+                                                                                       qglMultiTexCoord3f(GL_TEXTURE0 + j, p[0], p[1], p[2]);
                                                                                else if (gl_state.units[j].pointer_texcoord_components == 2)
-                                                                                       qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
+                                                                                       qglMultiTexCoord2f(GL_TEXTURE0 + j, p[0], p[1]);
                                                                                else
-                                                                                       qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
+                                                                                       qglMultiTexCoord1f(GL_TEXTURE0 + j, p[0]);
                                                                        }
                                                                        else
                                                                        {
@@ -2840,13 +3002,13 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
                                                                        if (vid.texarrayunits > 1)
                                                                        {
                                                                                if (gl_state.units[j].pointer_texcoord_components == 4)
-                                                                                       qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, s[0], s[1], s[2], s[3]);
+                                                                                       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_ARB + j, s[0], s[1], s[2]);
+                                                                                       qglMultiTexCoord3f(GL_TEXTURE0 + j, s[0], s[1], s[2]);
                                                                                else if (gl_state.units[j].pointer_texcoord_components == 2)
-                                                                                       qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, s[0], s[1]);
+                                                                                       qglMultiTexCoord2f(GL_TEXTURE0 + j, s[0], s[1]);
                                                                                else if (gl_state.units[j].pointer_texcoord_components == 1)
-                                                                                       qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, s[0]);
+                                                                                       qglMultiTexCoord1f(GL_TEXTURE0 + j, s[0]);
                                                                        }
                                                                        else
                                                                        {
@@ -2866,13 +3028,13 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
                                                                        if (vid.texarrayunits > 1)
                                                                        {
                                                                                if (gl_state.units[j].pointer_texcoord_components == 4)
-                                                                                       qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, sb[0], sb[1], sb[2], sb[3]);
+                                                                                       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_ARB + j, sb[0], sb[1], sb[2]);
+                                                                                       qglMultiTexCoord3f(GL_TEXTURE0 + j, sb[0], sb[1], sb[2]);
                                                                                else if (gl_state.units[j].pointer_texcoord_components == 2)
-                                                                                       qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, sb[0], sb[1]);
+                                                                                       qglMultiTexCoord2f(GL_TEXTURE0 + j, sb[0], sb[1]);
                                                                                else if (gl_state.units[j].pointer_texcoord_components == 1)
-                                                                                       qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, sb[0]);
+                                                                                       qglMultiTexCoord1f(GL_TEXTURE0 + j, sb[0]);
                                                                        }
                                                                        else
                                                                        {
@@ -2915,16 +3077,19 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
                                }
                                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 *)(firsttriangle * sizeof(unsigned short[3])));
                                        CHECKGLERROR
@@ -2933,12 +3098,14 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
                        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 *)(firsttriangle * sizeof(unsigned int[3])));
                                        CHECKGLERROR
@@ -2947,12 +3114,14 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
                        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
@@ -2961,12 +3130,14 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
                        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
@@ -3028,8 +3199,8 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
                                GLint           attribsize;
                                GLenum          attribtype;
                                GLchar          attribname[1024];
-                               r = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
-                               if (r != GL_FRAMEBUFFER_COMPLETE_EXT)
+                               r = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER);CHECKGLERROR
+                               if (r != GL_FRAMEBUFFER_COMPLETE)
                                        Con_DPrintf("fbo %i not complete (default %i)\n", gl_state.framebufferobject, gl_state.defaultframebufferobject);
 #ifndef GL_CURRENT_PROGRAM
 #define GL_CURRENT_PROGRAM 0x8B8D
@@ -3071,7 +3242,7 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri
 // restores backend state, used when done with 3D rendering
 void R_Mesh_Finish(void)
 {
-       R_Mesh_ResetRenderTargets();
+       R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
 }
 
 r_meshbuffer_t *R_Mesh_CreateMeshBuffer(const void *data, size_t size, const char *name, qboolean isindexbuffer, qboolean isdynamic, qboolean isindex16)
@@ -3119,7 +3290,7 @@ void R_Mesh_UpdateMeshBuffer(r_meshbuffer_t *buffer, const void *data, size_t si
                        GL_BindEBO(buffer->bufferobject);
                else
                        GL_BindVBO(buffer->bufferobject);
-               qglBufferDataARB(buffer->isindexbuffer ? GL_ELEMENT_ARRAY_BUFFER_ARB : GL_ARRAY_BUFFER_ARB, size, data, buffer->isdynamic ? GL_STREAM_DRAW_ARB : GL_STATIC_DRAW_ARB);
+               qglBufferDataARB(buffer->isindexbuffer ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER, size, data, buffer->isdynamic ? GL_STREAM_DRAW : GL_STATIC_DRAW);
                break;
        case RENDERPATH_D3D9:
 #ifdef SUPPORTD3D
@@ -3297,6 +3468,7 @@ void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void *
        case RENDERPATH_GL11:
        case RENDERPATH_GL13:
        case RENDERPATH_GLES1:
+#ifdef GL_MODELVIEW
                CHECKGLERROR
                if (pointer)
                {
@@ -3333,6 +3505,7 @@ void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void *
                                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:
@@ -3392,6 +3565,7 @@ void R_Mesh_TexCoordPointer(unsigned int unitnum, int components, int gltype, si
        case RENDERPATH_GL11:
        case RENDERPATH_GL13:
        case RENDERPATH_GLES1:
+#ifdef GL_MODELVIEW
                CHECKGLERROR
                if (pointer)
                {
@@ -3427,6 +3601,7 @@ void R_Mesh_TexCoordPointer(unsigned int unitnum, int components, int gltype, si
                                qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
                        }
                }
+#endif
                break;
        case RENDERPATH_GL20:
        case RENDERPATH_GLES2:
@@ -3480,7 +3655,7 @@ int R_Mesh_TexBound(unsigned int unitnum, int id)
                return unit->t2d;
        if (id == GL_TEXTURE_3D)
                return unit->t3d;
-       if (id == GL_TEXTURE_CUBE_MAP_ARB)
+       if (id == GL_TEXTURE_CUBE_MAP)
                return unit->tcubemap;
        return 0;
 }
@@ -3583,7 +3758,7 @@ void R_Mesh_TexBind(unsigned int unitnum, rtexture_t *tex)
                {
                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_ARB: if (unit->tcubemap != texnum) {GL_ActiveTexture(unitnum);unit->tcubemap = texnum;qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);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:
@@ -3604,7 +3779,7 @@ void R_Mesh_TexBind(unsigned int unitnum, rtexture_t *tex)
                        case GL_TEXTURE_3D:
                                tex3d = texnum;
                                break;
-                       case GL_TEXTURE_CUBE_MAP_ARB:
+                       case GL_TEXTURE_CUBE_MAP:
                                texcubemap = texnum;
                                break;
                        }
@@ -3659,18 +3834,18 @@ void R_Mesh_TexBind(unsigned int unitnum, rtexture_t *tex)
                        {
                                if (unit->tcubemap == 0)
                                {
-                                       qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
+                                       qglEnable(GL_TEXTURE_CUBE_MAP);CHECKGLERROR
                                }
                        }
                        else
                        {
                                if (unit->tcubemap)
                                {
-                                       qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
+                                       qglDisable(GL_TEXTURE_CUBE_MAP);CHECKGLERROR
                                }
                        }
                        unit->tcubemap = texcubemap;
-                       qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
+                       qglBindTexture(GL_TEXTURE_CUBE_MAP, unit->tcubemap);CHECKGLERROR
                }
                break;
        case RENDERPATH_D3D9:
@@ -3737,6 +3912,7 @@ void R_Mesh_TexMatrix(unsigned int unitnum, const matrix4x4_t *matrix)
        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
@@ -3767,6 +3943,7 @@ void R_Mesh_TexMatrix(unsigned int unitnum, const matrix4x4_t *matrix)
                                qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
                        }
                }
+#endif
                break;
        case RENDERPATH_D3D9:
        case RENDERPATH_D3D10:
@@ -3789,6 +3966,7 @@ void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, i
                break;
        case RENDERPATH_GL13:
        case RENDERPATH_GLES1:
+#ifdef GL_TEXTURE_ENV
                // GL_ARB_texture_env_combine
                if (!combinergb)
                        combinergb = GL_MODULATE;
@@ -3801,31 +3979,31 @@ void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, i
                if (combinergb != combinealpha || rgbscale != 1 || alphascale != 1)
                {
                        if (combinergb == GL_DECAL)
-                               combinergb = GL_INTERPOLATE_ARB;
-                       if (unit->combine != GL_COMBINE_ARB)
+                               combinergb = GL_INTERPOLATE;
+                       if (unit->combine != GL_COMBINE)
                        {
-                               unit->combine = GL_COMBINE_ARB;
+                               unit->combine = GL_COMBINE;
                                GL_ActiveTexture(unitnum);
-                               qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
-                               qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);CHECKGLERROR // for GL_INTERPOLATE_ARB mode
+                               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_ARB, unit->combinergb);CHECKGLERROR
+                               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_ARB, unit->combinealpha);CHECKGLERROR
+                               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_ARB, unit->rgbscale);CHECKGLERROR
+                               qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, unit->rgbscale);CHECKGLERROR
                        }
                        if (unit->alphascale != alphascale)
                        {
@@ -3843,9 +4021,11 @@ void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, i
                                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)
@@ -3854,6 +4034,7 @@ void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, i
                        GL_ActiveTexture(unitnum);
                        qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combine);CHECKGLERROR
                }
+#endif
                break;
        case RENDERPATH_D3D9:
        case RENDERPATH_D3D10:
@@ -4488,7 +4669,7 @@ void GL_BlendEquationSubtract(qboolean negated)
                case RENDERPATH_GL20:
                case RENDERPATH_GLES1:
                case RENDERPATH_GLES2:
-                       qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
+                       qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT);
                        break;
                case RENDERPATH_D3D9:
 #ifdef SUPPORTD3D
@@ -4515,7 +4696,7 @@ void GL_BlendEquationSubtract(qboolean negated)
                case RENDERPATH_GL20:
                case RENDERPATH_GLES1:
                case RENDERPATH_GLES2:
-                       qglBlendEquationEXT(GL_FUNC_ADD_EXT);
+                       qglBlendEquationEXT(GL_FUNC_ADD);
                        break;
                case RENDERPATH_D3D9:
 #ifdef SUPPORTD3D
index 0a35233621018c4c26ccc3381f40e34d4a8d0c41..86b2d310d97031cf49b95b8704abb31e02c5d18a 100644 (file)
@@ -52,8 +52,6 @@ void GL_Clear(int mask, const float *colorvalue, float depthvalue, int stencilva
 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_ResetRenderTargets(void);
-void R_Mesh_SetMainRenderTargets(void);
 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);
index ef1fee21241ecccbc7803fc06dbe00beb29f6a8f..05d6c92527fefa1c570359d3a4e8e84f51f90981 100644 (file)
@@ -323,6 +323,7 @@ cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags)
        qboolean ddshasalpha;
        float ddsavgcolor[4];
        qboolean loaded = false;
+       char vabuf[1024];
 
        texflags = TEXF_ALPHA;
        if (!(cachepicflags & CACHEPICFLAG_NOCLAMP))
@@ -361,30 +362,38 @@ cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags)
                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("dds/%s.dds", pic->name), pic->texflags, &ddshasalpha, ddsavgcolor, 0)))
+       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)))
        {
                // note this loads even if autoload is true, otherwise we can't get the width/height
                loaded = true;
@@ -413,8 +422,10 @@ reload:
                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("dds/%s.dds", pic->name), r_texture_dds_save.integer < 2, pic->hasalpha);
+                               R_SaveTextureDDSFile(pic->tex, va(vabuf, sizeof(vabuf), "dds/%s.dds", pic->name), r_texture_dds_save.integer < 2, pic->hasalpha);
+#endif
                }
        }
        if (!loaded)
@@ -488,6 +499,7 @@ reload:
                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;
@@ -500,25 +512,30 @@ cachepic_t *Draw_CachePic (const char *path)
 
 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("dds/%s.dds", pic->name), pic->texflags, &ddshasalpha, ddsavgcolor, 0);
+                       pic->tex = R_LoadTextureDDSFile(drawtexturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", pic->name), vid.sRGB2D, pic->texflags, &ddshasalpha, ddsavgcolor, 0);
                }
                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("dds/%s.dds", pic->name), r_texture_dds_save.integer < 2, pic->hasalpha);
+                               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("dds/%s.dds", pic->name), r_texture_dds_save.integer < 2, pic->hasalpha);
+                               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);
@@ -567,26 +584,24 @@ cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, u
        }
        else
        {
-               if (pic == NULL)
+               if (numcachepics == MAX_CACHED_PICS)
                {
-                       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++);
-                       strlcpy (pic->name, picname, sizeof(pic->name));
-                       // link into list
-                       pic->chain = cachepichash[hashkey];
-                       cachepichash[hashkey] = pic;
+                       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->tex)
+       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;
@@ -693,7 +708,7 @@ void LoadFont(qboolean override, const char *name, dp_font_t *fnt, float scale,
                ch = 0;
                while(ch < 256)
                {
-                       if(!COM_ParseToken_Simple(&p, false, false))
+                       if(!COM_ParseToken_Simple(&p, false, false, true))
                                return;
 
                        switch(*com_token)
@@ -717,20 +732,20 @@ void LoadFont(qboolean override, const char *name, dp_font_t *fnt, float scale,
                                default:
                                        if(!strcmp(com_token, "extraspacing"))
                                        {
-                                               if(!COM_ParseToken_Simple(&p, false, false))
+                                               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))
+                                               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))
+                                               if(!COM_ParseToken_Simple(&p, false, false, true))
                                                        return;
                                        }
                                        break;
@@ -983,6 +998,7 @@ Draw_Init
 static void gl_draw_start(void)
 {
        int i;
+       char vabuf[1024];
        drawtexturepool = R_AllocTexturePool();
 
        numcachepics = 0;
@@ -993,7 +1009,7 @@ static void gl_draw_start(void)
        // load default font textures
        for(i = 0; i < dp_fonts.maxsize; ++i)
                if (dp_fonts.f[i].title[0])
-                       LoadFont(false, va("gfx/font_%s", dp_fonts.f[i].title), &dp_fonts.f[i], 1, 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);
@@ -1053,33 +1069,19 @@ void GL_Draw_Init (void)
        R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap, NULL, NULL);
 }
 
-static void _DrawQ_Setup(void)
+static void _DrawQ_Setup(void) // see R_ResetViewRendering2D
 {
-       r_viewport_t viewport;
        if (r_refdef.draw2dstage == 1)
                return;
        r_refdef.draw2dstage = 1;
-       CHECKGLERROR
-       R_Viewport_InitOrtho(&viewport, &identitymatrix, r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height, 0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100, NULL);
-       R_Mesh_ResetRenderTargets();
-       R_SetViewport(&viewport);
-       GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
-       GL_DepthFunc(GL_LEQUAL);
-       GL_PolygonOffset(0,0);
-       GL_CullFace(GL_NONE);
-       R_EntityMatrix(&identitymatrix);
 
-       GL_DepthRange(0, 1);
-       GL_PolygonOffset(0, 0);
-       GL_DepthTest(false);
-       GL_Color(1,1,1,1);
+       R_ResetViewRendering2D_Common(0, NULL, NULL, vid_conwidth.integer, vid_conheight.integer);
 }
 
 qboolean r_draw2d_force = false;
-void _DrawQ_SetupAndProcessDrawFlag(int flags, cachepic_t *pic, float alpha)
+static void _DrawQ_SetupAndProcessDrawFlag(int flags, cachepic_t *pic, float alpha)
 {
        _DrawQ_Setup();
-       CHECKGLERROR
        if(!r_draw2d.integer && !r_draw2d_force)
                return;
        DrawQ_ProcessDrawFlag(flags, (alpha < 1) || (pic && pic->hasalpha));
@@ -1141,7 +1143,7 @@ void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, flo
                        width = pic->width;
                if (height == 0)
                        height = pic->height;
-               R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1, true);
+               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
@@ -1157,7 +1159,7 @@ void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, flo
 #endif
        }
        else
-               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, true);
+               R_SetupShader_Generic_NoTexture((flags & DRAWFLAGS_BLEND) ? false : true, true);
 
        floats[2] = floats[5] = floats[8] = floats[11] = 0;
        floats[0] = floats[9] = x;
@@ -1190,10 +1192,10 @@ void DrawQ_RotPic(float x, float y, cachepic_t *pic, float width, float height,
                        width = pic->width;
                if (height == 0)
                        height = pic->height;
-               R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1, true);
+               R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false);
        }
        else
-               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, true);
+               R_SetupShader_Generic_NoTexture((flags & DRAWFLAGS_BLEND) ? false : true, true);
 
        floats[2] = floats[5] = floats[8] = floats[11] = 0;
 
@@ -1235,7 +1237,7 @@ void DrawQ_Fill(float x, float y, float width, float height, float red, float gr
                return;
 
 //     R_Mesh_ResetTextureState();
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, true);
+       R_SetupShader_Generic_NoTexture((flags & DRAWFLAGS_BLEND) ? false : true, true);
 
        floats[2] = floats[5] = floats[8] = floats[11] = 0;
        floats[0] = floats[9] = x;
@@ -1562,7 +1564,7 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
 //     R_Mesh_ResetTextureState();
        if (!fontmap)
                R_Mesh_TexBind(0, fnt->tex);
-       R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1, true);
+       R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false);
 
        ac = color4f;
        at = texcoord2f;
@@ -1698,7 +1700,7 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
                                                        at = texcoord2f;
                                                        av = vertex3f;
                                                }
-                                               R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1, true);
+                                               R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false);
                                                map = ft2_oldstyle_map;
                                        }
                                }
@@ -1767,7 +1769,7 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
                                                        break;
                                                }
                                        }
-                                       R_SetupShader_Generic(map->pic->tex, NULL, GL_MODULATE, 1, true);
+                                       R_SetupShader_Generic(map->pic->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false);
                                }
 
                                mapch = ch - map->start;
@@ -1911,10 +1913,10 @@ void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height
                        width = pic->width;
                if (height == 0)
                        height = pic->height;
-               R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1, true);
+               R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false);
        }
        else
-               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, true);
+               R_SetupShader_Generic_NoTexture((flags & DRAWFLAGS_BLEND) ? false : true, true);
 
        floats[2] = floats[5] = floats[8] = floats[11] = 0;
        floats[0] = floats[9] = x;
@@ -1937,13 +1939,12 @@ void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height
 void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags, qboolean hasalpha)
 {
        _DrawQ_Setup();
-       CHECKGLERROR
        if(!r_draw2d.integer && !r_draw2d_force)
                return;
        DrawQ_ProcessDrawFlag(flags, hasalpha);
 
 //     R_Mesh_ResetTextureState();
-       R_SetupShader_Generic(mesh->texture, NULL, GL_MODULATE, 1, true);
+       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);
@@ -1963,6 +1964,7 @@ void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
        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++)
@@ -1973,6 +1975,7 @@ void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)
                }
                qglEnd();
                CHECKGLERROR
+#endif
                break;
        case RENDERPATH_D3D9:
                //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
@@ -2000,13 +2003,14 @@ void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, f
        if(!r_draw2d.integer && !r_draw2d_force)
                return;
 
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, true);
+       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
@@ -2018,6 +2022,7 @@ void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, f
                qglVertex2f(x2, y2);
                qglEnd();
                CHECKGLERROR
+#endif
                break;
        case RENDERPATH_D3D9:
                //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
@@ -2058,7 +2063,7 @@ void DrawQ_Lines (float width, int numlines, const float *vertex3f, const float
        case RENDERPATH_GL20:
                CHECKGLERROR
 
-               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, true);
+               R_SetupShader_Generic_NoTexture((flags & DRAWFLAGS_BLEND) ? false : true, true);
 
                //qglLineWidth(width);CHECKGLERROR
 
@@ -2163,7 +2168,7 @@ void R_DrawGamma(void)
        }
        // all the blends ignore depth
 //     R_Mesh_ResetTextureState();
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, true);
+       R_SetupShader_Generic_NoTexture(true, true);
        GL_DepthMask(true);
        GL_DepthRange(0, 1);
        GL_PolygonOffset(0, 0);
index 04ad617f91290c8c93cd1e66f980eae39cc20b6b..6c26b8de7040514c4269c65a585f824a9255e8cf 100644 (file)
@@ -50,14 +50,18 @@ static qboolean r_savedds;
 //
 r_refdef_t r_refdef;
 
-cvar_t r_motionblur = {CVAR_SAVE, "r_motionblur", "0", "motionblur value scale - 0.5 recommended"};
-cvar_t r_damageblur = {CVAR_SAVE, "r_damageblur", "0", "motionblur based on damage"};
-cvar_t r_motionblur_vmin = {CVAR_SAVE, "r_motionblur_vmin", "300", "minimum influence from velocity"};
-cvar_t r_motionblur_vmax = {CVAR_SAVE, "r_motionblur_vmax", "600", "maximum influence from velocity"};
-cvar_t r_motionblur_bmin = {CVAR_SAVE, "r_motionblur_bmin", "0.5", "velocity at which there is no blur yet (may be negative to always have some blur)"};
-cvar_t r_motionblur_vcoeff = {CVAR_SAVE, "r_motionblur_vcoeff", "0.05", "sliding average reaction time for velocity"};
-cvar_t r_motionblur_maxblur = {CVAR_SAVE, "r_motionblur_maxblur", "0.88", "cap for motionblur alpha value"};
+cvar_t r_motionblur = {CVAR_SAVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended"};
+cvar_t r_damageblur = {CVAR_SAVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended"};
+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"};
@@ -73,6 +77,8 @@ cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip pla
 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)"};
@@ -95,6 +101,7 @@ cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "
 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"};
 
@@ -122,6 +129,7 @@ cvar_t r_fog_exp2 = {0, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rat
 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", "0", "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"};
 
@@ -141,6 +149,7 @@ cvar_t r_textureunits = {0, "r_textureunits", "32", "number of texture units to
 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"};
@@ -157,6 +166,8 @@ cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_SAVE, "r_glsl_offsetmapping_re
 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)"};
@@ -174,6 +185,8 @@ cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "h
 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"};
@@ -182,22 +195,23 @@ cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll aro
 
 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_hdr = {CVAR_SAVE, "r_hdr", "0", "enables High Dynamic Range bloom effect (higher quality version of r_bloom)"};
 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_range = {CVAR_SAVE, "r_hdr_range", "4", "how much dynamic range to render bloom with (equivalent to multiplying r_bloom_brighten by this value and dividing r_bloom_colorscale by this value)"};
 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 = {CVAR_SAVE, "r_hdr_irisadaptation_fade", "1", "fade rate at which value adjusts"};
+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"};
 
@@ -215,39 +229,11 @@ cvar_t r_glsl_vertextextureblend_usebothalphas = {CVAR_SAVE, "r_glsl_vertextextu
 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)"};
 
 extern cvar_t v_glslgamma;
+extern cvar_t v_glslgamma_2d;
 
 extern qboolean v_flipped_state;
 
-static struct r_bloomstate_s
-{
-       qboolean enabled;
-       qboolean hdr;
-
-       int bloomwidth, bloomheight;
-
-       textype_t texturetype;
-       int viewfbo; // used to check if r_viewfbo cvar has changed
-
-       int fbo_framebuffer; // non-zero if r_viewfbo is enabled and working
-       rtexture_t *texture_framebuffercolor; // non-NULL if fbo_screen is non-zero
-       rtexture_t *texture_framebufferdepth; // non-NULL if fbo_screen is non-zero
-
-       int screentexturewidth, screentextureheight;
-       rtexture_t *texture_screen; /// \note also used for motion blur if enabled!
-
-       int bloomtexturewidth, bloomtextureheight;
-       rtexture_t *texture_bloom;
-
-       // arrays for rendering the screen passes
-       float screentexcoord2f[8];
-       float bloomtexcoord2f[8];
-       float offsettexcoord2f[8];
-
-       r_viewport_t viewport;
-}
-r_bloomstate;
-
-r_waterstate_t r_waterstate;
+r_framebufferstate_t r_fb;
 
 /// shadow volume bsp struct with automatically growing nodes buffer
 svbsp_t r_svbsp;
@@ -365,7 +351,7 @@ static void R_BuildBlankTextures(void)
        data[2] = 128; // normal X
        data[1] = 128; // normal Y
        data[0] = 255; // normal Z
-       data[3] = 128; // height
+       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;
@@ -659,18 +645,19 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
        {"#define USEOFFSETMAPPING\n", " offsetmapping"},
        {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
        {"#define USESHADOWMAP2D\n", " shadowmap2d"},
-       {"#define USESHADOWMAPPCF 1\n", " shadowmappcf"},
-       {"#define USESHADOWMAPPCF 2\n", " shadowmappcf2"},
-       {"#define USESHADOWSAMPLER\n", " shadowsampler"},
-       {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"},
+       {"#define USESHADOWMAPPCF 1\n", " shadowmappcf"}, // TODO make this a static parm
+       {"#define USESHADOWMAPPCF 2\n", " shadowmappcf2"}, // TODO make this a static parm
+       {"#define USESHADOWSAMPLER\n", " shadowsampler"}, // TODO make this a static parm
+       {"#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"},
+       {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
        {"#define USETRIPPY\n", " trippy"},
+       {"#define USEDEPTHRGB\n", " depthrgb"},
 };
 
 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
@@ -678,13 +665,15 @@ shadermodeinfo_t glslshadermodeinfo[SHADERMODE_COUNT] =
 {
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_GENERIC\n", " generic"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_POSTPROCESS\n", " postprocess"},
-       {"glsl/default.glsl", NULL, NULL               , "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
+       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_FLATCOLOR\n", " flatcolor"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTMAP\n", " lightmap"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_FAKELIGHT\n", " fakelight"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
+       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
+       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTSOURCE\n", " lightsource"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_REFRACTION\n", " refraction"},
@@ -705,6 +694,8 @@ shadermodeinfo_t hlslshadermodeinfo[SHADERMODE_COUNT] =
        {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_FAKELIGHT\n", " fakelight"},
        {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
        {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
+       {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
+       {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
        {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
        {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_LIGHTSOURCE\n", " lightsource"},
        {"hlsl/default.hlsl", NULL, "hlsl/default.hlsl", "#define MODE_REFRACTION\n", " refraction"},
@@ -750,7 +741,6 @@ typedef struct r_glsl_permutation_s
        int tex_Texture_Reflection;
        int tex_Texture_ShadowMap2D;
        int tex_Texture_CubeProjection;
-       int tex_Texture_ScreenDepth;
        int tex_Texture_ScreenNormalMap;
        int tex_Texture_ScreenDiffuse;
        int tex_Texture_ScreenSpecular;
@@ -781,7 +771,6 @@ typedef struct r_glsl_permutation_s
        int loc_Texture_Reflection;
        int loc_Texture_ShadowMap2D;
        int loc_Texture_CubeProjection;
-       int loc_Texture_ScreenDepth;
        int loc_Texture_ScreenNormalMap;
        int loc_Texture_ScreenDiffuse;
        int loc_Texture_ScreenSpecular;
@@ -813,6 +802,8 @@ typedef struct r_glsl_permutation_s
        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;
@@ -859,16 +850,17 @@ enum
        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_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
+       SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
 };
-#define SHADERSTATICPARMS_COUNT 7
+#define SHADERSTATICPARMS_COUNT 8
 
 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))
-qboolean R_CompileShader_CheckStaticParms(void)
+static qboolean R_CompileShader_CheckStaticParms(void)
 {
        static int r_compileshader_staticparms_save[1];
        memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
@@ -892,6 +884,8 @@ qboolean R_CompileShader_CheckStaticParms(void)
                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);
        return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
 }
 
@@ -900,7 +894,7 @@ qboolean R_CompileShader_CheckStaticParms(void)
                shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
        else \
                shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
-void R_CompileShader_AddStaticParms(unsigned int mode, unsigned int permutation)
+static void R_CompileShader_AddStaticParms(unsigned int mode, unsigned int permutation)
 {
        shaderstaticparms_count = 0;
 
@@ -912,6 +906,7 @@ void R_CompileShader_AddStaticParms(unsigned int mode, unsigned int permutation)
        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");
 }
 
 /// information about each possible shader permutation
@@ -985,9 +980,9 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
        int vertstrings_count = 0;
        int geomstrings_count = 0;
        int fragstrings_count = 0;
-       const char *vertstrings_list[32+3+SHADERSTATICPARMS_COUNT+1];
-       const char *geomstrings_list[32+3+SHADERSTATICPARMS_COUNT+1];
-       const char *fragstrings_list[32+3+SHADERSTATICPARMS_COUNT+1];
+       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;
@@ -1098,7 +1093,6 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                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_ScreenDepth        = qglGetUniformLocation(p->program, "Texture_ScreenDepth");
                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");
@@ -1130,6 +1124,8 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                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");
@@ -1184,7 +1180,6 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                p->tex_Texture_Reflection = -1;
                p->tex_Texture_ShadowMap2D = -1;
                p->tex_Texture_CubeProjection = -1;
-               p->tex_Texture_ScreenDepth = -1;
                p->tex_Texture_ScreenNormalMap = -1;
                p->tex_Texture_ScreenDiffuse = -1;
                p->tex_Texture_ScreenSpecular = -1;
@@ -1215,7 +1210,6 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                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_ScreenDepth     >= 0) {p->tex_Texture_ScreenDepth      = sampler;qglUniform1i(p->loc_Texture_ScreenDepth     , 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++;}
@@ -1237,7 +1231,7 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode
                Mem_Free(fragmentstring);
 }
 
-void R_SetupShader_SetPermutationGLSL(unsigned int mode, unsigned int permutation)
+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)
@@ -1369,7 +1363,9 @@ typedef enum D3DPSREGISTER_e
        D3DPSREGISTER_ViewToLight = 44, // float4x4
        D3DPSREGISTER_ModelToReflectCube = 48, // float4x4
        D3DPSREGISTER_NormalmapScrollBlend = 52,
-       // next at 53
+       D3DPSREGISTER_OffsetMapping_LodDistance = 53,
+       D3DPSREGISTER_OffsetMapping_Bias = 54,
+       // next at 54
 }
 D3DPSREGISTER_t;
 
@@ -1456,13 +1452,14 @@ static void R_HLSL_CacheShader(r_hlsl_permutation_t *p, const char *cachename, c
        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("%s.vsbin", cachename), r_main_mempool, true, &vsbinsize);
-               psbin = (DWORD *)FS_LoadFile(va("%s.psbin", cachename), r_main_mempool, true, &psbinsize);
+               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))
        {
@@ -1513,9 +1510,9 @@ static void R_HLSL_CacheShader(r_hlsl_permutation_t *p, const char *cachename, c
                                if (debugshader)
                                {
 //                                     vsresult = qD3DXPreprocessShader(vertstring, strlen(vertstring), NULL, NULL, &vsbuffer, &vslog);
-//                                     FS_WriteFile(va("%s_vs.fx", cachename), vsbuffer->GetBufferPointer(), vsbuffer->GetBufferSize());
-                                       FS_WriteFile(va("%s_vs.fx", cachename), vertstring, strlen(vertstring));
-                                       vsresult = qD3DXCompileShaderFromFileA(va("%s/%s_vs.fx", fs_gamedir, cachename), NULL, NULL, "main", vsversion, shaderflags, &vsbuffer, &vslog, &vsconstanttable);
+//                                     FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_vs.fx", cachename), vsbuffer->GetBufferPointer(), vsbuffer->GetBufferSize());
+                                       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);
@@ -1529,7 +1526,7 @@ static void R_HLSL_CacheShader(r_hlsl_permutation_t *p, const char *cachename, c
                                if (vslog)
                                {
                                        strlcpy(temp, (const char *)vslog->GetBufferPointer(), min(sizeof(temp), vslog->GetBufferSize()));
-                                       Con_Printf("HLSL vertex shader compile output for %s follows:\n%s\n", cachename, temp);
+                                       Con_DPrintf("HLSL vertex shader compile output for %s follows:\n%s\n", cachename, temp);
                                        vslog->Release();
                                }
                        }
@@ -1538,9 +1535,9 @@ static void R_HLSL_CacheShader(r_hlsl_permutation_t *p, const char *cachename, c
                                if (debugshader)
                                {
 //                                     psresult = qD3DXPreprocessShader(fragstring, strlen(fragstring), NULL, NULL, &psbuffer, &pslog);
-//                                     FS_WriteFile(va("%s_ps.fx", cachename), psbuffer->GetBufferPointer(), psbuffer->GetBufferSize());
-                                       FS_WriteFile(va("%s_ps.fx", cachename), fragstring, strlen(fragstring));
-                                       psresult = qD3DXCompileShaderFromFileA(va("%s/%s_ps.fx", fs_gamedir, cachename), NULL, NULL, "main", psversion, shaderflags, &psbuffer, &pslog, &psconstanttable);
+//                                     FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_ps.fx", cachename), psbuffer->GetBufferPointer(), psbuffer->GetBufferSize());
+                                       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);
@@ -1554,23 +1551,23 @@ static void R_HLSL_CacheShader(r_hlsl_permutation_t *p, const char *cachename, c
                                if (pslog)
                                {
                                        strlcpy(temp, (const char *)pslog->GetBufferPointer(), min(sizeof(temp), pslog->GetBufferSize()));
-                                       Con_Printf("HLSL pixel shader compile output for %s follows:\n%s\n", cachename, temp);
+                                       Con_DPrintf("HLSL pixel shader compile output for %s follows:\n%s\n", cachename, temp);
                                        pslog->Release();
                                }
                        }
                        Sys_UnloadLibrary(&d3dx9_dll);
                }
                else
-                       Con_Printf("Unable to compile shader - D3DXCompileShader function not found\n");
+                       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_Printf("HLSL CreateVertexShader failed for %s (hresult = %8x)\n", cachename, 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_Printf("HLSL CreatePixelShader failed for %s (hresult = %8x)\n", cachename, psresult);
+                       Con_DPrintf("HLSL CreatePixelShader failed for %s (hresult = %8x)\n", cachename, psresult);
        }
        // free the shader data
        vsbin = (DWORD *)Mem_Realloc(tempmempool, vsbin, 0);
@@ -1592,9 +1589,9 @@ static void R_HLSL_CompilePermutation(r_hlsl_permutation_t *p, unsigned int mode
        int vertstrings_count = 0;
        int geomstrings_count = 0;
        int fragstrings_count = 0;
-       const char *vertstrings_list[32+3+SHADERSTATICPARMS_COUNT+1];
-       const char *geomstrings_list[32+3+SHADERSTATICPARMS_COUNT+1];
-       const char *fragstrings_list[32+3+SHADERSTATICPARMS_COUNT+1];
+       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;
@@ -1781,7 +1778,7 @@ void R_SetupShader_SetPermutationHLSL(unsigned int mode, unsigned int permutatio
 }
 #endif
 
-void R_SetupShader_SetPermutationSoft(unsigned int mode, unsigned int permutation)
+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);
@@ -1789,7 +1786,7 @@ void R_SetupShader_SetPermutationSoft(unsigned int mode, unsigned int permutatio
        DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_ClientTime, cl.time);
 }
 
-void R_GLSL_Restart_f(void)
+static void R_GLSL_Restart_f(void)
 {
        unsigned int i, limit;
        if (glslshaderstring && glslshaderstring != builtinshaderstring)
@@ -1853,7 +1850,7 @@ void R_GLSL_Restart_f(void)
        }
 }
 
-void R_GLSL_DumpShader_f(void)
+static void R_GLSL_DumpShader_f(void)
 {
        int i;
        qfile_t *file;
@@ -1893,7 +1890,7 @@ void R_GLSL_DumpShader_f(void)
                Con_Printf("failed to write to hlsl/default.hlsl\n");
 }
 
-void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale, qboolean notrippy)
+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)
@@ -1909,6 +1906,10 @@ void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemod
                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)
@@ -1920,6 +1921,8 @@ void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemod
                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:
@@ -1933,6 +1936,8 @@ void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemod
                R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
                R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , first );
                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:
@@ -1953,11 +1958,18 @@ void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemod
        }
 }
 
-void R_SetupShader_DepthOrShadow(qboolean notrippy)
+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)
 {
        unsigned int permutation = 0;
        if (r_trippy.integer && !notrippy)
                permutation |= SHADERPERMUTATION_TRIPPY;
+       if (depthrgb)
+               permutation |= SHADERPERMUTATION_DEPTHRGB;
        if (vid.allowalphatocoverage)
                GL_AlphaToCoverage(false);
        switch (vid.renderpath)
@@ -1996,8 +2008,6 @@ void R_SetupShader_ShowDepth(qboolean notrippy)
        int permutation = 0;
        if (r_trippy.integer && !notrippy)
                permutation |= SHADERPERMUTATION_TRIPPY;
-       if (r_trippy.integer)
-               permutation |= SHADERPERMUTATION_TRIPPY;
        if (vid.allowalphatocoverage)
                GL_AlphaToCoverage(false);
        switch (vid.renderpath)
@@ -2029,7 +2039,6 @@ void R_SetupShader_ShowDepth(qboolean notrippy)
 }
 
 extern qboolean r_shadow_usingdeferredprepass;
-extern cvar_t r_shadow_deferred_8bitrange;
 extern rtexture_t *r_shadow_attenuationgradienttexture;
 extern rtexture_t *r_shadow_attenuation2dtexture;
 extern rtexture_t *r_shadow_attenuation3dtexture;
@@ -2040,16 +2049,15 @@ extern float r_shadow_shadowmap_parameters[4];
 extern qboolean r_shadow_shadowmapvsdct;
 extern qboolean r_shadow_shadowmapsampler;
 extern int r_shadow_shadowmappcf;
-extern rtexture_t *r_shadow_shadowmap2dtexture;
-extern rtexture_t *r_shadow_shadowmap2dcolortexture;
+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_prepassgeometrydepthtexture;
+extern rtexture_t *r_shadow_prepassgeometrydepthbuffer;
 extern rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
-extern rtexture_t *r_shadow_prepassgeometrydepthcolortexture;
 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
 
@@ -2156,7 +2164,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        }
        else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
        {
-               if (r_glsl_offsetmapping.integer)
+               if (r_glsl_offsetmapping.integer && ((R_TextureFlags(rsurface.texture->nmaptexture) & TEXF_ALPHA) || rsurface.texture->offsetbias != 0.0f))
                {
                        switch(rsurface.texture->offsetmapping)
                        {
@@ -2177,7 +2185,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        }
        else if (rsurfacepass == RSURFPASS_RTLIGHT)
        {
-               if (r_glsl_offsetmapping.integer)
+               if (r_glsl_offsetmapping.integer && ((R_TextureFlags(rsurface.texture->nmaptexture) & TEXF_ALPHA) || rsurface.texture->offsetbias != 0.0f))
                {
                        switch(rsurface.texture->offsetmapping)
                        {
@@ -2213,6 +2221,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
                        else if (r_shadow_shadowmappcf)
                                permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
+                       if (r_shadow_shadowmap2ddepthbuffer)
+                               permutation |= SHADERPERMUTATION_DEPTHRGB;
                }
                if (rsurface.texture->reflectmasktexture)
                        permutation |= SHADERPERMUTATION_REFLECTCUBE;
@@ -2223,7 +2233,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        }
        else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
        {
-               if (r_glsl_offsetmapping.integer)
+               if (r_glsl_offsetmapping.integer && ((R_TextureFlags(rsurface.texture->nmaptexture) & TEXF_ALPHA) || rsurface.texture->offsetbias != 0.0f))
                {
                        switch(rsurface.texture->offsetmapping)
                        {
@@ -2255,6 +2265,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
                        else if (r_shadow_shadowmappcf)
                                permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
+                       if (r_shadow_shadowmap2ddepthbuffer)
+                               permutation |= SHADERPERMUTATION_DEPTHRGB;
                }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
@@ -2276,7 +2288,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        }
        else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT_DIRECTIONAL)
        {
-               if (r_glsl_offsetmapping.integer)
+               if (r_glsl_offsetmapping.integer && ((R_TextureFlags(rsurface.texture->nmaptexture) & TEXF_ALPHA) || rsurface.texture->offsetbias != 0.0f))
                {
                        switch(rsurface.texture->offsetmapping)
                        {
@@ -2310,6 +2322,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
                        else if (r_shadow_shadowmappcf)
                                permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
+                       if (r_shadow_shadowmap2ddepthbuffer)
+                               permutation |= SHADERPERMUTATION_DEPTHRGB;
                }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
@@ -2317,7 +2331,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
                if (rsurface.texture->reflectmasktexture)
                        permutation |= SHADERPERMUTATION_REFLECTCUBE;
-               if (r_shadow_bouncegridtexture)
+               if (r_shadow_bouncegridtexture && cl.csqc_vidvars.drawworld)
                {
                        permutation |= SHADERPERMUTATION_BOUNCEGRID;
                        if (r_shadow_bouncegriddirectional)
@@ -2339,7 +2353,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        }
        else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
        {
-               if (r_glsl_offsetmapping.integer)
+               if (r_glsl_offsetmapping.integer && ((R_TextureFlags(rsurface.texture->nmaptexture) & TEXF_ALPHA) || rsurface.texture->offsetbias != 0.0f))
                {
                        switch(rsurface.texture->offsetmapping)
                        {
@@ -2370,6 +2384,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
                        else if (r_shadow_shadowmappcf)
                                permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
+                       if (r_shadow_shadowmap2ddepthbuffer)
+                               permutation |= SHADERPERMUTATION_DEPTHRGB;
                }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
@@ -2377,7 +2393,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
                if (rsurface.texture->reflectmasktexture)
                        permutation |= SHADERPERMUTATION_REFLECTCUBE;
-               if (r_shadow_bouncegridtexture)
+               if (r_shadow_bouncegridtexture && cl.csqc_vidvars.drawworld)
                {
                        permutation |= SHADERPERMUTATION_BOUNCEGRID;
                        if (r_shadow_bouncegriddirectional)
@@ -2399,7 +2415,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        }
        else
        {
-               if (r_glsl_offsetmapping.integer)
+               if (r_glsl_offsetmapping.integer && ((R_TextureFlags(rsurface.texture->nmaptexture) & TEXF_ALPHA) || rsurface.texture->offsetbias != 0.0f))
                {
                        switch(rsurface.texture->offsetmapping)
                        {
@@ -2429,6 +2445,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
                        else if (r_shadow_shadowmappcf)
                                permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
+                       if (r_shadow_shadowmap2ddepthbuffer)
+                               permutation |= SHADERPERMUTATION_DEPTHRGB;
                }
                if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
                        permutation |= SHADERPERMUTATION_REFLECTION;
@@ -2455,10 +2473,13 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        if (specularscale > 0)
                                permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
                }
-               else if (r_glsl_deluxemapping.integer >= 2 && rsurface.uselightmaptexture)
+               else if (r_glsl_deluxemapping.integer >= 2)
                {
                        // fake deluxemapping (uniform light direction in tangentspace)
-                       mode = SHADERMODE_LIGHTDIRECTIONMAP_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;
@@ -2473,7 +2494,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        // ordinary vertex coloring (q3bsp)
                        mode = SHADERMODE_VERTEXCOLOR;
                }
-               if (r_shadow_bouncegridtexture)
+               if (r_shadow_bouncegridtexture && cl.csqc_vidvars.drawworld)
                {
                        permutation |= SHADERPERMUTATION_BOUNCEGRID;
                        if (r_shadow_bouncegriddirectional)
@@ -2535,7 +2556,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
 
                        // 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));
+                       hlslPSSetParameter1f(D3DPSREGISTER_SpecularPower, rsurface.texture->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
                }
                else
                {
@@ -2548,8 +2569,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                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] * r_shadow_deferred_8bitrange.value, colormod[1] * r_shadow_deferred_8bitrange.value, colormod[2] * r_shadow_deferred_8bitrange.value);
-                               hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Specular, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value);
+                               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]);
                        }
@@ -2558,8 +2579,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                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 * r_shadow_deferred_8bitrange.value, colormod[1] * diffusescale * r_shadow_deferred_8bitrange.value, colormod[2] * diffusescale * r_shadow_deferred_8bitrange.value);
-                               hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Specular, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value);
+                               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)
@@ -2567,20 +2588,20 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        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_waterstate.screenscale[0], r_waterstate.screenscale[1], r_waterstate.screenscale[0], r_waterstate.screenscale[1]);
-                       hlslPSSetParameter4f(D3DPSREGISTER_ScreenCenterRefractReflect, r_waterstate.screencenter[0], r_waterstate.screencenter[1], r_waterstate.screencenter[0], r_waterstate.screencenter[1]);
+                       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 * (r_shadow_glossexact.integer ? 0.25f : 1.0f));
+                       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_waterstate.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1));
+               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]);
@@ -2600,6 +2621,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                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);
+               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);
 
@@ -2630,13 +2653,12 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                {
                        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_SCREENDEPTH       , r_shadow_prepassgeometrydepthtexture                );
 //             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_shadowmap2dcolortexture);
+                       R_Mesh_TexBind(GL20TU_SHADOWMAP2D, r_shadow_shadowmap2ddepthtexture);
                        if (rsurface.rtlight)
                        {
                                if (permutation & SHADERPERMUTATION_CUBEFILTER        ) R_Mesh_TexBind(GL20TU_CUBE              , rsurface.rtlight->currentcubemap                    );
@@ -2683,7 +2705,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        // 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));
+                       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
                {
@@ -2696,8 +2718,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                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] * r_shadow_deferred_8bitrange.value, colormod[1] * r_shadow_deferred_8bitrange.value, colormod[2] * r_shadow_deferred_8bitrange.value);
-                               if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value);
+                               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]);
                        }
@@ -2706,8 +2728,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                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 * r_shadow_deferred_8bitrange.value, colormod[1] * diffusescale * r_shadow_deferred_8bitrange.value, colormod[2] * diffusescale * r_shadow_deferred_8bitrange.value);
-                               if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value);
+                               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)
@@ -2718,13 +2740,13 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                        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_waterstate.screenscale[0], r_waterstate.screenscale[1], r_waterstate.screenscale[0], r_waterstate.screenscale[1]);
-                       if (r_glsl_permutation->loc_ScreenCenterRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenCenterRefractReflect, r_waterstate.screencenter[0], r_waterstate.screencenter[1], r_waterstate.screencenter[0], r_waterstate.screencenter[1]);
+                       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));
+                       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);}
@@ -2734,7 +2756,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                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_waterstate.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1));
+               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)
                {
@@ -2760,6 +2782,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                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);
+               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);}
@@ -2795,13 +2819,12 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                {
                        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_ScreenDepth     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDepth       , r_shadow_prepassgeometrydepthtexture                );
                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_shadowmap2dtexture                         );
+                       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                    );
@@ -2831,7 +2854,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        
                        // 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));
+                       DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_SpecularPower, rsurface.texture->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
                }
                else
                {
@@ -2844,8 +2867,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                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] * r_shadow_deferred_8bitrange.value, colormod[1] * r_shadow_deferred_8bitrange.value, colormod[2] * r_shadow_deferred_8bitrange.value);
-                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Specular, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value);
+                               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]);
                        }
@@ -2854,8 +2877,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                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 * r_shadow_deferred_8bitrange.value, colormod[1] * diffusescale * r_shadow_deferred_8bitrange.value, colormod[2] * diffusescale * r_shadow_deferred_8bitrange.value);
-                               DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Specular, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value, specularscale * r_shadow_deferred_8bitrange.value);
+                               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)
@@ -2863,13 +2886,13 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        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_waterstate.screenscale[0], r_waterstate.screenscale[1], r_waterstate.screenscale[0], r_waterstate.screenscale[1]);
-                       DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ScreenCenterRefractReflect, r_waterstate.screencenter[0], r_waterstate.screencenter[1], r_waterstate.screencenter[0], r_waterstate.screencenter[1]);
+                       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));
+                       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);}
@@ -2879,7 +2902,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                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_waterstate.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1));
+               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)
                {
@@ -2905,6 +2928,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                                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);
+               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);
 
@@ -2935,13 +2960,12 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                {
                        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_SCREENDEPTH       , r_shadow_prepassgeometrydepthtexture                );
 //             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_shadowmap2dcolortexture);
+                       R_Mesh_TexBind(GL20TU_SHADOWMAP2D, r_shadow_shadowmap2ddepthtexture);
                        if (rsurface.rtlight)
                        {
                                if (permutation & SHADERPERMUTATION_CUBEFILTER        ) R_Mesh_TexBind(GL20TU_CUBE              , rsurface.rtlight->currentcubemap                    );
@@ -2970,7 +2994,6 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
        matrix4x4_t viewtolight;
        matrix4x4_t lighttoview;
        float viewtolight16f[16];
-       float range = 1.0f / r_shadow_deferred_8bitrange.value;
        // light source
        mode = SHADERMODE_DEFERREDLIGHTSOURCE;
        if (rtlight->currentcubemap != r_texture_whitecube)
@@ -2991,6 +3014,8 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
                        permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
                else if (r_shadow_shadowmappcf)
                        permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
+               if (r_shadow_shadowmap2ddepthbuffer)
+                       permutation |= SHADERPERMUTATION_DEPTHRGB;
        }
        if (vid.allowalphatocoverage)
                GL_AlphaToCoverage(false);
@@ -3005,20 +3030,19 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
                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  * range, lightcolorbase[1] * ambientscale  * range, lightcolorbase[2] * ambientscale  * range);
-               hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale  * range, lightcolorbase[1] * diffusescale  * range, lightcolorbase[2] * diffusescale  * range);
-               hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Specular, lightcolorbase[0] * specularscale * range, lightcolorbase[1] * specularscale * range, lightcolorbase[2] * specularscale * range);
+               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));
+               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_SCREENDEPTH        , r_shadow_prepassgeometrydepthcolortexture           );
                R_Mesh_TexBind(GL20TU_SCREENNORMALMAP    , r_shadow_prepassgeometrynormalmaptexture            );
                R_Mesh_TexBind(GL20TU_CUBE               , rsurface.rtlight->currentcubemap                    );
-               R_Mesh_TexBind(GL20TU_SHADOWMAP2D        , r_shadow_shadowmap2dcolortexture                    );
+               R_Mesh_TexBind(GL20TU_SHADOWMAP2D        , r_shadow_shadowmap2ddepthtexture                    );
                R_Mesh_TexBind(GL20TU_CUBEPROJECTION     , r_shadow_shadowmapvsdcttexture                      );
 #endif
                break;
@@ -3033,20 +3057,19 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
                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  * range, lightcolorbase[1] * ambientscale  * range, lightcolorbase[2] * ambientscale  * range);
-               if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale  * range, lightcolorbase[1] * diffusescale  * range, lightcolorbase[2] * diffusescale  * range);
-               if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale * range, lightcolorbase[1] * specularscale * range, lightcolorbase[2] * specularscale * range);
+               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));
+               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_ScreenDepth       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDepth        , r_shadow_prepassgeometrydepthtexture                );
                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_shadowmap2dtexture                         );
+               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:
@@ -3057,20 +3080,19 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
                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  * range, lightcolorbase[1] * ambientscale  * range, lightcolorbase[2] * ambientscale  * range);
-               DPSOFTRAST_Uniform3f(       DPSOFTRAST_UNIFORM_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale  * range, lightcolorbase[1] * diffusescale  * range, lightcolorbase[2] * diffusescale  * range);
-               DPSOFTRAST_Uniform3f(       DPSOFTRAST_UNIFORM_DeferredColor_Specular   , lightcolorbase[0] * specularscale * range, lightcolorbase[1] * specularscale * range, lightcolorbase[2] * specularscale * range);
+               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));
+               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_SCREENDEPTH        , r_shadow_prepassgeometrydepthtexture                );
                R_Mesh_TexBind(GL20TU_SCREENNORMALMAP    , r_shadow_prepassgeometrynormalmaptexture            );
                R_Mesh_TexBind(GL20TU_CUBE               , rsurface.rtlight->currentcubemap                    );
-               R_Mesh_TexBind(GL20TU_SHADOWMAP2D        , r_shadow_shadowmap2dtexture                         );
+               R_Mesh_TexBind(GL20TU_SHADOWMAP2D        , r_shadow_shadowmap2ddepthtexture                    );
                R_Mesh_TexBind(GL20TU_CUBEPROJECTION     , r_shadow_shadowmapvsdcttexture                      );
                break;
        }
@@ -3165,7 +3187,7 @@ skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewid
 
        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) && item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc)
+               if (!strcmp(item->basename, basename) && (comparecrc < 0 || (item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc)))
                        break;
 
        if (!item) {
@@ -3178,13 +3200,35 @@ skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewid
                memset(item, 0, sizeof(*item));
                strlcpy(item->basename, basename, sizeof(item->basename));
                item->base = dyntexture; // either NULL or dyntexture handle
-               item->textureflags = textureflags;
+               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;
@@ -3250,6 +3294,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        int miplevel = R_PicmipForFlags(textureflags);
        int savemiplevel = miplevel;
        int mymiplevel;
+       char vabuf[1024];
 
        if (cls.state == ca_dedicated)
                return NULL;
@@ -3264,7 +3309,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        Image_StripImageExtension(name, basename, sizeof(basename));
 
        // check for DDS texture file first
-       if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s.dds", basename), textureflags, &ddshasalpha, ddsavgcolor, miplevel)))
+       if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel)))
        {
                basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
                if (basepixels == NULL)
@@ -3279,6 +3324,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        // 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;
@@ -3297,7 +3343,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
                skinframe->hasalpha = ddshasalpha;
                VectorCopy(ddsavgcolor, skinframe->avgcolor);
                if (r_loadfog && skinframe->hasalpha)
-                       skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_mask.dds", skinframe->basename), textureflags | TEXF_ALPHA, NULL, NULL, miplevel);
+                       skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), false, textureflags | TEXF_ALPHA, NULL, NULL, miplevel);
                //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
@@ -3326,46 +3372,48 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
                                        pixels[j+2] = 255;
                                        pixels[j+3] = basepixels[j+3];
                                }
-                               skinframe->fog = R_LoadTexture2D (r_main_texturepool, va("%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
+                               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("dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
+                       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("dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
+                       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("dds/%s_norm.dds", skinframe->basename), (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), NULL, NULL, mymiplevel);
-               skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_glow.dds", skinframe->basename), textureflags, NULL, NULL, mymiplevel);
+                       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);
+               skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel);
                if (r_loadgloss)
-                       skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_gloss.dds", skinframe->basename), textureflags, NULL, NULL, mymiplevel);
-               skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_pants.dds", skinframe->basename), textureflags, NULL, NULL, mymiplevel);
-               skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_shirt.dds", skinframe->basename), textureflags, NULL, NULL, mymiplevel);
-               skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va("dds/%s_reflect.dds", skinframe->basename), textureflags, NULL, NULL, mymiplevel);
+                       skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel);
+               skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel);
+               skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel);
+               skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel);
        }
 
        // _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("%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
+               if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
                {
-                       skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%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);
+                       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("%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != 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("%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);
+                       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);
                }
@@ -3373,60 +3421,72 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
                {
                        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("%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);
+                       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("dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
+                       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("%s_glow",  skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va("%s_luma", skinframe->basename), false, false, false, &mymiplevel))))
+       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("%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);
+               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("dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
+                       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("%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
+       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("%s_gloss", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_gloss.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
+               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("dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
+                       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("%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
+       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("%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);
+               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("dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
+                       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("%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
+       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("%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);
+               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("dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
+                       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("%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
+       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("%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);
+               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("dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
+                       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;
        }
@@ -3443,14 +3503,16 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co
        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, skindata ? CRC_Block(skindata, width*height*4) : 0, true);
+       skinframe = R_SkinFrame_Find(name, textureflags, width, height, (textureflags & TEXF_FORCE_RELOAD) ? -1 : skindata ? CRC_Block(skindata, width*height*4) : 0, true);
        if (skinframe && skinframe->base)
                return skinframe;
+       textureflags &= ~TEXF_FORCE_RELOAD;
 
        skinframe->stain = NULL;
        skinframe->merged = NULL;
@@ -3476,7 +3538,7 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co
                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("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
+               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);
@@ -3496,7 +3558,7 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co
                        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("%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
+                       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);
                }
        }
@@ -3520,6 +3582,7 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i
        skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
        if (skinframe && skinframe->base)
                return skinframe;
+       textureflags &= ~TEXF_FORCE_RELOAD;
 
        skinframe->stain = NULL;
        skinframe->merged = NULL;
@@ -3568,6 +3631,7 @@ static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboo
        int width;
        int height;
        unsigned char *skindata;
+       char vabuf[1024];
 
        if (!skinframe->qpixels)
                return;
@@ -3599,22 +3663,22 @@ static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboo
                // 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("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, (skinframe->textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
+               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("%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow
+               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("%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("%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("%s_shirt", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_shirtaswhite);
+               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
        {
@@ -3633,6 +3697,7 @@ skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, co
 {
        int i;
        skinframe_t *skinframe;
+       char vabuf[1024];
 
        if (cls.state == ca_dedicated)
                return NULL;
@@ -3641,6 +3706,7 @@ skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, co
        skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
        if (skinframe && skinframe->base)
                return skinframe;
+       textureflags &= ~TEXF_FORCE_RELOAD;
 
        skinframe->stain = NULL;
        skinframe->merged = NULL;
@@ -3673,7 +3739,7 @@ skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, co
                        }
                }
                if (r_loadfog && skinframe->hasalpha)
-                       skinframe->fog = R_LoadTexture2D(r_main_texturepool, va("%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
+                       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]);
@@ -3747,7 +3813,7 @@ static suffixinfo_t suffix[3][6] =
 
 static int componentorder[4] = {0, 1, 2, 3};
 
-rtexture_t *R_LoadCubemap(const char *basename)
+static rtexture_t *R_LoadCubemap(const char *basename)
 {
        int i, j, cubemapsize;
        unsigned char *cubemappixels, *image_buffer;
@@ -3829,44 +3895,7 @@ rtexture_t *R_GetCubemap(const char *basename)
        return r_texture_cubemaps[i]->texture;
 }
 
-void R_FreeCubemap(const char *basename)
-{
-       int i;
-
-       for (i = 0;i < r_texture_numcubemaps;i++)
-       {
-               if (r_texture_cubemaps[i] != NULL)
-               {
-                       if (r_texture_cubemaps[i]->texture)
-                       {
-                               if (developer_loading.integer)
-                                       Con_DPrintf("unloading cubemap \"%s\"\n", r_texture_cubemaps[i]->basename);
-                               R_FreeTexture(r_texture_cubemaps[i]->texture);
-                               Mem_Free(r_texture_cubemaps[i]);
-                               r_texture_cubemaps[i] = NULL;
-                       }
-               }
-       }
-}
-
-void R_FreeCubemaps(void)
-{
-       int i;
-       for (i = 0;i < r_texture_numcubemaps;i++)
-       {
-               if (developer_loading.integer)
-                       Con_DPrintf("unloading cubemap \"%s\"\n", r_texture_cubemaps[i]->basename);
-               if (r_texture_cubemaps[i] != NULL)
-               {
-                       if (r_texture_cubemaps[i]->texture)
-                               R_FreeTexture(r_texture_cubemaps[i]->texture);
-                       Mem_Free(r_texture_cubemaps[i]);
-               }
-       }
-       r_texture_numcubemaps = 0;
-}
-
-void R_Main_FreeViewCache(void)
+static void R_Main_FreeViewCache(void)
 {
        if (r_refdef.viewcache.entityvisible)
                Mem_Free(r_refdef.viewcache.entityvisible);
@@ -3879,7 +3908,7 @@ void R_Main_FreeViewCache(void)
        memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
 }
 
-void R_Main_ResizeViewCache(void)
+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;
@@ -3918,7 +3947,7 @@ void R_Main_ResizeViewCache(void)
 }
 
 extern rtexture_t *loadingscreentexture;
-void gl_main_start(void)
+static void gl_main_start(void)
 {
        loadingscreentexture = NULL;
        r_texture_blanknormalmap = NULL;
@@ -3999,8 +4028,7 @@ void gl_main_start(void)
        r_texture_fogheighttexture = NULL;
        r_texture_gammaramps = NULL;
        //r_texture_fogintensity = NULL;
-       memset(&r_bloomstate, 0, sizeof(r_bloomstate));
-       memset(&r_waterstate, 0, sizeof(r_waterstate));
+       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);
@@ -4019,7 +4047,7 @@ void gl_main_start(void)
        r_refdef.fogmasktable_density = 0;
 }
 
-void gl_main_shutdown(void)
+static void gl_main_shutdown(void)
 {
        R_AnimCache_Free();
        R_FrameData_Reset();
@@ -4033,8 +4061,10 @@ void gl_main_shutdown(void)
        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__);
@@ -4076,8 +4106,7 @@ void gl_main_shutdown(void)
        r_texture_gammaramps = NULL;
        r_texture_numcubemaps = 0;
        //r_texture_fogintensity = NULL;
-       memset(&r_bloomstate, 0, sizeof(r_bloomstate));
-       memset(&r_waterstate, 0, sizeof(r_waterstate));
+       memset(&r_fb, 0, sizeof(r_fb));
        R_GLSL_Restart_f();
 
        r_glsl_permutation = NULL;
@@ -4092,8 +4121,7 @@ void gl_main_shutdown(void)
        hlslshaderstring = NULL;
 }
 
-extern void CL_ParseEntityLump(char *entitystring);
-void gl_main_newmap(void)
+static void gl_main_newmap(void)
 {
        // FIXME: move this code to client
        char *entities, entname[MAX_QPATH];
@@ -4137,13 +4165,17 @@ void GL_Main_Init(void)
                Cvar_RegisterVariable (&gl_skyclip);
        }
        Cvar_RegisterVariable(&r_motionblur);
-       Cvar_RegisterVariable(&r_motionblur_maxblur);
-       Cvar_RegisterVariable(&r_motionblur_bmin);
-       Cvar_RegisterVariable(&r_motionblur_vmin);
-       Cvar_RegisterVariable(&r_motionblur_vmax);
-       Cvar_RegisterVariable(&r_motionblur_vcoeff);
-       Cvar_RegisterVariable(&r_motionblur_randomize);
        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);
@@ -4156,6 +4188,8 @@ void GL_Main_Init(void)
        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);
@@ -4176,6 +4210,7 @@ void GL_Main_Init(void)
        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);
@@ -4202,12 +4237,14 @@ void GL_Main_Init(void)
        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);
@@ -4224,6 +4261,8 @@ void GL_Main_Init(void)
        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);
@@ -4241,6 +4280,8 @@ void GL_Main_Init(void)
        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);
@@ -4253,16 +4294,16 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_bloom_resolution);
        Cvar_RegisterVariable(&r_bloom_colorexponent);
        Cvar_RegisterVariable(&r_bloom_colorsubtract);
-       Cvar_RegisterVariable(&r_hdr);
        Cvar_RegisterVariable(&r_hdr_scenebrightness);
        Cvar_RegisterVariable(&r_hdr_glowintensity);
-       Cvar_RegisterVariable(&r_hdr_range);
        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);
+       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);
@@ -4276,20 +4317,6 @@ void GL_Main_Init(void)
        R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
 }
 
-extern void R_Textures_Init(void);
-extern void GL_Draw_Init(void);
-extern void GL_Main_Init(void);
-extern void R_Shadow_Init(void);
-extern void R_Sky_Init(void);
-extern void GL_Surf_Init(void);
-extern void R_Particles_Init(void);
-extern void R_Explosion_Init(void);
-extern void gl_backend_init(void);
-extern void Sbar_Init(void);
-extern void R_LightningBeams_Init(void);
-extern void Mod_RenderInit(void);
-extern void Font_Init(void);
-
 void Render_Init(void)
 {
        gl_backend_init();
@@ -4312,6 +4339,7 @@ void Render_Init(void)
 GL_Init
 ===============
 */
+#ifndef USE_GLES2
 extern char *ENGINE_EXTENSIONS;
 void GL_Init (void)
 {
@@ -4339,6 +4367,7 @@ void GL_Init (void)
        // 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)
 {
@@ -4468,7 +4497,7 @@ void R_FrameData_Reset(void)
        }
 }
 
-void R_FrameData_Resize(void)
+static void R_FrameData_Resize(void)
 {
        size_t wantedsize;
        wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
@@ -4582,7 +4611,7 @@ void R_AnimCache_ClearCache(void)
        }
 }
 
-void R_AnimCache_UpdateEntityMeshBuffers(entity_render_t *ent, int numvertices)
+static void R_AnimCache_UpdateEntityMeshBuffers(entity_render_t *ent, int numvertices)
 {
        int i;
 
@@ -4711,12 +4740,12 @@ static void R_View_UpdateEntityLighting (void)
        {
                ent = r_refdef.scene.entities[i];
 
-               // skip unseen models
-               if (!r_refdef.viewcache.entityvisible[i] && skipunseen)
+               // skip unseen models and models that updated by CSQC
+               if ((!r_refdef.viewcache.entityvisible[i] && skipunseen) || ent->flags & RENDER_CUSTOMIZEDMODELLIGHT)
                        continue;
 
                // skip bsp models
-               if (ent->model && ent->model->brush.num_leafs)
+               if (ent->model && (ent->model == cl.worldmodel || ent->model->brush.parentmodel == cl.worldmodel))
                {
                        // TODO: use modellight for r_ambient settings on world?
                        VectorSet(ent->modellight_ambient, 0, 0, 0);
@@ -4852,8 +4881,8 @@ static void R_View_UpdateEntityVisible (void)
        entity_render_t *ent;
 
        renderimask = r_refdef.envmap                                    ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL)
-               : r_waterstate.renderingrefraction                       ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL)
-               : (chase_active.integer || r_waterstate.renderingscene)  ? 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;
@@ -4868,7 +4897,7 @@ static void R_View_UpdateEntityVisible (void)
                        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_VIEWMODEL)) || r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, ent->mins, ent->maxs))
+                       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;
                }
        }
@@ -4889,7 +4918,7 @@ static void R_View_UpdateEntityVisible (void)
                        if (!r_refdef.viewcache.entityvisible[i])
                                continue;
                        ent = r_refdef.scene.entities[i];
-                       if(!(ent->flags & (RENDER_VIEWMODEL | RENDER_NOCULL | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
+                       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)
@@ -4904,7 +4933,7 @@ static void R_View_UpdateEntityVisible (void)
 }
 
 /// only used if skyrendermasked, and normally returns false
-int R_DrawBrushModelsSky (void)
+static int R_DrawBrushModelsSky (void)
 {
        int i, sky;
        entity_render_t *ent;
@@ -4998,28 +5027,43 @@ static void R_DrawModelsAddWaterPlanes(void)
        }
 }
 
+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;
-               vec_t brightness;
+               vec3_t forward;
+               vec_t brightness = 0.0f;
                vec_t goal;
-               vec_t adjust;
                vec_t current;
-               R_CompleteLightPoint(ambient, diffuse, diffusenormal, point, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT);
-               brightness = (ambient[0] + ambient[1] + ambient[2] + diffuse[0] + diffuse[1] + diffuse[2]) * (1.0f / 3.0f);
-               brightness = max(0.0000001f, brightness);
+               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);
-               adjust = r_hdr_irisadaptation_fade.value * cl.realframetime;
                current = r_hdr_irisadaptation_value.value;
                if (current < goal)
-                       current = min(current + adjust, goal);
+                       current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
                else if (current > goal)
-                       current = max(current - adjust, 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);
        }
@@ -5230,27 +5274,29 @@ static void R_View_SetFrustum(const int *scissor)
        //PlaneClassify(&frustum[4]);
 }
 
-void R_View_UpdateWithScissor(const int *myscissor)
+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();
+       R_AnimCache_CacheVisibleEntities();
 }
 
-void R_View_Update(void)
+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();
+       R_AnimCache_CacheVisibleEntities();
 }
 
 float viewscalefpsadjusted = 1.0f;
 
-void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight)
+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);
@@ -5258,19 +5304,11 @@ void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight)
        *outheight = (int)ceil(height * scale);
 }
 
-void R_Mesh_SetMainRenderTargets(void)
-{
-       if (r_bloomstate.fbo_framebuffer)
-               R_Mesh_SetRenderTargets(r_bloomstate.fbo_framebuffer, r_bloomstate.texture_framebufferdepth, r_bloomstate.texture_framebuffercolor, NULL, NULL, NULL);
-       else
-               R_Mesh_ResetRenderTargets();
-}
-
-void R_SetupView(qboolean allowwaterclippingplane)
+void R_SetupView(qboolean allowwaterclippingplane, int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
        const float *customclipplane = NULL;
        float plane[4];
-       int scaledwidth, scaledheight;
+       int /*rtwidth,*/ rtheight, scaledwidth, scaledheight;
        if (r_refdef.view.useclipplane && allowwaterclippingplane)
        {
                // LordHavoc: couldn't figure out how to make this approach the
@@ -5285,14 +5323,17 @@ void R_SetupView(qboolean allowwaterclippingplane)
                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, vid.height - 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);
+               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, vid.height - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
+               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, vid.height - 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_SetMainRenderTargets();
+               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)
        {
@@ -5349,14 +5390,15 @@ void R_EntityMatrix(const matrix4x4_t *matrix)
        }
 }
 
-void R_ResetViewRendering2D(void)
+void R_ResetViewRendering2D_Common(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, float x2, float y2)
 {
        r_viewport_t viewport;
-       DrawQ_Finish();
+
+       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, 1, 1, -10, 100, NULL);
-       R_Mesh_ResetRenderTargets();
+       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);
@@ -5387,13 +5429,22 @@ void R_ResetViewRendering2D(void)
                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(void)
+void R_ResetViewRendering3D(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
        DrawQ_Finish();
 
-       R_SetupView(true);
+       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);
@@ -5430,7 +5481,7 @@ void R_ResetViewRendering3D(void)
 R_RenderView_UpdateViewVectors
 ================
 */
-static void R_RenderView_UpdateViewVectors(void)
+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
@@ -5441,14 +5492,15 @@ static void R_RenderView_UpdateViewVectors(void)
        Matrix4x4_Invert_Simple(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
 }
 
-void R_RenderScene(void);
-void R_RenderWaterPlanes(void);
+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.samples < 2;
 
        if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
                return;
@@ -5492,82 +5544,103 @@ static void R_Water_StartFrame(void)
        }
 
        // allocate textures as needed
-       if (r_waterstate.texturewidth != texturewidth || r_waterstate.textureheight != textureheight || r_waterstate.camerawidth != camerawidth || r_waterstate.cameraheight != cameraheight)
+       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_waterstate.maxwaterplanes = MAX_WATERPLANES;
-               for (i = 0, p = r_waterstate.waterplanes;i < r_waterstate.maxwaterplanes;i++, p++)
+               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_waterstate, 0, sizeof(r_waterstate));
-               r_waterstate.texturewidth = texturewidth;
-               r_waterstate.textureheight = textureheight;
-               r_waterstate.camerawidth = camerawidth;
-               r_waterstate.cameraheight = cameraheight;
+               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_waterstate.texturewidth)
+       if (r_fb.water.texturewidth)
        {
                int scaledwidth, scaledheight;
 
-               r_waterstate.enabled = true;
+               r_fb.water.enabled = true;
 
-               // when doing a reduced render (HDR) we want to use a smaller area
-               r_waterstate.waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
-               r_waterstate.waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
-               R_GetScaledViewSize(r_waterstate.waterwidth, r_waterstate.waterheight, &scaledwidth, &scaledheight);
+               // 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_waterstate.screenscale[0] = 0.5f * (float)scaledwidth / (float)r_waterstate.texturewidth;
-               r_waterstate.screenscale[1] = 0.5f * (float)scaledheight / (float)r_waterstate.textureheight;
-               r_waterstate.screencenter[0] = 0.5f * (float)scaledwidth / (float)r_waterstate.texturewidth;
-               r_waterstate.screencenter[1] = 0.5f * (float)scaledheight / (float)r_waterstate.textureheight;
+               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_waterstate.maxwaterplanes = MAX_WATERPLANES;
-       r_waterstate.numwaterplanes = 0;
+       r_fb.water.maxwaterplanes = MAX_WATERPLANES;
+       r_fb.water.numwaterplanes = 0;
 }
 
 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
 {
-       int triangleindex, planeindex;
-       const int *e;
-       vec3_t vert[3];
-       vec3_t normal;
-       vec3_t center;
+       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);
 
-       // just use the first triangle with a valid normal for any decisions
-       VectorClear(normal);
-       for (triangleindex = 0, e = rsurface.modelelement3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
-       {
-               Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[0]*3, vert[0]);
-               Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[1]*3, vert[1]);
-               Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[2]*3, vert[2]);
-               TriangleNormal(vert[0], vert[1], vert[2], normal);
-               if (VectorLength2(normal) >= 0.001)
-                       break;
-       }
+       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(vert[0], 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;
+//             if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
+//                     return;
                VectorNegate(plane.normal, plane.normal);
                plane.dist *= -1;
                PlaneClassify(&plane);
@@ -5575,42 +5648,52 @@ void R_Water_AddWaterPlane(msurface_t *surface, int entno)
 
 
        // find a matching plane if there is one
-       for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
+       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)
-                       if (fabs(PlaneDiff(vert[0], &p->plane)) < 1 && fabs(PlaneDiff(vert[1], &p->plane)) < 1 && fabs(PlaneDiff(vert[2], &p->plane)) < 1)
-                               break;
-       if (planeindex >= r_waterstate.maxwaterplanes)
-               return; // nothing we can do, out of planes
+               {
+                       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 triangle does not fit any known plane rendered this frame, add one
-       if (planeindex >= r_waterstate.numwaterplanes)
+       // 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
-               r_waterstate.numwaterplanes++;
+               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(surface->mins, p->mins);
-               VectorCopy(surface->maxs, p->maxs);
+               VectorCopy(mins, p->mins);
+               VectorCopy(maxs, p->maxs);
        }
        else
        {
-               // merge mins/maxs
-               p->mins[0] = min(p->mins[0], surface->mins[0]);
-               p->mins[1] = min(p->mins[1], surface->mins[1]);
-               p->mins[2] = min(p->mins[2], surface->mins[2]);
-               p->maxs[0] = max(p->maxs[0], surface->maxs[0]);
-               p->maxs[1] = max(p->maxs[1], surface->maxs[1]);
-               p->maxs[2] = max(p->maxs[2], surface->maxs[2]);
+               // 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
-               VectorMAM(0.5f, surface->mins, 0.5f, surface->maxs, center);
                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)
                {
@@ -5623,7 +5706,7 @@ void R_Water_AddWaterPlane(msurface_t *surface, int entno)
 extern cvar_t r_drawparticles;
 extern cvar_t r_drawdecals;
 
-static void R_Water_ProcessPlanes(void)
+static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
        int myscissor[4];
        r_refdef_view_t originalview;
@@ -5631,6 +5714,8 @@ static void R_Water_ProcessPlanes(void)
        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.samples < 2;
+       char vabuf[1024];
 
        originalview = r_refdef.view;
 
@@ -5659,48 +5744,69 @@ static void R_Water_ProcessPlanes(void)
        }
 
        // make sure enough textures are allocated
-       for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
+       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("waterplane%i_refraction", planeindex), r_waterstate.texturewidth, r_waterstate.textureheight, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
+                               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("waterplane%i_camera", planeindex), r_waterstate.camerawidth, r_waterstate.cameraheight, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCELINEAR, -1, NULL);
+                               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("waterplane%i_reflection", planeindex), r_waterstate.texturewidth, r_waterstate.textureheight, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
+                               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_waterstate.waterwidth;
-       r_refdef.view.height = r_waterstate.waterheight;
+       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_waterstate.renderingscene = true;
-       for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
+       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);
+                               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
                        }
@@ -5722,7 +5828,8 @@ static void R_Water_ProcessPlanes(void)
                                        memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
                        }
 
-                       R_ResetViewRendering3D();
+                       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);
@@ -5730,9 +5837,11 @@ static void R_Water_ProcessPlanes(void)
                                R_View_Update();
                        if(r_water_scissormode.integer & 1)
                                GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
-                       R_RenderScene();
+                       R_RenderScene(p->fbo_reflection, r_fb.water.depthtexture, p->texture_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);
+                       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
@@ -5742,12 +5851,12 @@ static void R_Water_ProcessPlanes(void)
                        r_refdef.view = myview;
                        if(r_water_scissormode.integer)
                        {
-                               R_SetupView(true);
+                               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_waterstate.renderingrefraction = true;
+                       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);
@@ -5756,7 +5865,7 @@ static void R_Water_ProcessPlanes(void)
                        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_waterstate.renderingrefraction = false; // we don't want to hide the player model from these ones
+                               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)
@@ -5768,7 +5877,7 @@ static void R_Water_ProcessPlanes(void)
 
                        PlaneClassify(&r_refdef.view.clipplane);
 
-                       R_ResetViewRendering3D();
+                       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);
@@ -5776,10 +5885,11 @@ static void R_Water_ProcessPlanes(void)
                                R_View_Update();
                        if(r_water_scissormode.integer & 1)
                                GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
-                       R_RenderScene();
+                       R_RenderScene(p->fbo_refraction, r_fb.water.depthtexture, p->texture_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_waterstate.renderingrefraction = false;
+                       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)
                {
@@ -5789,10 +5899,12 @@ static void R_Water_ProcessPlanes(void)
                        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_waterstate.camerawidth;
-                       r_refdef.view.height = r_waterstate.cameraheight;
+                       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)
                        {
@@ -5820,26 +5932,30 @@ static void R_Water_ProcessPlanes(void)
 
                        PlaneClassify(&r_refdef.view.clipplane);
 
-                       R_ResetViewRendering3D();
+                       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_RenderScene();
+                       R_RenderScene(p->fbo_camera, r_fb.water.depthtexture, p->texture_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_waterstate.renderingrefraction = false;
+                       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_waterstate.renderingscene = false;
+       r_fb.water.renderingscene = false;
        r_refdef.view = originalview;
-       R_ResetViewRendering3D();
-       R_ClearScreen(r_refdef.fogenabled);
+       R_ResetViewRendering3D(fbo, depthtexture, colortexture);
+       if (!r_fb.water.depthtexture)
+               R_ClearScreen(r_refdef.fogenabled);
        R_View_Update();
        goto finish;
 error:
        r_refdef.view = originalview;
-       r_waterstate.renderingscene = false;
+       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:
@@ -5861,11 +5977,37 @@ finish:
        }
 }
 
-void R_Bloom_StartFrame(void)
+static void R_Bloom_StartFrame(void)
 {
+       int i;
        int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
        int viewwidth, viewheight;
-       textype_t textype;
+       qboolean useviewfbo = r_viewfbo.integer >= 1 && vid.support.ext_framebuffer_object && 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)
+               {
+                       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)
        {
@@ -5903,143 +6045,139 @@ void R_Bloom_StartFrame(void)
 
        // set bloomwidth and bloomheight to the bloom resolution that will be
        // used (often less than the screen resolution for faster rendering)
-       r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, vid.height);
-       r_bloomstate.bloomheight = r_bloomstate.bloomwidth * vid.height / vid.width;
-       r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, vid.height);
-       r_bloomstate.bloomwidth = bound(1, r_bloomstate.bloomwidth, (int)vid.maxtexturesize_2d);
-       r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, (int)vid.maxtexturesize_2d);
+       r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.height);
+       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_bloomstate.bloomwidth;
-               bloomtextureheight = r_bloomstate.bloomheight;
+               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_bloomstate.bloomwidth ;bloomtexturewidth   *= 2);
-               for (bloomtextureheight  = 1;bloomtextureheight  < r_bloomstate.bloomheight;bloomtextureheight  *= 2);
+               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_hdr.integer || 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))
+       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_hdr, 0);
                Cvar_SetValueQuick(&r_bloom, 0);
                Cvar_SetValueQuick(&r_motionblur, 0);
                Cvar_SetValueQuick(&r_damageblur, 0);
        }
 
-       if (!(r_glsl_postprocess.integer || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial)) && !r_bloom.integer && !r_hdr.integer && (R_Stereo_Active() || (r_motionblur.value <= 0 && r_damageblur.value <= 0)) && r_viewfbo.integer < 1 && r_viewscale.value == 1.0f && !r_viewscale_fpsscaling.integer)
+       if (!(r_glsl_postprocess.integer || (!R_Stereo_ColorMasking() && 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_hdr.integer && !r_bloom.integer)
+       if (!r_bloom.integer)
                bloomtexturewidth = bloomtextureheight = 0;
 
-       textype = TEXTYPE_COLORBUFFER;
-       switch (vid.renderpath)
+       // 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))
        {
-       case RENDERPATH_GL20:
-       case RENDERPATH_GLES2:
-               if (vid.support.ext_framebuffer_object)
+               for (i = 0;i < (int)(sizeof(r_fb.bloomtexture)/sizeof(r_fb.bloomtexture[i]));i++)
                {
-                       if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
-                       if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
+                       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;
                }
-               break;
-       case RENDERPATH_GL11:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GLES1:
-       case RENDERPATH_D3D9:
-       case RENDERPATH_D3D10:
-       case RENDERPATH_D3D11:
-       case RENDERPATH_SOFT:
-               break;
-       }
 
-       // allocate textures as needed
-       if (r_bloomstate.screentexturewidth != screentexturewidth
-        || r_bloomstate.screentextureheight != screentextureheight
-        || r_bloomstate.bloomtexturewidth != bloomtexturewidth
-        || r_bloomstate.bloomtextureheight != bloomtextureheight
-        || r_bloomstate.texturetype != textype
-        || r_bloomstate.viewfbo != r_viewfbo.integer)
-       {
-               if (r_bloomstate.texture_bloom)
-                       R_FreeTexture(r_bloomstate.texture_bloom);
-               r_bloomstate.texture_bloom = NULL;
-               if (r_bloomstate.texture_screen)
-                       R_FreeTexture(r_bloomstate.texture_screen);
-               r_bloomstate.texture_screen = NULL;
-               if (r_bloomstate.fbo_framebuffer)
-                       R_Mesh_DestroyFramebufferObject(r_bloomstate.fbo_framebuffer);
-               r_bloomstate.fbo_framebuffer = 0;
-               if (r_bloomstate.texture_framebuffercolor)
-                       R_FreeTexture(r_bloomstate.texture_framebuffercolor);
-               r_bloomstate.texture_framebuffercolor = NULL;
-               if (r_bloomstate.texture_framebufferdepth)
-                       R_FreeTexture(r_bloomstate.texture_framebufferdepth);
-               r_bloomstate.texture_framebufferdepth = NULL;
-               r_bloomstate.screentexturewidth = screentexturewidth;
-               r_bloomstate.screentextureheight = screentextureheight;
-               if (r_bloomstate.screentexturewidth && r_bloomstate.screentextureheight)
-                       r_bloomstate.texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", r_bloomstate.screentexturewidth, r_bloomstate.screentextureheight, NULL, textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
-               if (r_viewfbo.integer >= 1 && vid.support.ext_framebuffer_object)
-               {
-                       // FIXME: choose depth bits based on a cvar
-                       r_bloomstate.texture_framebufferdepth = R_LoadTextureShadowMap2D(r_main_texturepool, "framebufferdepth", r_bloomstate.screentexturewidth, r_bloomstate.screentextureheight, 24, false);
-                       r_bloomstate.texture_framebuffercolor = R_LoadTexture2D(r_main_texturepool, "framebuffercolor", r_bloomstate.screentexturewidth, r_bloomstate.screentextureheight, NULL, textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
-                       r_bloomstate.fbo_framebuffer = R_Mesh_CreateFramebufferObject(r_bloomstate.texture_framebufferdepth, r_bloomstate.texture_framebuffercolor, NULL, NULL, NULL);
-                       R_Mesh_SetRenderTargets(r_bloomstate.fbo_framebuffer, r_bloomstate.texture_framebufferdepth, r_bloomstate.texture_framebuffercolor, NULL, NULL, NULL);
-                       // render depth into one texture and normalmap into the other
-                       if (qglDrawBuffer)
+               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)
                        {
-                               int status;
-                               qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
-                               qglReadBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
-                               status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
-                               if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
-                                       Con_Printf("R_Bloom_StartFrame: glCheckFramebufferStatusEXT returned %i\n", status);
+                               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);
                        }
                }
-               r_bloomstate.bloomtexturewidth = bloomtexturewidth;
-               r_bloomstate.bloomtextureheight = bloomtextureheight;
-               if (r_bloomstate.bloomtexturewidth && r_bloomstate.bloomtextureheight)
-                       r_bloomstate.texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", r_bloomstate.bloomtexturewidth, r_bloomstate.bloomtextureheight, NULL, textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
-               r_bloomstate.viewfbo = r_viewfbo.integer;
-               r_bloomstate.texturetype = textype;
        }
 
-       // when doing a reduced render (HDR) we want to use a smaller area
-       r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.height);
-       r_bloomstate.bloomheight = r_bloomstate.bloomwidth * r_refdef.view.height / r_refdef.view.width;
-       r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_refdef.view.height);
-       r_bloomstate.bloomwidth = bound(1, r_bloomstate.bloomwidth, r_bloomstate.bloomtexturewidth);
-       r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_bloomstate.bloomtextureheight);
+       // bloom texture is a different resolution
+       r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.height);
+       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_bloomstate.screentexcoord2f[0] = 0;
-       r_bloomstate.screentexcoord2f[1] = (float)viewheight    / (float)r_bloomstate.screentextureheight;
-       r_bloomstate.screentexcoord2f[2] = (float)viewwidth     / (float)r_bloomstate.screentexturewidth;
-       r_bloomstate.screentexcoord2f[3] = (float)viewheight    / (float)r_bloomstate.screentextureheight;
-       r_bloomstate.screentexcoord2f[4] = (float)viewwidth     / (float)r_bloomstate.screentexturewidth;
-       r_bloomstate.screentexcoord2f[5] = 0;
-       r_bloomstate.screentexcoord2f[6] = 0;
-       r_bloomstate.screentexcoord2f[7] = 0;
+       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;
 
        // set up a texcoord array for the reduced resolution bloom image
        // (which will be additive blended over the screen image)
-       r_bloomstate.bloomtexcoord2f[0] = 0;
-       r_bloomstate.bloomtexcoord2f[1] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
-       r_bloomstate.bloomtexcoord2f[2] = (float)r_bloomstate.bloomwidth  / (float)r_bloomstate.bloomtexturewidth;
-       r_bloomstate.bloomtexcoord2f[3] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
-       r_bloomstate.bloomtexcoord2f[4] = (float)r_bloomstate.bloomwidth  / (float)r_bloomstate.bloomtexturewidth;
-       r_bloomstate.bloomtexcoord2f[5] = 0;
-       r_bloomstate.bloomtexcoord2f[6] = 0;
-       r_bloomstate.bloomtexcoord2f[7] = 0;
+       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)
        {
@@ -6057,35 +6195,41 @@ void R_Bloom_StartFrame(void)
                        int i;
                        for (i = 0;i < 4;i++)
                        {
-                               r_bloomstate.screentexcoord2f[i*2+0] += 0.5f / (float)r_bloomstate.screentexturewidth;
-                               r_bloomstate.screentexcoord2f[i*2+1] += 0.5f / (float)r_bloomstate.screentextureheight;
-                               r_bloomstate.bloomtexcoord2f[i*2+0] += 0.5f / (float)r_bloomstate.bloomtexturewidth;
-                               r_bloomstate.bloomtexcoord2f[i*2+1] += 0.5f / (float)r_bloomstate.bloomtextureheight;
+                               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;
        }
 
-       if ((r_hdr.integer || r_bloom.integer) && r_bloomstate.bloomwidth)
-       {
-               r_bloomstate.enabled = true;
-               r_bloomstate.hdr = r_hdr.integer != 0 && !r_bloomstate.fbo_framebuffer;
-       }
-
-       R_Viewport_InitOrtho(&r_bloomstate.viewport, &identitymatrix, r_refdef.view.x, vid.height - r_bloomstate.bloomheight - r_refdef.view.y, r_bloomstate.bloomwidth, r_bloomstate.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
+       R_Viewport_InitOrtho(&r_fb.bloomviewport, &identitymatrix, r_refdef.view.x, (r_fb.bloomfbo[0] ? r_fb.bloomtextureheight : vid.height) - r_fb.bloomheight - r_refdef.view.y, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
 
-       if (r_bloomstate.fbo_framebuffer)
+       if (r_fb.fbo)
                r_refdef.view.clear = true;
 }
 
-void R_Bloom_CopyBloomTexture(float colorscale)
+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.bloom++;
 
+       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.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
+       }
+
        // scale down screen texture to the bloom texture size
        CHECKGLERROR
-       R_Mesh_SetMainRenderTargets();
-       R_SetViewport(&r_bloomstate.viewport);
+       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_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...
@@ -6097,90 +6241,81 @@ void R_Bloom_CopyBloomTexture(float colorscale)
        case RENDERPATH_GLES1:
        case RENDERPATH_GLES2:
        case RENDERPATH_SOFT:
-               R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.screentexcoord2f);
+               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_bloomstate.screentexcoord2f);
+               R_Mesh_PrepareVertices_Generic_Arrays(4, r_d3dscreenvertex3f, NULL, r_fb.screentexcoord2f);
                break;
        }
        // TODO: do boxfilter scale-down in shader?
-       R_SetupShader_Generic(r_bloomstate.texture_screen, NULL, GL_MODULATE, 1, true);
+       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.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
-
-       // we now have a bloom image in the framebuffer
-       // copy it into the bloom image texture for later processing
-       R_Mesh_CopyToTexture(r_bloomstate.texture_bloom, 0, 0, r_bloomstate.viewport.x, r_bloomstate.viewport.y, r_bloomstate.viewport.width, r_bloomstate.viewport.height);
-       r_refdef.stats.bloom_copypixels += r_bloomstate.viewport.width * r_bloomstate.viewport.height;
-}
-
-void R_Bloom_CopyHDRTexture(void)
-{
-       R_Mesh_CopyToTexture(r_bloomstate.texture_bloom, 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.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
-}
+       r_refdef.stats.bloom_drawpixels += r_fb.bloomwidth * r_fb.bloomheight;
 
-void R_Bloom_MakeTexture(void)
-{
-       int x, range, dir;
-       float xoffset, yoffset, r, brighten;
-
-       r_refdef.stats.bloom++;
-
-       R_ResetViewRendering2D();
-
-       // we have a bloom image in the framebuffer
-       CHECKGLERROR
-       R_SetViewport(&r_bloomstate.viewport);
+       // 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.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);
                GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
                GL_Color(r,r,r,1);
-               R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.bloomtexcoord2f);
-               R_SetupShader_Generic(r_bloomstate.texture_bloom, NULL, GL_MODULATE, 1, true);
+               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.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+               r_refdef.stats.bloom_drawpixels += r_fb.bloomwidth * r_fb.bloomheight;
 
-               // copy the vertically blurred bloom view to a texture
-               R_Mesh_CopyToTexture(r_bloomstate.texture_bloom, 0, 0, r_bloomstate.viewport.x, r_bloomstate.viewport.y, r_bloomstate.viewport.width, r_bloomstate.viewport.height);
-               r_refdef.stats.bloom_copypixels += r_bloomstate.viewport.width * r_bloomstate.viewport.height;
+               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.bloom_copypixels += r_fb.bloomviewport.width * r_fb.bloomviewport.height;
+               }
        }
 
-       range = r_bloom_blur.integer * r_bloomstate.bloomwidth / 320;
+       range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
        brighten = r_bloom_brighten.value;
-       if (r_bloomstate.hdr)
-               brighten *= r_hdr_range.value;
        brighten = sqrt(brighten);
        if(range >= 1)
                brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
-       R_SetupShader_Generic(r_bloomstate.texture_bloom, NULL, GL_MODULATE, 1, true);
 
        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_bloomstate.bloomtexturewidth;
-                       yoffset /= (float)r_bloomstate.bloomtextureheight;
+                       xoffset /= (float)r_fb.bloomtexturewidth;
+                       yoffset /= (float)r_fb.bloomtextureheight;
                        // compute a texcoord array with the specified x and y offset
-                       r_bloomstate.offsettexcoord2f[0] = xoffset+0;
-                       r_bloomstate.offsettexcoord2f[1] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
-                       r_bloomstate.offsettexcoord2f[2] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
-                       r_bloomstate.offsettexcoord2f[3] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
-                       r_bloomstate.offsettexcoord2f[4] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
-                       r_bloomstate.offsettexcoord2f[5] = yoffset+0;
-                       r_bloomstate.offsettexcoord2f[6] = xoffset+0;
-                       r_bloomstate.offsettexcoord2f[7] = yoffset+0;
+                       r_fb.offsettexcoord2f[0] = xoffset+0;
+                       r_fb.offsettexcoord2f[1] = yoffset+(float)r_fb.bloomheight / (float)r_fb.bloomtextureheight;
+                       r_fb.offsettexcoord2f[2] = xoffset+(float)r_fb.bloomwidth / (float)r_fb.bloomtexturewidth;
+                       r_fb.offsettexcoord2f[3] = yoffset+(float)r_fb.bloomheight / (float)r_fb.bloomtextureheight;
+                       r_fb.offsettexcoord2f[4] = xoffset+(float)r_fb.bloomwidth / (float)r_fb.bloomtexturewidth;
+                       r_fb.offsettexcoord2f[5] = yoffset+0;
+                       r_fb.offsettexcoord2f[6] = xoffset+0;
+                       r_fb.offsettexcoord2f[7] = yoffset+0;
                        // this r value looks like a 'dot' particle, fading sharply to
                        // black at the edges
                        // (probably not realistic but looks good enough)
@@ -6190,79 +6325,22 @@ void R_Bloom_MakeTexture(void)
                        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_bloomstate.offsettexcoord2f);
+                       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.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+                       r_refdef.stats.bloom_drawpixels += r_fb.bloomwidth * r_fb.bloomheight;
                        GL_BlendFunc(GL_ONE, GL_ONE);
                }
 
-               // copy the vertically blurred bloom view to a texture
-               R_Mesh_CopyToTexture(r_bloomstate.texture_bloom, 0, 0, r_bloomstate.viewport.x, r_bloomstate.viewport.y, r_bloomstate.viewport.width, r_bloomstate.viewport.height);
-               r_refdef.stats.bloom_copypixels += r_bloomstate.viewport.width * r_bloomstate.viewport.height;
+               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.bloom_copypixels += r_fb.bloomviewport.width * r_fb.bloomviewport.height;
+               }
        }
 }
 
-void R_HDR_RenderBloomTexture(void)
-{
-       int oldwidth, oldheight;
-       float oldcolorscale;
-       qboolean oldwaterstate;
-
-       oldwaterstate = r_waterstate.enabled;
-       oldcolorscale = r_refdef.view.colorscale;
-       oldwidth = r_refdef.view.width;
-       oldheight = r_refdef.view.height;
-       r_refdef.view.width = r_bloomstate.bloomwidth;
-       r_refdef.view.height = r_bloomstate.bloomheight;
-
-       if(r_hdr.integer < 2)
-               r_waterstate.enabled = false;
-
-       // TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer?  it might improve SLI performance.
-       // TODO: add exposure compensation features
-       // TODO: add fp16 framebuffer support (using GL_EXT_framebuffer_object)
-
-       r_refdef.view.showdebug = false;
-       r_refdef.view.colorscale *= r_bloom_colorscale.value / bound(1, r_hdr_range.value, 16);
-
-       R_ResetViewRendering3D();
-
-       R_ClearScreen(r_refdef.fogenabled);
-       if (r_timereport_active)
-               R_TimeReport("HDRclear");
-
-       R_View_Update();
-       if (r_timereport_active)
-               R_TimeReport("visibility");
-
-       // only do secondary renders with HDR if r_hdr is 2 or higher
-       r_waterstate.numwaterplanes = 0;
-       if (r_waterstate.enabled)
-               R_RenderWaterPlanes();
-
-       r_refdef.view.showdebug = true;
-       R_RenderScene();
-       r_waterstate.numwaterplanes = 0;
-
-       R_ResetViewRendering2D();
-
-       R_Bloom_CopyHDRTexture();
-       R_Bloom_MakeTexture();
-
-       // restore the view settings
-       r_waterstate.enabled = oldwaterstate;
-       r_refdef.view.width = oldwidth;
-       r_refdef.view.height = oldheight;
-       r_refdef.view.colorscale = oldcolorscale;
-
-       R_ResetViewRendering3D();
-
-       R_ClearScreen(r_refdef.fogenabled);
-       if (r_timereport_active)
-               R_TimeReport("viewclear");
-}
-
-static void R_BlendView(void)
+static void R_BlendView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
        unsigned int permutation;
        float uservecs[4][4];
@@ -6276,50 +6354,62 @@ static void R_BlendView(void)
        case RENDERPATH_SOFT:
        case RENDERPATH_GLES2:
                permutation =
-                         (r_bloomstate.texture_bloom ? SHADERPERMUTATION_BLOOM : 0)
+                         (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_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
 
-               if (r_bloomstate.texture_screen)
+               if (r_fb.colortexture)
                {
-                       // make sure the buffer is available
-                       if (r_bloom_blur.value < 1) { Cvar_SetValueQuick(&r_bloom_blur, 1); }
-
-                       R_ResetViewRendering2D();
-                       R_Mesh_SetMainRenderTargets();
+                       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.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
+                       }
 
-                       if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))
+                       if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
                        {
                                // declare variables
-                               float speed;
-                               static float avgspeed;
+                               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));
 
-                               speed = VectorLength(cl.movement_velocity);
+                               // 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;
 
-                               cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_vcoeff.value), 1);
-                               avgspeed = avgspeed * (1 - cl.motionbluralpha) + speed * cl.motionbluralpha;
+                               // enforce minimum amount of blur 
+                               blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
 
-                               speed = (avgspeed - r_motionblur_vmin.value) / max(1, r_motionblur_vmax.value - r_motionblur_vmin.value);
-                               speed = bound(0, speed, 1);
-                               speed = speed * (1 - r_motionblur_bmin.value) + r_motionblur_bmin.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 * speed / 80)
+                                                (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
-                               if (cl.motionbluralpha > 0 && !r_refdef.envmap)
+                               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);
@@ -6331,45 +6421,47 @@ static void R_BlendView(void)
                                        case RENDERPATH_GLES1:
                                        case RENDERPATH_GLES2:
                                        case RENDERPATH_SOFT:
-                                               R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.screentexcoord2f);
+                                               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_bloomstate.screentexcoord2f);
+                                               R_Mesh_PrepareVertices_Generic_Arrays(4, r_d3dscreenvertex3f, NULL, r_fb.screentexcoord2f);
                                                break;
                                        }
-                                       R_SetupShader_Generic(r_bloomstate.texture_screen, NULL, GL_MODULATE, 1, true);
+                                       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.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
                                }
-                       }
 
-                       // copy view into the screen texture
-                       R_Mesh_CopyToTexture(r_bloomstate.texture_screen, 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.bloom_copypixels += 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.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height;
+                               r_fb.ghosttexture_valid = true;
+                       }
                }
-               else if (!r_bloomstate.texture_bloom)
+               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();
+                               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(NULL, NULL, GL_MODULATE, 1, true);
+                               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_bloomstate.texture_bloom && !r_bloomstate.hdr)
+               if (r_fb.bloomtexture[0])
                {
-                       // render simple bloom effect
-                       // copy the screen and shrink it and darken it for the bloom process
-                       R_Bloom_CopyBloomTexture(r_bloom_colorscale.value);
                        // make the bloom texture
                        R_Bloom_MakeTexture();
                }
@@ -6387,7 +6479,7 @@ static void R_BlendView(void)
                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();
+               R_ResetViewRendering2D(0, NULL, NULL); // here we render to the real framebuffer!
                GL_Color(1, 1, 1, 1);
                GL_BlendFunc(GL_ONE, GL_ZERO);
 
@@ -6395,13 +6487,13 @@ static void R_BlendView(void)
                {
                case RENDERPATH_GL20:
                case RENDERPATH_GLES2:
-                       R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_bloomstate.screentexcoord2f, r_bloomstate.bloomtexcoord2f);
+                       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_bloomstate.texture_screen);
-                       if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , r_bloomstate.texture_bloom );
+                       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_bloomstate.screentexturewidth, 1.0/r_bloomstate.screentextureheight);
+                       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]);
@@ -6413,13 +6505,13 @@ static void R_BlendView(void)
                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_bloomstate.screentexcoord2f, r_bloomstate.bloomtexcoord2f);
+                       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_bloomstate.texture_screen);
-                       R_Mesh_TexBind(GL20TU_SECOND    , r_bloomstate.texture_bloom );
+                       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_bloomstate.screentexturewidth, 1.0/r_bloomstate.screentextureheight);
+                       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]);
@@ -6436,13 +6528,13 @@ static void R_BlendView(void)
                        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_bloomstate.screentexcoord2f, r_bloomstate.bloomtexcoord2f);
+                       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_bloomstate.texture_screen);
-                       R_Mesh_TexBind(GL20TU_SECOND    , r_bloomstate.texture_bloom );
+                       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_bloomstate.screentexturewidth, 1.0/r_bloomstate.screentextureheight);
+                       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]);
@@ -6463,10 +6555,10 @@ static void R_BlendView(void)
                if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
                {
                        // apply a color tint to the whole view
-                       R_ResetViewRendering2D();
+                       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(NULL, NULL, GL_MODULATE, 1, true);
+                       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);
                }
@@ -6476,67 +6568,9 @@ static void R_BlendView(void)
 
 matrix4x4_t r_waterscrollmatrix;
 
-void R_UpdateFogColor(void) // needs to be called before HDR subrender too, as that changes colorscale!
+void R_UpdateFog(void)
 {
-       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;
-       }
-       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;
-       }
-
+       // Nehahra fog
        if (gamemode == GAME_NEHAHRA)
        {
                if (gl_fogenable.integer)
@@ -6567,12 +6601,11 @@ void R_UpdateVariables(void)
                }
        }
 
+       // 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);
 
-       // R_UpdateFogColor(); // why? R_RenderScene does it anyway
-
        if (r_refdef.fog_density && r_drawfog.integer)
        {
                r_refdef.fogenabled = true;
@@ -6598,6 +6631,66 @@ void R_UpdateVariables(void)
        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;
+       }
+       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;
+       }
+
        switch(vid.renderpath)
        {
        case RENDERPATH_GL20:
@@ -6680,17 +6773,50 @@ r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t 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 void R_Shadow_UpdateBounceGridTexture(void);
 extern cvar_t r_shadow_bouncegrid;
 void R_RenderView(void)
 {
        matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
+       int fbo;
+       rtexture_t *depthtexture;
+       rtexture_t *colortexture;
 
        dpsoftrast_test = r_test.integer;
 
@@ -6704,6 +6830,8 @@ void R_RenderView(void)
 
        if (!r_drawentities.integer)
                r_refdef.scene.numentities = 0;
+       else if (r_sortentities.integer)
+               R_SortEntities();
 
        R_AnimCache_ClearCache();
        R_FrameData_NewFrame();
@@ -6718,15 +6846,16 @@ void R_RenderView(void)
        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_waterstate.enabled = false;
-               r_waterstate.numwaterplanes = 0;
+               r_fb.water.enabled = false;
+               r_fb.water.numwaterplanes = 0;
 
-               R_RenderScene();
+               R_RenderScene(0, NULL, NULL);
 
                r_refdef.view.matrix = originalmatrix;
 
@@ -6737,11 +6866,16 @@ void R_RenderView(void)
        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; //Host_Error ("R_RenderView: NULL worldmodel");
+               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();
@@ -6749,13 +6883,18 @@ void R_RenderView(void)
        R_Bloom_StartFrame();
        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();
+       R_ResetViewRendering3D(fbo, depthtexture, colortexture);
 
-       if (r_refdef.view.clear || r_refdef.fogenabled)
+       if (r_refdef.view.clear || r_refdef.fogenabled || fbo)
        {
                R_ClearScreen(r_refdef.fogenabled);
                if (r_timereport_active)
@@ -6763,14 +6902,6 @@ void R_RenderView(void)
        }
        r_refdef.view.clear = true;
 
-       // this produces a bloom texture to be used in R_BlendView() later
-       if (r_bloomstate.hdr)
-       {
-               R_HDR_RenderBloomTexture();
-               // we have to bump the texture frame again because r_refdef.view.colorscale is cached in the textures
-               r_textureframe++; // used only by R_GetCurrentTexture
-       }
-
        r_refdef.view.showdebug = true;
 
        R_View_Update();
@@ -6781,14 +6912,14 @@ void R_RenderView(void)
        if (r_timereport_active && r_shadow_bouncegrid.integer)
                R_TimeReport("bouncegrid");
 
-       r_waterstate.numwaterplanes = 0;
-       if (r_waterstate.enabled)
-               R_RenderWaterPlanes();
+       r_fb.water.numwaterplanes = 0;
+       if (r_fb.water.enabled)
+               R_RenderWaterPlanes(fbo, depthtexture, colortexture);
 
-       R_RenderScene();
-       r_waterstate.numwaterplanes = 0;
+       R_RenderScene(fbo, depthtexture, colortexture);
+       r_fb.water.numwaterplanes = 0;
 
-       R_BlendView();
+       R_BlendView(fbo, depthtexture, colortexture);
        if (r_timereport_active)
                R_TimeReport("blendview");
 
@@ -6800,7 +6931,7 @@ void R_RenderView(void)
        CHECKGLERROR
 }
 
-void R_RenderWaterPlanes(void)
+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)
        {
@@ -6817,26 +6948,21 @@ void R_RenderWaterPlanes(void)
        if (r_timereport_active)
                R_TimeReport("watermodels");
 
-       if (r_waterstate.numwaterplanes)
+       if (r_fb.water.numwaterplanes)
        {
-               R_Water_ProcessPlanes();
+               R_Water_ProcessPlanes(fbo, depthtexture, colortexture);
                if (r_timereport_active)
                        R_TimeReport("waterscenes");
        }
 }
 
-extern void R_DrawLightningBeams (void);
-extern void VM_CL_AddPolygonsToMeshQueue (void);
-extern void R_DrawPortals (void);
 extern cvar_t cl_locs_show;
 static void R_DrawLocs(void);
 static void R_DrawEntityBBoxes(void);
 static void R_DrawModelDecals(void);
-extern void R_DrawModelShadows(void);
-extern void R_DrawModelShadowMaps(void);
 extern cvar_t cl_decals_newsystem;
 extern qboolean r_shadow_usingdeferredprepass;
-void R_RenderScene(void)
+void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
        qboolean shadowmapping = false;
 
@@ -6845,7 +6971,7 @@ void R_RenderScene(void)
 
        r_refdef.stats.renders++;
 
-       R_UpdateFogColor();
+       R_UpdateFog();
 
        // don't let sound skip if going slow
        if (r_refdef.scene.extraupdate)
@@ -6879,19 +7005,15 @@ void R_RenderScene(void)
                if (skyrendermasked && skyrenderlater)
                {
                        // we have to force off the water clipping plane while rendering sky
-                       R_SetupView(false);
+                       R_SetupView(false, fbo, depthtexture, colortexture);
                        R_Sky();
-                       R_SetupView(true);
+                       R_SetupView(true, fbo, depthtexture, colortexture);
                        if (r_timereport_active)
                                R_TimeReport("sky");
                }
        }
 
-       R_AnimCache_CacheVisibleEntities();
-       if (r_timereport_active)
-               R_TimeReport("animation");
-
-       R_Shadow_PrepareLights();
+       R_Shadow_PrepareLights(fbo, depthtexture, colortexture);
        if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0)
                R_Shadow_PrepareModelShadows();
        if (r_timereport_active)
@@ -6918,8 +7040,9 @@ void R_RenderScene(void)
 
        if (r_shadows.integer >= 2 && shadowmapping && r_refdef.lightmapintensity > 0)
        {
-               R_DrawModelShadowMaps();
-               R_ResetViewRendering3D();
+               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 ();
@@ -6946,8 +7069,9 @@ void R_RenderScene(void)
 
        if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && !r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
        {
-               R_DrawModelShadows();
-               R_ResetViewRendering3D();
+               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 ();
@@ -6966,8 +7090,9 @@ void R_RenderScene(void)
 
        if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0)
        {
-               R_DrawModelShadows();
-               R_ResetViewRendering3D();
+               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 ();
@@ -7001,7 +7126,8 @@ void R_RenderScene(void)
                        R_TimeReport("lightning");
        }
 
-       VM_CL_AddPolygonsToMeshQueue();
+       if (cl.csqc_loaded)
+               VM_CL_AddPolygonsToMeshQueue(CLVM_prog);
 
        if (r_refdef.view.showdebug)
        {
@@ -7075,8 +7201,6 @@ void R_RenderScene(void)
        // don't let sound skip if going slow
        if (r_refdef.scene.extraupdate)
                S_ExtraUpdate ();
-
-       R_ResetViewRendering2D();
 }
 
 static const unsigned short bboxelements[36] =
@@ -7089,7 +7213,7 @@ static const unsigned short bboxelements[36] =
        1, 0, 2, 1, 2, 3,
 };
 
-void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
+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];
@@ -7124,26 +7248,24 @@ void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, floa
        }
        R_Mesh_PrepareVertices_Generic_Arrays(8, vertex3f, color4f, NULL);
        R_Mesh_ResetTextureState();
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false);
+       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;
-       prvm_prog_t *prog_save = prog;
 
        // this function draws bounding boxes of server entities
        if (!sv.active)
                return;
 
        GL_CullFace(GL_NONE);
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false);
+       R_SetupShader_Generic_NoTexture(false, false);
 
-       prog = 0;
-       SV_VM_Begin();
        for (i = 0;i < numsurfaces;i++)
        {
                edict = PRVM_EDICT_NUM(surfacelist[i]);
@@ -7162,8 +7284,6 @@ static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtligh
                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]);
        }
-       SV_VM_End();
-       prog = prog_save;
 }
 
 static void R_DrawEntityBBoxes(void)
@@ -7171,14 +7291,12 @@ static void R_DrawEntityBBoxes(void)
        int i;
        prvm_edict_t *edict;
        vec3_t center;
-       prvm_prog_t *prog_save = prog;
+       prvm_prog_t *prog = SVVM_prog;
 
        // this function draws bounding boxes of server entities
        if (!sv.active)
                return;
 
-       prog = 0;
-       SV_VM_Begin();
        for (i = 0;i < prog->num_edicts;i++)
        {
                edict = PRVM_EDICT_NUM(i);
@@ -7190,10 +7308,8 @@ static void R_DrawEntityBBoxes(void)
                if(PRVM_serveredictedict(edict, viewmodelforclient) != 0)
                        continue;
                VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
-               R_MeshQueue_AddTransparent(center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)NULL);
+               R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)NULL);
        }
-       SV_VM_End();
-       prog = prog_save;
 }
 
 static const int nomodelelement3i[24] =
@@ -7240,7 +7356,7 @@ static const float nomodelcolor4f[6*4] =
        0.5f, 0.0f, 0.0f, 1.0f
 };
 
-void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
+static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
 {
        int i;
        float f1, f2, *c;
@@ -7290,7 +7406,7 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight
                }
        }
 //     R_Mesh_ResetTextureState();
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false);
+       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);
 }
@@ -7300,7 +7416,7 @@ 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 ? r_refdef.view.origin : org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
+               R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? MESHQUEUE_SORT_HUD : MESHQUEUE_SORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
        else
                R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
 }
@@ -7351,7 +7467,7 @@ void R_CalcSprite_Vertex3f(float *vertex3f, const vec3_t origin, const vec3_t le
        vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
 }
 
-int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
+static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
 {
        int i;
        float *vertex3f;
@@ -7394,7 +7510,7 @@ void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
        }
 }
 
-void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
+static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
 {
        int i;
        int *e, element[3];
@@ -7470,7 +7586,7 @@ 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)] == 0)
+               if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
                        return false;
        return true;
 }
@@ -7509,11 +7625,11 @@ static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
        }
        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)];
+               f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
        return (float) f;
 }
 
-void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
+static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
 {
        int w, h, idx;
        double f;
@@ -7535,8 +7651,9 @@ void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *t
                        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, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
+                       Matrix4x4_ConcatRotate(&matrix, (f / 360 - floor(f / 360)) * 360, 0, 0, 1);
                        Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
                        break;
                case Q3TCMOD_SCALE:
@@ -7576,7 +7693,7 @@ void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *t
        Matrix4x4_Concat(texmatrix, &matrix, &temp);
 }
 
-void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
+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];
@@ -7673,9 +7790,9 @@ texture_t *R_GetCurrentTexture(texture_t *t)
        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_waterstate.enabled && !r_refdef.view.isoverlay)
+       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_waterstate.enabled || r_refdef.view.isoverlay)
+       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;
@@ -7695,6 +7812,9 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                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))
@@ -7788,6 +7908,7 @@ texture_t *R_GetCurrentTexture(texture_t *t)
        }
        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
@@ -8361,7 +8482,7 @@ float RSurf_FogVertex(const float *v)
        return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
 }
 
-void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
+static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
 {
        int i;
        for (i = 0;i < numelements;i++)
@@ -9268,7 +9389,7 @@ static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
        r_waterstate_waterplane_t *p;
        qboolean prepared = false;
        bestd = 0;
-       for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
+       for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
        {
                if(p->camera_entity != rsurface.texture->camera_entity)
                        continue;
@@ -9601,7 +9722,7 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_
        // transparent sky would be ridiculous
        if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
                return;
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false);
+       R_SetupShader_Generic_NoTexture(false, false);
        skyrenderlater = true;
        RSurf_SetupDepthAndCulling();
        GL_DepthMask(true);
@@ -9616,7 +9737,7 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_
                R_Mesh_ResetTextureState();
                if (skyrendermasked)
                {
-                       R_SetupShader_DepthOrShadow(false);
+                       R_SetupShader_DepthOrShadow(false, false);
                        // depth-only (masking)
                        GL_ColorMask(0,0,0,0);
                        // just to make sure that braindead drivers don't draw
@@ -9630,7 +9751,7 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_
                }
                else
                {
-                       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false);
+                       R_SetupShader_Generic_NoTexture(false, false);
                        // fog sky
                        GL_BlendFunc(GL_ONE, GL_ZERO);
                        RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
@@ -9649,7 +9770,7 @@ 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_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
+       if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
                return;
        if (prepass)
        {
@@ -9657,6 +9778,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface
                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
@@ -9682,7 +9804,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface
                        {
                                // 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_waterstate.waterplanes + startplaneindex), false);
+                               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);
@@ -9693,7 +9815,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface
                        {
                                // 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_waterstate.waterplanes + startplaneindex), false);
+                               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();
                        }
                }
@@ -9925,7 +10047,7 @@ static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const
        float c[4];
 
 //     R_Mesh_ResetTextureState();
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false);
+       R_SetupShader_Generic_NoTexture(false, false);
 
        if(rsurface.texture && rsurface.texture->currentskinframe)
        {
@@ -10031,7 +10153,7 @@ static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const
                RSurf_DrawBatch_GL11_ClampColor();
 
                R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.passcolor4f, NULL);
-               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false);
+               R_SetupShader_Generic_NoTexture(false, false);
                RSurf_DrawBatch();
        }
        else if (!r_refdef.view.showdebug)
@@ -10233,7 +10355,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
                                GL_BlendFunc(GL_ONE, GL_ZERO);
                                GL_DepthMask(true);
 //                             R_Mesh_ResetTextureState();
-                               R_SetupShader_DepthOrShadow(false);
+                               R_SetupShader_DepthOrShadow(false, false);
                        }
                        RSurf_SetupDepthAndCulling();
                        RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, texturenumsurfaces, texturesurfacelist);
@@ -10292,7 +10414,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }
 
-static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, const entity_render_t *queueentity)
+static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
 {
        // transparent surfaces get pushed off into the transparent queue
        int surfacelistindex;
@@ -10301,17 +10423,26 @@ static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const
        for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
        {
                surface = texturesurfacelist[surfacelistindex];
-               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;
+               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 (queueentity->transparent_offset) // transparent offset
+               if (rsurface.entity->transparent_offset) // transparent offset
                {
-                       center[0] += r_refdef.view.forward[0]*queueentity->transparent_offset;
-                       center[1] += r_refdef.view.forward[1]*queueentity->transparent_offset;
-                       center[2] += r_refdef.view.forward[2]*queueentity->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.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_refdef.view.origin : center, R_DrawSurface_TransparentCallback, queueentity, surface - rsurface.modelsurfaces, rsurface.rtlight);
+               R_MeshQueue_AddTransparent((rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) ? MESHQUEUE_SORT_HUD : ((rsurface.entity->flags & RENDER_WORLDOBJECT) ? MESHQUEUE_SORT_SKY : MESHQUEUE_SORT_DISTANCE), center, R_DrawSurface_TransparentCallback, rsurface.entity, surface - rsurface.modelsurfaces, rsurface.rtlight);
        }
 }
 
@@ -10319,7 +10450,7 @@ static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msu
 {
        if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
                return;
-       if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
+       if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
                return;
        RSurf_SetupDepthAndCulling();
        RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, texturenumsurfaces, texturesurfacelist);
@@ -10332,7 +10463,6 @@ static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msu
 
 static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
 {
-       const entity_render_t *queueentity = r_refdef.scene.worldentity;
        CHECKGLERROR
        if (depthonly)
                R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
@@ -10341,7 +10471,7 @@ static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurf
                if (!rsurface.texture->currentnumlayers)
                        return;
                if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
-                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist, queueentity);
+                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
                else
                        R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
        }
@@ -10349,11 +10479,11 @@ static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurf
                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))) && queueentity)
+       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, queueentity);
+                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
        }
        else
        {
@@ -10363,7 +10493,7 @@ static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurf
        CHECKGLERROR
 }
 
-void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
+static void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
 {
        int i, j;
        texture_t *texture;
@@ -10409,7 +10539,7 @@ void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, in
        R_FrameData_ReturnToMark();
 }
 
-static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, const entity_render_t *queueentity, qboolean prepass)
+static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
 {
        CHECKGLERROR
        if (depthonly)
@@ -10419,7 +10549,7 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurf
                if (!rsurface.texture->currentnumlayers)
                        return;
                if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
-                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist, queueentity);
+                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
                else
                        R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
        }
@@ -10427,11 +10557,11 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurf
                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))) && queueentity)
+       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, queueentity);
+                       R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
        }
        else
        {
@@ -10441,7 +10571,7 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurf
        CHECKGLERROR
 }
 
-void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
+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;
@@ -10482,7 +10612,7 @@ void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurfa
                                ;
                }
                // render the range of surfaces
-               R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, ent, prepass);
+               R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass);
        }
        R_FrameData_ReturnToMark();
 }
@@ -10507,7 +10637,7 @@ unsigned short locboxelements[6*2*3] =
        20,21,22, 20,22,23
 };
 
-void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
+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;
@@ -10546,7 +10676,7 @@ void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, in
                        vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
 
        R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false);
+       R_SetupShader_Generic_NoTexture(false, false);
        R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
 }
 
@@ -10559,7 +10689,7 @@ void R_DrawLocs(void)
        for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
        {
                VectorLerp(loc->mins, 0.5f, loc->maxs, center);
-               R_MeshQueue_AddTransparent(center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
+               R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
        }
 }
 
@@ -11173,7 +11303,7 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
                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);
+               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);
        }
 }
@@ -11215,7 +11345,7 @@ static void R_DrawModelDecals(void)
 }
 
 extern cvar_t mod_collision_bih;
-void R_DrawDebugModel(void)
+static void R_DrawDebugModel(void)
 {
        entity_render_t *ent = rsurface.entity;
        int i, j, k, l, flagsmask;
@@ -11230,7 +11360,7 @@ void R_DrawDebugModel(void)
        {
                float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
                flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
-               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false);
+               R_SetupShader_Generic_NoTexture(false, false);
                GL_DepthTest(false);
                GL_DepthMask(false);
                GL_DepthRange(0, 1);
@@ -11260,7 +11390,7 @@ void R_DrawDebugModel(void)
        flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
 
 //     R_Mesh_ResetTextureState();
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false);
+       R_SetupShader_Generic_NoTexture(false, false);
        GL_DepthRange(0, 1);
        GL_DepthTest(!r_showdisabledepthtest.integer);
        GL_DepthMask(false);
@@ -11316,6 +11446,7 @@ void R_DrawDebugModel(void)
 
        GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
 
+#ifndef USE_GLES2
        if (r_showtris.integer && qglPolygonMode)
        {
                if (r_showdisabledepthtest.integer)
@@ -11426,9 +11557,9 @@ void R_DrawDebugModel(void)
                }
                rsurface.texture = NULL;
        }
+#endif
 }
 
-extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
 int r_maxsurfacelist = 0;
 const msurface_t **r_surfacelist = NULL;
 void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
index 967edc6f56e8a1778c593ebd3c4fab365d3835e3..bc37840189571356248e4155bdcc121cbdcca064 100644 (file)
@@ -23,12 +23,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #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", "improve framerate by culling offscreen surfaces"};
+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"};
 
 /*
@@ -120,6 +121,8 @@ void R_BuildLightMap (const entity_render_t *ent, msurface_t *surface)
                }
        }
 
+       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
@@ -162,7 +165,7 @@ void R_BuildLightMap (const entity_render_t *ent, msurface_t *surface)
        }
 }
 
-void R_StainNode (mnode_t *node, dp_model_t *model, const vec3_t origin, float radius, const float fcolor[8])
+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;
@@ -362,7 +365,7 @@ static void R_DrawPortal_Callback(const entity_render_t *ent, const rtlight_t *r
        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(NULL, NULL, GL_MODULATE, 1, false);
+       R_SetupShader_Generic_NoTexture(false, false);
        R_Mesh_Draw(0, numpoints, 0, numpoints - 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
 }
 
@@ -390,13 +393,36 @@ void R_DrawPortals(void)
                                                VectorAdd(center, portal->points[i].position, center);
                                        f = ixtable[portal->numpoints];
                                        VectorScale(center, f, center);
-                                       R_MeshQueue_AddTransparent(center, R_DrawPortal_Callback, (entity_render_t *)portal, leafnum, rsurface.rtlight);
+                                       R_MeshQueue_AddTransparent(MESHQUEUE_SORT_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;
@@ -427,6 +453,7 @@ void R_View_WorldVisibility(qboolean forcenovis)
                                                r_refdef.viewcache.world_surfacevisible[*mark] = true;
                        }
                }
+               R_View_WorldVisibility_CullSurfaces();
                return;
        }
 
@@ -540,23 +567,7 @@ void R_View_WorldVisibility(qboolean forcenovis)
                }
        }
 
-       if (r_usesurfaceculling.integer)
-       {
-               int k = model->firstmodelsurface;
-               int l = k + model->nummodelsurfaces;
-               unsigned char *visible = r_refdef.viewcache.world_surfacevisible;
-               msurface_t *surfaces = model->data_surfaces;
-               msurface_t *surface;
-               for (;k < l;k++)
-               {
-                       if (visible[k])
-                       {
-                               surface = surfaces + k;
-                               if (R_CullBox(surface->mins, surface->maxs))
-                                       visible[k] = false;
-                       }
-               }
-}
+        R_View_WorldVisibility_CullSurfaces();
 }
 
 void R_Q1BSP_DrawSky(entity_render_t *ent)
@@ -569,7 +580,6 @@ void R_Q1BSP_DrawSky(entity_render_t *ent)
                R_DrawModelSurfaces(ent, true, true, false, false, false);
 }
 
-extern void R_Water_AddWaterPlane(msurface_t *surface, int entno);
 void R_Q1BSP_DrawAddWaterPlanes(entity_render_t *ent)
 {
        int i, j, n, flagsmask;
@@ -581,7 +591,7 @@ void R_Q1BSP_DrawAddWaterPlanes(entity_render_t *ent)
        if (ent == r_refdef.scene.worldentity)
                RSurf_ActiveWorldEntity();
        else
-               RSurf_ActiveModelEntity(ent, false, false, false);
+               RSurf_ActiveModelEntity(ent, true, false, false);
 
        surfaces = model->data_surfaces;
        flagsmask = MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA;
@@ -635,7 +645,7 @@ void R_Q1BSP_DrawDepth(entity_render_t *ent)
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_DepthMask(true);
 //     R_Mesh_ResetTextureState();
-       R_SetupShader_DepthOrShadow(false);
+       R_SetupShader_DepthOrShadow(false, false);
        if (ent == r_refdef.scene.worldentity)
                R_DrawWorldSurfaces(false, false, true, false, false);
        else
@@ -1172,7 +1182,7 @@ static void R_Q1BSP_CallRecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, qboo
 
 static msurface_t *r_q1bsp_getlightinfo_surfaces;
 
-int R_Q1BSP_GetLightInfo_comparefunc(const void *ap, const void *bp)
+static int R_Q1BSP_GetLightInfo_comparefunc(const void *ap, const void *bp)
 {
        int a = *(int*)ap;
        int b = *(int*)bp;
@@ -1353,6 +1363,8 @@ void R_Q1BSP_CompileShadowMap(entity_render_t *ent, vec3_t relativelightorigin,
        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++)
@@ -1494,9 +1506,9 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surface
                                ;
                        // now figure out what to do with this particular range of surfaces
                        // VorteX: added MATERIALFLAG_NORTLIGHT
-                       if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WALL + MATERIALFLAG_NORTLIGHT)) != MATERIALFLAG_WALL)
+                       if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WALL | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NORTLIGHT)) != MATERIALFLAG_WALL)
                                continue;
-                       if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
+                       if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
                                continue;
                        if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
                        {
@@ -1504,11 +1516,26 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surface
                                for (l = k;l < kend;l++)
                                {
                                        surface = batchsurfacelist[l];
-                                       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;
+                                       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);
-                                       R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_refdef.view.origin : center, R_Q1BSP_DrawLight_TransparentCallback, ent, surface - rsurface.modelsurfaces, rsurface.rtlight);
+                                       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.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) ? MESHQUEUE_SORT_HUD : ((rsurface.entity->flags & RENDER_WORLDOBJECT) ? MESHQUEUE_SORT_SKY : MESHQUEUE_SORT_DISTANCE), center, R_Q1BSP_DrawLight_TransparentCallback, ent, surface - rsurface.modelsurfaces, rsurface.rtlight);
                                }
                                continue;
                        }
@@ -1523,7 +1550,7 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surface
 }
 
 //Made by [515]
-void R_ReplaceWorldTexture (void)
+static void R_ReplaceWorldTexture (void)
 {
        dp_model_t              *m;
        texture_t       *t;
@@ -1573,7 +1600,7 @@ void R_ReplaceWorldTexture (void)
 }
 
 //Made by [515]
-void R_ListWorldTextures (void)
+static void R_ListWorldTextures (void)
 {
        dp_model_t              *m;
        texture_t       *t;
index edefc5a64f22da3367532d97781fe5fbc31a4f30..2a81cf50b3e15caca48b98d78733c7b9b1a7bc5b 100644 (file)
@@ -10,6 +10,10 @@ extern LPDIRECT3DDEVICE9 vid_d3d9dev;
 #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%"};
@@ -76,12 +80,40 @@ typedef struct textypeinfo_s
 }
 textypeinfo_t;
 
+#ifdef USE_GLES2
+// 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_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_shadowmap16_raw             = {"shadowmap16_raw",          TEXTYPE_SHADOWMAP16_RAW      ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_shadowmap24_comp            = {"shadowmap24_comp",         TEXTYPE_SHADOWMAP24_COMP     ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_shadowmap24_raw             = {"shadowmap24_raw",          TEXTYPE_SHADOWMAP24_RAW      ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_depth16                     = {"depth16",                  TEXTYPE_DEPTHBUFFER16        ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_depth24                     = {"depth24",                  TEXTYPE_DEPTHBUFFER24        ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_depth24stencil8             = {"depth24stencil8",          TEXTYPE_DEPTHBUFFER24STENCIL8,  2,  2,  2.0f, GL_DEPTH_COMPONENT16              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_colorbuffer                 = {"colorbuffer",              TEXTYPE_COLORBUFFER          ,  2,  2,  2.0f, GL_RGB565                         , GL_RGBA           , GL_UNSIGNED_SHORT_5_6_5};
+static textypeinfo_t textype_colorbuffer16f              = {"colorbuffer16f",           TEXTYPE_COLORBUFFER16F       ,  2,  2,  2.0f, GL_RGB565                         , GL_RGBA           , GL_UNSIGNED_SHORT_5_6_5};
+static textypeinfo_t textype_colorbuffer32f              = {"colorbuffer32f",           TEXTYPE_COLORBUFFER32F       ,  2,  2,  2.0f, GL_RGB565                         , GL_RGBA           , 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 };
+#else
 // framebuffer texture formats
-static textypeinfo_t textype_shadowmap16                 = {"shadowmap16",              TEXTYPE_SHADOWMAP     ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16_ARB              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
-static textypeinfo_t textype_shadowmap24                 = {"shadowmap24",              TEXTYPE_SHADOWMAP     ,  4,  4,  4.0f, GL_DEPTH_COMPONENT24_ARB              , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
-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         };
+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 };
@@ -113,6 +145,7 @@ static textypeinfo_t textype_sRGB_dxt1                   = {"sRGB_dxt1",
 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
 {
@@ -123,16 +156,16 @@ typedef enum gltexturetype_e
 }
 gltexturetype_t;
 
-static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB};
+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_ARB,
-       GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
-       GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
-       GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
-       GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
-       GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
+       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
@@ -140,12 +173,16 @@ 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 d3disdepthsurface; // for depth/stencil surfaces
+       qboolean d3disrendertargetsurface;
+       qboolean d3disdepthstencilsurface;
        int d3dformat;
        int d3dusage;
        int d3dpool;
@@ -239,10 +276,16 @@ static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
        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_SHADOWMAP: return (flags & TEXF_LOWPRECISION) ? &textype_shadowmap16 : &textype_shadowmap24;
        case TEXTYPE_COLORBUFFER: return &textype_colorbuffer;
        case TEXTYPE_COLORBUFFER16F: return &textype_colorbuffer16f;
        case TEXTYPE_COLORBUFFER32F: return &textype_colorbuffer32f;
+       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;
@@ -325,11 +368,16 @@ void R_FreeTexture(rtexture_t *rt)
                        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->d3disdepthsurface)
-                       IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
+               if (glt->d3dsurface)
+                       IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dsurface);
                else if (glt->tiledepth > 1)
                        IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
                else if (glt->sides == 6)
@@ -337,6 +385,7 @@ void R_FreeTexture(rtexture_t *rt)
                else
                        IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
                glt->d3dtexture = NULL;
+               glt->d3dsurface = NULL;
 #endif
                break;
        case RENDERPATH_D3D10:
@@ -517,7 +566,7 @@ static void GL_TextureMode_f (void)
                        for (glt = pool->gltchain;glt;glt = glt->chain)
                        {
                                // only update already uploaded images
-                               if (glt->d3dtexture && !glt->d3disdepthsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
+                               if (glt->d3dtexture && !glt->d3dsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR))))
                                {
                                        if (glt->flags & TEXF_MIPMAP)
                                        {
@@ -681,7 +730,7 @@ void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean print
                for (glt = pool->gltchain;glt;glt = glt->chain)
                {
                        glsize = R_CalcTexelDataSize(glt);
-                       isloaded = glt->texnum != 0;
+                       isloaded = glt->texnum != 0 || glt->renderbuffernum != 0 || glt->d3dtexture || glt->d3dsurface;
                        pooltotal++;
                        pooltotalt += glsize;
                        pooltotalp += glt->inputdatasize;
@@ -792,8 +841,8 @@ static void r_textures_devicelost(void)
                        break;
                case RENDERPATH_D3D9:
 #ifdef SUPPORTD3D
-                       if (glt->d3disdepthsurface)
-                               IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dtexture);
+                       if (glt->d3dsurface)
+                               IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dsurface);
                        else if (glt->tiledepth > 1)
                                IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture);
                        else if (glt->sides == 6)
@@ -801,6 +850,7 @@ static void r_textures_devicelost(void)
                        else
                                IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture);
                        glt->d3dtexture = NULL;
+                       glt->d3dsurface = NULL;
 #endif
                        break;
                case RENDERPATH_D3D10:
@@ -837,9 +887,14 @@ static void r_textures_devicerestored(void)
 #ifdef SUPPORTD3D
                        {
                                HRESULT d3dresult;
-                               if (glt->d3disdepthsurface)
+                               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->d3dtexture, NULL)))
+                                       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)
@@ -972,7 +1027,7 @@ void R_Textures_Frame (void)
        }
 }
 
-void R_MakeResizeBufferBigger(int size)
+static void R_MakeResizeBufferBigger(int size)
 {
        if (resizebuffersize < size)
        {
@@ -1004,10 +1059,12 @@ static void GL_SetupTextureParameters(int flags, textype_t textype, int texturet
        }
        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)
@@ -1054,21 +1111,22 @@ static void GL_SetupTextureParameters(int flags, textype_t textype, int texturet
                qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
        }
 
-       if (textype == TEXTYPE_SHADOWMAP)
+       switch(textype)
        {
-               if (vid.support.arb_shadow)
-               {
-                       if (flags & TEXF_COMPARE)
-                       {
-                               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
-                       }
-                       else
-                       {
-                               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
-                       }
-                       qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
-               }
+       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
@@ -1214,86 +1272,93 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
        case RENDERPATH_GL20:
        case RENDERPATH_GLES1:
        case RENDERPATH_GLES2:
-               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
-
-               if (qglGetCompressedTexImageARB)
+               if (glt->texnum) // not renderbuffers
                {
-                       if (gl_texturecompression.integer >= 2)
-                               qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
-                       else
-                               qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
                        CHECKGLERROR
-               }
-               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:
-                       qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
-                       if (glt->flags & TEXF_MIPMAP)
+
+                       // 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)
                        {
-                               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
-                               }
+                               if (gl_texturecompression.integer >= 2)
+                                       qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST);
+                               else
+                                       qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
+                               CHECKGLERROR
                        }
-                       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++)
+#endif
+                       switch(glt->texturetype)
                        {
-                               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)
+                       case GLTEXTURETYPE_2D:
+                               qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
+                               if (glt->flags & TEXF_MIPMAP)
                                {
-                                       Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth);
-                                       prevbuffer = resizebuffer;
+                                       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
+                                       }
                                }
-                               mip = 0;
-                               qglTexImage2D(cubemapside[i], 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;
-                                               qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
+                                               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;
                        }
-                       break;
+                       GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype);
+                       qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR
                }
-               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))
+               if (!(glt->flags & TEXF_RENDERTARGET) && glt->d3dtexture && !glt->d3dsurface)
                {
                        D3DLOCKED_RECT d3dlockedrect;
                        D3DLOCKED_BOX d3dlockedbox;
@@ -1508,6 +1573,27 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
                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)
        {
@@ -1523,7 +1609,8 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
                static int rgbaswapindices[4] = {2, 1, 0, 3};
                size = width * height * depth * sides * 4;
                temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
-               Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
+               if (data)
+                       Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices);
                data = temppixels;
        }
 
@@ -1550,6 +1637,7 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
                        {
                                temppixels = (unsigned char *)Mem_Alloc(tempmempool, size);
                                memcpy(temppixels, data, size);
+                               data = temppixels;
                        }
                        Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides);
                }
@@ -1615,7 +1703,10 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
                        }
                }
                break;
-       case TEXTYPE_SHADOWMAP:
+       case TEXTYPE_SHADOWMAP16_COMP:
+       case TEXTYPE_SHADOWMAP16_RAW:
+       case TEXTYPE_SHADOWMAP24_COMP:
+       case TEXTYPE_SHADOWMAP24_RAW:
                break;
        case TEXTYPE_DXT1:
        case TEXTYPE_SRGB_DXT1:
@@ -1668,6 +1759,7 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
        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;
@@ -1709,20 +1801,15 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
                        case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break;
                        case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break;
                        case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break;
-                       case TEXTYPE_SHADOWMAP: d3dformat = D3DFMT_D16;d3dusage = D3DUSAGE_DEPTHSTENCIL;break; // note: can not use D3DUSAGE_RENDERTARGET here
                        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->d3disdepthsurface = textype == TEXTYPE_SHADOWMAP;
-                       if (glt->d3disdepthsurface)
-                       {
-                               if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dtexture, NULL)))
-                                       Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!");
-                       }
-                       else if (glt->tiledepth > 1)
+                       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!");
@@ -1757,7 +1844,13 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
                        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_SHADOWMAP: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;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);
                        }
@@ -1800,25 +1893,133 @@ rtexture_t *R_LoadTextureCubeMap(rtexturepool_t *rtexturepool, const char *ident
        return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
 }
 
-static int R_ShadowMapTextureFlags(int precision, qboolean filter)
+rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter)
 {
-       int flags = TEXF_RENDERTARGET | TEXF_CLAMP;
-       if (filter)
-               flags |= TEXF_FORCELINEAR | TEXF_COMPARE;
-       else
-               flags |= TEXF_FORCENEAREST;
-       if (precision <= 16)
-               flags |= TEXF_LOWPRECISION;
-       return flags;
+       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_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int precision, qboolean filter)
+rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype)
 {
-       return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
+       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;
@@ -1868,7 +2069,7 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco
        mipinfo[0][0] = glt->tilewidth;
        mipinfo[0][1] = glt->tileheight;
        mipmaps = 1;
-       if (glt->flags & TEXF_MIPMAP)
+       if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tilewidth == 1))
        {
                for (mip = 1;mip < 16;mip++)
                {
@@ -1911,11 +2112,11 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco
        if(hasalpha)
                dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
        memcpy(dds, "DDS ", 4);
-       StoreLittleLong(dds+4, ddssize);
+       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, 1); // depth
+       StoreLittleLong(dds+24, 0); // depth
        StoreLittleLong(dds+28, mipmaps); // mipmaps
        StoreLittleLong(dds+76, 32); // format size
        StoreLittleLong(dds+80, dds_format_flags);
@@ -1944,9 +2145,10 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco
        ret = FS_WriteFile(filename, dds, ddssize);
        Mem_Free(dds);
        return ret ? ddssize : -5;
+#endif
 }
 
-rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint
+rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qboolean srgb, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel) // 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;
@@ -1957,9 +2159,11 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
        gltexturepool_t *pool = (gltexturepool_t *)rtexturepool;
        textypeinfo_t *texinfo;
        int mip, mipwidth, mipheight, mipsize, mipsize_total;
-       unsigned int c;
+       unsigned int c, r, g, b;
        GLint oldbindtexnum = 0;
-       const unsigned char *mippixels, *ddspixels, *mippixels_start;
+       unsigned char *mippixels;
+       unsigned char *mippixels_start;
+       unsigned char *ddspixels;
        unsigned char *dds;
        fs_offset_t ddsfilesize;
        unsigned int ddssize;
@@ -2037,9 +2241,9 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                        Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
                        return NULL;
                }
-               if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
+               if (flags & TEXF_ALPHA)
                {
-                       if(r_texture_dds_load_alphamode.integer == 1)
+                       if (r_texture_dds_load_alphamode.integer == 1)
                        {
                                // check alpha
                                for (i = 0;i < size;i += bytesperblock)
@@ -2056,6 +2260,8 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                                else
                                        flags &= ~TEXF_ALPHA;
                        }
+                       else if (r_texture_dds_load_alphamode.integer == 0)
+                               textype = TEXTYPE_DXT1A;
                        else
                        {
                                flags &= ~TEXF_ALPHA;
@@ -2125,6 +2331,18 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                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;
        if(bytesperblock)
        {
@@ -2277,6 +2495,101 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
                }
        }
 
+       // 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;
@@ -2432,11 +2745,13 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
        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;
@@ -2508,6 +2823,11 @@ 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;
index 8313cf67c40cf215d679a329ab6ca7436775e581..9686dc590525d6e953ec4b6f94d2f3526d6548ee 100644 (file)
@@ -21,6 +21,20 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #ifndef GLQUAKE_H
 #define GLQUAKE_H
 
+#ifdef USE_GLES2
+#ifdef __IPHONEOS__
+#include <OpenGLES/ES2/gl.h>
+#else
+#include <SDL_opengles2.h>
+#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
@@ -40,6 +54,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 //====================================================
 
+#ifndef USE_GLES2
 // wgl uses APIENTRY
 #ifndef APIENTRY
 #define APIENTRY
@@ -307,68 +322,68 @@ extern void (GLAPIENTRY *qglMultiTexCoord3f) (GLenum, GLfloat, GLfloat, GLfloat)
 extern void (GLAPIENTRY *qglMultiTexCoord4f) (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);
 extern void (GLAPIENTRY *qglActiveTexture) (GLenum);
 extern void (GLAPIENTRY *qglClientActiveTexture) (GLenum);
-#ifndef GL_ACTIVE_TEXTURE_ARB
-#define GL_ACTIVE_TEXTURE_ARB                  0x84E0
-#define GL_CLIENT_ACTIVE_TEXTURE_ARB   0x84E1
-#define GL_MAX_TEXTURE_UNITS_ARB               0x84E2
-#define GL_TEXTURE0_ARB                                        0x84C0
-#define GL_TEXTURE1_ARB                                        0x84C1
-#define GL_TEXTURE2_ARB                                        0x84C2
-#define GL_TEXTURE3_ARB                                        0x84C3
-#define GL_TEXTURE4_ARB                                        0x84C4
-#define GL_TEXTURE5_ARB                                        0x84C5
-#define GL_TEXTURE6_ARB                                        0x84C6
-#define GL_TEXTURE7_ARB                                        0x84C7
-#define GL_TEXTURE8_ARB                                        0x84C8
-#define GL_TEXTURE9_ARB                                        0x84C9
-#define GL_TEXTURE10_ARB                               0x84CA
-#define GL_TEXTURE11_ARB                               0x84CB
-#define GL_TEXTURE12_ARB                               0x84CC
-#define GL_TEXTURE13_ARB                               0x84CD
-#define GL_TEXTURE14_ARB                               0x84CE
-#define GL_TEXTURE15_ARB                               0x84CF
-#define GL_TEXTURE16_ARB                               0x84D0
-#define GL_TEXTURE17_ARB                               0x84D1
-#define GL_TEXTURE18_ARB                               0x84D2
-#define GL_TEXTURE19_ARB                               0x84D3
-#define GL_TEXTURE20_ARB                               0x84D4
-#define GL_TEXTURE21_ARB                               0x84D5
-#define GL_TEXTURE22_ARB                               0x84D6
-#define GL_TEXTURE23_ARB                               0x84D7
-#define GL_TEXTURE24_ARB                               0x84D8
-#define GL_TEXTURE25_ARB                               0x84D9
-#define GL_TEXTURE26_ARB                               0x84DA
-#define GL_TEXTURE27_ARB                               0x84DB
-#define GL_TEXTURE28_ARB                               0x84DC
-#define GL_TEXTURE29_ARB                               0x84DD
-#define GL_TEXTURE30_ARB                               0x84DE
-#define GL_TEXTURE31_ARB                               0x84DF
+#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_ARB
-#define GL_COMBINE_ARB                                 0x8570
-#define GL_COMBINE_RGB_ARB                             0x8571
-#define GL_COMBINE_ALPHA_ARB                   0x8572
-#define GL_SOURCE0_RGB_ARB                             0x8580
-#define GL_SOURCE1_RGB_ARB                             0x8581
-#define GL_SOURCE2_RGB_ARB                             0x8582
-#define GL_SOURCE0_ALPHA_ARB                   0x8588
-#define GL_SOURCE1_ALPHA_ARB                   0x8589
-#define GL_SOURCE2_ALPHA_ARB                   0x858A
-#define GL_OPERAND0_RGB_ARB                            0x8590
-#define GL_OPERAND1_RGB_ARB                            0x8591
-#define GL_OPERAND2_RGB_ARB                            0x8592
-#define GL_OPERAND0_ALPHA_ARB                  0x8598
-#define GL_OPERAND1_ALPHA_ARB                  0x8599
-#define GL_OPERAND2_ALPHA_ARB                  0x859A
-#define GL_RGB_SCALE_ARB                               0x8573
-#define GL_ADD_SIGNED_ARB                              0x8574
-#define GL_INTERPOLATE_ARB                             0x8575
-#define GL_SUBTRACT_ARB                                        0x84E7
-#define GL_CONSTANT_ARB                                        0x8576
-#define GL_PRIMARY_COLOR_ARB                   0x8577
-#define GL_PREVIOUS_ARB                                        0x8578
+#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
@@ -395,19 +410,19 @@ extern void (GLAPIENTRY *qglTexSubImage3D)(GLenum target, GLint level, GLint xof
 extern void (GLAPIENTRY *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_ARB
-#define GL_NORMAL_MAP_ARB                          0x8511
-#define GL_REFLECTION_MAP_ARB              0x8512
-#define GL_TEXTURE_CUBE_MAP_ARB                    0x8513
-#define GL_TEXTURE_BINDING_CUBE_MAP_ARB            0x8514
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB     0x8515
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB     0x8516
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB     0x8517
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB     0x8518
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB     0x8519
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB     0x851A
-#define GL_PROXY_TEXTURE_CUBE_MAP_ARB      0x851B
-#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB               0x851C
+#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
@@ -444,56 +459,56 @@ extern void (GLAPIENTRY *qglStencilFuncSeparate)(GLenum, GLenum, GLint, GLuint);
 extern void (GLAPIENTRY *qglActiveStencilFaceEXT)(GLenum);
 
 //GL_EXT_blend_minmax
-#ifndef GL_FUNC_ADD_EXT
-#define GL_FUNC_ADD_EXT                   0x8006 // also supplied by GL_EXT_blend_subtract
-#define GL_MIN_EXT                        0x8007
-#define GL_MAX_EXT                        0x8008
-#define GL_BLEND_EQUATION_EXT             0x8009 // also supplied by GL_EXT_blend_subtract
-extern void (GLAPIENTRY *qglBlendEquationEXT)(GLenum); // also supplied by GL_EXT_blend_subtract
+#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 (GLAPIENTRY *qglBlendEquationEXT)(GLenum); // also supplied by GL_blend_subtract
 #endif
 
 //GL_EXT_blend_subtract
-#ifndef GL_FUNC_SUBTRACT_EXT
-#define GL_FUNC_SUBTRACT_EXT              0x800A
-#define GL_FUNC_REVERSE_SUBTRACT_EXT      0x800B
-extern void (GLAPIENTRY *qglBlendEquationEXT)(GLenum); // also supplied by GL_EXT_blend_subtract
+#ifndef GL_FUNC_SUBTRACT
+#define GL_FUNC_SUBTRACT              0x800A
+#define GL_FUNC_REVERSE_SUBTRACT      0x800B
+extern void (GLAPIENTRY *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_ARB
-#define GL_ARRAY_BUFFER_ARB               0x8892
-#define GL_ELEMENT_ARRAY_BUFFER_ARB       0x8893
-#define GL_ARRAY_BUFFER_BINDING_ARB       0x8894
-#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895
-#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896
-#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897
-#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898
-#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899
-#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A
-#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B
-#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C
-#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D
-#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E
-#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F
-#define GL_STREAM_DRAW_ARB                0x88E0
-#define GL_STREAM_READ_ARB                0x88E1
-#define GL_STREAM_COPY_ARB                0x88E2
-#define GL_STATIC_DRAW_ARB                0x88E4
-#define GL_STATIC_READ_ARB                0x88E5
-#define GL_STATIC_COPY_ARB                0x88E6
-#define GL_DYNAMIC_DRAW_ARB               0x88E8
-#define GL_DYNAMIC_READ_ARB               0x88E9
-#define GL_DYNAMIC_COPY_ARB               0x88EA
-#define GL_READ_ONLY_ARB                  0x88B8
-#define GL_WRITE_ONLY_ARB                 0x88B9
-#define GL_READ_WRITE_ARB                 0x88BA
-#define GL_BUFFER_SIZE_ARB                0x8764
-#define GL_BUFFER_USAGE_ARB               0x8765
-#define GL_BUFFER_ACCESS_ARB              0x88BB
-#define GL_BUFFER_MAPPED_ARB              0x88BC
-#define GL_BUFFER_MAP_POINTER_ARB         0x88BD
+#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 (GLAPIENTRY *qglBindBufferARB) (GLenum target, GLuint buffer);
 extern void (GLAPIENTRY *qglDeleteBuffersARB) (GLsizei n, const GLuint *buffers);
@@ -504,77 +519,104 @@ extern GLboolean (GLAPIENTRY *qglUnmapBufferARB) (GLenum target);
 extern void (GLAPIENTRY *qglBufferDataARB) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage);
 extern void (GLAPIENTRY *qglBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data);
 
-//GL_EXT_framebuffer_object
-#ifndef GL_FRAMEBUFFER_EXT
-#define GL_FRAMEBUFFER_EXT                                   0x8D40
-#define GL_RENDERBUFFER_EXT                                  0x8D41
-#define GL_STENCIL_INDEX1_EXT                                0x8D46
-#define GL_STENCIL_INDEX4_EXT                                0x8D47
-#define GL_STENCIL_INDEX8_EXT                                0x8D48
-#define GL_STENCIL_INDEX16_EXT                               0x8D49
-#define GL_RENDERBUFFER_WIDTH_EXT                            0x8D42
-#define GL_RENDERBUFFER_HEIGHT_EXT                           0x8D43
-#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT                  0x8D44
-#define GL_RENDERBUFFER_RED_SIZE_EXT                         0x8D50
-#define GL_RENDERBUFFER_GREEN_SIZE_EXT                       0x8D51
-#define GL_RENDERBUFFER_BLUE_SIZE_EXT                        0x8D52
-#define GL_RENDERBUFFER_ALPHA_SIZE_EXT                       0x8D53
-#define GL_RENDERBUFFER_DEPTH_SIZE_EXT                       0x8D54
-#define GL_RENDERBUFFER_STENCIL_SIZE_EXT                     0x8D55
-#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT            0x8CD0
-#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT            0x8CD1
-#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT          0x8CD2
-#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT  0x8CD3
-#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT     0x8CD4
-#define GL_COLOR_ATTACHMENT0_EXT                             0x8CE0
-#define GL_COLOR_ATTACHMENT1_EXT                             0x8CE1
-#define GL_COLOR_ATTACHMENT2_EXT                             0x8CE2
-#define GL_COLOR_ATTACHMENT3_EXT                             0x8CE3
-#define GL_COLOR_ATTACHMENT4_EXT                             0x8CE4
-#define GL_COLOR_ATTACHMENT5_EXT                             0x8CE5
-#define GL_COLOR_ATTACHMENT6_EXT                             0x8CE6
-#define GL_COLOR_ATTACHMENT7_EXT                             0x8CE7
-#define GL_COLOR_ATTACHMENT8_EXT                             0x8CE8
-#define GL_COLOR_ATTACHMENT9_EXT                             0x8CE9
-#define GL_COLOR_ATTACHMENT10_EXT                            0x8CEA
-#define GL_COLOR_ATTACHMENT11_EXT                            0x8CEB
-#define GL_COLOR_ATTACHMENT12_EXT                            0x8CEC
-#define GL_COLOR_ATTACHMENT13_EXT                            0x8CED
-#define GL_COLOR_ATTACHMENT14_EXT                            0x8CEE
-#define GL_COLOR_ATTACHMENT15_EXT                            0x8CEF
-#define GL_DEPTH_ATTACHMENT_EXT                              0x8D00
-#define GL_STENCIL_ATTACHMENT_EXT                            0x8D20
-#define GL_FRAMEBUFFER_COMPLETE_EXT                          0x8CD5
-#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT             0x8CD6
-#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT     0x8CD7
-#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT             0x8CD9
-#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT                0x8CDA
-#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT            0x8CDB
-#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT            0x8CDC
-#define GL_FRAMEBUFFER_UNSUPPORTED_EXT                       0x8CDD
-#define GL_FRAMEBUFFER_BINDING_EXT                           0x8CA6
-#define GL_RENDERBUFFER_BINDING_EXT                          0x8CA7
-#define GL_MAX_COLOR_ATTACHMENTS_EXT                         0x8CDF
-#define GL_MAX_RENDERBUFFER_SIZE_EXT                         0x84E8
-#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT                 0x0506
-#endif
-extern GLboolean (GLAPIENTRY *qglIsRenderbufferEXT)(GLuint renderbuffer);
-extern void (GLAPIENTRY *qglBindRenderbufferEXT)(GLenum target, GLuint renderbuffer);
-extern void (GLAPIENTRY *qglDeleteRenderbuffersEXT)(GLsizei n, const GLuint *renderbuffers);
-extern void (GLAPIENTRY *qglGenRenderbuffersEXT)(GLsizei n, GLuint *renderbuffers);
-extern void (GLAPIENTRY *qglRenderbufferStorageEXT)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
-extern void (GLAPIENTRY *qglGetRenderbufferParameterivEXT)(GLenum target, GLenum pname, GLint *params);
-extern GLboolean (GLAPIENTRY *qglIsFramebufferEXT)(GLuint framebuffer);
-extern void (GLAPIENTRY *qglBindFramebufferEXT)(GLenum target, GLuint framebuffer);
-extern void (GLAPIENTRY *qglDeleteFramebuffersEXT)(GLsizei n, const GLuint *framebuffers);
-extern void (GLAPIENTRY *qglGenFramebuffersEXT)(GLsizei n, GLuint *framebuffers);
-extern GLenum (GLAPIENTRY *qglCheckFramebufferStatusEXT)(GLenum target);
-//extern void (GLAPIENTRY *qglFramebufferTexture1DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
-extern void (GLAPIENTRY *qglFramebufferTexture2DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
-extern void (GLAPIENTRY *qglFramebufferTexture3DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
-extern void (GLAPIENTRY *qglFramebufferRenderbufferEXT)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
-extern void (GLAPIENTRY *qglGetFramebufferAttachmentParameterivEXT)(GLenum target, GLenum attachment, GLenum pname, GLint *params);
-extern void (GLAPIENTRY *qglGenerateMipmapEXT)(GLenum target);
+//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 (GLAPIENTRY *qglIsRenderbuffer)(GLuint renderbuffer);
+extern GLvoid (GLAPIENTRY *qglBindRenderbuffer)(GLenum target, GLuint renderbuffer);
+extern GLvoid (GLAPIENTRY *qglDeleteRenderbuffers)(GLsizei n, const GLuint *renderbuffers);
+extern GLvoid (GLAPIENTRY *qglGenRenderbuffers)(GLsizei n, GLuint *renderbuffers);
+extern GLvoid (GLAPIENTRY *qglRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+extern GLvoid (GLAPIENTRY *qglRenderbufferStorageMultisample)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+extern GLvoid (GLAPIENTRY *qglGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint *params);
+extern GLboolean (GLAPIENTRY *qglIsFramebuffer)(GLuint framebuffer);
+extern GLvoid (GLAPIENTRY *qglBindFramebuffer)(GLenum target, GLuint framebuffer);
+extern GLvoid (GLAPIENTRY *qglDeleteFramebuffers)(GLsizei n, const GLuint *framebuffers);
+extern GLvoid (GLAPIENTRY *qglGenFramebuffers)(GLsizei n, GLuint *framebuffers);
+extern GLenum (GLAPIENTRY *qglCheckFramebufferStatus)(GLenum target);
+extern GLvoid (GLAPIENTRY *qglFramebufferTexture1D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+extern GLvoid (GLAPIENTRY *qglFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+extern GLvoid (GLAPIENTRY *qglFramebufferTexture3D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint layer);
+extern GLvoid (GLAPIENTRY *qglFramebufferTextureLayer)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+extern GLvoid (GLAPIENTRY *qglFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+extern GLvoid (GLAPIENTRY *qglGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint *params);
+extern GLvoid (GLAPIENTRY *qglBlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+extern GLvoid (GLAPIENTRY *qglGenerateMipmap)(GLenum target);
 
 // GL_ARB_draw_buffers
 #ifndef GL_MAX_DRAW_BUFFERS_ARB
@@ -667,6 +709,7 @@ extern void (GLAPIENTRY *qglClearDepth)(GLclampd depth);
 extern void (GLAPIENTRY *qglDepthFunc)(GLenum func);
 extern void (GLAPIENTRY *qglDepthMask)(GLboolean flag);
 extern void (GLAPIENTRY *qglDepthRange)(GLclampd near_val, GLclampd far_val);
+extern void (GLAPIENTRY *qglDepthRangef)(GLclampf near_val, GLclampf far_val);
 extern void (GLAPIENTRY *qglColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
 
 extern void (GLAPIENTRY *qglDrawRangeElements)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
@@ -1003,6 +1046,13 @@ extern void (GLAPIENTRY *qglSampleCoverageARB)(GLclampf value, GLboolean invert)
 
 extern void (GLAPIENTRY *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
@@ -1013,5 +1063,226 @@ void GL_PrintError(int errornumber, const char *filename, int linenumber);
 #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
 
index af0d11968e64bca065d1212d05118a0621453792..e740632df4884cd0789cbfbc80e04962eff00a5e 100644 (file)
@@ -8,10 +8,10 @@ qboolean hmac(
        const unsigned char *key, int k
 )
 {
-       static unsigned char hashbuf[32];
-       static unsigned char k_xor_ipad[128];
-       static unsigned char k_xor_opad[128];
-       static unsigned char catbuf[65600]; // 65535 bytes max quake packet size + 64 for the hash
+       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)
@@ -20,10 +20,8 @@ qboolean hmac(
                return false;
        if(sizeof(k_xor_ipad) < (size_t) hlen)
                return false;
-       if(sizeof(catbuf) < (size_t) hblock + (size_t) hlen)
-               return false;
-       if(sizeof(catbuf) < (size_t) hblock + (size_t) n)
-               return false;
+
+       catbuf = (unsigned char *)Mem_Alloc(tempmempool, (size_t) hblock + max((size_t) hlen, (size_t) n));
 
        if(k > hblock)
        {
@@ -56,5 +54,8 @@ qboolean hmac(
        memcpy(catbuf, k_xor_opad, hblock);
        memcpy(catbuf + hblock, hashbuf, hlen);
        hfunc(out, catbuf, hblock + hlen);
+
+       Mem_Free(catbuf);
+
        return true;
 }
index e7a37d9bea54788470e245d92d35c7e2708b67ef..a8a8e0de767d63be34b39acf583f824f0e9aea70 100644 (file)
@@ -24,13 +24,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include <time.h>
 #include "libcurl.h"
 #include "cdaudio.h"
-#include "cl_gecko.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"
 
 /*
 
@@ -49,17 +49,19 @@ int host_framecount = 0;
 // LordHavoc: set when quit is executed
 qboolean host_shuttingdown = false;
 
-// the real time since application started, without any slowmo or clamping
+// 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;
-double host_starttime = 0;
 
 // 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."};
@@ -83,6 +85,9 @@ cvar_t developer_entityparsing = {0, "developer_entityparsing", "0", "prints det
 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
@@ -92,6 +97,9 @@ aborts the current host frame and goes on with the next one
 */
 void Host_AbortCurrentFrame(void)
 {
+       // in case we were previously nice, make us mean again
+       Sys_MakeProcessMean();
+
        longjmp (host_abortframe, 1);
 }
 
@@ -104,8 +112,8 @@ This shuts down both the client and server
 */
 void Host_Error (const char *error, ...)
 {
-       static char hosterrorstring1[MAX_INPUTLINE];
-       static char hosterrorstring2[MAX_INPUTLINE];
+       static char hosterrorstring1[MAX_INPUTLINE]; // THREAD UNSAFE
+       static char hosterrorstring2[MAX_INPUTLINE]; // THREAD UNSAFE
        static qboolean hosterror = false;
        va_list argptr;
 
@@ -137,10 +145,17 @@ void Host_Error (const char *error, ...)
        //PR_Crash();
 
        // print out where the crash happened, if it was caused by QC (and do a cleanup)
-       PRVM_Crash();
+       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
@@ -153,7 +168,7 @@ void Host_Error (const char *error, ...)
        Host_AbortCurrentFrame();
 }
 
-void Host_ServerOptions (void)
+static void Host_ServerOptions (void)
 {
        int i;
 
@@ -217,6 +232,7 @@ 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);
@@ -252,7 +268,7 @@ Host_SaveConfig_f
 Writes key bindings and archived cvars to config.cfg
 ===============
 */
-void Host_SaveConfig_to(const char *file)
+static void Host_SaveConfig_to(const char *file)
 {
        qfile_t *f;
 
@@ -290,7 +306,7 @@ void Host_SaveConfig_f(void)
        Host_SaveConfig_to(file);
 }
 
-void Host_AddConfigText(void)
+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
@@ -435,6 +451,7 @@ 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);
 
@@ -470,8 +487,9 @@ void SV_DropClient(qboolean crash)
                // 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);
-               PRVM_ExecuteProgram(PRVM_serverfunction(ClientDisconnect), "QC function ClientDisconnect is missing");
+               prog->ExecuteProgram(prog, PRVM_serverfunction(ClientDisconnect), "QC function ClientDisconnect is missing");
                PRVM_serverglobaledict(self) = saveSelf;
        }
 
@@ -521,7 +539,7 @@ void SV_DropClient(qboolean crash)
        if (sv.active)
        {
                // clear a fields that matter to DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS, and also frags
-               PRVM_ED_ClearEdict(host_client->edict);
+               PRVM_ED_ClearEdict(prog, host_client->edict);
        }
 
        // clear the client struct (this sets active to false)
@@ -553,6 +571,7 @@ 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");
@@ -564,19 +583,20 @@ void Host_ShutdownServer(void)
        NetConn_Heartbeat(2);
 
 // make sure all the clients know we're disconnecting
-       SV_VM_Begin();
        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
-                       PRVM_ExecuteProgram(s,"SV_Shutdown() required");
+                       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
-       SV_VM_End();
 
        NetConn_CloseServerPorts();
 
@@ -586,6 +606,8 @@ void Host_ShutdownServer(void)
 //
        memset(&sv, 0, sizeof(sv));
        memset(svs.clients, 0, svs.maxclients*sizeof(client_t));
+
+       cl.islocalgame = false;
 }
 
 
@@ -598,7 +620,7 @@ Host_GetConsoleCommands
 Add them exactly as if they had been typed at the console
 ===================
 */
-void Host_GetConsoleCommands (void)
+static void Host_GetConsoleCommands (void)
 {
        char *cmd;
 
@@ -618,9 +640,9 @@ Host_TimeReport
 Returns a time report string, for example for
 ==================
 */
-const char *Host_TimingReport(void)
+const char *Host_TimingReport(char *buf, size_t buflen)
 {
-       return va("%.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);
+       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);
 }
 
 /*
@@ -636,17 +658,16 @@ void Host_Main(void)
        double time1 = 0;
        double time2 = 0;
        double time3 = 0;
-       double cl_timer, sv_timer;
-       double clframetime, deltarealtime, oldrealtime;
+       double cl_timer = 0, sv_timer = 0;
+       double clframetime, deltacleantime, olddirtytime, dirtytime;
        double wait;
        int pass1, pass2, pass3, i;
+       char vabuf[1024];
 
        Host_Init();
 
-       cl_timer = 0;
-       sv_timer = 0;
-
-       realtime = host_starttime = Sys_DoubleTime();
+       realtime = 0;
+       dirtytime = Sys_DirtyTime();
        for (;;)
        {
                if (setjmp(host_abortframe))
@@ -655,39 +676,56 @@ void Host_Main(void)
                        continue;                       // something bad happened, or the server disconnected
                }
 
-               oldrealtime = realtime;
-               realtime = Sys_DoubleTime();
-
-               deltarealtime = realtime - oldrealtime;
-               cl_timer += deltarealtime;
-               sv_timer += deltarealtime;
-
-               svs.perf_acc_realtime += deltarealtime;
-
-               // Look for clients who have spawned
-               for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
-                       if(host_client->spawned)
-                               if(host_client->netconnection)
-                                       break;
-               if(i == svs.maxclients)
+               olddirtytime = host_dirtytime;
+               dirtytime = Sys_DirtyTime();
+               deltacleantime = dirtytime - olddirtytime;
+               if (deltacleantime < 0)
                {
-                       // Nobody is looking? Then we won't do timing...
-                       // Instead, reset it to zero
-                       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;
+                       // 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(svs.perf_acc_realtime > 5)
+               else if (deltacleantime >= 1800)
                {
-                       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)
+                       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
+                       for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
+                               if(host_client->spawned)
+                                       if(host_client->netconnection)
+                                               break;
+                       if(i == svs.maxclients)
+                       {
+                               // Nobody is looking? Then we won't do timing...
+                               // Instead, reset it to zero
+                               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_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);
+                               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)
+                                       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(svs.perf_lost > 0 && developer_extra.integer)
-                               Con_DPrintf("Server can't keep up: %s\n", Host_TimingReport());
-                       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)
@@ -699,8 +737,6 @@ void Host_Main(void)
                if(!*sv_random_seed.string && !cls.demoplayback)
                        rand();
 
-               cl.islocalgame = NetConn_IsLocalGame();
-
                // get new key events
                Key_EventQueue_Unblock();
                SndSys_SendKeyEvents();
@@ -712,7 +748,7 @@ void Host_Main(void)
 
                // receive packets on each main loop iteration, as the main loop may
                // be undersleeping due to select() detecting a new packet
-               if (sv.active)
+               if (sv.active && !svs.threaded)
                        NetConn_ServerFrame();
 
                Curl_Run();
@@ -728,7 +764,7 @@ void Host_Main(void)
                        // process console commands
 //                     R_TimeReport("preconsole");
                        CL_VM_PreventInformationLeaks();
-                       Cbuf_Execute();
+                       Cbuf_Frame();
 //                     R_TimeReport("console");
                }
 
@@ -737,14 +773,14 @@ void Host_Main(void)
                // 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)
+               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;
+                       double time0, delta;
 
                        if(host_maxwait.value <= 0)
                                wait = min(wait, 1000000.0);
@@ -753,16 +789,29 @@ void Host_Main(void)
                        if(wait < 1)
                                wait = 1; // because we cast to int
 
-                       time0 = Sys_DoubleTime();
-                       if (sv_checkforpacketsduringsleep.integer && !sys_usenoclockbutbenchmark.integer)
+                       time0 = Sys_DirtyTime();
+                       if (sv_checkforpacketsduringsleep.integer && !sys_usenoclockbutbenchmark.integer && !svs.threaded)
                                NetConn_SleepMicroseconds((int)wait);
                        else
                                Sys_Sleep((int)wait);
-                       svs.perf_acc_sleeptime += Sys_DoubleTime() - time0;
+                       delta = Sys_DirtyTime() - time0;
+                       if (delta < 0 || delta >= 1800) delta = 0;
+                       if (!svs.threaded)
+                               svs.perf_acc_sleeptime += delta;
 //                     R_TimeReport("sleep");
                        continue;
                }
 
+               // 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("---");
 
        //-------------------
@@ -772,15 +821,7 @@ void Host_Main(void)
        //-------------------
 
                // limit the frametime steps to no more than 100ms each
-               if (cl_timer > 0.1)
-                       cl_timer = 0.1;
-               if (sv_timer > 0.1)
-               {
-                       svs.perf_acc_lost += (sv_timer - 0.1);
-                       sv_timer = 0.1;
-               }
-
-               if (sv.active && sv_timer > 0)
+               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
@@ -789,9 +830,7 @@ void Host_Main(void)
                        int framecount, framelimit = 1;
                        double advancetime, aborttime = 0;
                        float offset;
-
-                       if (cls.state == ca_dedicated)
-                               Collision_Cache_NewFrame();
+                       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
@@ -801,20 +840,15 @@ void Host_Main(void)
                                advancetime = sv_timer;
                        else if (cl.islocalgame && !sv_fixedframeratesingleplayer.integer)
                        {
-                               // synchronize to the client frametime, but no less than 10ms and no more than sys_ticrate
-                               advancetime = bound(0.01, cl_timer, sys_ticrate.value);
-                               framelimit = 10;
-                               aborttime = realtime + 0.1;
+                               // 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
-                               if (cls.state == ca_connected)
-                               {
-                                       framelimit = 10;
-                                       aborttime = realtime + 0.1;
-                               }
+                               framelimit = cl_maxphysicsframesperserverframe.integer;
+                               aborttime = Sys_DirtyTime() + 0.1;
                        }
                        if(slowmo.value > 0 && slowmo.value < 1)
                                advancetime = min(advancetime, 0.1 / slowmo.value);
@@ -823,7 +857,8 @@ void Host_Main(void)
 
                        if(advancetime > 0)
                        {
-                               offset = sv_timer + (Sys_DoubleTime() - realtime);
+                               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;
@@ -839,9 +874,6 @@ void Host_Main(void)
                        if (sv.paused || (cl.islocalgame && (key_dest != key_game || key_consoleactive || cl.csqc_paused)))
                                sv.frametime = 0;
 
-                       // setup the VM frame
-                       SV_VM_Begin();
-
                        for (framecount = 0;framecount < framelimit && sv_timer > 0;framecount++)
                        {
                                sv_timer -= advancetime;
@@ -851,27 +883,25 @@ void Host_Main(void)
                                        SV_Physics();
 
                                // if this server frame took too long, break out of the loop
-                               if (framelimit > 1 && Sys_DoubleTime() >= aborttime)
+                               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.generic[OFS_PARM0] = realtime - sv.pausedstart;
-                               PRVM_ExecuteProgram(PRVM_serverfunction(SV_PausedTic), "QC function SV_PausedTic is missing");
+                               PRVM_serverglobalfloat(time) = sv.time;
+                               prog->ExecuteProgram(prog, PRVM_serverfunction(SV_PausedTic), "QC function SV_PausedTic is missing");
                        }
 
-                       // end the server VM frame
-                       SV_VM_End();
-
                        // send an heartbeat if enough time has passed since the last one
                        NetConn_Heartbeat(0);
                        R_TimeReport("servernetwork");
                }
-               else
+               else if (!svs.threaded)
                {
                        // don't let r_speeds display jump around
                        R_TimeReport("serverphysics");
@@ -943,7 +973,7 @@ void Host_Main(void)
 
                        // update video
                        if (host_speeds.integer)
-                               time1 = Sys_DoubleTime();
+                               time1 = Sys_DirtyTime();
                        R_TimeReport("pre-input");
 
                        // Collect input into cmd
@@ -967,7 +997,6 @@ void Host_Main(void)
                        R_TimeReport("lerpworld");
 
                        CL_Video_Frame();
-                       CL_Gecko_Frame();
 
                        R_TimeReport("client");
 
@@ -975,7 +1004,7 @@ void Host_Main(void)
                        R_TimeReport("render");
 
                        if (host_speeds.integer)
-                               time2 = Sys_DoubleTime();
+                               time2 = Sys_DirtyTime();
 
                        // update audio
                        if(cl.csqc_usecsqclistener)
@@ -995,7 +1024,7 @@ void Host_Main(void)
                        if (host_speeds.integer)
                        {
                                pass1 = (int)((time1 - time3)*1000000);
-                               time3 = Sys_DoubleTime();
+                               time3 = Sys_DirtyTime();
                                pass2 = (int)((time2 - time1)*1000000);
                                pass3 = (int)((time3 - time2)*1000000);
                                Con_Printf("%6ius total %6ius server %6ius gfx %6ius snd\n",
@@ -1015,7 +1044,8 @@ void Host_Main(void)
                        cl_timer = 0;
                if (sv_timer >= 0)
                {
-                       svs.perf_acc_lost += sv_timer;
+                       if (!svs.threaded)
+                               svs.perf_acc_lost += sv_timer;
                        sv_timer = 0;
                }
 
@@ -1042,17 +1072,65 @@ char engineversion[128];
 
 qboolean sys_nostdout = false;
 
-extern void u8_Init(void);
-extern void Render_Init(void);
-extern void Mathlib_Init(void);
-extern void FS_Init_SelfPack(void);
-extern void FS_Init(void);
-extern void FS_Shutdown(void);
-extern void PR_Cmd_Init(void);
-extern void COM_Init_Commands(void);
-extern void FS_Init_Commands(void);
 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)
+       {
+               char vabuf[1024];
+               locksession_fh = FS_SysOpen(va(vabuf, sizeof(vabuf), "%slock%s", *fs_userdir ? fs_userdir : fs_basedir, sessionid.string), "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 %slock%s could not be acquired. Please run with -sessionid and an unique session name. Continuing anyway.\n", *fs_userdir ? fs_userdir : fs_basedir, sessionid.string);
+                       }
+                       else
+                       {
+                               Sys_Error("session lock %slock%s could not be acquired. Please run with -sessionid and an unique session name.\n", *fs_userdir ? fs_userdir : fs_basedir, sessionid.string);
+                       }
+               }
+       }
+}
+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
@@ -1062,6 +1140,7 @@ static void Host_Init (void)
 {
        int i;
        const char* os;
+       char vabuf[1024];
 
        if (COM_CheckParm("-profilegameonly"))
                Sys_AllowProfiling(false);
@@ -1082,7 +1161,7 @@ static void Host_Init (void)
                developer.string = "1";
        }
 
-       if (COM_CheckParm("-developer2"))
+       if (COM_CheckParm("-developer2") || COM_CheckParm("-developer3"))
        {
                developer.value = developer.integer = 1;
                developer.string = "1";
@@ -1096,6 +1175,12 @@ static void Host_Init (void)
                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;
@@ -1134,12 +1219,18 @@ static void Host_Init (void)
        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();
@@ -1157,6 +1248,8 @@ static void Host_Init (void)
        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
@@ -1166,7 +1259,6 @@ static void Host_Init (void)
                R_Modules_Init();
                Palette_Init();
                MR_Init_Commands();
-               Thread_Init();
                VID_Shared_Init();
                VID_Init();
                Render_Init();
@@ -1212,7 +1304,7 @@ static void Host_Init (void)
        if (i && i + 1 < com_argc)
        if (!sv.active && !cls.demoplayback && !cls.connect_trying)
        {
-               Cbuf_AddText(va("timedemo %s\n", com_argv[i + 1]));
+               Cbuf_AddText(va(vabuf, sizeof(vabuf), "timedemo %s\n", com_argv[i + 1]));
                Cbuf_Execute();
        }
 
@@ -1222,7 +1314,7 @@ static void Host_Init (void)
        if (i && i + 1 < com_argc)
        if (!sv.active && !cls.demoplayback && !cls.connect_trying)
        {
-               Cbuf_AddText(va("playdemo %s\n", com_argv[i + 1]));
+               Cbuf_AddText(va(vabuf, sizeof(vabuf), "playdemo %s\n", com_argv[i + 1]));
                Cbuf_Execute();
        }
 
@@ -1231,7 +1323,7 @@ static void Host_Init (void)
        if (i && i + 1 < com_argc)
        if (!sv.active && !cls.demoplayback && !cls.connect_trying)
        {
-               Cbuf_AddText(va("playdemo %s\ncl_capturevideo 1\n", com_argv[i + 1]));
+               Cbuf_AddText(va(vabuf, sizeof(vabuf), "playdemo %s\ncl_capturevideo 1\n", com_argv[i + 1]));
                Cbuf_Execute();
        }
 
@@ -1251,6 +1343,9 @@ static void Host_Init (void)
        Con_DPrint("========Initialized=========\n");
 
        //Host_StartVideo();
+
+       if (cls.state != ca_dedicated)
+               SV_StartThread();
 }
 
 
@@ -1281,11 +1376,17 @@ void Host_Shutdown(void)
        // 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)
@@ -1294,7 +1395,6 @@ void Host_Shutdown(void)
        // AK shutdown PRVM
        // AK hmm, no PRVM_Shutdown(); yet
 
-       CL_Gecko_Shutdown();
        CL_Video_Shutdown();
 
        Host_SaveConfig();
@@ -1309,16 +1409,20 @@ void Host_Shutdown(void)
        {
                R_Modules_Shutdown();
                VID_Shutdown();
-               Thread_Shutdown();
        }
 
+       SV_StopThread();
+       Thread_Shutdown();
        Cmd_Shutdown();
        Key_Shutdown();
        CL_Shutdown();
        Sys_Shutdown();
        Log_Close();
        Crypto_Shutdown();
-       FS_Shutdown();
+
+       Host_UnlockSession();
+
+       S_Shutdown();
        Con_Shutdown();
        Memory_Shutdown();
 }
index b8ac161b373e91de131094e08969e571d8ef20ed..e5d477cb3b15bd117d6078e8698baa107f0f50e1 100644 (file)
@@ -34,6 +34,7 @@ cvar_t sv_cheats = {0, "sv_cheats", "0", "enables cheat commands in any game, an
 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"};
@@ -66,14 +67,16 @@ void Host_Quit_f (void)
 Host_Status_f
 ==================
 */
-void Host_Status_f (void)
+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)
        {
@@ -90,10 +93,7 @@ void Host_Status_f (void)
 
        if (!sv.active)
                return;
-       
-       if(cmd_source == src_command)
-               SV_VM_Begin();
-       
+
        in = 0;
        if (Cmd_Argc() == 2)
        {
@@ -110,7 +110,7 @@ void Host_Status_f (void)
        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());
+       print ("timing:   %s\n", Host_TimingReport(vabuf, sizeof(vabuf)));
        print ("players:  %i active (%i max)\n\n", players, svs.maxclients);
 
        if (in == 1)
@@ -158,7 +158,7 @@ void Host_Status_f (void)
                if(sv_status_show_qcstatus.integer)
                {
                        prvm_edict_t *ed = PRVM_EDICT_NUM(i + 1);
-                       const char *str = PRVM_GetString(PRVM_serveredictstring(ed, clientstatus));
+                       const char *str = PRVM_GetString(prog, PRVM_serveredictstring(ed, clientstatus));
                        if(str && *str)
                        {
                                char *p;
@@ -197,9 +197,6 @@ void Host_Status_f (void)
                        print ("%s%-47s #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, i+1, client->name);
                }
        }
-
-       if(cmd_source == src_command)
-               SV_VM_End();
 }
 
 
@@ -210,8 +207,9 @@ Host_God_f
 Sets client to godmode
 ==================
 */
-void Host_God_f (void)
+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");
@@ -225,8 +223,9 @@ void Host_God_f (void)
                SV_ClientPrint("godmode ON\n");
 }
 
-void Host_Notarget_f (void)
+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");
@@ -242,8 +241,9 @@ void Host_Notarget_f (void)
 
 qboolean noclip_anglehack;
 
-void Host_Noclip_f (void)
+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");
@@ -271,8 +271,9 @@ Host_Fly_f
 Sets client to flymode
 ==================
 */
-void Host_Fly_f (void)
+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");
@@ -299,7 +300,7 @@ Host_Ping_f
 ==================
 */
 void Host_Pings_f (void); // called by Host_Ping_f
-void Host_Ping_f (void)
+static void Host_Ping_f (void)
 {
        int i;
        client_t *client;
@@ -351,7 +352,7 @@ map <servername>
 command from the console.  Active clients are kicked off.
 ======================
 */
-void Host_Map_f (void)
+static void Host_Map_f (void)
 {
        char level[MAX_QPATH];
 
@@ -398,7 +399,7 @@ Host_Changelevel_f
 Goes to a new map, taking all clients along
 ==================
 */
-void Host_Changelevel_f (void)
+static void Host_Changelevel_f (void)
 {
        char level[MAX_QPATH];
 
@@ -418,9 +419,7 @@ void Host_Changelevel_f (void)
                MR_ToggleMenu(0);
        key_dest = key_game;
 
-       SV_VM_Begin();
        SV_SaveSpawnparms ();
-       SV_VM_End();
        allowcheats = sv_cheats.integer != 0;
        strlcpy(level, Cmd_Argv(1), sizeof(level));
        SV_SpawnServer(level);
@@ -435,7 +434,7 @@ Host_Restart_f
 Restarts the current server for a dead player
 ==================
 */
-void Host_Restart_f (void)
+static void Host_Restart_f (void)
 {
        char mapname[MAX_QPATH];
 
@@ -525,7 +524,7 @@ Host_Connect_f
 User command to connect to server
 =====================
 */
-void Host_Connect_f (void)
+static void Host_Connect_f (void)
 {
        if (Cmd_Argc() < 2)
        {
@@ -549,7 +548,7 @@ LOAD / SAVE GAME
 
 #define        SAVEGAME_VERSION        5
 
-void Host_Savegame_to (const char *name)
+void Host_Savegame_to(prvm_prog_t *prog, const char *name)
 {
        qfile_t *f;
        int             i, k, l, lightstyles = 64;
@@ -564,7 +563,7 @@ void Host_Savegame_to (const char *name)
                if (sv.lightstyles[i][0])
                        lightstyles = i+1;
 
-       isserver = !strcmp(PRVM_NAME, "server");
+       isserver = prog == SVVM_prog;
 
        Con_Printf("Saving game to %s...\n", name);
        f = FS_OpenRealFile(name, "wb", false);
@@ -578,9 +577,9 @@ void Host_Savegame_to (const char *name)
 
        memset(comment, 0, sizeof(comment));
        if(isserver)
-               dpsnprintf(comment, sizeof(comment), "%-21.21s kills:%3i/%3i", PRVM_GetString(PRVM_serveredictstring(prog->edicts, message)), (int)PRVM_serverglobalfloat(killed_monsters), (int)PRVM_serverglobalfloat(total_monsters));
+               dpsnprintf(comment, sizeof(comment), "%-21.21s kills:%3i/%3i", PRVM_GetString(prog, PRVM_serveredictstring(prog->edicts, message)), (int)PRVM_serverglobalfloat(killed_monsters), (int)PRVM_serverglobalfloat(total_monsters));
        else
-               dpsnprintf(comment, sizeof(comment), "(crash dump of %s progs)", PRVM_NAME);
+               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 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
@@ -615,12 +614,12 @@ void Host_Savegame_to (const char *name)
                        FS_Print(f,"m\n");
        }
 
-       PRVM_ED_WriteGlobals (f);
+       PRVM_ED_WriteGlobals (prog, f);
        for (i=0 ; i<prog->num_edicts ; i++)
        {
                FS_Printf(f,"// edict %d\n", i);
                //Con_Printf("edict %d...\n", i);
-               PRVM_ED_Write (f, PRVM_EDICT_NUM(i));
+               PRVM_ED_Write (prog, f, PRVM_EDICT_NUM(i));
        }
 
 #if 1
@@ -697,8 +696,9 @@ void Host_Savegame_to (const char *name)
 Host_Savegame_f
 ===============
 */
-void Host_Savegame_f (void)
+static void Host_Savegame_f (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        char    name[MAX_QPATH];
        qboolean deadflag = false;
 
@@ -708,9 +708,7 @@ void Host_Savegame_f (void)
                return;
        }
 
-       SV_VM_Begin();
        deadflag = cl.islocalgame && svs.clients[0].active && PRVM_serveredictfloat(svs.clients[0].edict, deadflag);
-       SV_VM_End();
 
        if (cl.islocalgame)
        {
@@ -745,9 +743,7 @@ void Host_Savegame_f (void)
        strlcpy (name, Cmd_Argv(1), sizeof (name));
        FS_DefaultExtension (name, ".sav", sizeof (name));
 
-       SV_VM_Begin();
-       Host_Savegame_to(name);
-       SV_VM_End();
+       Host_Savegame_to(prog, name);
 }
 
 
@@ -757,8 +753,9 @@ Host_Loadgame_f
 ===============
 */
 
-void Host_Loadgame_f (void)
+static void Host_Loadgame_f (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        char filename[MAX_QPATH];
        char mapname[MAX_QPATH];
        float time;
@@ -807,7 +804,7 @@ void Host_Loadgame_f (void)
                Con_Printf("Host_Loadgame_f: loading version\n");
 
        // version
-       COM_ParseToken_Simple(&t, false, false);
+       COM_ParseToken_Simple(&t, false, false, true);
        version = atoi(com_token);
        if (version != SAVEGAME_VERSION)
        {
@@ -820,15 +817,15 @@ void Host_Loadgame_f (void)
                Con_Printf("Host_Loadgame_f: loading description\n");
 
        // description
-       COM_ParseToken_Simple(&t, false, false);
+       COM_ParseToken_Simple(&t, false, false, true);
 
        for (i = 0;i < NUM_SPAWN_PARMS;i++)
        {
-               COM_ParseToken_Simple(&t, false, false);
+               COM_ParseToken_Simple(&t, false, false, true);
                spawn_parms[i] = atof(com_token);
        }
        // skill
-       COM_ParseToken_Simple(&t, false, false);
+       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);
@@ -837,14 +834,14 @@ void Host_Loadgame_f (void)
                Con_Printf("Host_Loadgame_f: loading mapname\n");
 
        // mapname
-       COM_ParseToken_Simple(&t, false, false);
+       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);
+       COM_ParseToken_Simple(&t, false, false, true);
        time = atof(com_token);
 
        allowcheats = sv_cheats.integer != 0;
@@ -867,7 +864,6 @@ void Host_Loadgame_f (void)
 
 // load the light styles
 
-       SV_VM_Begin();
        // -1 is the globals
        entnum = -1;
 
@@ -875,7 +871,7 @@ void Host_Loadgame_f (void)
        {
                // light style
                start = t;
-               COM_ParseToken_Simple(&t, false, false);
+               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] == '{')
@@ -896,7 +892,7 @@ void Host_Loadgame_f (void)
        for (;;)
        {
                start = t;
-               if (!COM_ParseToken_Simple(&t, false, false))
+               if (!COM_ParseToken_Simple(&t, false, false, true))
                        break;
                if (com_token[0] == '{')
                {
@@ -913,10 +909,10 @@ void Host_Loadgame_f (void)
        for (;;)
        {
                start = t;
-               while (COM_ParseToken_Simple(&t, false, false))
+               while (COM_ParseToken_Simple(&t, false, false, true))
                        if (!strcmp(com_token, "}"))
                                break;
-               if (!COM_ParseToken_Simple(&start, false, false))
+               if (!COM_ParseToken_Simple(&start, false, false, true))
                {
                        // end of file
                        break;
@@ -933,7 +929,7 @@ void Host_Loadgame_f (void)
                                Con_Printf("Host_Loadgame_f: loading globals\n");
 
                        // parse the global vars
-                       PRVM_ED_ParseGlobals (start);
+                       PRVM_ED_ParseGlobals (prog, start);
 
                        // restore the autocvar globals
                        Cvar_UpdateAllAutoCvars();
@@ -947,7 +943,7 @@ void Host_Loadgame_f (void)
                                Host_Error("Host_PerformLoadGame: too many edicts in save file (reached MAX_EDICTS %i)", MAX_EDICTS);
                        }
                        while (entnum >= prog->max_edicts)
-                               PRVM_MEM_IncreaseEdicts();
+                               PRVM_MEM_IncreaseEdicts(prog);
                        ent = PRVM_EDICT_NUM(entnum);
                        memset(ent->fields.vp, 0, prog->entityfields * 4);
                        ent->priv.server->free = false;
@@ -955,7 +951,7 @@ void Host_Loadgame_f (void)
                        if(developer_entityparsing.integer)
                                Con_Printf("Host_Loadgame_f: loading edict %d\n", entnum);
 
-                       PRVM_ED_ParseEdict (start, ent);
+                       PRVM_ED_ParseEdict (prog, start, ent);
 
                        // link it into the bsp tree
                        if (!ent->priv.server->free)
@@ -992,13 +988,13 @@ void Host_Loadgame_f (void)
                        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));
-                       while (COM_ParseToken_Simple(&t, false, false))
+                       while (COM_ParseToken_Simple(&t, false, false, true))
                        {
                                if (!strcmp(com_token, "sv.lightstyles"))
                                {
-                                       COM_ParseToken_Simple(&t, false, false);
+                                       COM_ParseToken_Simple(&t, false, false, true);
                                        i = atoi(com_token);
-                                       COM_ParseToken_Simple(&t, false, false);
+                                       COM_ParseToken_Simple(&t, false, false, true);
                                        if (i >= 0 && i < MAX_LIGHTSTYLES)
                                                strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
                                        else
@@ -1006,9 +1002,9 @@ void Host_Loadgame_f (void)
                                }
                                else if (!strcmp(com_token, "sv.model_precache"))
                                {
-                                       COM_ParseToken_Simple(&t, false, false);
+                                       COM_ParseToken_Simple(&t, false, false, true);
                                        i = atoi(com_token);
-                                       COM_ParseToken_Simple(&t, false, false);
+                                       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]));
@@ -1019,9 +1015,9 @@ void Host_Loadgame_f (void)
                                }
                                else if (!strcmp(com_token, "sv.sound_precache"))
                                {
-                                       COM_ParseToken_Simple(&t, false, false);
+                                       COM_ParseToken_Simple(&t, false, false, true);
                                        i = atoi(com_token);
-                                       COM_ParseToken_Simple(&t, false, false);
+                                       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
@@ -1029,11 +1025,11 @@ void Host_Loadgame_f (void)
                                }
                                else if (!strcmp(com_token, "sv.bufstr"))
                                {
-                                       COM_ParseToken_Simple(&t, false, false);
+                                       COM_ParseToken_Simple(&t, false, false, true);
                                        i = atoi(com_token);
-                                       COM_ParseToken_Simple(&t, false, false);
+                                       COM_ParseToken_Simple(&t, false, false, true);
                                        k = atoi(com_token);
-                                       COM_ParseToken_Simple(&t, false, false);
+                                       COM_ParseToken_Simple(&t, false, false, true);
                                        stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);
                                        // VorteX: nasty code, cleanup required
                                        // create buffer at this index
@@ -1068,7 +1064,7 @@ void Host_Loadgame_f (void)
                                        }
                                }       
                                // skip any trailing text or unrecognized commands
-                               while (COM_ParseToken_Simple(&t, true, false) && strcmp(com_token, "\n"))
+                               while (COM_ParseToken_Simple(&t, true, false, true) && strcmp(com_token, "\n"))
                                        ;
                        }
                }
@@ -1078,8 +1074,6 @@ void Host_Loadgame_f (void)
        if(developer_entityparsing.integer)
                Con_Printf("Host_Loadgame_f: finished\n");
 
-       SV_VM_End();
-
        // make sure we're connected to loopback
        if (sv.active && cls.state == ca_disconnected)
                CL_EstablishConnection("local:1", -2);
@@ -1093,8 +1087,9 @@ 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)"};
-void Host_Name_f (void)
+static void Host_Name_f (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int i, j;
        qboolean valid_colors;
        const char *newNameSource;
@@ -1126,11 +1121,11 @@ void Host_Name_f (void)
 
        if (realtime < host_client->nametime)
        {
-               SV_ClientPrintf("You can't change name more than once every 5 seconds!\n");
+               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 + 5;
+       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));
@@ -1200,7 +1195,7 @@ void Host_Name_f (void)
        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(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->spawned)
@@ -1221,8 +1216,9 @@ 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
-void Host_Playermodel_f (void)
+static void Host_Playermodel_f (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int i, j;
        char newPath[sizeof(host_client->playermodel)];
 
@@ -1260,7 +1256,7 @@ void Host_Playermodel_f (void)
 
        // 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(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));
@@ -1277,8 +1273,9 @@ 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)"};
-void Host_Playerskin_f (void)
+static void Host_Playerskin_f (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int i, j;
        char newPath[sizeof(host_client->playerskin)];
 
@@ -1316,7 +1313,7 @@ void Host_Playerskin_f (void)
 
        // 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(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->spawned)
@@ -1329,13 +1326,14 @@ void Host_Playerskin_f (void)
        }
 }
 
-void Host_Version_f (void)
+static void Host_Version_f (void)
 {
        Con_Printf("Version: %s build %s\n", gamename, buildstring);
 }
 
-void Host_Say(qboolean teamonly)
+static void Host_Say(qboolean teamonly)
 {
+       prvm_prog_t *prog = SVVM_prog;
        client_t *save;
        int j, quoted;
        const char *p1;
@@ -1402,19 +1400,19 @@ void Host_Say(qboolean teamonly)
 }
 
 
-void Host_Say_f(void)
+static void Host_Say_f(void)
 {
        Host_Say(false);
 }
 
 
-void Host_Say_Team_f(void)
+static void Host_Say_Team_f(void)
 {
        Host_Say(true);
 }
 
 
-void Host_Tell_f(void)
+static void Host_Tell_f(void)
 {
        const char *playername_start = NULL;
        size_t playername_length = 0;
@@ -1549,8 +1547,9 @@ 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)"};
-void Host_Color(int changetop, int changebottom)
+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
@@ -1577,13 +1576,13 @@ void Host_Color(int changetop, int changebottom)
        if (cls.protocol == PROTOCOL_QUAKEWORLD)
                return;
 
-       if (host_client->edict && PRVM_clientfunction(SV_ChangeTeam))
+       if (host_client->edict && PRVM_serverfunction(SV_ChangeTeam))
        {
                Con_DPrint("Calling SV_ChangeTeam\n");
-               PRVM_serverglobalfloat(time) = sv.time;
                prog->globals.generic[OFS_PARM0] = playercolor;
+               PRVM_serverglobalfloat(time) = sv.time;
                PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
-               PRVM_ExecuteProgram(PRVM_clientfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing");
+               prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing");
        }
        else
        {
@@ -1604,7 +1603,7 @@ void Host_Color(int changetop, int changebottom)
        }
 }
 
-void Host_Color_f(void)
+static void Host_Color_f(void)
 {
        int             top, bottom;
 
@@ -1625,7 +1624,7 @@ void Host_Color_f(void)
        Host_Color(top, bottom);
 }
 
-void Host_TopColor_f(void)
+static void Host_TopColor_f(void)
 {
        if (Cmd_Argc() == 1)
        {
@@ -1637,7 +1636,7 @@ void Host_TopColor_f(void)
        Host_Color(atoi(Cmd_Argv(1)), -1);
 }
 
-void Host_BottomColor_f(void)
+static void Host_BottomColor_f(void)
 {
        if (Cmd_Argc() == 1)
        {
@@ -1650,7 +1649,7 @@ void Host_BottomColor_f(void)
 }
 
 cvar_t cl_rate = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "20000", "internal storage cvar for current rate (changed by rate command)"};
-void Host_Rate_f(void)
+static void Host_Rate_f(void)
 {
        int rate;
 
@@ -1677,8 +1676,9 @@ void Host_Rate_f(void)
 Host_Kill_f
 ==================
 */
-void Host_Kill_f (void)
+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");
@@ -1687,7 +1687,7 @@ void Host_Kill_f (void)
 
        PRVM_serverglobalfloat(time) = sv.time;
        PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
-       PRVM_ExecuteProgram (PRVM_serverfunction(ClientKill), "QC function ClientKill is missing");
+       prog->ExecuteProgram(prog, PRVM_serverfunction(ClientKill), "QC function ClientKill is missing");
 }
 
 
@@ -1696,18 +1696,39 @@ void Host_Kill_f (void)
 Host_Pause_f
 ==================
 */
-void Host_Pause_f (void)
+static void Host_Pause_f (void)
 {
-       if (!pausable.integer)
-               SV_ClientPrint("Pause not allowed.\n");
+       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)
        {
-               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);
+               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);
 }
 
 /*
@@ -1720,6 +1741,7 @@ LordHavoc: correction, Mindcrime will be removing pmodel in the future, but it's
 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)
@@ -1750,7 +1772,7 @@ static void Host_PModel_f (void)
 Host_PreSpawn_f
 ==================
 */
-void Host_PreSpawn_f (void)
+static void Host_PreSpawn_f (void)
 {
        if (host_client->spawned)
        {
@@ -1775,8 +1797,9 @@ void Host_PreSpawn_f (void)
 Host_Spawn_f
 ==================
 */
-void Host_Spawn_f (void)
+static void Host_Spawn_f (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int i;
        client_t *client;
        int stats[MAX_CL_STATS];
@@ -1805,7 +1828,7 @@ void Host_Spawn_f (void)
                        Con_DPrint("Calling RestoreGame\n");
                        PRVM_serverglobalfloat(time) = sv.time;
                        PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
-                       PRVM_ExecuteProgram(PRVM_serverfunction(RestoreGame), "QC function RestoreGame is missing");
+                       prog->ExecuteProgram(prog, PRVM_serverfunction(RestoreGame), "QC function RestoreGame is missing");
                }
        }
        else
@@ -1820,12 +1843,13 @@ void Host_Spawn_f (void)
                host_client->clientconnectcalled = true;
                PRVM_serverglobalfloat(time) = sv.time;
                PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
-               PRVM_ExecuteProgram (PRVM_serverfunction(ClientConnect), "QC function ClientConnect is missing");
+               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_ExecuteProgram (PRVM_serverfunction(PutClientInServer), "QC function PutClientInServer is missing");
+               PRVM_serverglobalfloat(time) = sv.time;
+               prog->ExecuteProgram(prog, PRVM_serverfunction(PutClientInServer), "QC function PutClientInServer is missing");
        }
 
        if (!host_client->netconnection)
@@ -1910,7 +1934,7 @@ void Host_Spawn_f (void)
 Host_Begin_f
 ==================
 */
-void Host_Begin_f (void)
+static void Host_Begin_f (void)
 {
        host_client->spawned = true;
 
@@ -1939,7 +1963,7 @@ Host_Kick_f
 Kicks a user off of the server
 ==================
 */
-void Host_Kick_f (void)
+static void Host_Kick_f (void)
 {
        const char *who;
        const char *message = NULL;
@@ -1950,7 +1974,6 @@ void Host_Kick_f (void)
        if (!sv.active)
                return;
 
-       SV_VM_Begin();
        save = host_client;
 
        if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
@@ -1990,7 +2013,7 @@ void Host_Kick_f (void)
                if (Cmd_Argc() > 2)
                {
                        message = Cmd_Args();
-                       COM_ParseToken_Simple(&message, false, false);
+                       COM_ParseToken_Simple(&message, false, false, true);
                        if (byNumber)
                        {
                                message++;                                                      // skip the #
@@ -2009,7 +2032,6 @@ void Host_Kick_f (void)
        }
 
        host_client = save;
-       SV_VM_End();
 }
 
 /*
@@ -2025,8 +2047,9 @@ DEBUGGING TOOLS
 Host_Give_f
 ==================
 */
-void Host_Give_f (void)
+static void Host_Give_f (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        const char *t;
        int v;
 
@@ -2147,7 +2170,7 @@ void Host_Give_f (void)
        }
 }
 
-prvm_edict_t   *FindViewthing (void)
+static prvm_edict_t    *FindViewthing(prvm_prog_t *prog)
 {
        int             i;
        prvm_edict_t    *e;
@@ -2155,7 +2178,7 @@ prvm_edict_t      *FindViewthing (void)
        for (i=0 ; i<prog->num_edicts ; i++)
        {
                e = PRVM_EDICT_NUM(i);
-               if (!strcmp (PRVM_GetString(PRVM_serveredictstring(e, classname)), "viewthing"))
+               if (!strcmp (PRVM_GetString(prog, PRVM_serveredictstring(e, classname)), "viewthing"))
                        return e;
        }
        Con_Print("No viewthing on map\n");
@@ -2167,29 +2190,27 @@ prvm_edict_t    *FindViewthing (void)
 Host_Viewmodel_f
 ==================
 */
-void Host_Viewmodel_f (void)
+static void Host_Viewmodel_f (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        prvm_edict_t    *e;
        dp_model_t      *m;
 
        if (!sv.active)
                return;
 
-       SV_VM_Begin();
-       e = FindViewthing ();
-       SV_VM_End();
-       if (!e)
-               return;
-
-       m = Mod_ForName (Cmd_Argv(1), false, true, NULL);
-       if (!m || !m->loaded || !m->Draw)
+       e = FindViewthing(prog);
+       if (e)
        {
-               Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(1));
-               return;
+               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));
        }
-
-       PRVM_serveredictfloat(e, frame) = 0;
-       cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)] = m;
 }
 
 /*
@@ -2197,8 +2218,9 @@ void Host_Viewmodel_f (void)
 Host_Viewframe_f
 ==================
 */
-void Host_Viewframe_f (void)
+static void Host_Viewframe_f (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        prvm_edict_t    *e;
        int             f;
        dp_model_t      *m;
@@ -2206,22 +2228,21 @@ void Host_Viewframe_f (void)
        if (!sv.active)
                return;
 
-       SV_VM_Begin();
-       e = FindViewthing ();
-       SV_VM_End();
-       if (!e)
-               return;
-       m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
+       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;
+               f = atoi(Cmd_Argv(1));
+               if (f >= m->numframes)
+                       f = m->numframes-1;
 
-       PRVM_serveredictfloat(e, frame) = f;
+               PRVM_serveredictfloat(e, frame) = f;
+       }
 }
 
 
-void PrintFrameName (dp_model_t *m, int frame)
+static void PrintFrameName (dp_model_t *m, int frame)
 {
        if (m->animscenes)
                Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name);
@@ -2234,26 +2255,26 @@ void PrintFrameName (dp_model_t *m, int frame)
 Host_Viewnext_f
 ==================
 */
-void Host_Viewnext_f (void)
+static void Host_Viewnext_f (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        prvm_edict_t    *e;
        dp_model_t      *m;
 
        if (!sv.active)
                return;
 
-       SV_VM_Begin();
-       e = FindViewthing ();
-       SV_VM_End();
-       if (!e)
-               return;
-       m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
+       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;
+               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));
+               PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
+       }
 }
 
 /*
@@ -2261,27 +2282,26 @@ void Host_Viewnext_f (void)
 Host_Viewprev_f
 ==================
 */
-void Host_Viewprev_f (void)
+static void Host_Viewprev_f (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        prvm_edict_t    *e;
        dp_model_t      *m;
 
        if (!sv.active)
                return;
 
-       SV_VM_Begin();
-       e = FindViewthing ();
-       SV_VM_End();
-       if (!e)
-               return;
-
-       m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
+       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;
+               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));
+               PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
+       }
 }
 
 /*
@@ -2298,7 +2318,7 @@ DEMO LOOP CONTROL
 Host_Startdemos_f
 ==================
 */
-void Host_Startdemos_f (void)
+static void Host_Startdemos_f (void)
 {
        int             i, c;
 
@@ -2337,7 +2357,7 @@ Host_Demos_f
 Return to looping demos
 ==================
 */
-void Host_Demos_f (void)
+static void Host_Demos_f (void)
 {
        if (cls.state == ca_dedicated)
                return;
@@ -2354,7 +2374,7 @@ Host_Stopdemo_f
 Return to looping demos
 ==================
 */
-void Host_Stopdemo_f (void)
+static void Host_Stopdemo_f (void)
 {
        if (!cls.demoplayback)
                return;
@@ -2362,12 +2382,13 @@ void Host_Stopdemo_f (void)
        Host_ShutdownServer ();
 }
 
-void Host_SendCvar_f (void)
+static void Host_SendCvar_f (void)
 {
        int             i;
        cvar_t  *c;
        const char *cvarname;
        client_t *old;
+       char vabuf[1024];
 
        if(Cmd_Argc() != 2)
                return;
@@ -2378,9 +2399,9 @@ void Host_SendCvar_f (void)
                // LordHavoc: if there is no such cvar or if it is private, send a
                // reply indicating that it has no value
                if(!c || (c->flags & CVAR_PRIVATE))
-                       Cmd_ForwardStringToServer(va("sentcvar %s", cvarname));
+                       Cmd_ForwardStringToServer(va(vabuf, sizeof(vabuf), "sentcvar %s", cvarname));
                else
-                       Cmd_ForwardStringToServer(va("sentcvar %s \"%s\"", c->name, c->string));
+                       Cmd_ForwardStringToServer(va(vabuf, sizeof(vabuf), "sentcvar %s \"%s\"", c->name, c->string));
                return;
        }
        if(!sv.active)// || !PRVM_serverfunction(SV_ParseClientCommand))
@@ -2434,7 +2455,7 @@ Host_PQRcon_f
 ProQuake rcon support
 =====================
 */
-void Host_PQRcon_f (void)
+static void Host_PQRcon_f (void)
 {
        int n;
        const char *e;
@@ -2468,15 +2489,18 @@ void Host_PQRcon_f (void)
        mysocket = NetConn_ChooseClientSocketForAddress(&to);
        if (mysocket)
        {
-               SZ_Clear(&net_message);
-               MSG_WriteLong (&net_message, 0);
-               MSG_WriteByte (&net_message, CCREQ_RCON);
-               SZ_Write(&net_message, (const unsigned char*)rcon_password.string, n);
-               MSG_WriteByte (&net_message, 0); // terminate the (possibly partial) string
-               MSG_WriteString (&net_message, Cmd_Args());
-               StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-               NetConn_Write(mysocket, net_message.data, net_message.cursize, &to);
-               SZ_Clear (&net_message);
+               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);
        }
 }
 
@@ -2492,12 +2516,13 @@ Host_Rcon_f
   an unconnected command.
 =====================
 */
-void Host_Rcon_f (void) // credit: taken from QuakeWorld
+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 (!rcon_password.string || !rcon_password.string[0])
        {
@@ -2560,7 +2585,7 @@ void Host_Rcon_f (void) // credit: taken from QuakeWorld
                }
                else
                {
-                       NetConn_WriteString(mysocket, va("\377\377\377\377rcon %.*s %s", n, rcon_password.string, Cmd_Args()), &to);
+                       NetConn_WriteString(mysocket, va(vabuf, sizeof(vabuf), "\377\377\377\377rcon %.*s %s", n, rcon_password.string, Cmd_Args()), &to);
                }
        }
 }
@@ -2574,7 +2599,7 @@ user <name or userid>
 Dump userdata / masterdata for a user
 ====================
 */
-void Host_User_f (void) // credit: taken from QuakeWorld
+static void Host_User_f (void) // credit: taken from QuakeWorld
 {
        int             uid;
        int             i;
@@ -2607,7 +2632,7 @@ Host_Users_f
 Dump userids for all current players
 ====================
 */
-void Host_Users_f (void) // credit: taken from QuakeWorld
+static void Host_Users_f (void) // credit: taken from QuakeWorld
 {
        int             i;
        int             c;
@@ -2635,7 +2660,7 @@ Sent by server when serverinfo changes
 ==================
 */
 // TODO: shouldn't this be a cvar instead?
-void Host_FullServerinfo_f (void) // credit: taken from QuakeWorld
+static void Host_FullServerinfo_f (void) // credit: taken from QuakeWorld
 {
        char temp[512];
        if (Cmd_Argc() != 2)
@@ -2657,7 +2682,7 @@ Allow clients to change userinfo
 ==================
 Casey was here :)
 */
-void Host_FullInfo_f (void) // credit: taken from QuakeWorld
+static void Host_FullInfo_f (void) // credit: taken from QuakeWorld
 {
        char key[512];
        char value[512];
@@ -2706,7 +2731,7 @@ CL_SetInfo_f
 Allow clients to change userinfo
 ==================
 */
-void Host_SetInfo_f (void) // credit: taken from QuakeWorld
+static void Host_SetInfo_f (void) // credit: taken from QuakeWorld
 {
        if (Cmd_Argc() == 1)
        {
@@ -2730,7 +2755,7 @@ packet <destination> <contents>
 Contents allows \n escape character
 ====================
 */
-void Host_Packet_f (void) // credit: taken from QuakeWorld
+static void Host_Packet_f (void) // credit: taken from QuakeWorld
 {
        char send[2048];
        int i, l;
@@ -2855,7 +2880,7 @@ void Host_Pings_f (void)
                MSG_WriteString(&host_client->netconnection->message, "\n");
 }
 
-void Host_PingPLReport_f(void)
+static void Host_PingPLReport_f(void)
 {
        char *errbyte;
        int i;
@@ -2901,7 +2926,7 @@ void Host_InitCommands (void)
        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", NULL, Host_Pause_f, "pause the game (if the server allows pausing)");
+       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");
@@ -2968,6 +2993,7 @@ void Host_InitCommands (void)
        Cvar_RegisterVariable(&sv_adminnick);
        Cvar_RegisterVariable(&sv_status_privacy);
        Cvar_RegisterVariable(&sv_status_show_qcstatus);
+       Cvar_RegisterVariable(&sv_namechangetimer);
 }
 
 void Host_NoOperation_f(void)
index c556f3930bfbc7cd0170ceaeeb439908673d9718..988fbef8e7f27b4a8abcfaf89edb8e92cecea14e 100644 (file)
@@ -8,7 +8,7 @@
 int            image_width;
 int            image_height;
 
-void Image_CopyAlphaFromBlueBGRA(unsigned char *outpixels, const unsigned char *inpixels, int w, int h)
+static void Image_CopyAlphaFromBlueBGRA(unsigned char *outpixels, const unsigned char *inpixels, int w, int h)
 {
        int i, n;
        n = w * h;
@@ -189,7 +189,7 @@ typedef struct pcx_s
 LoadPCX
 ============
 */
-unsigned char* LoadPCX_BGRA (const unsigned char *f, int filesize, int *miplevel)
+static unsigned char* LoadPCX_BGRA (const unsigned char *f, int filesize, int *miplevel)
 {
        pcx_t pcx;
        unsigned char *a, *b, *image_buffer, *pbuf;
@@ -372,7 +372,7 @@ typedef struct _TargaHeader
 }
 TargaHeader;
 
-void PrintTargaHeader(TargaHeader *t)
+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);
 }
@@ -746,7 +746,7 @@ typedef struct q2wal_s
        int                     value;
 } q2wal_t;
 
-unsigned char *LoadWAL_BGRA (const unsigned char *f, int filesize, int *miplevel)
+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;
@@ -797,6 +797,7 @@ void Image_StripImageExtension (const char *in, char *out, size_t 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)
 {
@@ -804,7 +805,7 @@ void Image_MakeLinearColorsFromsRGB(unsigned char *pout, const unsigned char *pi
        // 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)(Image_LinearFloatFromsRGB(i) * 256.0f);
+                       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]];
@@ -814,6 +815,22 @@ void Image_MakeLinearColorsFromsRGB(unsigned char *pout, const unsigned char *pi
        }
 }
 
+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;
@@ -899,6 +916,7 @@ unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qbo
        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)
@@ -942,7 +960,7 @@ unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qbo
                        {
                                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("%s_alpha", basename));
+                                       dpsnprintf (name2, sizeof(name2), format->formatstring, va(vabuf, sizeof(vabuf), "%s_alpha", basename));
                                        f = FS_LoadFile(name2, tempmempool, true, &filesize);
                                        if(f)
                                        {
@@ -1288,7 +1306,7 @@ static void Image_Resample32LerpLine (const unsigned char *in, unsigned char *ou
 }
 
 #define LERPBYTE(i) r = resamplerow1[i];out[i] = (unsigned char) ((((resamplerow2[i] - r) * lerp) >> 16) + r)
-void Image_Resample32Lerp(const void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight)
+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;
@@ -1392,7 +1410,7 @@ void Image_Resample32Lerp(const void *indata, int inwidth, int inheight, void *o
        resamplerow2 = NULL;
 }
 
-void Image_Resample32Nolerp(const void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight)
+static void Image_Resample32Nolerp(const void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight)
 {
        int i, j;
        unsigned frac, fracstep;
index 60fbcce681c1aa93311efc3d4e3e1dd6f61de373..915357739ed24048a9dce598f41d34b4681f25ec 100644 (file)
@@ -49,9 +49,14 @@ void Image_HeightmapToNormalmap_BGRA(const unsigned char *inpixels, unsigned cha
 void Image_FixTransparentPixels_f(void);
 extern cvar_t r_fixtrans_auto;
 
-#define Image_LinearFloatFromsRGB(c) (((c) < 11) ? (c) * 0.000302341331f : (float)pow(((c)*(1.0f/256.0f) + 0.055f)*(1.0f/1.0555f), 2.4f))
+#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
 
index 4267331be738462ceaacfd07541f5bedab60861a..9c03f8f3c05be418a2cd97c36a243281e06d6a2e 100644 (file)
@@ -217,7 +217,7 @@ static struct
 } my_png;
 
 //LordHavoc: removed __cdecl prefix, added overrun protection, and rewrote this to be more efficient
-void PNG_fReadData(void *png, unsigned char *data, size_t length)
+static void PNG_fReadData(void *png, unsigned char *data, size_t length)
 {
        size_t l;
        l = my_png.tmpBuflength - my_png.tmpi;
@@ -234,21 +234,21 @@ void PNG_fReadData(void *png, unsigned char *data, size_t length)
        //Com_HexDumpToConsole(data, (int)length);
 }
 
-void PNG_fWriteData(void *png, unsigned char *data, size_t length)
+static void PNG_fWriteData(void *png, unsigned char *data, size_t length)
 {
        FS_Write(my_png.outfile, data, length);
 }
 
-void PNG_fFlushData(void *png)
+static void PNG_fFlushData(void *png)
 {
 }
 
-void PNG_error_fn(void *png, const char *message)
+static void PNG_error_fn(void *png, const char *message)
 {
        Con_Printf("PNG_LoadImage: error: %s\n", message);
 }
 
-void PNG_warning_fn(void *png, const char *message)
+static void PNG_warning_fn(void *png, const char *message)
 {
        Con_Printf("PNG_LoadImage: warning: %s\n", message);
 }
index 8df1b484083a2c9bf0951ee91ec12492ea5aa240..4b276d2e1549c5fd5c2ca175a16c5e8e25c5a703 100644 (file)
@@ -1003,7 +1003,8 @@ static CompressedImageCacheItem *CompressedImageCache[COMPRESSEDIMAGECACHE_SIZE]
 
 static void CompressedImageCache_Add(const char *imagename, size_t maxsize, void *compressed, size_t compressed_size)
 {
-       const char *hashkey = va("%s:%d", imagename, (int) 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;
 
@@ -1021,7 +1022,8 @@ static void CompressedImageCache_Add(const char *imagename, size_t maxsize, void
 
 static CompressedImageCacheItem *CompressedImageCache_Find(const char *imagename, size_t maxsize)
 {
-       const char *hashkey = va("%s:%d", imagename, (int) 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];
 
index ea6e2d5985c397392f77eb1563806ad25adde2b2..18b7a8446ed91e485485dce36603236ef4da46a0 100644 (file)
@@ -23,6 +23,7 @@
 #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"};
 
@@ -114,7 +115,7 @@ static void Key_History_Push(void)
                history_matchfound = false;
 }
 
-qboolean Key_History_Get_foundCommand(void)
+static qboolean Key_History_Get_foundCommand(void)
 {
        if (!history_matchfound)
                return false;
@@ -201,7 +202,8 @@ static void Key_History_Find_Backwards(void)
 {
        int i;
        const char *partial = key_line + 1;
-       size_t digits = strlen(va("%i", HIST_MAXLINES));
+       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));
@@ -219,7 +221,7 @@ static void Key_History_Find_Backwards(void)
        if (!*partial)
                partial = "*";
        else if (!( strchr(partial, '*') || strchr(partial, '?') )) // no pattern?
-               partial = va("*%s*", partial);
+               partial = va(vabuf, sizeof(vabuf), "*%s*", partial);
 
        for ( ; i >= 0; i--)
                if (matchpattern_with_separator(ConBuffer_GetLine(&history, i), partial, true, "", false))
@@ -235,7 +237,8 @@ static void Key_History_Find_Forwards(void)
 {
        int i;
        const char *partial = key_line + 1;
-       size_t digits = strlen(va("%i", HIST_MAXLINES));
+       char vabuf[1024];
+       size_t digits = strlen(va(vabuf, sizeof(vabuf), "%i", HIST_MAXLINES));
 
        if (history_line == -1) // editing the "new" line
                return;
@@ -250,7 +253,7 @@ static void Key_History_Find_Forwards(void)
        if (!*partial)
                partial = "*";
        else if (!( strchr(partial, '*') || strchr(partial, '?') )) // no pattern?
-               partial = va("*%s*", partial);
+               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))
@@ -266,13 +269,14 @@ static void Key_History_Find_All(void)
 {
        const char *partial = key_line + 1;
        int i, count = 0;
-       size_t digits = strlen(va("%i", HIST_MAXLINES));
+       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("*%s*", partial);
+               partial = va(vabuf, sizeof(vabuf), "*%s*", partial);
 
        for (i=0; i<CONBUFFER_LINES_COUNT(&history); i++)
                if (matchpattern_with_separator(ConBuffer_GetLine(&history, i), partial, true, "", false))
@@ -287,7 +291,8 @@ static void Key_History_f(void)
 {
        char *errchar = NULL;
        int i = 0;
-       size_t digits = strlen(va("%i", HIST_MAXLINES));
+       char vabuf[1024];
+       size_t digits = strlen(va(vabuf, sizeof(vabuf), "%i", HIST_MAXLINES));
 
        if (Cmd_Argc () > 1)
        {
@@ -1192,17 +1197,16 @@ int chat_mode;
 char           chat_buffer[MAX_INPUTLINE];
 unsigned int   chat_bufferlen = 0;
 
-extern int Nicks_CompleteChatLine(char *buffer, size_t size, unsigned int pos);
-
 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); // not Cbuf_AddText to allow semiclons in args; however, this allows no variables then. Use aliases!
+                       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("%s %s", chat_mode ? "say_team" : "say ", chat_buffer));
+                       Cmd_ForwardStringToServer(va(vabuf, sizeof(vabuf), "%s %s", chat_mode ? "say_team" : "say ", chat_buffer));
 
                key_dest = key_game;
                chat_bufferlen = 0;
@@ -1283,10 +1287,9 @@ FIXME: handle quote special (general escape sequence?)
 ===================
 */
 const char *
-Key_KeynumToString (int keynum)
+Key_KeynumToString (int keynum, char *tinystr, size_t tinystrlength)
 {
        const keyname_t  *kn;
-       static char tinystr[2];
 
        // -1 is an invalid code
        if (keynum < 0)
@@ -1300,8 +1303,11 @@ Key_KeynumToString (int keynum)
        // if it is printable, output it as a single character
        if (keynum > 32 && keynum < 256)
        {
-               tinystr[0] = keynum;
-               tinystr[1] = 0;
+               if (tinystrlength >= 2)
+               {
+                       tinystr[0] = keynum;
+                       tinystr[1] = 0;
+               }
                return tinystr;
        }
 
@@ -1494,6 +1500,7 @@ static void
 Key_PrintBindList(int j)
 {
        char bindbuf[MAX_INPUTLINE];
+       char tinystr[2];
        const char *p;
        int i;
 
@@ -1504,9 +1511,9 @@ Key_PrintBindList(int j)
                {
                        Cmd_QuoteString(bindbuf, sizeof(bindbuf), p, "\"\\", false);
                        if (j == 0)
-                               Con_Printf("^2%s ^7= \"%s\"\n", Key_KeynumToString (i), bindbuf);
+                               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), bindbuf);
+                               Con_Printf("^3bindmap %d: ^2%s ^7= \"%s\"\n", j, Key_KeynumToString (i, tinystr, sizeof(tinystr)), bindbuf);
                }
        }
 }
@@ -1586,6 +1593,7 @@ 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++)
@@ -1597,9 +1605,9 @@ Key_WriteBindings (qfile_t *f)
                        {
                                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), bindbuf);
+                                       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), bindbuf);
+                                       FS_Printf(f, "in_bind %d %s \"%s\"\n", j, Key_KeynumToString (i, tinystr, sizeof(tinystr)), bindbuf);
                        }
                }
        }
@@ -1686,8 +1694,6 @@ void Key_FindKeysForCommand (const char *command, int *keys, int numkeys, int bi
        }
 }
 
-qboolean CL_VM_InputEvent (qboolean down, int key, int ascii);
-
 /*
 ===================
 Called by the system between frames for both key up and key down events
@@ -1741,6 +1747,7 @@ 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;
@@ -1852,7 +1859,7 @@ Key_Event (int key, int ascii, qboolean down)
 
                        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, key, ascii);
+                               q = CL_VM_InputEvent(down ? 0 : 1, key, ascii);
                                if (!q && down)
                                        MR_ToggleMenu(1);
                                break;
@@ -1874,14 +1881,14 @@ Key_Event (int key, int ascii, qboolean down)
                        {
                                // button commands add keynum as a parm
                                if (bind[0] == '+')
-                                       Cbuf_AddText (va("%s %i\n", bind, key));
+                                       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("-%s %i\n", bind + 1, key));
+                               Cbuf_AddText(va(vabuf, sizeof(vabuf), "-%s %i\n", bind + 1, key));
                }
                return;
        }
@@ -1899,6 +1906,10 @@ Key_Event (int key, int ascii, qboolean down)
                        Con_ToggleConsole_f ();
                        return;
                }
+
+               if (COM_CheckParm ("-noconsole"))
+                       return; // only allow the key bind to turn off console
+
                Key_Console (key, ascii);
                return;
        }
@@ -1936,7 +1947,7 @@ Key_Event (int key, int ascii, qboolean down)
                        MR_KeyEvent (key, ascii, down);
                        break;
                case key_game:
-                       q = CL_VM_InputEvent(down, key, ascii);
+                       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)
                        {
@@ -1944,14 +1955,14 @@ Key_Event (int key, int ascii, qboolean down)
                                {
                                        // button commands add keynum as a parm
                                        if (bind[0] == '+')
-                                               Cbuf_AddText (va("%s %i\n", bind, key));
+                                               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("-%s %i\n", bind + 1, key));
+                                       Cbuf_AddText(va(vabuf, sizeof(vabuf), "-%s %i\n", bind + 1, key));
                        }
                        break;
                default:
@@ -1959,6 +1970,21 @@ Key_Event (int key, int ascii, qboolean down)
        }
 }
 
+// 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
index c2587aed1b3a0796f25535a1d359982386759c06..a84eb4c6f7cced9246b4faaf430ffb851467ed28 100644 (file)
@@ -367,17 +367,18 @@ extern    keydest_t       key_dest;
 extern int                     key_consoleactive;
 extern char            *keybindings[MAX_BINDMAPS][MAX_KEYS];
 
-extern void Key_ClearEditLine(int edit_line);
 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_ClearStates (void);
+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);
 
index 05ac8135ed06748d9682ba7491e5c2f5e8c2ef87..b755ea4cec4e15346325b9d482ae1bc2fd550593 100644 (file)
@@ -815,6 +815,7 @@ struct codepair {
   { 0x20ac, 0x20ac }, /*                    EuroSign â‚¬ EURO SIGN */
 };
 
+extern long keysym2ucs(KeySym keysym); // LordHavoc: suppress warning just in this case, it's not worth having a header file for this...
 long keysym2ucs(KeySym keysym)
 {
     int min = 0;
index 7f9664c05da90dc410509fd7b983224af87579a7..cb87b6d319e2ae866f94ca9bf11d1856120aa9cd 100644 (file)
@@ -612,7 +612,7 @@ int LHNETADDRESS_GetAddressType(const lhnetaddress_t *address)
                return LHNETADDRESSTYPE_NONE;
 }
 
-const char *LHNETADDRESS_GetInterfaceName(const lhnetaddress_t *vaddress)
+const char *LHNETADDRESS_GetInterfaceName(const lhnetaddress_t *vaddress, char *ifname, size_t ifnamelength)
 {
 #ifdef SUPPORTIPV6
        lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress;
@@ -621,8 +621,6 @@ const char *LHNETADDRESS_GetInterfaceName(const lhnetaddress_t *vaddress)
        {
 #ifndef _WIN32
 
-               static char ifname [IF_NAMESIZE];
-               
                if (if_indextoname(address->addr.in6.sin6_scope_id, ifname) == ifname)
                        return ifname;
 
@@ -631,9 +629,7 @@ const char *LHNETADDRESS_GetInterfaceName(const lhnetaddress_t *vaddress)
                // The Win32 API doesn't have if_indextoname() until Windows Vista,
                // but luckily it just uses the interface ID as the interface name
 
-               static char ifname [16];
-
-               if (dpsnprintf(ifname, sizeof(ifname), "%lu", address->addr.in6.sin6_scope_id) > 0)
+               if (dpsnprintf(ifname, ifnamelength, "%lu", address->addr.in6.sin6_scope_id) > 0)
                        return ifname;
 
 #endif
index d46dbe99a859cfb6db3a2ad8ed095febcd79073c..518ccdf91566a5bda09fa5fe27776b7ed7d5a40f 100644 (file)
@@ -25,7 +25,7 @@ int LHNETADDRESS_FromPort(lhnetaddress_t *address, lhnetaddresstype_t addresstyp
 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);
+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);
index b472d9e9c4033d69ff98a44ea1b3e06da9eb947a..637a649dcd16269961417d3c18acc27512c65099 100644 (file)
@@ -1,6 +1,7 @@
 #include "quakedef.h"
 #include "fs.h"
 #include "libcurl.h"
+#include "thread.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)"};
@@ -182,6 +183,8 @@ static dllfunction_t curlfuncs[] =
 static dllhandle_t curl_dll = NULL;
 // will be checked at many places to find out if qcurl calls are allowed
 
+void *curl_mutex = NULL;
+
 typedef struct downloadinfo_s
 {
        char filename[MAX_OSPATH];
@@ -231,7 +234,7 @@ all downloads since last server connect ended with a successful status.
 Setting the command to NULL clears it.
 ====================
 */
-void Curl_CommandWhenDone(const char *cmd)
+static void Curl_CommandWhenDone(const char *cmd)
 {
        if(!curl_dll)
                return;
@@ -247,7 +250,7 @@ Do not use yet. Not complete.
 Problem: what counts as an error?
 */
 
-void Curl_CommandWhenError(const char *cmd)
+static void Curl_CommandWhenError(const char *cmd)
 {
        if(!curl_dll)
                return;
@@ -269,6 +272,7 @@ 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);
@@ -276,6 +280,7 @@ void Curl_Clear_forthismap(void)
        numdownloads_fail = 0;
        numdownloads_success = 0;
        numdownloads_added = 0;
+       if (curl_mutex) Thread_UnlockMutex(curl_mutex);
 }
 
 /*
@@ -292,8 +297,10 @@ qboolean Curl_Have_forthismap(void)
 
 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);
 }
 
 /*
@@ -308,20 +315,22 @@ static void Curl_CheckCommandWhenDone(void)
 {
        if(!curl_dll)
                return;
-       if(numdownloads_added && (numdownloads_success == numdownloads_added) && *command_when_done)
+       if(numdownloads_added && ((numdownloads_success + numdownloads_fail) == numdownloads_added))
        {
-               Con_DPrintf("cURL downloads occurred, executing %s\n", command_when_done);
-               Cbuf_AddText("\n");
-               Cbuf_AddText(command_when_done);
-               Cbuf_AddText("\n");
-               Curl_Clear_forthismap();
-       }
-       else if(numdownloads_added && numdownloads_fail && *command_when_error)
-       {
-               Con_DPrintf("cURL downloads FAILED, executing %s\n", command_when_error);
-               Cbuf_AddText("\n");
-               Cbuf_AddText(command_when_error);
-               Cbuf_AddText("\n");
+               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();
        }
 }
@@ -448,11 +457,6 @@ static void curl_default_callback(int status, size_t length_received, unsigned c
        }
 }
 
-static void curl_quiet_callback(int status, size_t length_received, unsigned char *buffer, void *cbdata)
-{
-       curl_default_callback(status, length_received, buffer, cbdata);
-}
-
 /*
 ====================
 Curl_EndDownload
@@ -560,9 +564,8 @@ CleanURL
 Returns a "cleaned up" URL for display (to strip login data)
 ====================
 */
-static const char *CleanURL(const char *url)
+static const char *CleanURL(const char *url, char *urlbuf, size_t urlbuflength)
 {
-       static char urlbuf[1024];
        const char *p, *q, *r;
 
        // if URL is of form anything://foo-without-slash@rest, replace by anything://rest
@@ -575,7 +578,7 @@ static const char *CleanURL(const char *url)
                        r = strchr(p + 3, '/');
                        if(!r || q < r)
                        {
-                               dpsnprintf(urlbuf, sizeof(urlbuf), "%.*s%s", (int)(p - url + 3), url, q + 1);
+                               dpsnprintf(urlbuf, urlbuflength, "%.*s%s", (int)(p - url + 3), url, q + 1);
                                return urlbuf;
                        }
                }
@@ -596,6 +599,8 @@ 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)
@@ -607,7 +612,7 @@ static void CheckPendingDownloads(void)
                        {
                                if(!di->buffer)
                                {
-                                       Con_Printf("Downloading %s -> %s", CleanURL(di->url), di->filename);
+                                       Con_Printf("Downloading %s -> %s", CleanURL(di->url, urlbuf, sizeof(urlbuf)), di->filename);
 
                                        di->stream = FS_OpenRealFile(di->filename, "ab", false);
                                        if(!di->stream)
@@ -625,7 +630,7 @@ static void CheckPendingDownloads(void)
                                }
                                else
                                {
-                                       Con_DPrintf("Downloading %s -> memory\n", CleanURL(di->url));
+                                       Con_DPrintf("Downloading %s -> memory\n", CleanURL(di->url, urlbuf, sizeof(urlbuf)));
                                        di->startpos = 0;
                                }
 
@@ -652,7 +657,7 @@ static void CheckPendingDownloads(void)
                                        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("Content-Type: %s", di->post_content_type));
+                                       di->slist = qcurl_slist_append(di->slist, va(vabuf, sizeof(vabuf), "Content-Type: %s", di->post_content_type));
                                }
 
                                // parse extra headers into slist
@@ -677,7 +682,6 @@ static void CheckPendingDownloads(void)
                                }
 
                                qcurl_easy_setopt(di->curle, CURLOPT_HTTPHEADER, di->slist);
-
                                
                                qcurl_multi_add_handle(curlm, di->curle);
                                di->started = true;
@@ -702,6 +706,7 @@ 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();
 }
@@ -720,6 +725,7 @@ void Curl_Shutdown(void)
                return;
        Curl_ClearRequirements();
        Curl_CancelAll();
+       if (curl_mutex) Thread_DestroyMutex(curl_mutex);
        CURL_CloseLibrary();
        curl_dll = NULL;
 }
@@ -742,24 +748,6 @@ static downloadinfo *Curl_Find(const char *filename)
        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);
-                       di = downloads;
-               }
-               else
-                       di = di->next;
-       }
-}
-
 /*
 ====================
 Curl_Begin
@@ -829,7 +817,9 @@ static qboolean Curl_Begin(const char *URL, const char *extraheaders, double max
                //   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(!name)
-                       name = CleanURL(URL);
+                       name = CleanURL(URL, urlbuf, sizeof(urlbuf));
+
+               if (curl_mutex) Thread_LockMutex(curl_mutex);
 
                if(!buf)
                {
@@ -846,7 +836,7 @@ static qboolean Curl_Begin(const char *URL, const char *extraheaders, double max
                                downloadinfo *di = Curl_Find(fn);
                                if(di)
                                {
-                                       Con_Printf("Can't download %s, already getting it from %s!\n", fn, CleanURL(di->url));
+                                       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)
@@ -911,6 +901,7 @@ static qboolean Curl_Begin(const char *URL, const char *extraheaders, double max
                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;
                }
 
@@ -963,6 +954,7 @@ static qboolean Curl_Begin(const char *URL, const char *extraheaders, double max
                }
 
                downloads = di;
+               if (curl_mutex) Thread_UnlockMutex(curl_mutex);
                return true;
        }
 }
@@ -1001,13 +993,21 @@ void Curl_Run(void)
        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;
@@ -1022,12 +1022,15 @@ void Curl_Run(void)
                for(di = downloads; di; di = di->next)
                {
                        double b = 0;
-                       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;
+                       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(;;)
@@ -1087,6 +1090,8 @@ void Curl_Run(void)
        }
        else
                curltime = realtime;
+
+       if (curl_mutex) Thread_UnlockMutex(curl_mutex);
 }
 
 /*
@@ -1101,11 +1106,15 @@ 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);
                // INVARIANT: downloads will point to the next download after that!
        }
+
+       if (curl_mutex) Thread_UnlockMutex(curl_mutex);
 }
 
 /*
@@ -1180,15 +1189,17 @@ prints the download list
 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), di->filename);
+                       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)
@@ -1196,6 +1207,7 @@ static void Curl_Info_f(void)
                        else
                                Con_Print("(queued)\n");
                }
+               if (curl_mutex) Thread_UnlockMutex(curl_mutex);
        }
        else
        {
@@ -1229,7 +1241,7 @@ curl --finish_autodownload
        once the last download completes successfully, reconnect to the current server
 ====================
 */
-void Curl_Curl_f(void)
+static void Curl_Curl_f(void)
 {
        double maxspeed = 0;
        int i;
@@ -1398,12 +1410,11 @@ 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)
+Curl_downloadinfo_t *Curl_GetDownloadInfo(int *nDownloads, const char **additional_info, char *addinfo, size_t addinfolength)
 {
        int i;
        downloadinfo *di;
        Curl_downloadinfo_t *downinfo;
-       static char addinfo[128];
 
        if(!curl_dll)
        {
@@ -1413,6 +1424,8 @@ Curl_downloadinfo_t *Curl_GetDownloadInfo(int *nDownloads, const char **addition
                return NULL;
        }
 
+       if (curl_mutex) Thread_LockMutex(curl_mutex);
+
        i = 0;
        for(di = downloads; di; di = di->next)
                ++i;
@@ -1445,11 +1458,11 @@ Curl_downloadinfo_t *Curl_GetDownloadInfo(int *nDownloads, const char **addition
                if(*command_when_done && !numdownloads_fail && numdownloads_added)
                {
                        if(!strncmp(command_when_done, "connect ", 8))
-                               dpsnprintf(addinfo, sizeof(addinfo), "(will join %s when done)", command_when_done + 8);
+                               dpsnprintf(addinfo, addinfolength, "(will join %s when done)", command_when_done + 8);
                        else if(!strcmp(command_when_done, "cl_begindownloads"))
-                               dpsnprintf(addinfo, sizeof(addinfo), "(will enter the game when done)");
+                               dpsnprintf(addinfo, addinfolength, "(will enter the game when done)");
                        else
-                               dpsnprintf(addinfo, sizeof(addinfo), "(will do '%s' when done)", command_when_done);
+                               dpsnprintf(addinfo, addinfolength, "(will do '%s' when done)", command_when_done);
                        *additional_info = addinfo;
                }
                else
@@ -1457,6 +1470,7 @@ Curl_downloadinfo_t *Curl_GetDownloadInfo(int *nDownloads, const char **addition
        }
 
        *nDownloads = i;
+       if (curl_mutex) Thread_UnlockMutex(curl_mutex);
        return downinfo;
 }
 
@@ -1487,7 +1501,7 @@ this file for obvious reasons.
 */
 static const char *Curl_FindPackURL(const char *filename)
 {
-       static char foundurl[1024];
+       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)
@@ -1649,7 +1663,7 @@ void Curl_SendRequirements(void)
                foundone = Curl_SendRequirement(req->filename, foundone, sendbuffer, sizeof(sendbuffer)) || foundone;
 
        p = sv_curl_serverpackages.string;
-       while(COM_ParseToken_Simple(&p, false, false))
+       while(COM_ParseToken_Simple(&p, false, false, true))
                foundone = Curl_SendRequirement(com_token, foundone, sendbuffer, sizeof(sendbuffer)) || foundone;
 
        if(foundone)
index ed05551c10bf27d31043951425b9a584bc7787cc..c5e55dd3707d4d17c008ee5e32a48e1d6dcc6604 100644 (file)
@@ -15,9 +15,6 @@ qboolean Curl_Begin_ToFile(const char *URL, double maxspeed, const char *name, q
 
 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);
-       // NOTE: if these return false, the callback will NOT get called, so free your buffer then!
-void Curl_Cancel_ToMemory(curl_callback_t callback, void *cbdata);
-       // removes all downloads with the given callback and cbdata (this does NOT call the callbacks!)
 
 void Curl_Init(void);
 void Curl_Init_Commands(void);
@@ -39,7 +36,7 @@ typedef struct Curl_downloadinfo_s
        qboolean queued;
 }
 Curl_downloadinfo_t;
-Curl_downloadinfo_t *Curl_GetDownloadInfo(int *nDownloads, const char **additional_info);
+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
index 84db7512929f70e67687b17d5bb9840f6fe0247b..7a8a4cfb9ca05a986c69e8c5ac4eb15dab907519 100644 (file)
@@ -213,7 +213,7 @@ ifeq ($(D3D), 1)
        LDFLAGS_D3D=-ld3d9
 else
        CFLAGS_D3D=
-       CFLAGS_WARNINGS=-Wall -Wold-style-definition -Wstrict-prototypes -Wsign-compare -Wdeclaration-after-statement
+       CFLAGS_WARNINGS=-Wall -Wold-style-definition -Wstrict-prototypes -Wsign-compare -Wdeclaration-after-statement -Wmissing-prototypes
        LDFLAGS_D3D=
 endif
 
index dd55442a6b02be277ce1d47d08d83582accc6bdb..409cd2ec22f0486f12c00e1e9f77f1ad06c01a72 100644 (file)
@@ -101,7 +101,6 @@ OBJ_COMMON= \
        cl_collision.o \
        cl_demo.o \
        cl_dyntexture.o \
-       cl_gecko.o \
        cl_input.o \
        cl_main.o \
        cl_parse.o \
index e1c7f647d8eb17f90d1fd9065fc9c48dd432071e..06a5ba9274c6970c87d2c5fd9aa25166aef22676 100644 (file)
@@ -293,5 +293,7 @@ void BoxFromPoints(vec3_t mins, vec3_t maxs, int numpoints, vec_t *point3f);
 
 int LoopingFrameNumberFromDouble(double t, int loopframes);
 
+void Mathlib_Init(void);
+
 #endif
 
index c09abda45607d87d3a67eb22f02c091db70456e1..eb741b2a2437a9033bebcd1939d7b01de28e342a 100644 (file)
@@ -273,7 +273,7 @@ static void M_DrawTextBox(float x, float y, float width, float height)
 M_ToggleMenu
 ================
 */
-void M_ToggleMenu(int mode)
+static void M_ToggleMenu(int mode)
 {
        m_entersound = true;
 
@@ -308,7 +308,7 @@ static void M_Demo_Draw (void)
 }
 
 
-void M_Menu_Demos_f (void)
+static void M_Menu_Demos_f (void)
 {
        key_dest = key_menu;
        m_state = m_demo;
@@ -318,6 +318,7 @@ void M_Menu_Demos_f (void)
 
 static void M_Demo_Key (int k, int ascii)
 {
+       char vabuf[1024];
        switch (k)
        {
        case K_ESCAPE:
@@ -328,7 +329,7 @@ static void M_Demo_Key (int k, int ascii)
                S_LocalSound ("sound/misc/menu2.wav");
                m_state = m_none;
                key_dest = key_game;
-               Cbuf_AddText (va ("playdemo %s\n", NehahraDemos[demo_cursor].name));
+               Cbuf_AddText (va(vabuf, sizeof(vabuf), "playdemo %s\n", NehahraDemos[demo_cursor].name));
                return;
 
        case K_UPARROW:
@@ -431,6 +432,7 @@ static void M_Main_Draw (void)
 {
        int             f;
        cachepic_t      *p;
+       char vabuf[1024];
 
        if (m_missingdata)
        {
@@ -460,14 +462,14 @@ static void M_Main_Draw (void)
                {
                        if (MAIN_ITEMS == 7 && y1 == 4)
                                y1++;
-                       M_DrawPic (0, y2, va("gfx/menu/mainmenu%i", 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("gfx/menu/mainmenu%iselected", y3));
+               M_DrawPic (0, 120 + m_main_cursor * 40, va(vabuf, sizeof(vabuf), "gfx/menu/mainmenu%iselected", y3));
                return;
        }
 
@@ -490,7 +492,7 @@ static void M_Main_Draw (void)
 
        f = (int)(realtime * 10)%6;
 
-       M_DrawPic (54, 32 + m_main_cursor * 20, va("gfx/menudot%i", f+1));
+       M_DrawPic (54, 32 + m_main_cursor * 20, va(vabuf, sizeof(vabuf), "gfx/menudot%i", f+1));
 }
 
 
@@ -743,6 +745,7 @@ void M_Menu_SinglePlayer_f (void)
 static void M_SinglePlayer_Draw (void)
 {
        cachepic_t      *p;
+       char vabuf[1024];
 
        M_Background(320, 200);
 
@@ -770,7 +773,7 @@ static void M_SinglePlayer_Draw (void)
 
                f = (int)(realtime * 10)%6;
 
-               M_DrawPic (54, 32 + m_singleplayer_cursor * 20, va("gfx/menudot%i", f+1));
+               M_DrawPic (54, 32 + m_singleplayer_cursor * 20, va(vabuf, sizeof(vabuf), "gfx/menudot%i", f+1));
        }
 }
 
@@ -866,10 +869,10 @@ static void M_ScanSaves (void)
                buf[len] = 0;
                t = buf;
                // version
-               COM_ParseToken_Simple(&t, false, false);
+               COM_ParseToken_Simple(&t, false, false, true);
                //version = atoi(com_token);
                // description
-               COM_ParseToken_Simple(&t, false, false);
+               COM_ParseToken_Simple(&t, false, false, true);
                strlcpy (m_filenames[i], com_token, sizeof (m_filenames[i]));
 
        // change _ back to space
@@ -949,6 +952,7 @@ static void M_Save_Draw (void)
 
 static void M_Load_Key (int k, int ascii)
 {
+       char vabuf[1024];
        switch (k)
        {
        case K_ESCAPE:
@@ -966,7 +970,7 @@ static void M_Load_Key (int k, int ascii)
                key_dest = key_game;
 
                // issue the load command
-               Cbuf_AddText (va ("load s%i\n", load_cursor) );
+               Cbuf_AddText (va(vabuf, sizeof(vabuf), "load s%i\n", load_cursor) );
                return;
 
        case K_UPARROW:
@@ -990,6 +994,7 @@ static void M_Load_Key (int k, int ascii)
 
 static void M_Save_Key (int k, int ascii)
 {
+       char vabuf[1024];
        switch (k)
        {
        case K_ESCAPE:
@@ -1002,7 +1007,7 @@ static void M_Save_Key (int k, int ascii)
        case K_ENTER:
                m_state = m_none;
                key_dest = key_game;
-               Cbuf_AddText (va("save s%i\n", load_cursor));
+               Cbuf_AddText (va(vabuf, sizeof(vabuf), "save s%i\n", load_cursor));
                return;
 
        case K_UPARROW:
@@ -1040,15 +1045,16 @@ 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("gfx/menu/episode%i", y+1));
+               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("gfx/menu/episode%iselected", m_episode_cursor + 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)
@@ -1097,6 +1103,7 @@ 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");
@@ -1104,9 +1111,9 @@ static void M_Transfusion_Skill_Draw (void)
 
        for (y = 0; y < SKILL_ITEMS; y++)
        {
-               M_DrawPic (0, 180 + y * 40, va("gfx/menu/difficulty%i", y+1));
+               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("gfx/menu/difficulty%iselected", m_skill_cursor + 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)
@@ -1199,6 +1206,7 @@ static void M_MultiPlayer_Draw (void)
 {
        int             f;
        cachepic_t      *p;
+       char vabuf[1024];
 
        if (gamemode == GAME_TRANSFUSION)
        {
@@ -1206,8 +1214,8 @@ static void M_MultiPlayer_Draw (void)
                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("gfx/menu/online%i", f));
-               M_DrawPic (0, 220 + m_multiplayer_cursor * 40, va("gfx/menu/online%iselected", m_multiplayer_cursor + 1));
+                       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);
@@ -1219,7 +1227,7 @@ static void M_MultiPlayer_Draw (void)
 
        f = (int)(realtime * 10)%6;
 
-       M_DrawPic (54, 32 + m_multiplayer_cursor * 20, va("gfx/menudot%i", f+1));
+       M_DrawPic (54, 32 + m_multiplayer_cursor * 20, va(vabuf, sizeof(vabuf), "gfx/menudot%i", f+1));
 }
 
 
@@ -1327,6 +1335,7 @@ static void M_Setup_Draw (void)
 {
        int i, j;
        cachepic_t      *p;
+       char vabuf[1024];
 
        M_Background(320, 200);
 
@@ -1345,7 +1354,7 @@ static void M_Setup_Draw (void)
        }
 
        M_Print(64, 124-8, "Network speed limit");
-       M_Print(168, 124, va("%i (%s)", setup_rate, setup_ratetable[setup_rateindex(setup_rate)].name));
+       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");
@@ -1419,6 +1428,7 @@ static void M_Setup_Draw (void)
 static void M_Setup_Key (int k, int ascii)
 {
        int                     l;
+       char vabuf[1024];
 
        switch (k)
        {
@@ -1483,11 +1493,11 @@ forward:
 
                // setup_cursor == 4 (Accept changes)
                if (strcmp(cl_name.string, setup_myname) != 0)
-                       Cbuf_AddText ( va ("name \"%s\"\n", setup_myname) );
+                       Cbuf_AddText(va(vabuf, sizeof(vabuf), "name \"%s\"\n", setup_myname) );
                if (setup_top != setup_oldtop || setup_bottom != setup_oldbottom)
-                       Cbuf_AddText( va ("color %i %i\n", setup_top, setup_bottom) );
+                       Cbuf_AddText(va(vabuf, sizeof(vabuf), "color %i %i\n", setup_top, setup_bottom) );
                if (setup_rate != setup_oldrate)
-                       Cbuf_AddText(va("rate %i\n", setup_rate));
+                       Cbuf_AddText(va(vabuf, sizeof(vabuf), "rate %i\n", setup_rate));
 
                m_entersound = true;
                M_Menu_MultiPlayer_f ();
@@ -1978,10 +1988,8 @@ 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;
 extern cvar_t r_hdr_scenebrightness;
 extern cvar_t r_hdr_glowintensity;
-extern cvar_t r_hdr_range;
 extern cvar_t gl_picmip;
 
 static void M_Menu_Options_Graphics_AdjustSliders (int dir)
@@ -1999,10 +2007,8 @@ static void M_Menu_Options_Graphics_AdjustSliders (int dir)
        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_hdr_scenebrightness,                   bound(0.25, r_hdr_scenebrightness.value + dir * 0.125, 4));
        else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom,                                 !r_bloom.integer);
-       else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_hdr,                                   !r_hdr.integer);
-       else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_hdr_range,                             bound(1, r_hdr_range.value + dir * 0.25, 16));
+       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));
@@ -2038,17 +2044,15 @@ static void M_Options_Graphics_Draw (void)
        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_PrintCheckbox("          Bloom Effect", !r_hdr.integer, r_bloom.integer);
-       M_Options_PrintCheckbox("      HDR Bloom Effect", true, r_hdr.integer);
-       M_Options_PrintSlider(  "     HDR Dynamic Range", r_hdr.integer, r_hdr_range.value, 1, 16);
-       M_Options_PrintSlider(  "    HDR Glow Intensity", r_hdr.integer, r_hdr_glowintensity.value, 0, 4);
-       M_Options_PrintSlider(  "     Bloom Color Scale", r_hdr.integer || r_bloom.integer, r_bloom_colorscale.value, 0.0625, 1);
-       M_Options_PrintSlider(  "  Bloom Color Subtract", r_hdr.integer || r_bloom.integer, r_bloom_colorsubtract.value, 0, 1-0.0625);
-       M_Options_PrintSlider(  "  Bloom Color Exponent", r_hdr.integer || r_bloom.integer, r_bloom_colorexponent.value, 1, 8);
-       M_Options_PrintSlider(  "       Bloom Intensity", r_hdr.integer || r_bloom.integer, r_bloom_brighten.value, 1, 4);
-       M_Options_PrintSlider(  "            Bloom Blur", r_hdr.integer || r_bloom.integer, r_bloom_blur.value, 1, 16);
-       M_Options_PrintSlider(  "      Bloom Resolution", r_hdr.integer || r_bloom.integer, r_bloom_resolution.value, 64, 2048);
+       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);
 }
 
@@ -2635,6 +2639,7 @@ static void M_Keys_Draw (void)
                        strlcpy(keystring, "???", sizeof(keystring));
                else
                {
+                       char tinystr[2];
                        keystring[0] = 0;
                        for (j = 0;j < NUMKEYS;j++)
                        {
@@ -2642,7 +2647,7 @@ static void M_Keys_Draw (void)
                                {
                                        if (j > 0)
                                                strlcat(keystring, " or ", sizeof(keystring));
-                                       strlcat(keystring, Key_KeynumToString (keys[j]), sizeof(keystring));
+                                       strlcat(keystring, Key_KeynumToString (keys[j], tinystr, sizeof(tinystr)), sizeof(keystring));
                                }
                        }
                }
@@ -2660,6 +2665,7 @@ static void M_Keys_Key (int k, int ascii)
 {
        char    cmd[80];
        int             keys[NUMKEYS];
+       char    tinystr[2];
 
        if (bind_grab)
        {       // defining a key
@@ -2670,7 +2676,7 @@ static void M_Keys_Key (int k, int ascii)
                }
                else //if (k != '`')
                {
-                       dpsnprintf (cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", Key_KeynumToString (k), bindnames[keys_cursor][0]);
+                       dpsnprintf (cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", Key_KeynumToString (k, tinystr, sizeof(tinystr)), bindnames[keys_cursor][0]);
                        Cbuf_InsertText (cmd);
                }
 
@@ -2902,6 +2908,7 @@ static void M_Video_Draw (void)
 {
        int t;
        cachepic_t      *p;
+       char vabuf[1024];
 
        if(!!vid_fullscreen.integer != menu_video_resolutions_forfullscreen)
        {
@@ -2921,12 +2928,12 @@ static void M_Video_Draw (void)
        // 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("%dx%d %.2fhz", vid.width, vid.height, vid.refreshrate));
+               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("%dx%d", vid.width, vid.height));
+               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("%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("Type: %s", menu_video_resolutions[menu_video_resolution].type));
+       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
@@ -3101,8 +3108,9 @@ void M_Menu_Help_f (void)
 
 static void M_Help_Draw (void)
 {
+       char vabuf[1024];
        M_Background(320, 200);
-       M_DrawPic (0, 0, va("gfx/help%i", help_page));
+       M_DrawPic (0, 0, va(vabuf, sizeof(vabuf), "gfx/help%i", help_page));
 }
 
 
@@ -3348,6 +3356,7 @@ static void M_LanConfig_Draw (void)
        int             basex;
        const char      *startJoin;
        const char      *protocol;
+       char vabuf[1024];
 
        M_Background(320, 200);
 
@@ -3361,7 +3370,7 @@ static void M_LanConfig_Draw (void)
        else
                startJoin = "Join Game";
        protocol = "TCP/IP";
-       M_Print(basex, 32, va ("%s - %s", startJoin, protocol));
+       M_Print(basex, 32, va(vabuf, sizeof(vabuf), "%s - %s", startJoin, protocol));
        basex += 8;
 
        M_Print(basex, lanConfig_cursor_table[0], "Port");
@@ -3398,6 +3407,7 @@ static void M_LanConfig_Draw (void)
 static void M_LanConfig_Key (int key, int ascii)
 {
        int             l;
+       char vabuf[1024];
 
        switch (key)
        {
@@ -3447,7 +3457,7 @@ static void M_LanConfig_Key (int key, int ascii)
                }
 
                if (lanConfig_cursor == 3)
-                       Cbuf_AddText ( va ("connect \"%s\"\n", lanConfig_joinname) );
+                       Cbuf_AddText(va(vabuf, sizeof(vabuf), "connect \"%s\"\n", lanConfig_joinname) );
                break;
 
        case K_BACKSPACE:
@@ -3969,6 +3979,7 @@ void M_GameOptions_Draw (void)
 {
        cachepic_t      *p;
        int             x;
+       char vabuf[1024];
 
        M_Background(320, 200);
 
@@ -3980,7 +3991,7 @@ void M_GameOptions_Draw (void)
        M_Print(160, 40, "begin game");
 
        M_Print(0, 56, "      Max players");
-       M_Print(160, 56, va("%i", maxplayers) );
+       M_Print(160, 56, va(vabuf, sizeof(vabuf), "%i", maxplayers) );
 
        if (gamemode != GAME_GOODVSBAD2)
        {
@@ -4073,20 +4084,20 @@ void M_GameOptions_Draw (void)
                if (fraglimit.integer == 0)
                        M_Print(160, 88, "none");
                else
-                       M_Print(160, 88, va("%i frags", fraglimit.integer));
+                       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("%i minutes", timelimit.integer));
+                       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("%i", sv_maxrate.integer));
+       M_Print(160, 112, va(vabuf, sizeof(vabuf), "%i", sv_maxrate.integer));
 
        M_Print(0, 128, "      Server name");
        M_DrawTextBox (0, 132, 38, 1);
@@ -4290,6 +4301,7 @@ static void M_GameOptions_Key (int key, int ascii)
 {
        int l;
        char hostnamebuf[128];
+       char vabuf[1024];
 
        switch (key)
        {
@@ -4330,10 +4342,10 @@ static void M_GameOptions_Key (int key, int ascii)
                if (gameoptions_cursor == 0)
                {
                        if (sv.active)
-                               Cbuf_AddText ("disconnect\n");
-                       Cbuf_AddText ( va ("maxplayers %u\n", maxplayers) );
+                               Cbuf_AddText("disconnect\n");
+                       Cbuf_AddText(va(vabuf, sizeof(vabuf), "maxplayers %u\n", maxplayers) );
 
-                       Cbuf_AddText ( va ("map %s\n", gameoptions_levels->levels[gameoptions_levels->episodes[startepisode].firstLevel + startlevel].name) );
+                       Cbuf_AddText(va(vabuf, sizeof(vabuf), "map %s\n", gameoptions_levels->levels[gameoptions_levels->episodes[startepisode].firstLevel + startlevel].name) );
                        return;
                }
 
@@ -4395,6 +4407,7 @@ 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)
@@ -4403,7 +4416,7 @@ static void M_ServerList_Draw (void)
                M_Background(640, vid_conheight.integer);
        // scroll the list as the cursor moves
        ServerList_GetPlayerStatistics(&numplayers, &maxplayers);
-       s = va("%i/%i masters %i/%i servers %i/%i players", masterreplycount, masterquerycount, serverreplycount, serverquerycount, 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);
@@ -4443,6 +4456,7 @@ static void M_ServerList_Draw (void)
 
 static void M_ServerList_Key(int k, int ascii)
 {
+       char vabuf[1024];
        switch (k)
        {
        case K_ESCAPE:
@@ -4475,7 +4489,7 @@ static void M_ServerList_Key(int k, int ascii)
        case K_ENTER:
                S_LocalSound ("sound/misc/menu2.wav");
                if (serverlist_viewcount)
-                       Cbuf_AddText(va("connect \"%s\"\n", ServerList_GetViewEntry(slist_cursor)->info.cname));
+                       Cbuf_AddText(va(vabuf, sizeof(vabuf), "connect \"%s\"\n", ServerList_GetViewEntry(slist_cursor)->info.cname));
                break;
 
        default:
@@ -4508,7 +4522,7 @@ static int modlist_cursor;
 static int modlist_count = 0;
 static modlist_entry_t modlist[MODLIST_TOTALSIZE];
 
-void ModList_RebuildList(void)
+static void ModList_RebuildList(void)
 {
        int i,j;
        stringlist_t list;
@@ -4545,7 +4559,7 @@ void ModList_RebuildList(void)
        stringlistfreecontents(&list);
 }
 
-void ModList_Enable (void)
+static void ModList_Enable (void)
 {
        int i;
        int numgamedirs;
@@ -4714,7 +4728,7 @@ static void M_Draw(void);
 void M_ToggleMenu(int mode);
 static void M_Shutdown(void);
 
-void M_Init (void)
+static void M_Init (void)
 {
        menuplyr_load = true;
        menuplyr_pixels = NULL;
@@ -4742,6 +4756,7 @@ void M_Init (void)
 
 void M_Draw (void)
 {
+       char vabuf[1024];
        if (key_dest != key_menu && key_dest != key_menu_grabbed)
                m_state = m_none;
 
@@ -4855,7 +4870,7 @@ void M_Draw (void)
                        g = (int)(realtime * 64)%96;
                        scale_y_rate = (float)(g+1) / 96;
                        top_offset = (g+12)/12;
-                       p = Draw_CachePic (va("gfx/menu/blooddrip%i", top_offset));
+                       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");
@@ -4873,7 +4888,7 @@ void M_Draw (void)
                                        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("gfx/menu/blooddrip%i", top_offset)), 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);
                        }
                }
        }
@@ -4992,7 +5007,7 @@ void M_KeyEvent (int key, int ascii, qboolean downevent)
 
 }
 
-void M_NewMap(void)
+static void M_NewMap(void)
 {
 }
 
@@ -5175,9 +5190,10 @@ static int m_numrequiredglobals = sizeof(m_required_globals) / sizeof(m_required
 
 void MR_SetRouting (qboolean forceold);
 
-void MP_Error(const char *format, ...) DP_FUNC_PRINTF(1);
-void MP_Error(const char *format, ...)
+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;
@@ -5189,10 +5205,10 @@ void MP_Error(const char *format, ...)
 
        if( !processingError ) {
                processingError = true;
-               PRVM_Crash();
+               PRVM_Crash(prog);
                processingError = false;
        } else {
-               Con_Printf( "Menu_Error: Recursive call to MP_Error (from PRVM_Crash)!\n" );
+               Con_Printf( "Menu_Error: Recursive call to MVM_error_cmd (from PRVM_Crash)!\n" );
        }
 
        // fall back to the normal menu
@@ -5211,24 +5227,62 @@ void MP_Error(const char *format, ...)
        Host_AbortCurrentFrame();
 }
 
-void MP_KeyEvent (int key, int ascii, qboolean downevent)
+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 ; i<prog->num_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)
 {
-       PRVM_Begin;
-       PRVM_SetProg(PRVM_MENUPROG);
+       return true;
+}
+
+static void MP_KeyEvent (int key, int ascii, qboolean downevent)
+{
+       prvm_prog_t *prog = MVM_prog;
 
        // pass key
        prog->globals.generic[OFS_PARM0] = (float) key;
        prog->globals.generic[OFS_PARM1] = (float) ascii;
        if (downevent)
-               PRVM_ExecuteProgram(PRVM_menufunction(m_keydown),"m_keydown(float key, float ascii) required");
+               prog->ExecuteProgram(prog, PRVM_menufunction(m_keydown),"m_keydown(float key, float ascii) required");
        else if (PRVM_menufunction(m_keyup))
-               PRVM_ExecuteProgram(PRVM_menufunction(m_keyup),"m_keyup(float key, float ascii) required");
-
-       PRVM_End;
+               prog->ExecuteProgram(prog, PRVM_menufunction(m_keyup),"m_keyup(float key, float ascii) required");
 }
 
-void MP_Draw (void)
+static void MP_Draw (void)
 {
+       prvm_prog_t *prog = MVM_prog;
        // declarations that are needed right now
 
        float oldquality;
@@ -5244,14 +5298,9 @@ void MP_Draw (void)
        // TODO: this needs to be exposed to R_SetView (or something similar) ASAP [2/5/2008 Andreas]
        r_refdef.scene.time = realtime;
 
-       PRVM_Begin;
-       PRVM_SetProg(PRVM_MENUPROG);
-
        // FIXME: this really shouldnt error out lest we have a very broken refdef state...?
        // or does it kill the server too?
-       PRVM_ExecuteProgram(PRVM_menufunction(m_draw),"m_draw() required");
-
-       PRVM_End;
+       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;
@@ -5259,63 +5308,63 @@ void MP_Draw (void)
        R_SelectScene( RST_CLIENT );
 }
 
-void MP_ToggleMenu(int mode)
+static void MP_ToggleMenu(int mode)
 {
-       PRVM_Begin;
-       PRVM_SetProg(PRVM_MENUPROG);
+       prvm_prog_t *prog = MVM_prog;
 
        prog->globals.generic[OFS_PARM0] = (float) mode;
-       PRVM_ExecuteProgram(PRVM_menufunction(m_toggle),"m_toggle() required");
-
-       PRVM_End;
+       prog->ExecuteProgram(prog, PRVM_menufunction(m_toggle),"m_toggle() required");
 }
 
-void MP_NewMap(void)
+static void MP_NewMap(void)
 {
-       PRVM_Begin;
-       PRVM_SetProg(PRVM_MENUPROG);
+       prvm_prog_t *prog = MVM_prog;
        if (PRVM_menufunction(m_newmap))
-               PRVM_ExecuteProgram(PRVM_menufunction(m_newmap),"m_newmap() required");
-       PRVM_End;
+               prog->ExecuteProgram(prog, PRVM_menufunction(m_newmap),"m_newmap() required");
 }
 
-void MP_Shutdown (void)
+static void MP_Shutdown (void)
 {
-       PRVM_Begin;
-       PRVM_SetProg(PRVM_MENUPROG);
+       prvm_prog_t *prog = MVM_prog;
 
-       PRVM_ExecuteProgram(PRVM_menufunction(m_shutdown),"m_shutdown() required");
+       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_ResetProg();
-
-       PRVM_End;
+       PRVM_Prog_Reset(prog);
 }
 
-void MP_Init (void)
+static void MP_Init (void)
 {
-       PRVM_Begin;
-       PRVM_InitProg(PRVM_MENUPROG);
+       prvm_prog_t *prog = MVM_prog;
+       PRVM_Prog_Init(prog);
 
        prog->edictprivate_size = 0; // no private struct used
-       prog->name = M_NAME;
+       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;
-       prog->init_cmd = VM_M_Cmd_Init;
-       prog->reset_cmd = VM_M_Cmd_Reset;
-       prog->error_cmd = MP_Error;
-       prog->ExecuteProgram = MVM_ExecuteProgram;
+
+       // 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(M_PROG_FILENAME, 0, NULL);
 
-       PRVM_LoadProgs(M_PROG_FILENAME, m_numrequiredfunc, m_required_func, m_numrequiredfields, m_required_fields, m_numrequiredglobals, m_required_globals);
+       PRVM_Prog_Load(prog, M_PROG_FILENAME, 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
@@ -5323,9 +5372,7 @@ void MP_Init (void)
        in_client_mouse = true;
 
        // call the prog init
-       PRVM_ExecuteProgram(PRVM_menufunction(m_init),"m_init() required");
-
-       PRVM_End;
+       prog->ExecuteProgram(prog, PRVM_menufunction(m_init),"m_init() required");
 }
 
 //============================================================================
@@ -5369,7 +5416,7 @@ void MR_Restart(void)
        MR_SetRouting (FALSE);
 }
 
-void Call_MR_ToggleMenu_f(void)
+static void Call_MR_ToggleMenu_f(void)
 {
        int m;
        m = ((Cmd_Argc() < 2) ? -1 : atoi(Cmd_Argv(1)));
index 1ca8799b6bb185ff189f24b5b956822ecef414c6..aac8a4bc52dbdc48cb3e0904c69fbbbdc3b6f120 100644 (file)
@@ -22,7 +22,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #define MENU_H
 
 #define M_PROG_FILENAME "menu.dat"
-#define M_NAME "menu"
 
 enum m_state_e {
        m_none,
index d21ba627aec464dc0e7fa359d06e169319b5bb9f..69bb69198e2fcc65406b5e3324f6d855535d831e 100644 (file)
@@ -10,14 +10,13 @@ typedef struct meshqueue_s
        int surfacenumber;
        const rtlight_t *rtlight;
        float dist;
+       meshqueue_sortcategory_t category;
 }
 meshqueue_t;
 
 int trans_sortarraysize;
 meshqueue_t **trans_hash = NULL;
 meshqueue_t ***trans_hashpointer = NULL;
-extern cvar_t r_transparent_sortarraysize;
-extern cvar_t r_transparent_sortmaxdist;
 
 float mqt_viewplanedist;
 float mqt_viewmaxdist;
@@ -32,7 +31,7 @@ void R_MeshQueue_BeginScene(void)
        mqt_viewmaxdist = 0;
 }
 
-void R_MeshQueue_AddTransparent(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_AddTransparent(meshqueue_sortcategory_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)
@@ -52,7 +51,11 @@ void R_MeshQueue_AddTransparent(const vec3_t center, void (*callback)(const enti
        mq->ent = ent;
        mq->surfacenumber = surfacenumber;
        mq->rtlight = rtlight;
-       mq->dist = DotProduct(center, r_refdef.view.forward) - mqt_viewplanedist;
+       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);
 }
@@ -73,8 +76,10 @@ void R_MeshQueue_RenderTransparent(void)
        // 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_sortmaxdist.integer < 1 || r_transparent_sortmaxdist.integer > 32768)
-               Cvar_SetValueQuick(&r_transparent_sortmaxdist, bound(1, r_transparent_sortmaxdist.integer, 32768));
+       if (r_transparent_sortmindist.integer < 1 || r_transparent_sortmindist.integer >= r_transparent_sortmaxdist.integer)
+               Cvar_SetValueQuick(&r_transparent_sortmindist, 0);
+       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)
@@ -96,7 +101,20 @@ void R_MeshQueue_RenderTransparent(void)
        maxhashindex = trans_sortarraysize - 1;
        for (i = 0, mqt = mqt_array; i < mqt_count; i++, mqt++)
        {
-               hashindex = bound(0, (int)(min(mqt->dist, r_transparent_sortmaxdist.integer) * distscale), maxhashindex);
+               switch(mqt->category)
+               {
+               default:
+               case MESHQUEUE_SORT_HUD:
+                       hashindex = 0;
+                       break;
+               case MESHQUEUE_SORT_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 MESHQUEUE_SORT_SKY:
+                       hashindex = maxhashindex;
+                       break;
+               }
                // link to tail of hash chain (to preserve render order)
                mqt->next = NULL;
                *trans_hashpointer[hashindex] = mqt;
index f54c4ce39e3e0320d12f2a230ebf4dd38ff39451..9a727f30ff110674d784baa014e11b56a61f4d3f 100644 (file)
@@ -5,8 +5,16 @@
 // VorteX: seems this value is hardcoded in other several defines as it's changing makes mess
 #define MESHQUEUE_TRANSPARENT_BATCHSIZE 256
 
+typedef enum meshqueue_sortcategory_e
+{
+       MESHQUEUE_SORT_SKY,
+       MESHQUEUE_SORT_DISTANCE,
+       MESHQUEUE_SORT_HUD,
+}
+meshqueue_sortcategory_t;
+
 void R_MeshQueue_BeginScene(void);
-void R_MeshQueue_AddTransparent(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_AddTransparent(meshqueue_sortcategory_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
index 24cc8a9e8eb2f2f40605971310533d1f3847b3d5..00ab435d9661176aeb80ba1baee7a087ffed448a 100644 (file)
@@ -16,9 +16,6 @@ void Mod_Skeletal_AnimateVertices_Generic(const dp_model_t * RESTRICT model, con
        float m[12];
        const blendweights_t * RESTRICT weights;
 
-       if (!model->surfmesh.num_vertices)
-               return;
-
        //unsigned long long ts = rdtsc();
        bonepose = (float12_t *) Mod_Skeletal_AnimateVertices_AllocBuffers(sizeof(float12_t) * (model->num_bones*2 + model->surfmesh.num_blends));
        boneposerelative = bonepose + model->num_bones;
index 06d74317147200df89267e118097f6326a10f8d1..f575d24522db67e7b2d3f604e639905f8d6706c4 100644 (file)
@@ -20,9 +20,6 @@ void Mod_Skeletal_AnimateVertices_SSE(const dp_model_t * RESTRICT model, const f
        const blendweights_t * RESTRICT weights;
        int num_vertices_minus_one;
 
-       if (!model->surfmesh.num_vertices)
-               return;
-
        num_vertices_minus_one = model->surfmesh.num_vertices - 1;
 
        //unsigned long long ts = rdtsc();
index 2231f3df546326c1b65a01d40818ff15260b05c5..7a53d59e4a14051f8db336716db287824559c7f6 100644 (file)
@@ -40,29 +40,42 @@ cvar_t mod_alias_supporttagscale = {0, "mod_alias_supporttagscale", "1", "suppor
 
 float mod_md3_sin[320];
 
-static size_t Mod_Skeltal_AnimateVertices_maxbonepose = 0;
-static void *Mod_Skeltal_AnimateVertices_bonepose = NULL;
+static size_t Mod_Skeletal_AnimateVertices_maxbonepose = 0;
+static void *Mod_Skeletal_AnimateVertices_bonepose = NULL;
 void Mod_Skeletal_FreeBuffers(void)
 {
-       if(Mod_Skeltal_AnimateVertices_bonepose)
-               Mem_Free(Mod_Skeltal_AnimateVertices_bonepose);
-       Mod_Skeltal_AnimateVertices_maxbonepose = 0;
-       Mod_Skeltal_AnimateVertices_bonepose = NULL;
+       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_Skeltal_AnimateVertices_maxbonepose < nbytes)
+       if(Mod_Skeletal_AnimateVertices_maxbonepose < nbytes)
        {
-               if(Mod_Skeltal_AnimateVertices_bonepose)
-                       Mem_Free(Mod_Skeltal_AnimateVertices_bonepose);
-               Mod_Skeltal_AnimateVertices_bonepose = Z_Malloc(nbytes);
-               Mod_Skeltal_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_Skeltal_AnimateVertices_bonepose;
+       return Mod_Skeletal_AnimateVertices_bonepose;
 }
 
-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)
+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)
@@ -100,7 +113,7 @@ void Mod_AliasInit (void)
 #endif
 }
 
-int Mod_Skeletal_AddBlend(dp_model_t *model, const blendweights_t *newweights)
+static int Mod_Skeletal_AddBlend(dp_model_t *model, const blendweights_t *newweights)
 {
        int i;
        blendweights_t *weights;
@@ -117,7 +130,7 @@ int Mod_Skeletal_AddBlend(dp_model_t *model, const blendweights_t *newweights)
        return model->num_bones + i;
 }
 
-int Mod_Skeletal_CompressBlend(dp_model_t *model, const int *newindex, const float *newinfluence)
+static int Mod_Skeletal_CompressBlend(dp_model_t *model, const int *newindex, const float *newinfluence)
 {
        int i, total;
        float scale;
@@ -160,7 +173,7 @@ int Mod_Skeletal_CompressBlend(dp_model_t *model, const int *newindex, const flo
        return Mod_Skeletal_AddBlend(model, &newweights);
 }
 
-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)
+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;
@@ -248,7 +261,7 @@ void Mod_MD3_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend
                }
        }
 }
-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)
+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;
@@ -516,19 +529,51 @@ static void Mod_Alias_CalculateBoundingBox(void)
        qboolean firstvertex = true;
        float dist, yawradius, radius;
        float *v;
-       float *vertex3f;
-       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]));
        VectorClear(loadmodel->normalmins);
        VectorClear(loadmodel->normalmaxs);
        yawradius = 0;
        radius = 0;
-       for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
+       if (loadmodel->AnimateVertices)
        {
-               loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL);
-               for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
+               float *vertex3f;
+               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]));
+               for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
+               {
+                       loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL);
+                       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)
                        {
@@ -553,8 +598,6 @@ static void Mod_Alias_CalculateBoundingBox(void)
                                radius = dist;
                }
        }
-       if (vertex3f)
-               Mem_Free(vertex3f);
        radius = sqrt(radius);
        yawradius = sqrt(yawradius);
        loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius;
@@ -600,19 +643,14 @@ static void Mod_MDLMD2MD3_TraceLine(dp_model_t *model, const frameblend_t *frame
        int i;
        float segmentmins[3], segmentmaxs[3];
        msurface_t *surface;
-       static int maxvertices = 0;
-       static float *vertex3f = NULL;
+       float vertex3fbuf[1024*3];
+       float *vertex3f = vertex3fbuf;
        memset(trace, 0, sizeof(*trace));
        trace->fraction = 1;
        trace->realfraction = 1;
        trace->hitsupercontentsmask = hitsupercontentsmask;
-       if (maxvertices < model->surfmesh.num_vertices)
-       {
-               if (vertex3f)
-                       Z_Free(vertex3f);
-               maxvertices = (model->surfmesh.num_vertices + 255) & ~255;
-               vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3]));
-       }
+       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;
@@ -622,17 +660,18 @@ static void Mod_MDLMD2MD3_TraceLine(dp_model_t *model, const frameblend_t *frame
        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 int maxvertices = 0;
-static float *vertex3f = NULL;
-
 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;
 
@@ -650,13 +689,8 @@ static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, const frameblend_t *frameb
        trace->fraction = 1;
        trace->realfraction = 1;
        trace->hitsupercontentsmask = hitsupercontentsmask;
-       if (maxvertices < model->surfmesh.num_vertices)
-       {
-               if (vertex3f)
-                       Z_Free(vertex3f);
-               maxvertices = (model->surfmesh.num_vertices + 255) & ~255;
-               vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3]));
-       }
+       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;
@@ -669,16 +703,11 @@ static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, const frameblend_t *frameb
        VectorAdd(end, boxmaxs, boxendmaxs);
        Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL);
        Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL);
-       if (maxvertices < model->surfmesh.num_vertices)
-       {
-               if (vertex3f)
-                       Z_Free(vertex3f);
-               maxvertices = (model->surfmesh.num_vertices + 255) & ~255;
-               vertex3f = (float *)Z_Malloc(maxvertices * sizeof(float[3]));
-       }
        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)
@@ -787,6 +816,7 @@ static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *ski
        texture->currentmaterialflags = texture->basematerialflags;
        texture->offsetmapping = OFFSETMAPPING_DEFAULT;
        texture->offsetscale = 1;
+       texture->offsetbias = 0;
        texture->specularscalemod = 1;
        texture->specularpowermod = 1;
        texture->surfaceflags = 0;
@@ -798,7 +828,7 @@ static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *ski
 void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
 {
        int i;
-       static char stripbuf[MAX_QPATH];
+       char stripbuf[MAX_QPATH];
        skinfileitem_t *skinfileitem;
        if(developer_extra.integer)
                Con_DPrintf("Looking up texture for %s (default: %s)\n", meshname, shadername);
@@ -864,6 +894,7 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
        float *vertst;
        int *vertonseam, *vertremap;
        skinfile_t *skinfiles;
+       char vabuf[1024];
 
        datapointer = (unsigned char *)buffer;
        pinmodel = (mdl_t *)datapointer;
@@ -877,7 +908,6 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->modeldatatypestring = "MDL";
 
        loadmodel->type = mod_alias;
-       loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
        loadmodel->DrawSky = NULL;
        loadmodel->DrawAddWaterPlanes = NULL;
        loadmodel->Draw = R_Q1BSP_Draw;
@@ -1058,10 +1088,12 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
                loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
        }
        Mod_MDL_LoadFrames (startframes, numverts, vertremap);
+       loadmodel->AnimateVertices = Mod_MDL_AnimateVertices; // needed during loading, may be cleared by code later in this function
        if (loadmodel->surfmesh.data_neighbor3i)
                Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
        Mod_Alias_CalculateBoundingBox();
        Mod_Alias_MorphMesh_CompileFrames();
+       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MDL_AnimateVertices : NULL;
 
        Mem_Free(vertst);
        Mem_Free(vertremap);
@@ -1141,7 +1173,7 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
                // 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("%s_%i", loadmodel->name, loadmodel->numskins), (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false)))
+               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;
@@ -1180,7 +1212,8 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
        surface->num_firstvertex = 0;
        surface->num_vertices = loadmodel->surfmesh.num_vertices;
 
-       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
+       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
+       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MDL_AnimateVertices : NULL;
 
        if (!loadmodel->surfmesh.isanimated)
        {
@@ -1191,6 +1224,15 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
                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)
@@ -1225,7 +1267,6 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->modeldatatypestring = "MD2";
 
        loadmodel->type = mod_alias;
-       loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
        loadmodel->DrawSky = NULL;
        loadmodel->DrawAddWaterPlanes = NULL;
        loadmodel->Draw = R_Q1BSP_Draw;
@@ -1430,10 +1471,13 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
 
        Mem_Free(vertremap);
 
+       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
+       loadmodel->AnimateVertices = Mod_MDL_AnimateVertices; // needed during loading, may be cleared by code later in this function
        if (loadmodel->surfmesh.data_neighbor3i)
                Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
        Mod_Alias_CalculateBoundingBox();
        Mod_Alias_MorphMesh_CompileFrames();
+       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MDL_AnimateVertices : NULL;
 
        surface = loadmodel->data_surfaces;
        surface->texture = loadmodel->data_textures;
@@ -1442,8 +1486,6 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
        surface->num_firstvertex = 0;
        surface->num_vertices = loadmodel->surfmesh.num_vertices;
 
-       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
-
        if (!loadmodel->surfmesh.isanimated)
        {
                Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
@@ -1453,6 +1495,15 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
                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)
@@ -1482,7 +1533,6 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->modeldatatypestring = "MD3";
 
        loadmodel->type = mod_alias;
-       loadmodel->AnimateVertices = Mod_MD3_AnimateVertices;
        loadmodel->DrawSky = NULL;
        loadmodel->DrawAddWaterPlanes = NULL;
        loadmodel->Draw = R_Q1BSP_Draw;
@@ -1621,15 +1671,15 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
        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];
+       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
+       loadmodel->AnimateVertices = Mod_MD3_AnimateVertices; // needed during loading, may be cleared by code later in this function
        if (loadmodel->surfmesh.data_neighbor3i)
                Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
        Mod_Alias_MorphMesh_CompileFrames();
        Mod_Alias_CalculateBoundingBox();
        Mod_FreeSkinFiles(skinfiles);
        Mod_MakeSortedSurfaces(loadmodel);
-
-       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1
-            || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
+       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_MD3_AnimateVertices : NULL;
 
        if (!loadmodel->surfmesh.isanimated)
        {
@@ -1640,6 +1690,15 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
                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)
@@ -1714,7 +1773,6 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                return;
        }
 
-       loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
        loadmodel->DrawSky = NULL;
        loadmodel->DrawAddWaterPlanes = NULL;
        loadmodel->Draw = R_Q1BSP_Draw;
@@ -1817,6 +1875,8 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        meshvertices = pheader->numverts;
        meshtriangles = pheader->numtris;
 
+       loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
+       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
        loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
        loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
        loadmodel->num_texturesperskin = loadmodel->num_surfaces;
@@ -2008,8 +2068,6 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        if (loadmodel->surfmesh.data_neighbor3i)
                Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
 
-       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
-
        if (!loadmodel->surfmesh.isanimated)
        {
                Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
@@ -2019,6 +2077,15 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                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)
@@ -2077,7 +2144,6 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                return;
        }
 
-       loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
        loadmodel->DrawSky = NULL;
        loadmodel->DrawAddWaterPlanes = NULL;
        loadmodel->Draw = R_Q1BSP_Draw;
@@ -2130,6 +2196,8 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs;
        loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
        loadmodel->num_texturesperskin = loadmodel->num_surfaces;
+       loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
+       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
        // 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)) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]) + 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);
@@ -2365,8 +2433,6 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        if (loadmodel->surfmesh.data_neighbor3i)
                Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
 
-       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
-
        if (!loadmodel->surfmesh.isanimated)
        {
                Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
@@ -2376,6 +2442,15 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                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...
@@ -2409,7 +2484,6 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->modeldatatypestring = "PSK";
 
        loadmodel->type = mod_alias;
-       loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
        loadmodel->DrawSky = NULL;
        loadmodel->DrawAddWaterPlanes = NULL;
        loadmodel->Draw = R_Q1BSP_Draw;
@@ -2430,8 +2504,8 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        strlcat(animname, ".psa", sizeof(animname));
        animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize);
        animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize);
-       if (animbuffer == NULL)
-               Host_Error("%s: can't find .psa file (%s)", loadmodel->name, animname);
+       if (!animbuffer)
+               animbufferend = animbuffer;
 
        numpnts = 0;
        pnts = NULL;
@@ -2749,15 +2823,19 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                        Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id);
        }
 
-       if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights || !numanims || !anims || !numanimkeys || !animkeys)
+       if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights)
                Host_Error("%s: missing required chunks", loadmodel->name);
 
-       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);
+       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;
@@ -2773,6 +2851,8 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->num_texturesperskin = loadmodel->num_surfaces;
        loadmodel->surfmesh.num_vertices = meshvertices;
        loadmodel->surfmesh.num_triangles = meshtriangles;
+       loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
+       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
        // 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 short) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]) + 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);
@@ -2857,6 +2937,30 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                        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++)
@@ -2895,49 +2999,91 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                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
-       for (index = 0, i = 0;index < numanims;index++)
+       if (numanims)
        {
-               for (j = 0;j < anims[index].numframes;j++, i++)
+               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++)
                {
-                       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;
+                       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[6] format for longterm storage
+                       loadmodel->data_poses6s[index*6+0] = k->origin[0] * loadmodel->num_poseinvscale;
+                       loadmodel->data_poses6s[index*6+1] = k->origin[1] * loadmodel->num_poseinvscale;
+                       loadmodel->data_poses6s[index*6+2] = k->origin[2] * loadmodel->num_poseinvscale;
+                       loadmodel->data_poses6s[index*6+3] = quat[0] * 32767.0f;
+                       loadmodel->data_poses6s[index*6+4] = quat[1] * 32767.0f;
+                       loadmodel->data_poses6s[index*6+5] = quat[2] * 32767.0f;
                }
        }
-
-       // calculate the scaling value for bone origins so they can be compressed to short
-       biggestorigin = 0;
-       for (index = 0;index < numanimkeys;index++)
+       else
        {
-               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;
+               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;
 
-       // 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[6] format for longterm storage
-               loadmodel->data_poses6s[index*6+0] = k->origin[0] * loadmodel->num_poseinvscale;
-               loadmodel->data_poses6s[index*6+1] = k->origin[1] * loadmodel->num_poseinvscale;
-               loadmodel->data_poses6s[index*6+2] = k->origin[2] * loadmodel->num_poseinvscale;
-               loadmodel->data_poses6s[index*6+3] = quat[0] * 32767.0f;
-               loadmodel->data_poses6s[index*6+4] = quat[1] * 32767.0f;
-               loadmodel->data_poses6s[index*6+5] = quat[2] * 32767.0f;
+               // 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[6] format for longterm storage
+                       loadmodel->data_poses6s[index*6+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale;
+                       loadmodel->data_poses6s[index*6+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale;
+                       loadmodel->data_poses6s[index*6+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale;
+                       loadmodel->data_poses6s[index*6+3] = quat[0] * 32767.0f;
+                       loadmodel->data_poses6s[index*6+4] = quat[1] * 32767.0f;
+                       loadmodel->data_poses6s[index*6+5] = quat[2] * 32767.0f;
+               }
        }
+
        Mod_FreeSkinFiles(skinfiles);
-       Mem_Free(animfilebuffer);
+       if (animfilebuffer)
+               Mem_Free(animfilebuffer);
        Mod_MakeSortedSurfaces(loadmodel);
 
        // compute all the mesh information that was not loaded from the file
@@ -2946,15 +3092,12 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                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);
        Mod_Alias_CalculateBoundingBox();
 
-       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
-
        if (!loadmodel->surfmesh.isanimated)
        {
                Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
@@ -2964,38 +3107,64 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                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;
-       unsigned char *pbase, *pend;
-       iqmheader_t *header;
+       const unsigned char *pbase, *pend;
+       iqmheader_t header;
        skinfile_t *skinfiles;
        int i, j, k, meshvertices, meshtriangles;
-       float *vposition = NULL, *vtexcoord = NULL, *vnormal = NULL, *vtangent = NULL;
-       unsigned char *vblendindexes = NULL, *vblendweights = NULL;
+       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;
-       iqmanim_t *anim;
-       iqmmesh_t *mesh;
-       iqmbounds_t *bounds;
-       iqmvertexarray_t *va;
-       unsigned short *framedata;
-       float biggestorigin;
-       const int *inelements;
-       int *outelements;
-       float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector;
+       iqmvertexarray_t *vas = NULL;
 
        pbase = (unsigned char *)buffer;
        pend = (unsigned char *)bufferend;
-       header = (iqmheader_t *)buffer;
-       if (memcmp(header->id, "INTERQUAKEMODEL", 16))
+
+       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)
+       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";
@@ -3004,116 +3173,137 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        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->num_triangles < 1 || header->num_vertexes < 3 || header->num_vertexarrays < 1 || header->num_meshes < 1)
-       {
-               Con_Printf("%s has no geometry\n", loadmodel->name);
-               return;
+       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;
+               }
        }
-       if (header->num_frames < 1 || header->num_anims < 1)
+       else
        {
-               Con_Printf("%s has no animations\n", loadmodel->name);
-               return;
+               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_joints + header->num_joints*sizeof(iqmjoint_t) > pend ||
-               pbase + header->ofs_poses + header->num_poses*sizeof(iqmpose_t) > 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)
+       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;
        }
 
-       va = (iqmvertexarray_t *)(pbase + header->ofs_vertexarrays);
-       for (i = 0;i < (int)header->num_vertexarrays;i++)
+       // 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[i].type = LittleLong(va[i].type);
-               va[i].flags = LittleLong(va[i].flags);
-               va[i].format = LittleLong(va[i].format);
-               va[i].size = LittleLong(va[i].size);
-               va[i].offset = LittleLong(va[i].offset);
-               vsize = header->num_vertexes*va[i].size;
-               switch (va[i].format)
+               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[i].offset + vsize > pend)
-                 continue;
-               switch (va[i].type)
+               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[i].format == IQM_FLOAT && va[i].size == 3)
-                               vposition = (float *)(pbase + va[i].offset);
+                       if (va.format == IQM_FLOAT && va.size == 3)
+                               vposition = (const float *)(pbase + va.offset);
                        break;
                case IQM_TEXCOORD:
-                       if (va[i].format == IQM_FLOAT && va[i].size == 2)
-                               vtexcoord = (float *)(pbase + va[i].offset);
+                       if (va.format == IQM_FLOAT && va.size == 2)
+                               vtexcoord = (const float *)(pbase + va.offset);
                        break;
                case IQM_NORMAL:
-                       if (va[i].format == IQM_FLOAT && va[i].size == 3)
-                               vnormal = (float *)(pbase + va[i].offset);
+                       if (va.format == IQM_FLOAT && va.size == 3)
+                               vnormal = (const float *)(pbase + va.offset);
                        break;
                case IQM_TANGENT:
-                       if (va[i].format == IQM_FLOAT && va[i].size == 4)
-                               vtangent = (float *)(pbase + va[i].offset);
+                       if (va.format == IQM_FLOAT && va.size == 4)
+                               vtangent = (const float *)(pbase + va.offset);
                        break;
                case IQM_BLENDINDEXES:
-                       if (va[i].format == IQM_UBYTE && va[i].size == 4)
-                               vblendindexes = (unsigned char *)(pbase + va[i].offset);
+                       if (va.format == IQM_UBYTE && va.size == 4)
+                               vblendindexes = (const unsigned char *)(pbase + va.offset);
                        break;
                case IQM_BLENDWEIGHTS:
-                       if (va[i].format == IQM_UBYTE && va[i].size == 4)
-                               vblendweights = (unsigned char *)(pbase + va[i].offset);
+                       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 (!vposition || !vtexcoord || !vblendindexes || !vblendweights)
+       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) : "";
+       text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : "";
 
-       loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices;
        loadmodel->DrawSky = NULL;
        loadmodel->DrawAddWaterPlanes = NULL;
        loadmodel->Draw = R_Q1BSP_Draw;
@@ -3134,18 +3324,19 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        if (loadmodel->numskins < 1)
                loadmodel->numskins = 1;
 
-       loadmodel->numframes = header->num_anims;
-       loadmodel->num_bones = header->num_joints;
-       loadmodel->num_poses = header->num_frames;
-       loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header->num_meshes;
+       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;
+       loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices; // updated later
 
-       meshvertices = header->num_vertexes;
-       meshtriangles = header->num_triangles;
+       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]) + sizeof(unsigned short)) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t));
+       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) : 0) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]) + 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);
@@ -3161,18 +3352,26 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        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]);
+       }
        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 (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_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
-       loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
+       if (vblendindexes && vblendweights)
+               loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t));
 
        for (i = 0;i < loadmodel->numskins;i++)
        {
@@ -3183,19 +3382,21 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        }
 
        // load the bone info
-       if (header->version == 1)
+       if (header.version == 1)
        {
-               joint1 = (iqmjoint1_t *) (pbase + header->ofs_joints);
+               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(joint1[i].name);
-                       joint1[i].parent = LittleLong(joint1[i].parent);
+                       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(joint1[i].origin[j]);
-                               joint1[i].rotation[j] = LittleFloat(joint1[i].rotation[j]);
-                               joint1[i].scale[j] = LittleFloat(joint1[i].scale[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;
@@ -3214,26 +3415,28 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        }
        else
        {
-               joint = (iqmjoint_t *) (pbase + header->ofs_joints);
+               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(joint[i].name);
-                       joint[i].parent = LittleLong(joint[i].parent);
+                       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(joint[i].origin[j]);
-                               joint[i].rotation[j] = LittleFloat(joint[i].rotation[j]);
-                               joint[i].scale[j] = LittleFloat(joint[i].scale[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(joint[i].rotation[3]);
+                       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);
+                       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)
@@ -3247,34 +3450,47 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        }
 
        // set up the animscenes based on the anims
-       anim = (iqmanim_t *) (pbase + header->ofs_anims);
-       for (i = 0;i < (int)header->num_anims;i++)
-       {
-               anim[i].name = LittleLong(anim[i].name);
-               anim[i].first_frame = LittleLong(anim[i].first_frame);
-               anim[i].num_frames = LittleLong(anim[i].num_frames);
-               anim[i].framerate = LittleFloat(anim[i].framerate);
-               anim[i].flags = LittleLong(anim[i].flags);
-               strlcpy(loadmodel->animscenes[i].name, &text[anim[i].name], sizeof(loadmodel->animscenes[i].name));
-               loadmodel->animscenes[i].firstframe = anim[i].first_frame;
-               loadmodel->animscenes[i].framecount = anim[i].num_frames;
-               loadmodel->animscenes[i].loop = ((anim[i].flags & IQM_LOOP) != 0);
-               loadmodel->animscenes[i].framerate = anim[i].framerate;
+       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);
+       loadmodel->AnimateVertices = loadmodel->surfmesh.isanimated ? Mod_Skeletal_AnimateVertices : NULL;
+
        biggestorigin = 0;
-       if (header->version == 1)
+       if (header.version == 1)
        {
-               pose1 = (iqmpose1_t *) (pbase + header->ofs_poses);
-               for (i = 0;i < (int)header->num_poses;i++)
+               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(pose1[i].parent);
-                       pose1[i].channelmask = LittleLong(pose1[i].channelmask);
+                       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(pose1[i].channeloffset[j]);
-                               pose1[i].channelscale[j] = LittleFloat(pose1[i].channelscale[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);
@@ -3283,19 +3499,31 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                        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
        {
-               pose = (iqmpose_t *) (pbase + header->ofs_poses);
-               for (i = 0;i < (int)header->num_poses;i++)
+               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(pose[i].parent);
-                       pose[i].channelmask = LittleLong(pose[i].channelmask);
+                       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(pose[i].channeloffset[j]);
-                               pose[i].channelscale[j] = LittleFloat(pose[i].channelscale[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);
@@ -3304,17 +3532,28 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                        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
-       framedata = (unsigned short *) (pbase + header->ofs_frames);
-       if (header->version == 1)
+       // 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 (i = 0, k = 0;i < (int)header.num_frames;i++)
                {
-                       for (j = 0;j < (int)header->num_poses;j++, k++)
+                       for (j = 0;j < (int)header.num_poses;j++, k++)
                        {
                                loadmodel->data_poses6s[k*6 + 0] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[0] + (pose1[j].channelmask&1 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[0] : 0));
                                loadmodel->data_poses6s[k*6 + 1] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[1] + (pose1[j].channelmask&2 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[1] : 0));
@@ -3328,12 +3567,24 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                                if(pose1[j].channelmask&256) framedata++;
                        }
                }
+               if (header.num_frames <= 0)
+               {
+                       for (i = 0;i < loadmodel->num_bones;i++)
+                       {
+                               loadmodel->data_poses6s[i*6 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0];
+                               loadmodel->data_poses6s[i*6 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1];
+                               loadmodel->data_poses6s[i*6 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2];
+                               loadmodel->data_poses6s[i*6 + 3] = 32767.0f * joint1[i].rotation[0];
+                               loadmodel->data_poses6s[i*6 + 4] = 32767.0f * joint1[i].rotation[1];
+                               loadmodel->data_poses6s[i*6 + 5] = 32767.0f * joint1[i].rotation[2];
+                       }
+               }
        }
        else
        {
-               for (i = 0, k = 0;i < (int)header->num_frames;i++)      
+               for (i = 0, k = 0;i < (int)header.num_frames;i++)       
                {
-                       for (j = 0;j < (int)header->num_poses;j++, k++)
+                       for (j = 0;j < (int)header.num_poses;j++, k++)
                        {
                                float rot[4];
                                loadmodel->data_poses6s[k*6 + 0] = loadmodel->num_poseinvscale * (pose[j].channeloffset[0] + (pose[j].channelmask&1 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[0] : 0));
@@ -3355,43 +3606,55 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                                if(pose[j].channelmask&512) framedata++;
                        }
                }
+               if (header.num_frames <= 0)
+               {
+                       for (i = 0;i < loadmodel->num_bones;i++)
+                       {
+                               loadmodel->data_poses6s[i*6 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0];
+                               loadmodel->data_poses6s[i*6 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1];
+                               loadmodel->data_poses6s[i*6 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2];
+                               loadmodel->data_poses6s[i*6 + 3] = 32767.0f * joint[i].rotation[0];
+                               loadmodel->data_poses6s[i*6 + 4] = 32767.0f * joint[i].rotation[1];
+                               loadmodel->data_poses6s[i*6 + 5] = 32767.0f * joint[i].rotation[2];
+                       }
+               }
        }
 
        // load bounding box data
-       if (header->ofs_bounds)
+       if (header.ofs_bounds)
        {
                float xyradius = 0, radius = 0;
-               bounds = (iqmbounds_t *) (pbase + header->ofs_bounds);
                VectorClear(loadmodel->normalmins);
                VectorClear(loadmodel->normalmaxs);
-               for (i = 0; i < (int)header->num_frames;i++)
-               {
-                       bounds[i].mins[0] = LittleFloat(bounds[i].mins[0]);
-                       bounds[i].mins[1] = LittleFloat(bounds[i].mins[1]);
-                       bounds[i].mins[2] = LittleFloat(bounds[i].mins[2]);
-                       bounds[i].maxs[0] = LittleFloat(bounds[i].maxs[0]);                     
-                       bounds[i].maxs[1] = LittleFloat(bounds[i].maxs[1]);     
-                       bounds[i].maxs[2] = LittleFloat(bounds[i].maxs[2]);     
-                       bounds[i].xyradius = LittleFloat(bounds[i].xyradius);
-                       bounds[i].radius = LittleFloat(bounds[i].radius);
+               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(bounds[i].mins, loadmodel->normalmins);
-                               VectorCopy(bounds[i].maxs, loadmodel->normalmaxs);
+                               VectorCopy(bound.mins, loadmodel->normalmins);
+                               VectorCopy(bound.maxs, loadmodel->normalmaxs);
                        }
                        else
                        {
-                               if (loadmodel->normalmins[0] > bounds[i].mins[0]) loadmodel->normalmins[0] = bounds[i].mins[0];
-                               if (loadmodel->normalmins[1] > bounds[i].mins[1]) loadmodel->normalmins[1] = bounds[i].mins[1];
-                               if (loadmodel->normalmins[2] > bounds[i].mins[2]) loadmodel->normalmins[2] = bounds[i].mins[2];
-                               if (loadmodel->normalmaxs[0] < bounds[i].maxs[0]) loadmodel->normalmaxs[0] = bounds[i].maxs[0];
-                               if (loadmodel->normalmaxs[1] < bounds[i].maxs[1]) loadmodel->normalmaxs[1] = bounds[i].maxs[1];
-                               if (loadmodel->normalmaxs[2] < bounds[i].maxs[2]) loadmodel->normalmaxs[2] = bounds[i].maxs[2];
+                               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 (bounds[i].xyradius > xyradius)
-                               xyradius = bounds[i].xyradius;
-                       if (bounds[i].radius > radius)
-                               radius = bounds[i].radius;
+                       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;
@@ -3404,35 +3667,38 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        }
 
        // load triangle data
-       inelements = (const int *) (pbase + header->ofs_triangles);
+       // 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++)
+       for (i = 0;i < (int)header.num_triangles;i++)
        {
-               outelements[0] = LittleLong(inelements[0]);             
+               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__);
+       Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__);
 
-       if (header->ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
+       if (header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i)
        {
-               inelements = (const int *) (pbase + header->ofs_neighbors);
-               outelements = loadmodel->surfmesh.data_neighbor3i;
-               for (i = 0;i < (int)header->num_triangles;i++)
+               // 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++)
                {
-                       outelements[0] = LittleLong(inelements[0]);
-                       outelements[1] = LittleLong(inelements[1]);
-                       outelements[2] = LittleLong(inelements[2]);
-                       outelements += 3;
-                       inelements += 3;
+                       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++)
+       for (i = 0;i < (int)header.num_vertexes;i++)
        {
                outvertex[0] = LittleFloat(vposition[0]);
                outvertex[1] = LittleFloat(vposition[1]);
@@ -3442,7 +3708,8 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        }
 
        outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f;
-       for (i = 0;i < (int)header->num_vertexes;i++)
+       // 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]);
@@ -3450,10 +3717,11 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                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++)
+               for (i = 0;i < (int)header.num_vertexes;i++)
                {
                        outnormal[0] = LittleFloat(vnormal[0]);
                        outnormal[1] = LittleFloat(vnormal[1]);
@@ -3463,12 +3731,13 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                }
        }
 
+       // 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++)
+               for (i = 0;i < (int)header.num_vertexes;i++)
                {
                        outsvector[0] = LittleFloat(vtangent[0]);
                        outsvector[1] = LittleFloat(vtangent[1]);
@@ -3484,36 +3753,69 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                }
        }
 
-       for (i = 0; i < (int)header->num_vertexes;i++)
+       // 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);
+               }
+       }
+
+       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)
        {
-               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);
+               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
-       mesh = (iqmmesh_t *) (pbase + header->ofs_meshes);
-       for (i = 0;i < (int)header->num_meshes;i++)
+       for (i = 0;i < (int)header.num_meshes;i++)
        {
+               iqmmesh_t mesh;
                msurface_t *surface;
 
-               mesh[i].name = LittleLong(mesh[i].name);
-               mesh[i].material = LittleLong(mesh[i].material);
-               mesh[i].first_vertex = LittleLong(mesh[i].first_vertex);
-               mesh[i].num_vertexes = LittleLong(mesh[i].num_vertexes);
-               mesh[i].first_triangle = LittleLong(mesh[i].first_triangle);
-               mesh[i].num_triangles = LittleLong(mesh[i].num_triangles);
+               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[i].first_triangle;
-               surface->num_triangles = mesh[i].num_triangles;
-               surface->num_firstvertex = mesh[i].first_vertex;
-               surface->num_vertices = mesh[i].num_vertexes;
+               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[i].name], &text[mesh[i].material]);
+               Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]);
        }
 
        Mod_FreeSkinFiles(skinfiles);
@@ -3527,14 +3829,12 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                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)
+       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)
+       if (!header.ofs_bounds)
                Mod_Alias_CalculateBoundingBox();
 
-       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
-
-       if (!loadmodel->surfmesh.isanimated)
+       if (!loadmodel->surfmesh.isanimated && loadmodel->surfmesh.num_triangles >= 1)
        {
                Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih);
                loadmodel->TraceBox = Mod_CollisionBIH_TraceBox;
@@ -3543,6 +3843,18 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
                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;
+       }
+}
index 6a329ccd513c400f3c67bb0e1bd5b0f28cc1b6cc..eca6546481101dedfd507574e689578fe36e6d35 100644 (file)
@@ -48,10 +48,13 @@ cvar_t mod_q3bsp_debugtracebrush = {0, "mod_q3bsp_debugtracebrush", "0", "select
 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_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"};
@@ -85,14 +88,23 @@ void Mod_BrushInit(void)
        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_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;
@@ -1282,7 +1294,7 @@ loc0:
        }
 }
 
-void Mod_Q1BSP_LightPoint(dp_model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal)
+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);
@@ -1520,7 +1532,7 @@ R_Q1BSP_LoadSplitSky
 A sky texture is 256*128, with the right side being a masked overlay
 ==============
 */
-void R_Q1BSP_LoadSplitSky (unsigned char *src, int width, int height, int bytesperpixel)
+static void R_Q1BSP_LoadSplitSky (unsigned char *src, int width, int height, int bytesperpixel)
 {
        int x, y;
        int w = width/2;
@@ -1598,6 +1610,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l)
        const char *s;
        char mapname[MAX_QPATH], name[MAX_QPATH];
        unsigned char zeroopaque[4], zerotrans[4];
+       char vabuf[1024];
        Vector4Set(zeroopaque, 0, 0, 0, 255);
        Vector4Set(zerotrans, 0, 0, 0, 128);
 
@@ -1661,6 +1674,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l)
                tx->r_water_wateralpha = 1;
                tx->offsetmapping = OFFSETMAPPING_DEFAULT;
                tx->offsetscale = 1;
+               tx->offsetbias = 0;
                tx->specularscalemod = 1;
                tx->specularpowermod = 1;
        }
@@ -1760,6 +1774,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l)
                {
                        tx->supercontents = mod_q1bsp_texture_sky.supercontents;
                        tx->surfaceflags = mod_q1bsp_texture_sky.surfaceflags;
+                       tx->supercontents |= SUPERCONTENTS_SOLID; // for the surface traceline we need to hit this surface as a solid...
                }
                else
                {
@@ -1772,9 +1787,9 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l)
                        // 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("textures/%s/%s", mapname, tx->name), false, false, false, NULL);
+                               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("textures/%s", tx->name), false, false, false, NULL);
+                                       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);
@@ -1785,9 +1800,9 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l)
                        }
                        else
                        {
-                               skinframe = R_SkinFrame_LoadExternal(gamemode == GAME_TENEBRAE ? tx->name : va("textures/%s/%s", mapname, tx->name), TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS, false);
+                               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("textures/%s", tx->name), TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS, false);
+                                       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)
@@ -2062,13 +2077,13 @@ static void Mod_Q1BSP_ParseWadsFromEntityLump(const char *data)
        int i, j, k;
        if (!data)
                return;
-       if (!COM_ParseToken_Simple(&data, false, false))
+       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))
+               if (!COM_ParseToken_Simple(&data, false, false, true))
                        return; // error
                if (com_token[0] == '}')
                        break; // end of worldspawn
@@ -2078,7 +2093,7 @@ static void Mod_Q1BSP_ParseWadsFromEntityLump(const char *data)
                        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))
+               if (!COM_ParseToken_Simple(&data, false, false, true))
                        return; // error
                dpsnprintf(value, sizeof(value), "%s", com_token);
                if (!strcmp("wad", key)) // for HalfLife maps
@@ -2151,7 +2166,7 @@ static void Mod_Q1BSP_LoadVertexes(lump_t *l)
 // The following two functions should be removed and MSG_* or SZ_* function sets adjusted so they
 // can be used for this
 // REMOVEME
-int SB_ReadInt (unsigned char **buffer)
+static int SB_ReadInt (unsigned char **buffer)
 {
        int     i;
        i = ((*buffer)[0]) + 256*((*buffer)[1]) + 65536*((*buffer)[2]) + 16777216*((*buffer)[3]);
@@ -2160,7 +2175,7 @@ int SB_ReadInt (unsigned char **buffer)
 }
 
 // REMOVEME
-float SB_ReadFloat (unsigned char **buffer)
+static float SB_ReadFloat (unsigned char **buffer)
 {
        union
        {
@@ -2447,6 +2462,7 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
        int i, j, count, surfacenum, planenum, smax, tmax, ssize, tsize, firstedge, numedges, totalverts, totaltris, lightmapnumber, lightmapsize, totallightmapsamples;
        float texmins[2], texmaxs[2], val;
        rtexture_t *lightmaptexture, *deluxemaptexture;
+       char vabuf[1024];
 
        in = (dface_t *)(mod_base + l->fileofs);
        if (l->filelen % sizeof(*in))
@@ -2655,9 +2671,9 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l)
                                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("lightmap%i", lightmapnumber), lightmapsize, lightmapsize, NULL, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_ALLOWUPDATES, -1, NULL);
+                               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("deluxemap%i", lightmapnumber), lightmapsize, lightmapsize, NULL, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_ALLOWUPDATES, -1, NULL);
+                                       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);
@@ -2877,7 +2893,7 @@ static void Mod_Q1BSP_LoadLeafs(lump_t *l)
        }
 }
 
-qboolean Mod_Q1BSP_CheckWaterAlphaSupport(void)
+static qboolean Mod_Q1BSP_CheckWaterAlphaSupport(void)
 {
        int i, j;
        mleaf_t *leaf;
@@ -3047,12 +3063,12 @@ static void Mod_Q1BSP_LoadMapBrushes(void)
        if (!maptext)
                return;
        text = maptext;
-       if (!COM_ParseToken_Simple(&data, false, false))
+       if (!COM_ParseToken_Simple(&data, false, false, true))
                return; // error
        submodel = 0;
        for (;;)
        {
-               if (!COM_ParseToken_Simple(&data, false, false))
+               if (!COM_ParseToken_Simple(&data, false, false, true))
                        break;
                if (com_token[0] != '{')
                        return; // error
@@ -3063,7 +3079,7 @@ static void Mod_Q1BSP_LoadMapBrushes(void)
                brushes = Mem_Alloc(loadmodel->mempool, maxbrushes * sizeof(mbrush_t));
                for (;;)
                {
-                       if (!COM_ParseToken_Simple(&data, false, false))
+                       if (!COM_ParseToken_Simple(&data, false, false, true))
                                return; // error
                        if (com_token[0] == '}')
                                break; // end of entity
@@ -3087,7 +3103,7 @@ static void Mod_Q1BSP_LoadMapBrushes(void)
                                }
                                for (;;)
                                {
-                                       if (!COM_ParseToken_Simple(&data, false, false))
+                                       if (!COM_ParseToken_Simple(&data, false, false, true))
                                                return; // error
                                        if (com_token[0] == '}')
                                                break; // end of brush
@@ -3096,25 +3112,25 @@ static void Mod_Q1BSP_LoadMapBrushes(void)
                                        // FIXME: support hl .map format
                                        for (pointnum = 0;pointnum < 3;pointnum++)
                                        {
-                                               COM_ParseToken_Simple(&data, false, false);
+                                               COM_ParseToken_Simple(&data, false, false, true);
                                                for (componentnum = 0;componentnum < 3;componentnum++)
                                                {
-                                                       COM_ParseToken_Simple(&data, false, false);
+                                                       COM_ParseToken_Simple(&data, false, false, true);
                                                        point[pointnum][componentnum] = atof(com_token);
                                                }
-                                               COM_ParseToken_Simple(&data, false, false);
+                                               COM_ParseToken_Simple(&data, false, false, true);
                                        }
-                                       COM_ParseToken_Simple(&data, false, false);
+                                       COM_ParseToken_Simple(&data, false, false, true);
                                        strlcpy(facetexture, com_token, sizeof(facetexture));
-                                       COM_ParseToken_Simple(&data, false, false);
+                                       COM_ParseToken_Simple(&data, false, false, true);
                                        //scroll_s = atof(com_token);
-                                       COM_ParseToken_Simple(&data, false, false);
+                                       COM_ParseToken_Simple(&data, false, false, true);
                                        //scroll_t = atof(com_token);
-                                       COM_ParseToken_Simple(&data, false, false);
+                                       COM_ParseToken_Simple(&data, false, false, true);
                                        //rotate = atof(com_token);
-                                       COM_ParseToken_Simple(&data, false, false);
+                                       COM_ParseToken_Simple(&data, false, false, true);
                                        //scale_s = atof(com_token);
-                                       COM_ParseToken_Simple(&data, false, false);
+                                       COM_ParseToken_Simple(&data, false, false, true);
                                        //scale_t = atof(com_token);
                                        TriangleNormal(point[0], point[1], point[2], planenormal);
                                        VectorNormalizeDouble(planenormal);
@@ -4361,7 +4377,7 @@ static void Mod_Q2BSP_LoadModels(lump_t *l)
 */
 }
 
-void static Mod_Q2BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
+static void Mod_Q2BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
 {
        int i;
        q2dheader_t *header;
@@ -4437,11 +4453,11 @@ static void Mod_Q3BSP_LoadEntities(lump_t *l)
        // 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) && com_token[0] == '{')
+       if (data && COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{')
        {
                while (1)
                {
-                       if (!COM_ParseToken_Simple(&data, false, false))
+                       if (!COM_ParseToken_Simple(&data, false, false, true))
                                break; // error
                        if (com_token[0] == '}')
                                break; // end of worldspawn
@@ -4451,7 +4467,7 @@ static void Mod_Q3BSP_LoadEntities(lump_t *l)
                                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))
+                       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
@@ -4712,9 +4728,43 @@ static void Mod_Q3BSP_LoadVertices(lump_t *l)
                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
-               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);
+               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)
+                       {
+                               // actually we do: 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->brushq3.data_color4f[i * 4 + 0] = in->color4ub[0] * (1.0f / 255.0f) * 0.679942f; // fixes neutral level
+                               loadmodel->brushq3.data_color4f[i * 4 + 1] = in->color4ub[1] * (1.0f / 255.0f) * 0.679942f; // fixes neutral level
+                               loadmodel->brushq3.data_color4f[i * 4 + 2] = in->color4ub[2] * (1.0f / 255.0f) * 0.679942f; // fixes neutral level
+                       }
+                       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;
@@ -4786,6 +4836,7 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump)
        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;
@@ -4822,7 +4873,7 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump)
                if (developer_loading.integer)
                        Con_Printf("Using external lightmaps\n");
                FS_StripExtension(loadmodel->name, mapname, sizeof(mapname));
-               inpixels[0] = loadimagepixelsbgra(va("%s/lm_%04d", mapname, 0), false, false, false, NULL);
+               inpixels[0] = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s/lm_%04d", mapname, 0), false, false, false, NULL);
                if(!inpixels[0])
                        return;
 
@@ -4842,7 +4893,7 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump)
 
                for(count = 1; ; ++count)
                {
-                       inpixels[count] = loadimagepixelsbgra(va("%s/lm_%04d", mapname, count), false, false, false, NULL);
+                       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)
@@ -4980,7 +5031,7 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump)
                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_Printf("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);
+                       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++)
@@ -4996,9 +5047,40 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump)
                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("deluxemap%04i", lightmapindex), mergedwidth, mergedheight, mergeddeluxepixels, TEXTYPE_BGRA, TEXF_FORCELINEAR | (gl_texturecompression_q3bspdeluxemaps.integer ? TEXF_COMPRESS : 0), -1, NULL);
+                               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
-                               loadmodel->brushq3.data_lightmaps [lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%04i", lightmapindex), mergedwidth, mergedheight, mergedpixels, TEXTYPE_BGRA, TEXF_FORCELINEAR | (gl_texturecompression_q3bsplightmaps.integer ? TEXF_COMPRESS : 0), -1, NULL);
+                       {
+                               if(mod_q3bsp_sRGBlightmaps.integer)
+                               {
+                                       textype_t t;
+                                       if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
+                                       {
+                                               // TODO (should we do this, or should we instead knowingly render brighter in sRGB fallback mode?)
+                                               int n = mergedwidth * mergedheight * 4;
+                                               int i;
+                                               for(i = 0; i < n; i += 4)
+                                               {
+                                                       // actually we do: 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)
+                                                       mergedpixels[i+0] = (mergedpixels[i+0] * (int)173 + 128) / 255;
+                                                       mergedpixels[i+1] = (mergedpixels[i+1] * (int)173 + 128) / 255;
+                                                       mergedpixels[i+2] = (mergedpixels[i+2] * (int)173 + 128) / 255;
+                                               }
+                                               t = TEXTYPE_BGRA; // in stupid fallback mode, we upload lightmaps in sRGB form and just fix their brightness
+                                       }
+                                       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);
+                               }
+                       }
                }
        }
 
@@ -5748,6 +5830,7 @@ 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))
@@ -5783,6 +5866,58 @@ static void Mod_Q3BSP_LoadLightGrid(lump_t *l)
                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)
+                       {
+                               // TODO (should we do this, or should we instead knowingly render brighter in sRGB fallback mode?)
+                               for(i = 0; i < count; ++i)
+                               {
+                                       // actually we do: 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)
+                                       out[i].ambientrgb[0] = (out[i].ambientrgb[0] * (int)173 + 128) / 255; // fixes neutral level
+                                       out[i].ambientrgb[1] = (out[i].ambientrgb[1] * (int)173 + 128) / 255; // fixes neutral level
+                                       out[i].ambientrgb[2] = (out[i].ambientrgb[2] * (int)173 + 128) / 255; // fixes neutral level
+                                       out[i].diffusergb[0] = (out[i].diffusergb[0] * (int)173 + 128) / 255; // fixes neutral level
+                                       out[i].diffusergb[1] = (out[i].diffusergb[1] * (int)173 + 128) / 255; // fixes neutral level
+                                       out[i].diffusergb[2] = (out[i].diffusergb[2] * (int)173 + 128) / 255; // fixes neutral level
+                               }
+                       }
+                       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
+                       }
+               }
        }
 }
 
@@ -6048,7 +6183,7 @@ void Mod_CollisionBIH_TracePoint(dp_model_t *model, const frameblend_t *frameble
        }
 }
 
-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)
+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;
@@ -6322,7 +6457,7 @@ void Mod_CollisionBIH_TraceBox(dp_model_t *model, const frameblend_t *frameblend
 }
 
 
-int Mod_CollisionBIH_PointSuperContents(struct model_s *model, int frame, const vec3_t point)
+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);
@@ -6644,7 +6779,7 @@ static void Mod_Q3BSP_TraceLine(dp_model_t *model, const frameblend_t *frameblen
                Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, model, model->brush.data_nodes, start, end, 0, 1, start, end, ++markframe, segmentmins, segmentmaxs);
 }
 
-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)
+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;
@@ -6709,9 +6844,7 @@ static int Mod_Q3BSP_PointSuperContents(struct model_s *model, int frame, const
        q3mbrush_t *brush;
        if (mod_collision_bih.integer)
        {
-               trace_t trace;
-               Mod_Q3BSP_TracePoint(model, NULL, NULL, &trace, point, 0);
-               supercontents = trace.startsupercontents;
+               supercontents = Mod_CollisionBIH_PointSuperContents(model, frame, point);
        }
        // test if the point is inside each brush
        else if (model->brush.submodel)
@@ -6941,7 +7074,7 @@ static int Mod_Q3BSP_NativeContentsFromSuperContents(dp_model_t *model, int supe
        return nativecontents;
 }
 
-void Mod_Q3BSP_RecursiveFindNumLeafs(mnode_t *node)
+static void Mod_Q3BSP_RecursiveFindNumLeafs(mnode_t *node)
 {
        int numleafs;
        while (node->plane)
@@ -6954,7 +7087,7 @@ void Mod_Q3BSP_RecursiveFindNumLeafs(mnode_t *node)
                loadmodel->brush.num_leafs = numleafs;
 }
 
-void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
+static void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
 {
        int i, j, lumps;
        q3dheader_t *header;
@@ -7798,40 +7931,3 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend)
 
        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);
 }
-
-qboolean Mod_CanSeeBox_Trace(int numsamples, float t, dp_model_t *model, vec3_t eye, vec3_t minsX, vec3_t maxsX)
-{
-       // we already have done PVS culling at this point...
-       // so we don't need to do it again.
-
-       int i;
-       vec3_t testorigin, mins, maxs;
-
-       testorigin[0] = (minsX[0] + maxsX[0]) * 0.5;
-       testorigin[1] = (minsX[1] + maxsX[1]) * 0.5;
-       testorigin[2] = (minsX[2] + maxsX[2]) * 0.5;
-
-       if(model->brush.TraceLineOfSight(model, eye, testorigin))
-               return 1;
-
-       // expand the box a little
-       mins[0] = (t+1) * minsX[0] - t * maxsX[0];
-       maxs[0] = (t+1) * maxsX[0] - t * minsX[0];
-       mins[1] = (t+1) * minsX[1] - t * maxsX[1];
-       maxs[1] = (t+1) * maxsX[1] - t * minsX[1];
-       mins[2] = (t+1) * minsX[2] - t * maxsX[2];
-       maxs[2] = (t+1) * maxsX[2] - t * minsX[2];
-
-       for(i = 0; i != numsamples; ++i)
-       {
-               testorigin[0] = lhrandom(mins[0], maxs[0]);
-               testorigin[1] = lhrandom(mins[1], maxs[1]);
-               testorigin[2] = lhrandom(mins[2], maxs[2]);
-
-               if(model->brush.TraceLineOfSight(model, eye, testorigin))
-                       return 1;
-       }
-
-       return 0;
-}
-
index 906594ad4c893db4dc623ca2e12c10151c435070..f1b60e0e7dc15b79a80eb01f1a99e4259316345b 100644 (file)
@@ -638,17 +638,17 @@ q3dpvs_t;
 #define Q3SURFACEFLAG_NODAMAGE 1
 #define Q3SURFACEFLAG_SLICK 2
 #define Q3SURFACEFLAG_SKY 4
-#define Q3SURFACEFLAG_LADDER 8
+#define Q3SURFACEFLAG_LADDER 8 // has no surfaceparm
 #define Q3SURFACEFLAG_NOIMPACT 16
 #define Q3SURFACEFLAG_NOMARKS 32
-#define Q3SURFACEFLAG_FLESH 64
+#define Q3SURFACEFLAG_FLESH 64 // has no surfaceparm
 #define Q3SURFACEFLAG_NODRAW 128
 #define Q3SURFACEFLAG_HINT 256
-#define Q3SURFACEFLAG_SKIP 512
+#define Q3SURFACEFLAG_SKIP 512 // has no surfaceparm
 #define Q3SURFACEFLAG_NOLIGHTMAP 1024
 #define Q3SURFACEFLAG_POINTLIGHT 2048
 #define Q3SURFACEFLAG_METALSTEPS 4096
-#define Q3SURFACEFLAG_NOSTEPS 8192
+#define Q3SURFACEFLAG_NOSTEPS 8192 // has no surfaceparm
 #define Q3SURFACEFLAG_NONSOLID 16384
 #define Q3SURFACEFLAG_LIGHTFILTER 32768
 #define Q3SURFACEFLAG_ALPHASHADOW 65536
index d4021ee0bf46731690676e6f984dde0b60c26fe3..2afe928b13d5daee77c506d932ce7f34550f1ea3 100644 (file)
@@ -228,78 +228,95 @@ void Mod_UnloadModel (dp_model_t *mod)
        mod->loaded = false;
 }
 
-void R_Model_Null_Draw(entity_render_t *ent)
+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, void *pass);
+typedef void (*mod_framegroupify_parsegroups_t) (unsigned int i, int start, int len, float fps, qboolean loop, const char *name, void *pass);
 
-int Mod_FrameGroupify_ParseGroups(const char *buf, mod_framegroupify_parsegroups_t cb, 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;
-       for(;;)
+       while(bufptr)
        {
                // an anim scene!
-               if (!COM_ParseToken_Simple(&bufptr, true, false))
-                       break;
+
+               // 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);
-               if (!COM_ParseToken_Simple(&bufptr, true, false))
-                       break;
-               if (!strcmp(com_token, "\n"))
+
+               // 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);
-               if (!COM_ParseToken_Simple(&bufptr, true, false))
-                       break;
-               // we default to looping as it's usually wanted, so to NOT loop you append a 0
-               if (strcmp(com_token, "\n"))
+
+               // 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);
-                       if (!COM_ParseToken_Simple(&bufptr, true, false))
-                               break;
-                       if (strcmp(com_token, "\n"))
-                               loop = atoi(com_token) != 0;
-                       else
-                               loop = true;
+                       COM_ParseToken_Simple(&bufptr, true, false, true);
                }
-               else
+
+               // 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"))
                {
-                       fps = 20;
-                       loop = true;
+                       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, pass);
+                       cb(i, start, len, fps, loop, (name[0] ? name : NULL), pass);
                ++i;
        }
 
        return i;
 }
 
-void Mod_FrameGroupify_ParseGroups_Count (unsigned int i, int start, int len, float fps, qboolean loop, void *pass)
-{
-       unsigned int *cnt = (unsigned int *) pass;
-       ++*cnt;
-}
-
-void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int len, float fps, qboolean loop, void *pass)
+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];
-       dpsnprintf(anim->name, sizeof(anim[i].name), "groupified_%d_anim", 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);
@@ -307,7 +324,7 @@ void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int len, fl
        //Con_Printf("frame group %d is %d %d %f %d\n", i, start, len, fps, loop);
 }
 
-void Mod_FrameGroupify(dp_model_t *mod, const char *buf)
+static void Mod_FrameGroupify(dp_model_t *mod, const char *buf)
 {
        unsigned int cnt;
 
@@ -328,7 +345,7 @@ void Mod_FrameGroupify(dp_model_t *mod, const char *buf)
        Mod_FrameGroupify_ParseGroups(buf, Mod_FrameGroupify_ParseGroups_Store, mod);
 }
 
-void Mod_FindPotentialDeforms(dp_model_t *mod)
+static void Mod_FindPotentialDeforms(dp_model_t *mod)
 {
        int i, j;
        texture_t *texture;
@@ -366,6 +383,7 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk)
        unsigned int crc;
        void *buf;
        fs_offset_t filesize = 0;
+       char vabuf[1024];
 
        mod->used = true;
 
@@ -491,8 +509,8 @@ dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk)
                Mem_Free(buf);
 
                Mod_FindPotentialDeforms(mod);
-                                       
-               buf = FS_LoadFile (va("%s.framegroups", mod->name), tempmempool, false, &filesize);
+
+               buf = FS_LoadFile(va(vabuf, sizeof(vabuf), "%s.framegroups", mod->name), tempmempool, false, &filesize);
                if(buf)
                {
                        Mod_FrameGroupify(mod, (const char *)buf);
@@ -856,7 +874,8 @@ void Mod_BuildNormals(int firstvertex, int numvertices, int numtriangles, const
                VectorNormalize(vectorNormal);
 }
 
-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)
+#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
@@ -899,6 +918,7 @@ void Mod_BuildBumpVectors(const float *v0, const float *v1, const float *v2, con
                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)
@@ -1394,7 +1414,8 @@ void Mod_CreateCollisionMesh(dp_model_t *mod)
        mod->brush.collisionmesh = Mod_ShadowMesh_Finish(mempool, mod->brush.collisionmesh, false, false, false);
 }
 
-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)
+#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;
@@ -1409,7 +1430,7 @@ void Mod_GetTerrainVertex3fTexCoord2fFromBGRA(const unsigned char *imagepixels,
        texcoord2f[1] = tc[1];
 }
 
-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)
+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];
@@ -1434,7 +1455,7 @@ void Mod_GetTerrainVertexFromBGRA(const unsigned char *imagepixels, int imagewid
        VectorAdd(normal3f, nl, normal3f);
 }
 
-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)
+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;
@@ -1456,6 +1477,7 @@ void Mod_ConstructTerrainPatchFromBGRA(const unsigned char *imagepixels, int ima
                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)
@@ -1537,7 +1559,7 @@ void Mod_Terrain_UpdateSurfacesForViewOrigin(dp_model_t *model)
 }
 #endif
 
-int Mod_LoadQ3Shaders_EnumerateWaveFunc(const char *s)
+static int Mod_LoadQ3Shaders_EnumerateWaveFunc(const char *s)
 {
        int offset = 0;
        if (!strncasecmp(s, "user", 4)) // parse stuff like "user1sin", always user<n>func
@@ -1573,15 +1595,31 @@ static void Q3Shader_AddToHash (q3shaderinfo_t* shader)
        {
                if (strcasecmp (entry->shader.name, shader->name) == 0)
                {
-                       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);
+                       // 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
-                               Con_DPrintf("Shader '%s' already defined\n", shader->name);
-                       return;
+                       {
+                               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;
@@ -1607,8 +1645,11 @@ static void Q3Shader_AddToHash (q3shaderinfo_t* shader)
 
 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;
 void Mod_LoadQ3Shaders(void)
 {
        int j;
@@ -1623,6 +1664,7 @@ void Mod_LoadQ3Shaders(void)
        char *custsurfaceparmnames[256]; // VorteX: q3map2 has 64 but well, someone will need more
        unsigned long custsurfaceparms[256]; 
        int numcustsurfaceparms;
+       qboolean dpshaderkill;
 
        Mod_FreeQ3Shaders();
 
@@ -1696,7 +1738,8 @@ void Mod_LoadQ3Shaders(void)
                        Vector4Set(shader.reflectcolor4f, 1, 1, 1, 1);
                        shader.r_water_wateralpha = 1;
                        shader.offsetmapping = (mod_q3shader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
-                       shader.offsetscale = 1;
+                       shader.offsetscale = mod_q3shader_default_offsetmapping_scale.value;
+                       shader.offsetbias = mod_q3shader_default_offsetmapping_bias.value;
                        shader.specularscalemod = 1;
                        shader.specularpowermod = 1;
                        shader.biaspolygonoffset = mod_q3shader_default_polygonoffset.value;
@@ -1769,6 +1812,11 @@ void Mod_LoadQ3Shaders(void)
                                                                        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;
@@ -1796,7 +1844,7 @@ void Mod_LoadQ3Shaders(void)
                                                                        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_ONE_MINUS_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"))
@@ -1950,7 +1998,32 @@ void Mod_LoadQ3Shaders(void)
                                                        shader.textureblendalpha = true;
                                                }
                                        }
-                                       layer->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))
@@ -2079,6 +2152,58 @@ void Mod_LoadQ3Shaders(void)
                                        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
@@ -2155,17 +2280,33 @@ void Mod_LoadQ3Shaders(void)
                                {
                                        shader.specularpowermod = atof(parameter[1]);
                                }
-                               else if (!strcasecmp(parameter[0], "dpoffsetmapping") && numparameters >= 3)
+                               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"))
+                                       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;
-                                       shader.offsetscale = atof(parameter[2]);
+                                       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)
                                {
@@ -2207,6 +2348,9 @@ void Mod_LoadQ3Shaders(void)
                                        }
                                }
                        }
+                       // 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)
                        {
@@ -2286,8 +2430,10 @@ qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qbool
        // 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;
        // WHEN ADDING DEFAULTS HERE, REMEMBER TO SYNC TO SHADER LOADING ABOVE
        // HERE, AND Q1BSP LOADING
        // JUST GREP FOR "specularscalemod = 1".
@@ -2296,7 +2442,6 @@ qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qbool
        {
                if (developer_loading.integer)
                        Con_Printf("%s: loaded shader for %s\n", loadmodel->name, name);
-               texture->surfaceparms = shader->surfaceparms;
 
                // allow disabling of picmip or compression by defaulttexflags
                texture->textureflags = (shader->textureflags & texflagsmask) | texflagsor;
@@ -2435,8 +2580,10 @@ nothing                GL_ZERO GL_ONE
                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);
 
@@ -2483,21 +2630,55 @@ nothing                GL_ZERO GL_ONE
        //      if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID    ) texture->supercontents |= SUPERCONTENTS_LIGHTGRID    ;
        //      if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL   ) texture->supercontents |= SUPERCONTENTS_ANTIPORTAL   ;
 
+               texture->surfaceflags = 0;
+               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->surfaceparms = 0;
                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->surfaceparms = 0;
                texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
                texture->supercontents = SUPERCONTENTS_SOLID;
        }
@@ -2505,7 +2686,6 @@ nothing                GL_ZERO GL_ONE
        {
                if (developer_extra.integer)
                        Con_DPrintf("^1%s:^7 No shader found for texture ^3\"%s\"\n", loadmodel->name, texture->name);
-               texture->surfaceparms = 0;
                if (texture->surfaceflags & Q3SURFACEFLAG_NODRAW)
                {
                        texture->basematerialflags |= MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
@@ -2564,6 +2744,7 @@ skinfile_t *Mod_LoadSkinFiles(void)
        skinfile_t *skinfile = NULL, *first = NULL;
        skinfileitem_t *skinfileitem;
        char word[10][MAX_QPATH];
+       char vabuf[1024];
 
 /*
 sample file:
@@ -2581,7 +2762,7 @@ tag_weapon,
 tag_torso,
 */
        memset(word, 0, sizeof(word));
-       for (i = 0;i < 256 && (data = text = (char *)FS_LoadFile(va("%s_%i.skin", loadmodel->name, i), tempmempool, true, NULL));i++)
+       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)
@@ -3152,6 +3333,7 @@ static void Mod_Decompile_f(void)
        int zymtextsize = 0;
        int dpmtextsize = 0;
        int framegroupstextsize = 0;
+       char vabuf[1024];
 
        if (Cmd_Argc() != 2)
        {
@@ -3258,11 +3440,11 @@ static void Mod_Decompile_f(void)
                        }
                }
                if (zymtextsize)
-                       FS_WriteFile(va("%s_decompiled/out_zym.txt", basename), zymtextbuffer, (fs_offset_t)zymtextsize);
+                       FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_zym.txt", basename), zymtextbuffer, (fs_offset_t)zymtextsize);
                if (dpmtextsize)
-                       FS_WriteFile(va("%s_decompiled/out_dpm.txt", basename), dpmtextbuffer, (fs_offset_t)dpmtextsize);
+                       FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_dpm.txt", basename), dpmtextbuffer, (fs_offset_t)dpmtextsize);
                if (framegroupstextsize)
-                       FS_WriteFile(va("%s_decompiled.framegroups", basename), framegroupstextbuffer, (fs_offset_t)framegroupstextsize);
+                       FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled.framegroups", basename), framegroupstextbuffer, (fs_offset_t)framegroupstextsize);
        }
 }
 
@@ -3396,7 +3578,6 @@ static float mod_generatelightmaps_offsets[3][MAX_LIGHTMAPSAMPLES][3];
 static int mod_generatelightmaps_numlights;
 static lightmaplight_t *mod_generatelightmaps_lightinfo;
 
-extern int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color);
 extern cvar_t r_shadow_lightattenuationdividebias;
 extern cvar_t r_shadow_lightattenuationlinearscale;
 
@@ -3977,6 +4158,7 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
        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)
@@ -4159,8 +4341,8 @@ static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
 
        for (lightmapindex = 0;lightmapindex < model->brushq3.num_mergedlightmaps;lightmapindex++)
        {
-               model->brushq3.data_lightmaps[lightmapindex] = R_LoadTexture2D(model->texturepool, va("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("deluxemap%i", lightmapindex), lm_texturesize, lm_texturesize, deluxemappixels + lightmapindex * lm_texturesize * lm_texturesize * 4, TEXTYPE_BGRA, TEXF_FORCELINEAR, -1, NULL);
+               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)
index c34890cad8af0c43ee088e057f387b2a303817a0..747bec0cfb32b39b703156937e1b638ff1aba4c9 100644 (file)
@@ -452,6 +452,9 @@ typedef struct q3shaderinfo_s
        // add collisions to all triangles of the surface
        qboolean dpmeshcollisions;
 
+       // kill shader based on cvar checks
+       qboolean dpshaderkill;
+
        // fake reflection
        char dpreflectcube[Q3PATHLENGTH];
 
@@ -468,6 +471,7 @@ typedef struct q3shaderinfo_s
        // 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;
@@ -475,7 +479,10 @@ typedef struct q3shaderinfo_s
        // gloss
        float specularscalemod;
        float specularpowermod;
-#define Q3SHADERINFO_COMPARE_END specularpowermod
+
+       // rtlightning ambient addition
+       float rtlightambient;
+#define Q3SHADERINFO_COMPARE_END rtlightambient
 }
 q3shaderinfo_t;
 
@@ -592,7 +599,6 @@ typedef struct texture_s
        char name[64];
        int surfaceflags;
        int supercontents;
-       int surfaceparms;
        int textureflags;
 
        // reflection
@@ -609,10 +615,14 @@ typedef struct texture_s
        // offsetmapping
        dpoffsetmapping_technique_t offsetmapping;
        float offsetscale;
+       float offsetbias;
 
        // gloss
        float specularscalemod;
        float specularpowermod;
+
+       // diffuse and ambient
+       float rtlightambient;
 }
  texture_t;
 
index 7b683988951dad01320b62957677e96e1c95a679..c4d2b088234a61962243ae9ef565a32efe442581 100644 (file)
@@ -63,6 +63,7 @@ static void Mod_SpriteSetupTexture(texture_t *texture, skinframe_t *skinframe, q
                skinframe = R_SkinFrame_LoadMissing();
        texture->offsetmapping = OFFSETMAPPING_OFF;
        texture->offsetscale = 1;
+       texture->offsetbias = 0;
        texture->specularscalemod = 1;
        texture->specularpowermod = 1;
        texture->basematerialflags = MATERIALFLAG_WALL;
@@ -95,7 +96,7 @@ static void Mod_Sprite_SharedSetup(const unsigned char *datapointer, int version
        float                           modelradius, interval;
        char                            name[MAX_QPATH], fogname[MAX_QPATH];
        const void                      *startframes;
-       int                 texflags = (r_mipsprites.integer ? TEXF_MIPMAP : 0) | (gl_texturecompression_sprites.integer ? TEXF_COMPRESS : 0) | TEXF_ISSPRITE | TEXF_PICMIP | TEXF_ALPHA | TEXF_CLAMP;
+       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)
@@ -258,7 +259,6 @@ static void Mod_Sprite_SharedSetup(const unsigned char *datapointer, int version
        loadmodel->radius2 = modelradius * modelradius;
 }
 
-extern void R_Model_Sprite_Draw(entity_render_t *ent);
 void Mod_IDSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
 {
        int version;
@@ -367,7 +367,7 @@ void Mod_IDSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                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[0].framecount > 1;
+       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
 }
 
 
@@ -475,5 +475,5 @@ void Mod_IDS2_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->radius = modelradius;
        loadmodel->radius2 = modelradius * modelradius;
 
-       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
+       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1);
 }
index 9d154b4969510e8ac968bfac217618d382589925..e90dcdec6e5e38921925775aebc845f4851b39fa 100644 (file)
@@ -3,6 +3,7 @@
 #include "prvm_cmds.h"
 #include "clvm_cmds.h"
 #include "menu.h"
+#include "csprogs.h"
 
 // TODO check which strings really should be engine strings
 
@@ -18,7 +19,6 @@ const char *vm_m_extensions =
 "DP_GFX_FONTS_FREETYPE "
 "DP_UTF8 "
 "DP_FONT_VARIABLEWIDTH "
-"DP_GECKO_SUPPORT "
 "DP_MENU_EXTRESPONSEPACKET "
 "DP_QC_ASINACOSATANATAN2TAN "
 "DP_QC_AUTOCVARS "
@@ -26,7 +26,10 @@ const char *vm_m_extensions =
 "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 "
@@ -53,7 +56,7 @@ VM_M_setmousetarget
 setmousetarget(float target)
 =========
 */
-void VM_M_setmousetarget(void)
+static void VM_M_setmousetarget(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_M_setmousetarget);
 
@@ -66,7 +69,7 @@ void VM_M_setmousetarget(void)
                in_client_mouse = true;
                break;
        default:
-               PRVM_ERROR("VM_M_setmousetarget: wrong destination %f !",PRVM_G_FLOAT(OFS_PARM0));
+               prog->error_cmd("VM_M_setmousetarget: wrong destination %f !",PRVM_G_FLOAT(OFS_PARM0));
        }
 }
 
@@ -77,7 +80,7 @@ VM_M_getmousetarget
 float  getmousetarget
 =========
 */
-void VM_M_getmousetarget(void)
+static void VM_M_getmousetarget(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0,VM_M_getmousetarget);
 
@@ -96,7 +99,7 @@ VM_M_setkeydest
 setkeydest(float dest)
 =========
 */
-void VM_M_setkeydest(void)
+static void VM_M_setkeydest(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1,VM_M_setkeydest);
 
@@ -119,7 +122,7 @@ void VM_M_setkeydest(void)
                // key_dest = key_message
                // break;
        default:
-               PRVM_ERROR("VM_M_setkeydest: wrong destination %f !", PRVM_G_FLOAT(OFS_PARM0));
+               prog->error_cmd("VM_M_setkeydest: wrong destination %f !", PRVM_G_FLOAT(OFS_PARM0));
        }
 }
 
@@ -130,7 +133,7 @@ VM_M_getkeydest
 float  getkeydest
 =========
 */
-void VM_M_getkeydest(void)
+static void VM_M_getkeydest(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0,VM_M_getkeydest);
 
@@ -163,7 +166,7 @@ VM_M_getresolution
 vector getresolution(float number)
 =========
 */
-void VM_M_getresolution(void)
+static void VM_M_getresolution(prvm_prog_t *prog)
 {
        int nr, fs;
        VM_SAFEPARMCOUNTRANGE(1, 2, VM_getresolution);
@@ -187,7 +190,7 @@ void VM_M_getresolution(void)
        }
 }
 
-void VM_M_getgamedirinfo(void)
+static void VM_M_getgamedirinfo(prvm_prog_t *prog)
 {
        int nr, item;
        VM_SAFEPARMCOUNT(2, VM_getgamedirinfo);
@@ -200,9 +203,9 @@ void VM_M_getgamedirinfo(void)
        if(nr >= 0 && nr < fs_all_gamedirs_count)
        {
                if(item == 0)
-                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( fs_all_gamedirs[nr].name );
+                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, fs_all_gamedirs[nr].name );
                else if(item == 1)
-                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( fs_all_gamedirs[nr].description );
+                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, fs_all_gamedirs[nr].description );
        }
 }
 
@@ -224,7 +227,7 @@ float       getserverliststat(float type)
 6      sortfield
 7      sortflags
 */
-void VM_M_getserverliststat( void )
+static void VM_M_getserverliststat(prvm_prog_t *prog)
 {
        int type;
        VM_SAFEPARMCOUNT ( 1, VM_M_getserverliststat );
@@ -259,7 +262,7 @@ void VM_M_getserverliststat( void )
                PRVM_G_FLOAT ( OFS_RETURN ) = serverlist_sortflags;
                return;
        default:
-               VM_Warning( "VM_M_getserverliststat: bad type %i!\n", type );
+               VM_Warning(prog, "VM_M_getserverliststat: bad type %i!\n", type );
        }
 }
 
@@ -270,7 +273,7 @@ VM_M_resetserverlistmasks
 resetserverlistmasks()
 ========================
 */
-void VM_M_resetserverlistmasks( void )
+static void VM_M_resetserverlistmasks(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0, VM_M_resetserverlistmasks);
        ServerList_ResetMasks();
@@ -286,7 +289,7 @@ setserverlistmaskstring(float mask, float fld, string str, float op)
 512 - 1024     or
 ========================
 */
-void VM_M_setserverlistmaskstring( void )
+static void VM_M_setserverlistmaskstring(prvm_prog_t *prog)
 {
        const char *str;
        int masknr;
@@ -303,7 +306,7 @@ void VM_M_setserverlistmaskstring( void )
                mask = &serverlist_ormasks[masknr - 512 ];
        else
        {
-               VM_Warning( "VM_M_setserverlistmaskstring: invalid mask number %i\n", masknr );
+               VM_Warning(prog, "VM_M_setserverlistmaskstring: invalid mask number %i\n", masknr );
                return;
        }
 
@@ -332,7 +335,7 @@ void VM_M_setserverlistmaskstring( void )
                        strlcpy( mask->info.game, str, sizeof(mask->info.game)  );
                        break;
                default:
-                       VM_Warning( "VM_M_setserverlistmaskstring: Bad field number %i passed!\n", field );
+                       VM_Warning(prog, "VM_M_setserverlistmaskstring: Bad field number %i passed!\n", field );
                        return;
        }
 
@@ -350,7 +353,7 @@ setserverlistmasknumber(float mask, float fld, float num, float op)
 512 - 1024     or
 ========================
 */
-void VM_M_setserverlistmasknumber( void )
+static void VM_M_setserverlistmasknumber(prvm_prog_t *prog)
 {
        int number;
        serverlist_mask_t *mask;
@@ -365,7 +368,7 @@ void VM_M_setserverlistmasknumber( void )
                mask = &serverlist_ormasks[masknr - 512 ];
        else
        {
-               VM_Warning( "VM_M_setserverlistmasknumber: invalid mask number %i\n", masknr );
+               VM_Warning(prog, "VM_M_setserverlistmasknumber: invalid mask number %i\n", masknr );
                return;
        }
 
@@ -398,7 +401,7 @@ void VM_M_setserverlistmasknumber( void )
                        mask->info.isfavorite = number != 0;
                        break;
                default:
-                       VM_Warning( "VM_M_setserverlistmasknumber: Bad field number %i passed!\n", field );
+                       VM_Warning(prog, "VM_M_setserverlistmasknumber: Bad field number %i passed!\n", field );
                        return;
        }
 
@@ -414,7 +417,7 @@ VM_M_resortserverlist
 resortserverlist
 ========================
 */
-void VM_M_resortserverlist( void )
+static void VM_M_resortserverlist(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0, VM_M_resortserverlist);
        ServerList_RebuildViewList();
@@ -427,7 +430,7 @@ VM_M_getserverliststring
 string getserverliststring(float field, float hostnr)
 =========
 */
-void VM_M_getserverliststring(void)
+static void VM_M_getserverliststring(prvm_prog_t *prog)
 {
        serverlist_entry_t *cache;
        int hostnr;
@@ -446,32 +449,32 @@ void VM_M_getserverliststring(void)
        cache = ServerList_GetViewEntry(hostnr);
        switch( (int) PRVM_G_FLOAT(OFS_PARM0) ) {
                case SLIF_CNAME:
-                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( cache->info.cname );
+                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, cache->info.cname );
                        break;
                case SLIF_NAME:
-                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( cache->info.name );
+                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, cache->info.name );
                        break;
                case SLIF_QCSTATUS:
-                       PRVM_G_INT (OFS_RETURN ) = PRVM_SetTempString (cache->info.qcstatus );
+                       PRVM_G_INT (OFS_RETURN ) = PRVM_SetTempString( prog, cache->info.qcstatus );
                        break;
                case SLIF_PLAYERS:
-                       PRVM_G_INT (OFS_RETURN ) = PRVM_SetTempString (cache->info.players );
+                       PRVM_G_INT (OFS_RETURN ) = PRVM_SetTempString( prog, cache->info.players );
                        break;
                case SLIF_GAME:
-                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( cache->info.game );
+                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, cache->info.game );
                        break;
                case SLIF_MOD:
-                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( cache->info.mod );
+                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, cache->info.mod );
                        break;
                case SLIF_MAP:
-                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( cache->info.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( cache->line1 );
+                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, cache->line1 );
                        break;
                case 1025:
-                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( cache->line2 );
+                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, cache->line2 );
                        break;
                default:
                        Con_Print("VM_M_getserverliststring: bad field number passed!\n");
@@ -485,7 +488,7 @@ VM_M_getserverlistnumber
 float  getserverlistnumber(float field, float hostnr)
 =========
 */
-void VM_M_getserverlistnumber(void)
+static void VM_M_getserverlistnumber(prvm_prog_t *prog)
 {
        serverlist_entry_t *cache;
        int hostnr;
@@ -539,7 +542,7 @@ VM_M_setserverlistsort
 setserverlistsort(float field, float flags)
 ========================
 */
-void VM_M_setserverlistsort( void )
+static void VM_M_setserverlistsort(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT( 2, VM_M_setserverlistsort );
 
@@ -554,7 +557,7 @@ VM_M_refreshserverlist
 refreshserverlist()
 ========================
 */
-void VM_M_refreshserverlist( void )
+static void VM_M_refreshserverlist(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT( 0, VM_M_refreshserverlist );
        ServerList_QueryList(false, true, false, false);
@@ -567,13 +570,13 @@ VM_M_getserverlistindexforkey
 float getserverlistindexforkey(string key)
 ========================
 */
-void VM_M_getserverlistindexforkey( void )
+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( key );
+       VM_CheckEmptyString( prog, key );
 
        if( !strcmp( key, "cname" ) )
                PRVM_G_FLOAT( OFS_RETURN ) = SLIF_CNAME;
@@ -616,7 +619,7 @@ VM_M_addwantedserverlistkey
 addwantedserverlistkey(string key)
 ========================
 */
-void VM_M_addwantedserverlistkey( void )
+static void VM_M_addwantedserverlistkey(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT( 1, VM_M_addwantedserverlistkey );
 }
@@ -638,13 +641,13 @@ Write*(* data, float type, float to)
 #define        MSG_ALL                 2               // reliable to all
 #define        MSG_INIT                3               // write to the init string
 
-sizebuf_t *VM_M_WriteDest (void)
+static sizebuf_t *VM_M_WriteDest (prvm_prog_t *prog)
 {
        int             dest;
        int             destclient;
 
        if(!sv.active)
-               PRVM_ERROR("VM_M_WriteDest: game is not server (%s)", PRVM_NAME);
+               prog->error_cmd("VM_M_WriteDest: game is not server (%s)", prog->name);
 
        dest = (int)PRVM_G_FLOAT(OFS_PARM1);
        switch (dest)
@@ -655,7 +658,7 @@ sizebuf_t *VM_M_WriteDest (void)
        case MSG_ONE:
                destclient = (int) PRVM_G_FLOAT(OFS_PARM2);
                if (destclient < 0 || destclient >= svs.maxclients || !svs.clients[destclient].active || !svs.clients[destclient].netconnection)
-                       PRVM_ERROR("VM_clientcommand: %s: invalid client !", PRVM_NAME);
+                       prog->error_cmd("VM_clientcommand: %s: invalid client !", prog->name);
 
                return &svs.clients[destclient].netconnection->message;
 
@@ -666,59 +669,59 @@ sizebuf_t *VM_M_WriteDest (void)
                return &sv.signon;
 
        default:
-               PRVM_ERROR ("WriteDest: bad destination");
+               prog->error_cmd("WriteDest: bad destination");
                break;
        }
 
        return NULL;
 }
 
-void VM_M_WriteByte (void)
+static void VM_M_WriteByte (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_M_WriteByte);
-       MSG_WriteByte (VM_M_WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM0));
+       MSG_WriteByte (VM_M_WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM0));
 }
 
-void VM_M_WriteChar (void)
+static void VM_M_WriteChar (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_M_WriteChar);
-       MSG_WriteChar (VM_M_WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM0));
+       MSG_WriteChar (VM_M_WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM0));
 }
 
-void VM_M_WriteShort (void)
+static void VM_M_WriteShort (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_M_WriteShort);
-       MSG_WriteShort (VM_M_WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM0));
+       MSG_WriteShort (VM_M_WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM0));
 }
 
-void VM_M_WriteLong (void)
+static void VM_M_WriteLong (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_M_WriteLong);
-       MSG_WriteLong (VM_M_WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM0));
+       MSG_WriteLong (VM_M_WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM0));
 }
 
-void VM_M_WriteAngle (void)
+static void VM_M_WriteAngle (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_M_WriteAngle);
-       MSG_WriteAngle (VM_M_WriteDest(), PRVM_G_FLOAT(OFS_PARM0), sv.protocol);
+       MSG_WriteAngle (VM_M_WriteDest(prog), PRVM_G_FLOAT(OFS_PARM0), sv.protocol);
 }
 
-void VM_M_WriteCoord (void)
+static void VM_M_WriteCoord (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_M_WriteCoord);
-       MSG_WriteCoord (VM_M_WriteDest(), PRVM_G_FLOAT(OFS_PARM0), sv.protocol);
+       MSG_WriteCoord (VM_M_WriteDest(prog), PRVM_G_FLOAT(OFS_PARM0), sv.protocol);
 }
 
-void VM_M_WriteString (void)
+static void VM_M_WriteString (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_M_WriteString);
-       MSG_WriteString (VM_M_WriteDest(), PRVM_G_STRING(OFS_PARM0));
+       MSG_WriteString (VM_M_WriteDest(prog), PRVM_G_STRING(OFS_PARM0));
 }
 
-void VM_M_WriteEntity (void)
+static void VM_M_WriteEntity (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_M_WriteEntity);
-       MSG_WriteShort (VM_M_WriteDest(), PRVM_G_EDICTNUM(OFS_PARM0));
+       MSG_WriteShort (VM_M_WriteDest(prog), PRVM_G_EDICTNUM(OFS_PARM0));
 }
 
 /*
@@ -730,7 +733,7 @@ copies data from one entity to another
 copyentity(entity src, entity dst)
 =================
 */
-static void VM_M_copyentity (void)
+static void VM_M_copyentity (prvm_prog_t *prog)
 {
        prvm_edict_t *in, *out;
        VM_SAFEPARMCOUNT(2,VM_M_copyentity);
@@ -740,7 +743,7 @@ static void VM_M_copyentity (void)
 }
 
 //#66 vector() getmousepos (EXT_CSQC)
-static void VM_M_getmousepos(void)
+static void VM_M_getmousepos(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0,VM_M_getmousepos);
 
@@ -752,7 +755,7 @@ static void VM_M_getmousepos(void)
                VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_mouse_x * vid_conwidth.integer / vid.width, in_mouse_y * vid_conheight.integer / vid.height, 0);
 }
 
-void VM_M_crypto_getkeyfp(void)
+static void VM_M_crypto_getkeyfp(prvm_prog_t *prog)
 {
        lhnetaddress_t addr;
        const char *s;
@@ -761,14 +764,14 @@ void VM_M_crypto_getkeyfp(void)
        VM_SAFEPARMCOUNT(1,VM_M_crypto_getkeyfp);
 
        s = PRVM_G_STRING( OFS_PARM0 );
-       VM_CheckEmptyString( s );
+       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( keyfp );
+               PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, keyfp );
        else
                PRVM_G_INT( OFS_RETURN ) = OFS_NULL;
 }
-void VM_M_crypto_getidfp(void)
+static void VM_M_crypto_getidfp(prvm_prog_t *prog)
 {
        lhnetaddress_t addr;
        const char *s;
@@ -777,30 +780,31 @@ void VM_M_crypto_getidfp(void)
        VM_SAFEPARMCOUNT(1,VM_M_crypto_getidfp);
 
        s = PRVM_G_STRING( OFS_PARM0 );
-       VM_CheckEmptyString( s );
+       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( idfp );
+               PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, idfp );
        else
                PRVM_G_INT( OFS_RETURN ) = OFS_NULL;
 }
-void VM_M_crypto_getencryptlevel(void)
+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( s );
+       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(aeslevel ? va("%d AES128", aeslevel) : "0");
+               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;
 }
-void VM_M_crypto_getmykeyfp(void)
+static void VM_M_crypto_getmykeyfp(prvm_prog_t *prog)
 {
        int i;
        char keyfp[FP64_SIZE + 1];
@@ -811,18 +815,18 @@ void VM_M_crypto_getmykeyfp(void)
        switch(Crypto_RetrieveLocalKey(i, keyfp, sizeof(keyfp), NULL, 0))
        {
                case -1:
-                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString("");
+                       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(keyfp);
+                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog, keyfp);
                        break;
        }
 }
-void VM_M_crypto_getmyidfp(void)
+static void VM_M_crypto_getmyidfp(prvm_prog_t *prog)
 {
        int i;
        char idfp[FP64_SIZE + 1];
@@ -833,14 +837,14 @@ void VM_M_crypto_getmyidfp(void)
        switch(Crypto_RetrieveLocalKey(i, NULL, 0, idfp, sizeof(idfp)))
        {
                case -1:
-                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString("");
+                       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(idfp);
+                       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog, idfp);
                        break;
        }
 }
@@ -1511,17 +1515,19 @@ 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
 };
 
 const int vm_m_numbuiltins = sizeof(vm_m_builtins) / sizeof(prvm_builtin_t);
 
-void VM_M_Cmd_Init(void)
+void MVM_init_cmd(prvm_prog_t *prog)
 {
        r_refdef_scene_t *scene;
 
-       VM_Cmd_Init();
-       VM_Polygons_Reset();
+       VM_Cmd_Init(prog);
+       VM_Polygons_Reset(prog);
 
        scene = R_GetScenePointer( RST_MENU );
 
@@ -1536,11 +1542,11 @@ void VM_M_Cmd_Init(void)
        scene->ambient = 32.0f;
 }
 
-void VM_M_Cmd_Reset(void)
+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();
-       VM_Polygons_Reset();
+       VM_Cmd_Reset(prog);
+       VM_Polygons_Reset(prog);
 }
index 65b64830067da60339105a1a36e91d4cacd5cd98..c5858c807155edf82ede94d42a7ec2768bf6e91b 100644 (file)
@@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 
 #include "quakedef.h"
+#include "thread.h"
 #include "lhnet.h"
 
 // for secure rcon authentication
@@ -62,14 +63,18 @@ static cvar_t sv_qwmasters [] =
        {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", "kubus.rulez.pl:27000", "Poland 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 net_message;
-static unsigned char net_message_buf[NET_MAXMESSAGE];
+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."};
@@ -95,18 +100,6 @@ static cvar_t rcon_secure_maxdiff = {0, "rcon_secure_maxdiff", "5", "maximum tim
 extern cvar_t rcon_secure;
 extern cvar_t rcon_secure_challengetimeout;
 
-/* statistic counters */
-static int packetsSent = 0;
-static int packetsReSent = 0;
-static int packetsReceived = 0;
-static int receivedDuplicateCount = 0;
-static int droppedDatagrams = 0;
-
-static int unreliableMessagesSent = 0;
-static int unreliableMessagesReceived = 0;
-static int reliableMessagesSent = 0;
-static int reliableMessagesReceived = 0;
-
 double masterquerytime = -1000;
 int masterquerycount = 0;
 int masterreplycount = 0;
@@ -123,11 +116,6 @@ static qboolean serverlist_paused = false;
 /// flooding in (which would make a mess of the ping times)
 static double serverlist_querywaittime = 0;
 
-static unsigned char sendbuffer[NET_HEADERSIZE+NET_MAXMESSAGE];
-static unsigned char readbuffer[NET_HEADERSIZE+NET_MAXMESSAGE];
-static unsigned char cryptosendbuffer[NET_HEADERSIZE+NET_MAXMESSAGE+CRYPTO_HEADERSIZE];
-static unsigned char cryptoreadbuffer[NET_HEADERSIZE+NET_MAXMESSAGE+CRYPTO_HEADERSIZE];
-
 static int cl_numsockets;
 static lhnetsocket_t *cl_sockets[16];
 static int sv_numsockets;
@@ -135,6 +123,7 @@ 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"};
@@ -413,8 +402,8 @@ static void ServerList_ViewList_Insert( serverlist_entry_t *entry )
                !(
                           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
+                       && gameversion_min.integer <= entry->info.gameversion // version of server in min/max range?
+                       && gameversion_max.integer >= entry->info.gameversion
                 )
        )
                return;
@@ -597,8 +586,13 @@ void ServerList_QueryList(qboolean resetcache, qboolean querydp, qboolean queryq
 
 int NetConn_Read(lhnetsocket_t *mysocket, void *data, int maxlength, lhnetaddress_t *peeraddress)
 {
-       int length = LHNET_Read(mysocket, data, maxlength, 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)
@@ -629,7 +623,11 @@ int NetConn_Write(lhnetsocket_t *mysocket, const void *data, int length, const l
                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];
@@ -666,6 +664,8 @@ qboolean NetConn_CanSend(netconn_t *conn)
 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
@@ -735,8 +735,8 @@ int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolvers
 
                NetConn_Write(conn->mysocket, (void *)&sendbuffer, packetLen, &conn->peeraddress);
 
-               packetsSent++;
-               unreliableMessagesSent++;
+               conn->packetsSent++;
+               conn->unreliableMessagesSent++;
 
                totallen += packetLen + 28;
        }
@@ -774,7 +774,7 @@ int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolvers
                        if (sendme && NetConn_Write(conn->mysocket, sendme, sendmelen, &conn->peeraddress) == (int)sendmelen)
                        {
                                conn->lastSendTime = realtime;
-                               packetsReSent++;
+                               conn->packetsReSent++;
                        }
 
                        totallen += sendmelen + 28;
@@ -826,8 +826,8 @@ int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolvers
                                NetConn_Write(conn->mysocket, sendme, sendmelen, &conn->peeraddress);
 
                        conn->lastSendTime = realtime;
-                       packetsSent++;
-                       reliableMessagesSent++;
+                       conn->packetsSent++;
+                       conn->reliableMessagesSent++;
 
                        totallen += sendmelen + 28;
                }
@@ -855,8 +855,8 @@ int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolvers
                        if(sendme)
                                NetConn_Write(conn->mysocket, sendme, sendmelen, &conn->peeraddress);
 
-                       packetsSent++;
-                       unreliableMessagesSent++;
+                       conn->packetsSent++;
+                       conn->unreliableMessagesSent++;
 
                        totallen += sendmelen + 28;
                }
@@ -889,7 +889,7 @@ void NetConn_CloseClientPorts(void)
                        LHNET_CloseSocket(cl_sockets[cl_numsockets - 1]);
 }
 
-void NetConn_OpenClientPort(const char *addressstring, lhnetaddresstype_t addresstype, int defaultport)
+static void NetConn_OpenClientPort(const char *addressstring, lhnetaddresstype_t addresstype, int defaultport)
 {
        lhnetaddress_t address;
        lhnetsocket_t *s;
@@ -922,6 +922,11 @@ 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);
@@ -943,7 +948,7 @@ void NetConn_CloseServerPorts(void)
                        LHNET_CloseSocket(sv_sockets[sv_numsockets - 1]);
 }
 
-qboolean NetConn_OpenServerPort(const char *addressstring, lhnetaddresstype_t addresstype, int defaultport, int range)
+static qboolean NetConn_OpenServerPort(const char *addressstring, lhnetaddresstype_t addresstype, int defaultport, int range)
 {
        lhnetaddress_t address;
        lhnetsocket_t *s;
@@ -987,6 +992,11 @@ 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)
@@ -1127,6 +1137,9 @@ void NetConn_UpdateSockets(void)
 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;
 
@@ -1153,7 +1166,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                        length -= 2;
                }
 
-               packetsReceived++;
+               conn->packetsReceived++;
                reliable_message = (sequence >> 31) & 1;
                reliable_ack = (sequence_ack >> 31) & 1;
                sequence &= ~(1<<31);
@@ -1166,7 +1179,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                count = sequence - (conn->qw.incoming_sequence + 1);
                if (count > 0)
                {
-                       droppedDatagrams += count;
+                       conn->droppedDatagrams += count;
                        //Con_DPrintf("Dropped %u datagram(s)\n", count);
                        while (count--)
                        {
@@ -1186,7 +1199,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                {
                        // received, now we will be able to send another reliable message
                        conn->sendMessageLength = 0;
-                       reliableMessagesReceived++;
+                       conn->reliableMessagesReceived++;
                }
                conn->qw.incoming_sequence = sequence;
                if (conn == cls.netcon)
@@ -1197,10 +1210,19 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                        conn->qw.incoming_reliable_sequence ^= 1;
                conn->lastMessageTime = realtime;
                conn->timeout = realtime + newtimeout;
-               unreliableMessagesReceived++;
-               SZ_Clear(&net_message);
-               SZ_Write(&net_message, data, length);
-               MSG_BeginReading();
+               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
@@ -1226,7 +1248,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                if (!(flags & NETFLAG_CTL) && qlength == length)
                {
                        sequence = BuffBigLong(data + 4);
-                       packetsReceived++;
+                       conn->packetsReceived++;
                        data += 8;
                        length -= 8;
                        if (flags & NETFLAG_UNRELIABLE)
@@ -1236,7 +1258,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                                        if (sequence > conn->nq.unreliableReceiveSequence)
                                        {
                                                count = sequence - conn->nq.unreliableReceiveSequence;
-                                               droppedDatagrams += count;
+                                               conn->droppedDatagrams += count;
                                                //Con_DPrintf("Dropped %u datagram(s)\n", count);
                                                while (count--)
                                                {
@@ -1255,12 +1277,21 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                                        conn->nq.unreliableReceiveSequence = sequence + 1;
                                        conn->lastMessageTime = realtime;
                                        conn->timeout = realtime + newtimeout;
-                                       unreliableMessagesReceived++;
+                                       conn->unreliableMessagesReceived++;
                                        if (length > 0)
                                        {
-                                               SZ_Clear(&net_message);
-                                               SZ_Write(&net_message, data, length);
-                                               MSG_BeginReading();
+                                               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;
                                        }
                                }
@@ -1312,7 +1343,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                                                        if (sendme && NetConn_Write(conn->mysocket, sendme, sendmelen, &conn->peeraddress) == (int)sendmelen)
                                                        {
                                                                conn->lastSendTime = realtime;
-                                                               packetsSent++;
+                                                               conn->packetsSent++;
                                                        }
                                                }
                                                else
@@ -1351,20 +1382,29 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                                        }
                                        if (flags & NETFLAG_EOM)
                                        {
-                                               reliableMessagesReceived++;
+                                               conn->reliableMessagesReceived++;
                                                length = conn->receiveMessageLength;
                                                conn->receiveMessageLength = 0;
                                                if (length > 0)
                                                {
-                                                       SZ_Clear(&net_message);
-                                                       SZ_Write(&net_message, conn->receiveMessage, length);
-                                                       MSG_BeginReading();
+                                                       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
-                                       receivedDuplicateCount++;
+                                       conn->receivedDuplicateCount++;
                                return 1;
                        }
                }
@@ -1372,7 +1412,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
        return 0;
 }
 
-void NetConn_ConnectionEstablished(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress, protocolversion_t initialprotocol)
+static void NetConn_ConnectionEstablished(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress, protocolversion_t initialprotocol)
 {
        crypto_t *crypto;
        cls.connect_trying = false;
@@ -1381,7 +1421,11 @@ void NetConn_ConnectionEstablished(lhnetsocket_t *mysocket, lhnetaddress_t *peer
        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;
@@ -1498,8 +1542,8 @@ static void NetConn_ClientParsePacket_ServerList_UpdateCache(int n)
                         !(
                                    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
+                                && gameversion_min.integer <= info->gameversion // version of server in min/max range?
+                                && gameversion_max.integer >= info->gameversion
                          )
                        ) ? '1' : '4',
                        info->mod, info->map);
@@ -1592,10 +1636,11 @@ static void NetConn_ClientParsePacket_ServerList_ParseDPList(lhnetaddress_t *sen
                        {
 #ifdef WHY_JUST_WHY
                                const char *ifname;
+                               char ifnamebuf[16];
 
                                /// \TODO: make some basic checks of the IP address (broadcast, ...)
 
-                               ifname = LHNETADDRESS_GetInterfaceName(senderaddress);
+                               ifname = LHNETADDRESS_GetInterfaceName(senderaddress, ifnamebuf, sizeof(ifnamebuf));
                                if (ifname != NULL)
                                {
                                        dpsnprintf (ipstring, sizeof (ipstring), "[%x:%x:%x:%x:%x:%x:%x:%x%%%s]:%hu",
@@ -1646,6 +1691,8 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
        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);
@@ -1758,7 +1805,7 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        // 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, va("\377\377\377\377connect\\protocol\\darkplaces 3\\protocols\\%s%s\\challenge\\%s", protocolnames, cls.connect_userinfo, string + 10), peeraddress);
+                       NetConn_WriteString(mysocket, 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)
@@ -1813,17 +1860,17 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        else
                                Con_Printf("statusResponse without players block?\n");
 
-                       if ((s = SearchInfostring(string, "gamename"     )) != NULL) strlcpy(info->game, s, sizeof (info->game));
-                       if ((s = SearchInfostring(string, "modname"      )) != NULL) strlcpy(info->mod , s, sizeof (info->mod ));
-                       if ((s = SearchInfostring(string, "mapname"      )) != NULL) strlcpy(info->map , s, sizeof (info->map ));
-                       if ((s = SearchInfostring(string, "hostname"     )) != NULL) strlcpy(info->name, s, sizeof (info->name));
-                       if ((s = SearchInfostring(string, "protocol"     )) != NULL) info->protocol = atoi(s);
-                       if ((s = SearchInfostring(string, "clients"      )) != NULL) info->numplayers = atoi(s);
-                       if ((s = SearchInfostring(string, "bots"         )) != NULL) info->numbots = atoi(s);
-                       if ((s = SearchInfostring(string, "sv_maxclients")) != NULL) info->maxplayers = atoi(s);
-                       if ((s = SearchInfostring(string, "gameversion"  )) != NULL) info->gameversion = atoi(s);
-                       if ((s = SearchInfostring(string, "qcstatus"     )) != NULL) strlcpy(info->qcstatus, s, sizeof(info->qcstatus));
-                       if (p                                               != NULL) strlcpy(info->players, p, sizeof(info->players));
+                       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;
 
@@ -1855,16 +1902,16 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        info->maxplayers  = 0;
                        info->gameversion = 0;
 
-                       if ((s = SearchInfostring(string, "gamename"     )) != NULL) strlcpy(info->game, s, sizeof (info->game));
-                       if ((s = SearchInfostring(string, "modname"      )) != NULL) strlcpy(info->mod , s, sizeof (info->mod ));
-                       if ((s = SearchInfostring(string, "mapname"      )) != NULL) strlcpy(info->map , s, sizeof (info->map ));
-                       if ((s = SearchInfostring(string, "hostname"     )) != NULL) strlcpy(info->name, s, sizeof (info->name));
-                       if ((s = SearchInfostring(string, "protocol"     )) != NULL) info->protocol = atoi(s);
-                       if ((s = SearchInfostring(string, "clients"      )) != NULL) info->numplayers = atoi(s);
-                       if ((s = SearchInfostring(string, "bots"         )) != NULL) info->numbots = atoi(s);
-                       if ((s = SearchInfostring(string, "sv_maxclients")) != NULL) info->maxplayers = atoi(s);
-                       if ((s = SearchInfostring(string, "gameversion"  )) != NULL) info->gameversion = atoi(s);
-                       if ((s = SearchInfostring(string, "qcstatus"     )) != NULL) strlcpy(info->qcstatus, s, sizeof(info->qcstatus));
+                       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;
 
@@ -1942,7 +1989,7 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        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, va("\377\377\377\377connect %i %i %i \"%s%s\"\n", 28, cls.qw_qport, atoi(string + 1), cls.userinfo, cls.connect_userinfo), peeraddress);
+                       NetConn_WriteString(mysocket, 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)
@@ -1969,14 +2016,14 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
 
                        info = &serverlist_cache[n].info;
                        strlcpy(info->game, "QuakeWorld", sizeof(info->game));
-                       if ((s = SearchInfostring(string, "*gamedir"     )) != NULL) strlcpy(info->mod , s, sizeof (info->mod ));else info->mod[0]  = 0;
-                       if ((s = SearchInfostring(string, "map"          )) != NULL) strlcpy(info->map , s, sizeof (info->map ));else info->map[0]  = 0;
-                       if ((s = SearchInfostring(string, "hostname"     )) != NULL) strlcpy(info->name, s, sizeof (info->name));else info->name[0] = 0;
+                       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 = SearchInfostring(string, "maxclients"   )) != NULL) info->maxplayers = atoi(s);else info->maxplayers  = 0;
-                       if ((s = SearchInfostring(string, "gameversion"  )) != NULL) info->gameversion = atoi(s);else info->gameversion = 0;
+                       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)
@@ -2024,10 +2071,10 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
 
                data += 4;
                length -= 4;
-               SZ_Clear(&net_message);
-               SZ_Write(&net_message, data, length);
-               MSG_BeginReading();
-               c = MSG_ReadByte();
+               SZ_Clear(&cl_message);
+               SZ_Write(&cl_message, data, length);
+               MSG_BeginReading(&cl_message);
+               c = MSG_ReadByte(&cl_message);
                switch (c)
                {
                case CCREP_ACCEPT:
@@ -2037,18 +2084,18 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        {
                                lhnetaddress_t clientportaddress;
                                clientportaddress = *peeraddress;
-                               LHNETADDRESS_SetPort(&clientportaddress, MSG_ReadLong());
+                               LHNETADDRESS_SetPort(&clientportaddress, MSG_ReadLong(&cl_message));
                                // extra ProQuake stuff
                                if (length >= 6)
-                                       cls.proquake_servermod = MSG_ReadByte(); // MOD_PROQUAKE
+                                       cls.proquake_servermod = MSG_ReadByte(&cl_message); // MOD_PROQUAKE
                                else
                                        cls.proquake_servermod = 0;
                                if (length >= 7)
-                                       cls.proquake_serverversion = MSG_ReadByte(); // version * 10
+                                       cls.proquake_serverversion = MSG_ReadByte(&cl_message); // version * 10
                                else
                                        cls.proquake_serverversion = 0;
                                if (length >= 8)
-                                       cls.proquake_serverflags = MSG_ReadByte(); // flags (mainly PQF_CHEATFREE)
+                                       cls.proquake_serverflags = MSG_ReadByte(&cl_message); // flags (mainly PQF_CHEATFREE)
                                else
                                        cls.proquake_serverflags = 0;
                                if (cls.proquake_servermod == 1)
@@ -2063,14 +2110,14 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        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());
+                       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();
+                       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)
@@ -2079,11 +2126,11 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        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(), sizeof(info->name));
-                       strlcpy(info->map , MSG_ReadString(), sizeof(info->map));
-                       info->numplayers = MSG_ReadByte();
-                       info->maxplayers = MSG_ReadByte();
-                       info->protocol = MSG_ReadByte();
+                       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);
 
@@ -2092,7 +2139,7 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        if (developer_extra.integer)
                                Con_DPrintf("Datagram_ParseConnectionless: received CCREP_RCON from %s.\n", addressstring2);
 
-                       Con_Printf("%s\n", MSG_ReadString());
+                       Con_Printf("%s\n", MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));
                        break;
                case CCREP_PLAYER_INFO:
                        // we got a CCREP_PLAYER_INFO??
@@ -2107,7 +2154,7 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                default:
                        break;
                }
-               SZ_Clear(&net_message);
+               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;
@@ -2211,6 +2258,7 @@ 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)
        {
@@ -2227,24 +2275,24 @@ void NetConn_ClientFrame(void)
                // 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(&net_message);
+               SZ_Clear(&cl_message);
                // save space for the header, filled in later
-               MSG_WriteLong(&net_message, 0);
-               MSG_WriteByte(&net_message, CCREQ_CONNECT);
-               MSG_WriteString(&net_message, "QUAKE");
-               MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
+               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(&net_message, 1); // mod = MOD_PROQUAKE
+               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(&net_message, 34); // version * 10
-               MSG_WriteByte(&net_message, 0); // flags
-               MSG_WriteLong(&net_message, 0); // password
+               MSG_WriteByte(&cl_message, 34); // version * 10
+               MSG_WriteByte(&cl_message, 0); // flags
+               MSG_WriteLong(&cl_message, 0); // password
                // write the packetsize now...
-               StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-               NetConn_Write(cls.connect_mysocket, net_message.data, net_message.cursize, &cls.connect_address);
-               SZ_Clear(&net_message);
+               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++)
        {
@@ -2260,7 +2308,9 @@ void NetConn_ClientFrame(void)
        {
                Con_Print("Connection timed out\n");
                CL_Disconnect();
+               SV_LockThreadMutex();
                Host_ShutdownServer ();
+               SV_UnlockThreadMutex();
        }
 }
 
@@ -2282,6 +2332,7 @@ static void NetConn_BuildChallengeString(char *buffer, int bufferlength)
 /// (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;
@@ -2289,8 +2340,6 @@ static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg
        const char *crypto_idstring;
        const char *str;
 
-       SV_VM_Begin();
-
        // How many clients are there?
        for (i = 0;i < (unsigned int)svs.maxclients;i++)
        {
@@ -2303,13 +2352,13 @@ static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg
        }
 
        *qcstatus = 0;
-       str = PRVM_GetString(PRVM_serverglobalstring(worldstatus));
+       str = PRVM_GetString(prog, PRVM_serverglobalstring(worldstatus));
        if(str && *str)
        {
                char *p;
                const char *q;
                p = qcstatus;
-               for(q = str; *q && p - qcstatus < (ptrdiff_t)(sizeof(qcstatus)) - 1; ++q)
+               for(q = str; *q && (size_t)(p - qcstatus) < (sizeof(qcstatus) - 1); ++q)
                        if(*q != '\\' && *q != '\n')
                                *p++ = *q;
                *p = 0;
@@ -2382,7 +2431,7 @@ static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg
 
                                *qcstatus = 0;
                                ed = PRVM_EDICT_NUM(i + 1);
-                               str = PRVM_GetString(PRVM_serveredictstring(ed, clientstatus));
+                               str = PRVM_GetString(prog, PRVM_serveredictstring(ed, clientstatus));
                                if(str && *str)
                                {
                                        char *p;
@@ -2441,11 +2490,9 @@ static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg
                }
        }
 
-       SV_VM_End();
        return true;
 
 bad:
-       SV_VM_End();
        return false;
 }
 
@@ -2511,7 +2558,7 @@ void NetConn_ClearConnectFlood(lhnetaddress_t *peeraddress)
 
 typedef qboolean (*rcon_matchfunc_t) (lhnetaddress_t *peeraddress, const char *password, const char *hash, const char *s, int slen);
 
-qboolean hmac_mdfour_time_matching(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;
@@ -2527,7 +2574,7 @@ qboolean hmac_mdfour_time_matching(lhnetaddress_t *peeraddress, const char *pass
        return !memcmp(mdfourbuf, hash, 16);
 }
 
-qboolean hmac_mdfour_challenge_matching(lhnetaddress_t *peeraddress, const char *password, const char *hash, const char *s, int slen)
+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;
@@ -2556,19 +2603,20 @@ qboolean hmac_mdfour_challenge_matching(lhnetaddress_t *peeraddress, const char
        return true;
 }
 
-qboolean plaintext_matching(lhnetaddress_t *peeraddress, const char *password, const char *hash, const char *s, int slen)
+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
-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)
+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, ' ')))
@@ -2640,7 +2688,7 @@ check:
                                {
                                        if(!strcmp(com_token, s))
                                                goto match;
-                                       if(!memcmp(va("%s ", com_token), s, strlen(com_token) + 1))
+                                       if(!memcmp(va(vabuf, sizeof(vabuf), "%s ", com_token), s, strlen(com_token) + 1))
                                                goto match;
                                }
                        }
@@ -2654,12 +2702,12 @@ match:
 allow:
        userpass_startpass = strchr(userpass_start, ':');
        if(have_usernames && userpass_startpass && userpass_startpass < userpass_end)
-               return va("%srcon (username %.*s)", restricted ? "restricted " : "", (int)(userpass_startpass-userpass_start), userpass_start);
+               return va(vabuf, sizeof(vabuf), "%srcon (username %.*s)", restricted ? "restricted " : "", (int)(userpass_startpass-userpass_start), userpass_start);
 
-       return va("%srcon", restricted ? "restricted " : "");
+       return va(vabuf, sizeof(vabuf), "%srcon", restricted ? "restricted " : "");
 }
 
-void RCon_Execute(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress, const char *addressstring2, const char *userlevel, const char *s, const char *endpos, qboolean proquakeprotocol)
+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)
        {
@@ -2683,7 +2731,7 @@ void RCon_Execute(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress, const ch
                        if(l)
                        {
                                client_t *host_client_save = host_client;
-                               Cmd_ExecuteString(s, src_command);
+                               Cmd_ExecuteString(s, src_command, true);
                                host_client = host_client_save;
                                // in case it is a command that changes host_client (like restart)
                        }
@@ -2697,17 +2745,18 @@ void RCon_Execute(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress, const ch
        }
 }
 
-extern void SV_SendServerinfo (client_t *client);
 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];
+       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;
@@ -2817,7 +2866,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        }
                        else
                        {
-                               if ((s = SearchInfostring(string, "challenge")))
+                               if ((s = InfoString_GetValue(string, "challenge", infostringvalue, sizeof(infostringvalue))))
                                {
                                        // validate the challenge
                                        for (i = 0;i < MAX_CHALLENGES;i++)
@@ -2830,19 +2879,19 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                }
                        }
 
-                       if((s = SearchInfostring(string, "message")))
+                       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, va("\377\377\377\377reject %s", sv_public_rejectreason.string), peeraddress);
+                               NetConn_WriteString(mysocket, va(vabuf, sizeof(vabuf), "\377\377\377\377reject %s", sv_public_rejectreason.string), peeraddress);
                                return true;
                        }
 
                        // check engine protocol
-                       if(!(s = SearchInfostring(string, "protocol")) || strcmp(s, "darkplaces 3"))
+                       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);
@@ -2899,9 +2948,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                                NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress);
                                                if(crypto && crypto->authenticated)
                                                        Crypto_ServerFinishInstance(&client->netconnection->crypto, crypto);
-                                               SV_VM_Begin();
                                                SV_SendServerinfo(client);
-                                               SV_VM_End();
                                        }
                                        else
                                        {
@@ -2933,9 +2980,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                        // now set up the client
                                        if(crypto && crypto->authenticated)
                                                Crypto_ServerFinishInstance(&conn->crypto, crypto);
-                                       SV_VM_Begin();
                                        SV_ConnectClient(clientnum, conn);
-                                       SV_VM_End();
                                        NetConn_Heartbeat(1);
                                        return true;
                                }
@@ -3071,10 +3116,10 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                const char *protocolname;
                data += 4;
                length -= 4;
-               SZ_Clear(&net_message);
-               SZ_Write(&net_message, data, length);
-               MSG_BeginReading();
-               c = MSG_ReadByte();
+               SZ_Clear(&sv_message);
+               SZ_Write(&sv_message, data, length);
+               MSG_BeginReading(&sv_message);
+               c = MSG_ReadByte(&sv_message);
                switch (c)
                {
                case CCREQ_CONNECT:
@@ -3084,31 +3129,31 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        {
                                if (developer_extra.integer)
                                        Con_DPrintf("Datagram_ParseConnectionless: sending CCREP_REJECT \"%s\" to %s.\n", sv_public_rejectreason.string, addressstring2);
-                               SZ_Clear(&net_message);
+                               SZ_Clear(&sv_message);
                                // save space for the header, filled in later
-                               MSG_WriteLong(&net_message, 0);
-                               MSG_WriteByte(&net_message, CCREP_REJECT);
-                               MSG_WriteString(&net_message, va("%s\n", sv_public_rejectreason.string));
-                               StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                               NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress);
-                               SZ_Clear(&net_message);
+                               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();
-                       protocolnumber = MSG_ReadByte();
+                       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(&net_message);
+                               SZ_Clear(&sv_message);
                                // save space for the header, filled in later
-                               MSG_WriteLong(&net_message, 0);
-                               MSG_WriteByte(&net_message, CCREP_REJECT);
-                               MSG_WriteString(&net_message, "Incompatible version.\n");
-                               StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                               NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress);
-                               SZ_Clear(&net_message);
+                               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;
                        }
 
@@ -3124,23 +3169,19 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                        // send a reply
                                        if (developer_extra.integer)
                                                Con_DPrintf("Datagram_ParseConnectionless: sending duplicate CCREP_ACCEPT to %s.\n", addressstring2);
-                                       SZ_Clear(&net_message);
+                                       SZ_Clear(&sv_message);
                                        // save space for the header, filled in later
-                                       MSG_WriteLong(&net_message, 0);
-                                       MSG_WriteByte(&net_message, CCREP_ACCEPT);
-                                       MSG_WriteLong(&net_message, LHNETADDRESS_GetPort(LHNET_AddressFromSocket(client->netconnection->mysocket)));
-                                       StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                                       NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress);
-                                       SZ_Clear(&net_message);
+                                       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->spawned)
-                                       {
-                                               SV_VM_Begin();
                                                SV_SendServerinfo(client);
-                                               SV_VM_End();
-                                       }
                                        return true;
                                }
                        }
@@ -3161,18 +3202,16 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                        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(&net_message);
+                                       SZ_Clear(&sv_message);
                                        // save space for the header, filled in later
-                                       MSG_WriteLong(&net_message, 0);
-                                       MSG_WriteByte(&net_message, CCREP_ACCEPT);
-                                       MSG_WriteLong(&net_message, LHNETADDRESS_GetPort(LHNET_AddressFromSocket(conn->mysocket)));
-                                       StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                                       NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress);
-                                       SZ_Clear(&net_message);
+                                       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_VM_Begin();
                                        SV_ConnectClient(clientnum, conn);
-                                       SV_VM_End();
                                        NetConn_Heartbeat(1);
                                        return true;
                                }
@@ -3181,44 +3220,44 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        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(&net_message);
+                       SZ_Clear(&sv_message);
                        // save space for the header, filled in later
-                       MSG_WriteLong(&net_message, 0);
-                       MSG_WriteByte(&net_message, CCREP_REJECT);
-                       MSG_WriteString(&net_message, "Server is full.\n");
-                       StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                       NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress);
-                       SZ_Clear(&net_message);
+                       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 (sv.active && !strcmp(MSG_ReadString(), "QUAKE"))
+                       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(&net_message);
+                               SZ_Clear(&sv_message);
                                // save space for the header, filled in later
-                               MSG_WriteLong(&net_message, 0);
-                               MSG_WriteByte(&net_message, CCREP_SERVER_INFO);
+                               MSG_WriteLong(&sv_message, 0);
+                               MSG_WriteByte(&sv_message, CCREP_SERVER_INFO);
                                LHNETADDRESS_ToString(LHNET_AddressFromSocket(mysocket), myaddressstring, sizeof(myaddressstring), true);
-                               MSG_WriteString(&net_message, myaddressstring);
-                               MSG_WriteString(&net_message, hostname.string);
-                               MSG_WriteString(&net_message, sv.name);
+                               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(&net_message, numclients);
-                               MSG_WriteByte(&net_message, svs.maxclients);
-                               MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
-                               StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                               NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress);
-                               SZ_Clear(&net_message);
+                               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:
@@ -3231,29 +3270,29 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                int playerNumber, activeNumber, clientNumber;
                                client_t *client;
 
-                               playerNumber = MSG_ReadByte();
+                               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(&net_message);
+                                       SZ_Clear(&sv_message);
                                        // save space for the header, filled in later
-                                       MSG_WriteLong(&net_message, 0);
-                                       MSG_WriteByte(&net_message, CCREP_PLAYER_INFO);
-                                       MSG_WriteByte(&net_message, playerNumber);
-                                       MSG_WriteString(&net_message, client->name);
-                                       MSG_WriteLong(&net_message, client->colors);
-                                       MSG_WriteLong(&net_message, client->frags);
-                                       MSG_WriteLong(&net_message, (int)(realtime - client->connecttime));
+                                       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(&net_message, client->netconnection ? "hidden" : "botclient");
+                                               MSG_WriteString(&sv_message, client->netconnection ? "hidden" : "botclient");
                                        else
-                                               MSG_WriteString(&net_message, client->netconnection ? client->netconnection->address : "botclient");
-                                       StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                                       NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress);
-                                       SZ_Clear(&net_message);
+                                               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;
@@ -3268,22 +3307,22 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                cvar_t *var;
 
                                // find the search start location
-                               prevCvarName = MSG_ReadString();
+                               prevCvarName = MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring));
                                var = Cvar_FindVarAfter(prevCvarName, CVAR_NOTIFY);
 
                                // send the response
-                               SZ_Clear(&net_message);
+                               SZ_Clear(&sv_message);
                                // save space for the header, filled in later
-                               MSG_WriteLong(&net_message, 0);
-                               MSG_WriteByte(&net_message, CCREP_RULE_INFO);
+                               MSG_WriteLong(&sv_message, 0);
+                               MSG_WriteByte(&sv_message, CCREP_RULE_INFO);
                                if (var)
                                {
-                                       MSG_WriteString(&net_message, var->name);
-                                       MSG_WriteString(&net_message, var->string);
+                                       MSG_WriteString(&sv_message, var->name);
+                                       MSG_WriteString(&sv_message, var->string);
                                }
-                               StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                               NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress);
-                               SZ_Clear(&net_message);
+                               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:
@@ -3296,8 +3335,8 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                char *s;
                                char *endpos;
                                const char *userlevel;
-                               strlcpy(password, MSG_ReadString(), sizeof(password));
-                               strlcpy(cmd, MSG_ReadString(), sizeof(cmd));
+                               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);
@@ -3308,7 +3347,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                default:
                        break;
                }
-               SZ_Clear(&net_message);
+               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;
@@ -3317,9 +3356,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
        {
                if ((ret = NetConn_ReceivedMessage(host_client->netconnection, data, length, sv.protocol, host_client->spawned ? net_messagetimeout.value : net_connecttimeout.value)) == 2)
                {
-                       SV_VM_Begin();
                        SV_ReadClientMessage();
-                       SV_VM_End();
                        return ret;
                }
        }
@@ -3330,6 +3367,7 @@ 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);
@@ -3339,9 +3377,7 @@ void NetConn_ServerFrame(void)
                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_VM_Begin();
                        SV_DropClient(false);
-                       SV_VM_End();
                }
        }
 }
@@ -3379,15 +3415,15 @@ void NetConn_QueryMasters(qboolean querydp, qboolean queryqw)
                                if(LHNETADDRESS_GetAddressType(&broadcastaddress) == af)
                                {
                                        // search LAN for Quake servers
-                                       SZ_Clear(&net_message);
+                                       SZ_Clear(&cl_message);
                                        // save space for the header, filled in later
-                                       MSG_WriteLong(&net_message, 0);
-                                       MSG_WriteByte(&net_message, CCREQ_SERVER_INFO);
-                                       MSG_WriteString(&net_message, "QUAKE");
-                                       MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
-                                       StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
-                                       NetConn_Write(cl_sockets[i], net_message.data, net_message.cursize, &broadcastaddress);
-                                       SZ_Clear(&net_message);
+                                       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);
@@ -3525,26 +3561,26 @@ static void Net_Heartbeat_f(void)
                Con_Print("No server running, can not heartbeat to master server.\n");
 }
 
-void PrintStats(netconn_t *conn)
+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_Printf("unreliable messages sent   = %i\n", unreliableMessagesSent);
-       Con_Printf("unreliable messages recv   = %i\n", unreliableMessagesReceived);
-       Con_Printf("reliable messages sent     = %i\n", reliableMessagesSent);
-       Con_Printf("reliable messages received = %i\n", reliableMessagesReceived);
-       Con_Printf("packetsSent                = %i\n", packetsSent);
-       Con_Printf("packetsReSent              = %i\n", packetsReSent);
-       Con_Printf("packetsReceived            = %i\n", packetsReceived);
-       Con_Printf("receivedDuplicateCount     = %i\n", receivedDuplicateCount);
-       Con_Printf("droppedDatagrams           = %i\n", droppedDatagrams);
        Con_Print("connections                =\n");
        for (conn = netconn_list;conn;conn = conn->next)
                PrintStats(conn);
@@ -3651,10 +3687,15 @@ void NetConn_Init(void)
        }
        cl_numsockets = 0;
        sv_numsockets = 0;
-       net_message.data = net_message_buf;
-       net_message.maxsize = sizeof(net_message_buf);
-       net_message.cursize = 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)
@@ -3662,5 +3703,8 @@ void NetConn_Shutdown(void)
        NetConn_CloseClientPorts();
        NetConn_CloseServerPorts();
        LHNET_Shutdown();
+       if (netconn_mutex)
+               Thread_DestroyMutex(netconn_mutex);
+       netconn_mutex = NULL;
 }
 
index f93d297eb6f52d78f49af8b5c9f004c65442d943..69b0de518946ea361668d41b48234a536ff8e726 100644 (file)
@@ -221,6 +221,17 @@ typedef struct netconn_s
 
        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;
@@ -229,10 +240,7 @@ extern mempool_t *netconn_mempool;
 extern cvar_t hostname;
 extern cvar_t developer_networking;
 
-#define SERVERLIST_TOTALSIZE           2048
 #define SERVERLIST_VIEWLISTSIZE                SERVERLIST_TOTALSIZE
-#define SERVERLIST_ANDMASKCOUNT                5
-#define SERVERLIST_ORMASKCOUNT         5
 
 typedef enum serverlist_maskop_e
 {
@@ -392,7 +400,10 @@ extern int masterreplycount;
 extern int serverquerycount;
 extern int serverreplycount;
 
-extern sizebuf_t net_message;
+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;
 
index af4131469d45cacdfb616ca9c5849e06db1f085f..9fb36de352170e0f6d18481baea4dd000aa5e840 100644 (file)
@@ -76,7 +76,7 @@ unsigned char host_quakepal[768] =
        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 ^
 
-void Palette_SetupSpecialPalettes(void)
+static void Palette_SetupSpecialPalettes(void)
 {
        int i;
        int fullbright_start, fullbright_end;
@@ -221,15 +221,15 @@ void BuildGammaTable16(float prescale, float gamma, float scale, float base, flo
        }
 }
 
-void Palette_Shutdown(void)
+static void Palette_Shutdown(void)
 {
 }
 
-void Palette_NewMap(void)
+static void Palette_NewMap(void)
 {
 }
 
-void Palette_Load(void)
+static void Palette_Load(void)
 {
        int i;
        unsigned char *out;
index 3b770f9ea40c79cbf4b55bf8d77bcee9e16e0d5e..0900a34f8f6c9c6fb41dc12b53c77baaa03a8398 100644 (file)
@@ -1,6 +1,7 @@
 
 #include "quakedef.h"
 #include "polygon.h"
+#include "portals.h"
 
 #define MAXRECURSIVEPORTALPLANES 1024
 #define MAXRECURSIVEPORTALS 256
index 30219148e9ecaf8ab4be5fc0363f181b3a1f3099..72813bbf4d9a93c540153414729ec826bcf05c4e 100644 (file)
@@ -106,6 +106,7 @@ typedef struct edict_engineprivate_s
        vec3_t ode_mins;
        vec3_t ode_maxs;
        vec_t ode_mass;
+       float ode_friction;
        vec3_t ode_origin;
        vec3_t ode_velocity;
        vec3_t ode_angles;
index 60c3f212f0bc31a1b7e8991fc900d8458f09403d..0082938d6a6a422ecb7f40a2883fc2624fbd0f34 100644 (file)
@@ -37,9 +37,6 @@ The code uses void pointers instead.
 #define PROFILING
 #endif
 
-// forward declaration of clgecko_t
-struct clgecko_s;
-
 typedef struct prvm_stack_s
 {
        int                             s;
@@ -74,7 +71,9 @@ typedef struct prvm_edict_private_s
 {
        qboolean free;
        float freetime;
-       int mark;
+       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;
 
@@ -115,6 +114,43 @@ typedef struct prvm_edict_s
        } 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))
@@ -226,17 +262,16 @@ extern prvm_eval_t prvm_badvalue;
 
 #define PRVM_MAX_OPENFILES 16
 #define PRVM_MAX_OPENSEARCHES 8
-#define PRVM_MAX_GECKOINSTANCES 1
 #else
 #define        PRVM_MAX_STACK_DEPTH            1024
 #define        PRVM_LOCALSTACK_SIZE            16384
 
 #define PRVM_MAX_OPENFILES 256
 #define PRVM_MAX_OPENSEARCHES 128
-#define PRVM_MAX_GECKOINSTANCES 32
 #endif
 
-typedef void (*prvm_builtin_t) (void);
+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
@@ -492,7 +527,8 @@ prvm_stringbuffer_t;
 // NOTE: external code has to create and free the mempools but everything else is done by prvm !
 typedef struct prvm_prog_s
 {
-       double              starttime;
+       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;
@@ -573,9 +609,15 @@ typedef struct prvm_prog_s
        const char *         openfiles_origin[PRVM_MAX_OPENFILES];
        fssearch_t                      *opensearches[PRVM_MAX_OPENSEARCHES];
        const char *         opensearches_origin[PRVM_MAX_OPENSEARCHES];
-       struct clgecko_s                *opengeckoinstances[PRVM_MAX_GECKOINSTANCES];
        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
@@ -634,32 +676,41 @@ typedef struct prvm_prog_s
        //============================================================================
        // function pointers
 
-       void                            (*begin_increase_edicts)(void); // [INIT] used by PRVM_MEM_Increase_Edicts
-       void                            (*end_increase_edicts)(void); // [INIT]
+       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)(prvm_edict_t *edict); // [INIT] used by PRVM_ED_ClearEdict
-       void                            (*free_edict)(prvm_edict_t *ed); // [INIT] used by PRVM_ED_Free
+       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)(void); // [INIT] used by PRVM_ED_Count_f
+       void                            (*count_edicts)(struct prvm_prog_s *prog); // [INIT] used by PRVM_ED_Count_f
 
-       qboolean                        (*load_edict)(prvm_edict_t *ent); // [INIT] used by PRVM_ED_LoadFromFile
+       qboolean                        (*load_edict)(struct prvm_prog_s *prog, prvm_edict_t *ent); // [INIT] used by PRVM_ED_LoadFromFile
 
-       void                            (*init_cmd)(void); // [INIT] used by PRVM_InitProg
-       void                            (*reset_cmd)(void); // [INIT] used by PRVM_ResetProg
+       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)(func_t fnum, const char *errormessage); // pointer to one of the *VM_ExecuteProgram functions
+       void                            (*ExecuteProgram)(struct prvm_prog_s *prog, func_t fnum, const char *errormessage); // pointer to one of the *VM_ExecuteProgram functions
 } prvm_prog_t;
 
-extern prvm_prog_t * prog;
-
-#define PRVM_MAXPROGS 3
-#define PRVM_SERVERPROG 0 // actually not used at the moment
-#define PRVM_CLIENTPROG 1
-#define PRVM_MENUPROG  2
+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_MAXPROGS];
+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
@@ -675,80 +726,75 @@ extern const int vm_m_numbuiltins;
 extern const char * vm_sv_extensions; // client also uses this
 extern const char * vm_m_extensions;
 
-void VM_SV_Cmd_Init(void);
-void VM_SV_Cmd_Reset(void);
+void SVVM_init_cmd(prvm_prog_t *prog);
+void SVVM_reset_cmd(prvm_prog_t *prog);
 
-void VM_CL_Cmd_Init(void);
-void VM_CL_Cmd_Reset(void);
+void CLVM_init_cmd(prvm_prog_t *prog);
+void CLVM_reset_cmd(prvm_prog_t *prog);
 
-void VM_M_Cmd_Init(void);
-void VM_M_Cmd_Reset(void);
+void MVM_init_cmd(prvm_prog_t *prog);
+void MVM_reset_cmd(prvm_prog_t *prog);
 
-void VM_Cmd_Init(void);
-void VM_Cmd_Reset(void);
+void VM_Cmd_Init(prvm_prog_t *prog);
+void VM_Cmd_Reset(prvm_prog_t *prog);
 //============================================================================
 
 void PRVM_Init (void);
 
 #ifdef PROFILING
-void MVM_ExecuteProgram (func_t fnum, const char *errormessage);
-void CLVM_ExecuteProgram (func_t fnum, const char *errormessage);
-void SVVM_ExecuteProgram (func_t fnum, const char *errormessage);
+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 MVM_ExecuteProgram SVVM_ExecuteProgram
-#define CLVM_ExecuteProgram SVVM_ExecuteProgram
-void SVVM_ExecuteProgram (func_t fnum, const char *errormessage);
+#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_ExecuteProgram prog->ExecuteProgram
 
-#define PRVM_Alloc(buffersize) _PRVM_Alloc(buffersize, __FILE__, __LINE__)
-#define PRVM_Free(buffer) _PRVM_Free(buffer, __FILE__, __LINE__)
-#define PRVM_FreeAll() _PRVM_FreeAll(__FILE__, __LINE__)
-void *_PRVM_Alloc (size_t buffersize, const char *filename, int fileline);
-void _PRVM_Free (void *buffer, const char *filename, int fileline);
-void _PRVM_FreeAll (const char *filename, int fileline);
+#define PRVM_Alloc(buffersize) Mem_Alloc(prog->progs_mempool, buffersize)
+#define PRVM_Free(buffer) Mem_Free(buffer)
 
-void PRVM_Profile (int maxfunctions, double mintime, int sortby);
+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(void);
-void PRVM_CrashAll (void);
-void PRVM_Crash (void);
-void PRVM_ShortStackTrace(char *buf, size_t bufsize);
-const char *PRVM_AllocationOrigin(void);
+void PRVM_PrintState(prvm_prog_t *prog);
+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(const char *name);
-ddef_t *PRVM_ED_FindGlobal(const char *name);
-mfunction_t *PRVM_ED_FindFunction(const char *name);
+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(const char *name);
-int PRVM_ED_FindGlobalOffset(const char *name);
-func_t PRVM_ED_FindFunctionOffset(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(void);
+void PRVM_MEM_IncreaseEdicts(prvm_prog_t *prog);
 
-qboolean PRVM_ED_CanAlloc(prvm_edict_t *e);
-prvm_edict_t *PRVM_ED_Alloc (void);
-void PRVM_ED_Free (prvm_edict_t *ed);
-void PRVM_ED_ClearEdict (prvm_edict_t *e);
+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 (const char *name);
-void PRVM_ED_Print(prvm_edict_t *ed, const char *wildcard_fieldname);
-void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed);
-const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent);
+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 (qfile_t *f);
-void PRVM_ED_ParseGlobals (const char *data);
+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 (const char *data);
+void PRVM_ED_LoadFromFile(prvm_prog_t *prog, const char *data);
 
-unsigned int PRVM_EDICT_NUM_ERROR(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((unsigned int)(n), __FILE__, __LINE__))
+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);
@@ -769,58 +815,37 @@ unsigned int PRVM_EDICT_NUM_ERROR(unsigned int n, const char *filename, int file
 #define        PRVM_G_EDICT(o) (PRVM_PROG_TO_EDICT(*(int *)&prog->globals.generic[o]))
 #define PRVM_G_EDICTNUM(o) PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(o))
 #define        PRVM_G_VECTOR(o) (&prog->globals.generic[o])
-#define        PRVM_G_STRING(o) (PRVM_GetString(*(string_t *)&prog->globals.generic[o]))
-//#define      PRVM_G_FUNCTION(o) (*(func_t *)&prog->globals.generic[o])
+#define        PRVM_G_STRING(o) (PRVM_GetString(prog, *(string_t *)&prog->globals.generic[o]))
+//#define      PRVM_G_FUNCTION(prog, o) (*(func_t *)&prog->globals.generic[o])
 
 // FIXME: make these go away?
 #define        PRVM_E_FLOAT(e,o) (((float*)e->fields.vp)[o])
 #define        PRVM_E_INT(e,o) (((int*)e->fields.vp)[o])
 //#define      PRVM_E_VECTOR(e,o) (&((float*)e->fields.vp)[o])
-#define        PRVM_E_STRING(e,o) (PRVM_GetString(*(string_t *)&((float*)e->fields.vp)[o]))
+#define        PRVM_E_STRING(e,o) (PRVM_GetString(prog, *(string_t *)&((float*)e->fields.vp)[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(void);
+void PRVM_Init_Exec(prvm_prog_t *prog);
 
 void PRVM_ED_PrintEdicts_f (void);
-void PRVM_ED_PrintNum (int ent, const char *wildcard_fieldname);
-
-const char *PRVM_GetString(int num);
-int PRVM_SetEngineString(const char *s);
-const char *PRVM_ChangeEngineString(int i, const char *s);
-int PRVM_SetTempString(const char *s);
-int PRVM_AllocString(size_t bufferlength, char **pointer);
-void PRVM_FreeString(int num);
+void PRVM_ED_PrintNum (prvm_prog_t *prog, int ent, const char *wildcard_fieldname);
 
-//============================================================================
-
-// used as replacement for a prog stack
-//#define PRVM_DEBUGPRSTACK
-
-#ifdef PRVM_DEBUGPRSTACK
-#define PRVM_Begin  if(prog != 0) Con_Printf("prog not 0(prog = %i) in file: %s line: %i!\n", PRVM_GetProgNr(), __FILE__, __LINE__)
-#define PRVM_End       prog = 0
-#else
-#define PRVM_Begin
-#define PRVM_End       prog = 0
-#endif
-
-//#define PRVM_SAFENAME
-#ifndef PRVM_SAFENAME
-#      define PRVM_NAME        (prog->name)
-#else
-#      define PRVM_NAME        (prog->name ? prog->name : "Unknown prog name")
-#endif
-
-// helper macro to make function pointer calls easier
-#define PRVM_GCALL(func)       if(prog->func) prog->func
+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);
 
-#define PRVM_ERROR             prog->error_cmd
+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);
 
-// other prog handling functions
-qboolean PRVM_SetProgFromString(const char *str);
-void PRVM_SetProg(int prognr);
+//============================================================================
 
 /*
 Initializing a vm:
@@ -828,23 +853,18 @@ Call InitProg with the num
 Set up the fields marked with [INIT] in the prog struct
 Load a program with LoadProgs
 */
-void PRVM_InitProg(int prognr);
-// LoadProgs expects to be called right after InitProg
-void PRVM_LoadProgs (const char *filename, int numrequiredfunc, const char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, prvm_required_field_t *required_global);
-void PRVM_ResetProg(void);
-
-qboolean PRVM_ProgLoaded(int prognr);
-
-int    PRVM_GetProgNr(void);
+// Load expects to be called right after Init
+void PRVM_Prog_Init(prvm_prog_t *prog);
+void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, 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 VM_Warning(const char *fmt, ...) DP_FUNC_PRINTF(1);
+void PRVM_StackTrace(prvm_prog_t *prog);
 
-// TODO: fill in the params
-//void PRVM_Create();
+void VM_Warning(prvm_prog_t *prog, const char *fmt, ...) DP_FUNC_PRINTF(2);
 
-void VM_GenerateFrameGroupBlend(framegroupblend_t *framegroupblend, const prvm_edict_t *ed);
+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);
-void VM_UpdateEdictSkeleton(prvm_edict_t *ed, const dp_model_t *edmodel, const frameblend_t *frameblend);
-void VM_RemoveEdictSkeleton(prvm_edict_t *ed);
+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
index 3e384e16fccb0face48c7b49f3087702575e1439..d63d0918af10111711fda04ef9eafd38248bfa8c 100644 (file)
@@ -7,7 +7,7 @@
        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(PRVM_serveredictstring(ed, classname)) : "(no classname)"); \
+               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)
@@ -131,18 +131,18 @@ void EntityFrameQuake_ReadEntity(int bits)
        entity_state_t s;
 
        if (bits & U_MOREBITS)
-               bits |= (MSG_ReadByte()<<8);
+               bits |= (MSG_ReadByte(&cl_message)<<8);
        if ((bits & U_EXTEND1) && cls.protocol != PROTOCOL_NEHAHRAMOVIE)
        {
-               bits |= MSG_ReadByte() << 16;
+               bits |= MSG_ReadByte(&cl_message) << 16;
                if (bits & U_EXTEND2)
-                       bits |= MSG_ReadByte() << 24;
+                       bits |= MSG_ReadByte(&cl_message) << 24;
        }
 
        if (bits & U_LONGENTITY)
-               num = (unsigned short) MSG_ReadShort ();
+               num = (unsigned short) MSG_ReadShort(&cl_message);
        else
-               num = MSG_ReadByte ();
+               num = MSG_ReadByte(&cl_message);
 
        if (num >= MAX_EDICTS)
                Host_Error("EntityFrameQuake_ReadEntity: entity number (%i) >= MAX_EDICTS (%i)", num, MAX_EDICTS);
@@ -178,30 +178,30 @@ void EntityFrameQuake_ReadEntity(int bits)
        if (bits & U_MODEL)
        {
                if (cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3)
-                                                       s.modelindex = (unsigned short) MSG_ReadShort();
+                                                       s.modelindex = (unsigned short) MSG_ReadShort(&cl_message);
                else
-                                                       s.modelindex = (s.modelindex & 0xFF00) | MSG_ReadByte();
-       }
-       if (bits & U_FRAME)             s.frame = (s.frame & 0xFF00) | MSG_ReadByte();
-       if (bits & U_COLORMAP)  s.colormap = MSG_ReadByte();
-       if (bits & U_SKIN)              s.skin = MSG_ReadByte();
-       if (bits & U_EFFECTS)   s.effects = (s.effects & 0xFF00) | MSG_ReadByte();
-       if (bits & U_ORIGIN1)   s.origin[0] = MSG_ReadCoord(cls.protocol);
-       if (bits & U_ANGLE1)    s.angles[0] = MSG_ReadAngle(cls.protocol);
-       if (bits & U_ORIGIN2)   s.origin[1] = MSG_ReadCoord(cls.protocol);
-       if (bits & U_ANGLE2)    s.angles[1] = MSG_ReadAngle(cls.protocol);
-       if (bits & U_ORIGIN3)   s.origin[2] = MSG_ReadCoord(cls.protocol);
-       if (bits & U_ANGLE3)    s.angles[2] = MSG_ReadAngle(cls.protocol);
+                                                       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();
-       if (bits & U_SCALE)             s.scale = MSG_ReadByte();
-       if (bits & U_EFFECTS2)  s.effects = (s.effects & 0x00FF) | (MSG_ReadByte() << 8);
-       if (bits & U_GLOWSIZE)  s.glowsize = MSG_ReadByte();
-       if (bits & U_GLOWCOLOR) s.glowcolor = MSG_ReadByte();
-       if (bits & U_COLORMOD)  {int c = MSG_ReadByte();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_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() << 8);
-       if (bits & U_MODEL2)    s.modelindex = (s.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
+       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;
 
@@ -209,11 +209,11 @@ void EntityFrameQuake_ReadEntity(int bits)
        if (cls.protocol == PROTOCOL_NEHAHRAMOVIE && (bits & U_EXTEND1))
        {
                // LordHavoc: evil format
-               int i = (int)MSG_ReadFloat();
-               int j = (int)(MSG_ReadFloat() * 255.0f);
+               int i = (int)MSG_ReadFloat(&cl_message);
+               int j = (int)(MSG_ReadFloat(&cl_message) * 255.0f);
                if (i == 2)
                {
-                       i = (int)MSG_ReadFloat();
+                       i = (int)MSG_ReadFloat(&cl_message);
                        if (i)
                                s.effects |= EF_FULLBRIGHT;
                }
@@ -233,7 +233,7 @@ void EntityFrameQuake_ReadEntity(int bits)
                cl.entities_active[ent->state_current.number] = true;
        }
 
-       if (msg_badread)
+       if (cl_message.badread)
                Host_Error("EntityFrameQuake_ReadEntity: read error");
 }
 
@@ -270,6 +270,7 @@ void EntityFrameQuake_ISeeDeadEntities(void)
 // 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;
@@ -297,7 +298,7 @@ void EntityFrameCSQC_LostFrame(client_t *client, int framenum)
        int i, j;
        qboolean valid;
        int ringfirst, ringlast;
-       static int recoversendflags[MAX_EDICTS];
+       static int recoversendflags[MAX_EDICTS]; // client only
        csqcentityframedb_t *d;
 
        if(client->csqcentityframe_lastreset < 0)
@@ -432,6 +433,7 @@ static void EntityFrameCSQC_DeallocFrame(client_t *client, int framenum)
 // 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;
@@ -555,7 +557,7 @@ qboolean EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int maxsize, int numnumbers
                                        PRVM_G_INT(OFS_PARM0) = sv.writeentitiestoclient_cliententitynumber;
                                        PRVM_G_FLOAT(OFS_PARM1) = sendflags;
                                        PRVM_serverglobaledict(self) = number;
-                                       PRVM_ExecuteProgram(PRVM_serveredictfunction(ed, SendEntity), "Null SendEntity\n");
+                                       prog->ExecuteProgram(prog, PRVM_serveredictfunction(ed, SendEntity), "Null SendEntity\n");
                                        msg->allowoverflow = false;
                                        if(PRVM_G_FLOAT(OFS_RETURN) && msg->cursize + 2 <= maxsize)
                                        {
@@ -677,6 +679,7 @@ void Protocol_WriteStatsReliable(void)
 
 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;
@@ -1022,6 +1025,7 @@ void EntityState_WriteFields(const entity_state_t *ent, sizebuf_t *msg, unsigned
 
 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)
@@ -1050,15 +1054,15 @@ void EntityState_WriteUpdate(const entity_state_t *ent, sizebuf_t *msg, const en
 int EntityState_ReadExtendBits(void)
 {
        unsigned int bits;
-       bits = MSG_ReadByte();
+       bits = MSG_ReadByte(&cl_message);
        if (bits & 0x00000080)
        {
-               bits |= MSG_ReadByte() << 8;
+               bits |= MSG_ReadByte(&cl_message) << 8;
                if (bits & 0x00008000)
                {
-                       bits |= MSG_ReadByte() << 16;
+                       bits |= MSG_ReadByte(&cl_message) << 16;
                        if (bits & 0x00800000)
-                               bits |= MSG_ReadByte() << 24;
+                               bits |= MSG_ReadByte(&cl_message) << 24;
                }
        }
        return bits;
@@ -1069,96 +1073,96 @@ void EntityState_ReadFields(entity_state_t *e, unsigned int bits)
        if (cls.protocol == PROTOCOL_DARKPLACES2)
        {
                if (bits & E_ORIGIN1)
-                       e->origin[0] = MSG_ReadCoord16i();
+                       e->origin[0] = MSG_ReadCoord16i(&cl_message);
                if (bits & E_ORIGIN2)
-                       e->origin[1] = MSG_ReadCoord16i();
+                       e->origin[1] = MSG_ReadCoord16i(&cl_message);
                if (bits & E_ORIGIN3)
-                       e->origin[2] = MSG_ReadCoord16i();
+                       e->origin[2] = MSG_ReadCoord16i(&cl_message);
        }
        else
        {
                if (bits & E_FLAGS)
-                       e->flags = MSG_ReadByte();
+                       e->flags = MSG_ReadByte(&cl_message);
                if (e->flags & RENDER_LOWPRECISION)
                {
                        if (bits & E_ORIGIN1)
-                               e->origin[0] = MSG_ReadCoord16i();
+                               e->origin[0] = MSG_ReadCoord16i(&cl_message);
                        if (bits & E_ORIGIN2)
-                               e->origin[1] = MSG_ReadCoord16i();
+                               e->origin[1] = MSG_ReadCoord16i(&cl_message);
                        if (bits & E_ORIGIN3)
-                               e->origin[2] = MSG_ReadCoord16i();
+                               e->origin[2] = MSG_ReadCoord16i(&cl_message);
                }
                else
                {
                        if (bits & E_ORIGIN1)
-                               e->origin[0] = MSG_ReadCoord32f();
+                               e->origin[0] = MSG_ReadCoord32f(&cl_message);
                        if (bits & E_ORIGIN2)
-                               e->origin[1] = MSG_ReadCoord32f();
+                               e->origin[1] = MSG_ReadCoord32f(&cl_message);
                        if (bits & E_ORIGIN3)
-                               e->origin[2] = MSG_ReadCoord32f();
+                               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();
+                       e->angles[0] = MSG_ReadAngle16i(&cl_message);
                if (bits & E_ANGLE2)
-                       e->angles[1] = MSG_ReadAngle16i();
+                       e->angles[1] = MSG_ReadAngle16i(&cl_message);
                if (bits & E_ANGLE3)
-                       e->angles[2] = MSG_ReadAngle16i();
+                       e->angles[2] = MSG_ReadAngle16i(&cl_message);
        }
        else
        {
                if (bits & E_ANGLE1)
-                       e->angles[0] = MSG_ReadAngle8i();
+                       e->angles[0] = MSG_ReadAngle8i(&cl_message);
                if (bits & E_ANGLE2)
-                       e->angles[1] = MSG_ReadAngle8i();
+                       e->angles[1] = MSG_ReadAngle8i(&cl_message);
                if (bits & E_ANGLE3)
-                       e->angles[2] = MSG_ReadAngle8i();
+                       e->angles[2] = MSG_ReadAngle8i(&cl_message);
        }
        if (bits & E_MODEL1)
-               e->modelindex = (e->modelindex & 0xFF00) | (unsigned int) MSG_ReadByte();
+               e->modelindex = (e->modelindex & 0xFF00) | (unsigned int) MSG_ReadByte(&cl_message);
        if (bits & E_MODEL2)
-               e->modelindex = (e->modelindex & 0x00FF) | ((unsigned int) MSG_ReadByte() << 8);
+               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();
+               e->frame = (e->frame & 0xFF00) | (unsigned int) MSG_ReadByte(&cl_message);
        if (bits & E_FRAME2)
-               e->frame = (e->frame & 0x00FF) | ((unsigned int) MSG_ReadByte() << 8);
+               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();
+               e->effects = (e->effects & 0xFF00) | (unsigned int) MSG_ReadByte(&cl_message);
        if (bits & E_EFFECTS2)
-               e->effects = (e->effects & 0x00FF) | ((unsigned int) MSG_ReadByte() << 8);
+               e->effects = (e->effects & 0x00FF) | ((unsigned int) MSG_ReadByte(&cl_message) << 8);
        if (bits & E_COLORMAP)
-               e->colormap = MSG_ReadByte();
+               e->colormap = MSG_ReadByte(&cl_message);
        if (bits & E_SKIN)
-               e->skin = MSG_ReadByte();
+               e->skin = MSG_ReadByte(&cl_message);
        if (bits & E_ALPHA)
-               e->alpha = MSG_ReadByte();
+               e->alpha = MSG_ReadByte(&cl_message);
        if (bits & E_SCALE)
-               e->scale = MSG_ReadByte();
+               e->scale = MSG_ReadByte(&cl_message);
        if (bits & E_GLOWSIZE)
-               e->glowsize = MSG_ReadByte();
+               e->glowsize = MSG_ReadByte(&cl_message);
        if (bits & E_GLOWCOLOR)
-               e->glowcolor = MSG_ReadByte();
+               e->glowcolor = MSG_ReadByte(&cl_message);
        if (cls.protocol == PROTOCOL_DARKPLACES2)
                if (bits & E_FLAGS)
-                       e->flags = MSG_ReadByte();
+                       e->flags = MSG_ReadByte(&cl_message);
        if (bits & E_TAGATTACHMENT)
        {
-               e->tagentity = (unsigned short) MSG_ReadShort();
-               e->tagindex = MSG_ReadByte();
+               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();
-               e->light[1] = (unsigned short) MSG_ReadShort();
-               e->light[2] = (unsigned short) MSG_ReadShort();
-               e->light[3] = (unsigned short) MSG_ReadShort();
+               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();
+               e->lightstyle = MSG_ReadByte(&cl_message);
        if (bits & E_LIGHTPFLAGS)
-               e->lightpflags = MSG_ReadByte();
+               e->lightpflags = MSG_ReadByte(&cl_message);
 
        if (developer_networkentities.integer >= 2)
        {
@@ -1210,8 +1214,6 @@ void EntityState_ReadFields(entity_state_t *e, unsigned int bits)
        }
 }
 
-extern void CL_NewFrameReceived(int num);
-
 // (client and server) allocates a new empty database
 entityframe_database_t *EntityFrame_AllocDatabase(mempool_t *mempool)
 {
@@ -1384,6 +1386,7 @@ void EntityFrame_AddFrame_Server(entityframe_database_t *d, vec3_t eye, int fram
 // (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;
@@ -1468,20 +1471,20 @@ void EntityFrame_CL_ReadFrame(void)
 
        // read the frame header info
        f->time = cl.mtime[0];
-       number = MSG_ReadLong();
-       f->framenum = MSG_ReadLong();
+       number = MSG_ReadLong(&cl_message);
+       f->framenum = MSG_ReadLong(&cl_message);
        CL_NewFrameReceived(f->framenum);
-       f->eye[0] = MSG_ReadFloat();
-       f->eye[1] = MSG_ReadFloat();
-       f->eye[2] = MSG_ReadFloat();
+       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()) != 0xFFFF && !msg_badread)
+       while ((number = (unsigned short) MSG_ReadShort(&cl_message)) != 0xFFFF && !cl_message.badread)
        {
-               if (msg_badread)
+               if (cl_message.badread)
                        Host_Error("EntityFrame_Read: read error");
                removed = number & 0x8000;
                number &= 0x7FFF;
@@ -1733,12 +1736,12 @@ void EntityFrame4_CL_ReadFrame(void)
                cl.entitydatabase4 = EntityFrame4_AllocDatabase(cls.levelmempool);
        d = cl.entitydatabase4;
        // read the number of the frame this refers to
-       referenceframenum = MSG_ReadLong();
+       referenceframenum = MSG_ReadLong(&cl_message);
        // read the number of this frame
-       framenum = MSG_ReadLong();
+       framenum = MSG_ReadLong(&cl_message);
        CL_NewFrameReceived(framenum);
        // read the start number
-       enumber = (unsigned short) MSG_ReadShort();
+       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);
@@ -1768,18 +1771,18 @@ void EntityFrame4_CL_ReadFrame(void)
                skip = true;
        }
        done = false;
-       while (!done && !msg_badread)
+       while (!done && !cl_message.badread)
        {
                // read the number of the modified entity
                // (gaps will be copied unmodified)
-               n = (unsigned short)MSG_ReadShort();
+               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();
+                       n = (unsigned short)MSG_ReadShort(&cl_message);
                }
                // high bit means it's a remove message
                cnumber = n & 0x7FFF;
@@ -1859,6 +1862,7 @@ void EntityFrame4_CL_ReadFrame(void)
 
 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;
@@ -2058,8 +2062,34 @@ static int EntityState5_Priority(entityframe5_database_t *d, int stateindex)
        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);
@@ -2226,50 +2256,54 @@ void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbi
                                        MSG_WriteShort(msg, pose6s[5]);
                                }
                        }
-                       else 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)((sv.time - s->framegroupblend[0].start) * 1000.0));
-                               MSG_WriteShort(msg, (int)((sv.time - s->framegroupblend[1].start) * 1000.0));
-                               MSG_WriteShort(msg, (int)((sv.time - s->framegroupblend[2].start) * 1000.0));
-                               MSG_WriteShort(msg, (int)((sv.time - s->framegroupblend[3].start) * 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)((sv.time - s->framegroupblend[0].start) * 1000.0));
-                               MSG_WriteShort(msg, (int)((sv.time - s->framegroupblend[1].start) * 1000.0));
-                               MSG_WriteShort(msg, (int)((sv.time - s->framegroupblend[2].start) * 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)((sv.time - s->framegroupblend[0].start) * 1000.0));
-                               MSG_WriteShort(msg, (int)((sv.time - s->framegroupblend[1].start) * 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)((sv.time - s->framegroupblend[0].start) * 1000.0));
+                               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)
@@ -2279,20 +2313,18 @@ void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbi
        ENTITYSIZEPROFILING_END(msg, s->number);
 }
 
-extern dp_model_t *CL_GetModelByIndex(int modelindex);
-
 static void EntityState5_ReadUpdate(entity_state_t *s, int number)
 {
        int bits;
-       bits = MSG_ReadByte();
+       bits = MSG_ReadByte(&cl_message);
        if (bits & E5_EXTEND1)
        {
-               bits |= MSG_ReadByte() << 8;
+               bits |= MSG_ReadByte(&cl_message) << 8;
                if (bits & E5_EXTEND2)
                {
-                       bits |= MSG_ReadByte() << 16;
+                       bits |= MSG_ReadByte(&cl_message) << 16;
                        if (bits & E5_EXTEND3)
-                               bits |= MSG_ReadByte() << 24;
+                               bits |= MSG_ReadByte(&cl_message) << 24;
                }
        }
        if (bits & E5_FULLUPDATE)
@@ -2301,98 +2333,98 @@ static void EntityState5_ReadUpdate(entity_state_t *s, int number)
                s->active = ACTIVE_NETWORK;
        }
        if (bits & E5_FLAGS)
-               s->flags = MSG_ReadByte();
+               s->flags = MSG_ReadByte(&cl_message);
        if (bits & E5_ORIGIN)
        {
                if (bits & E5_ORIGIN32)
                {
-                       s->origin[0] = MSG_ReadCoord32f();
-                       s->origin[1] = MSG_ReadCoord32f();
-                       s->origin[2] = MSG_ReadCoord32f();
+                       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();
-                       s->origin[1] = MSG_ReadCoord13i();
-                       s->origin[2] = MSG_ReadCoord13i();
+                       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();
-                       s->angles[1] = MSG_ReadAngle16i();
-                       s->angles[2] = MSG_ReadAngle16i();
+                       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();
-                       s->angles[1] = MSG_ReadAngle8i();
-                       s->angles[2] = MSG_ReadAngle8i();
+                       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();
+                       s->modelindex = (unsigned short) MSG_ReadShort(&cl_message);
                else
-                       s->modelindex = MSG_ReadByte();
+                       s->modelindex = MSG_ReadByte(&cl_message);
        }
        if (bits & E5_FRAME)
        {
                if (bits & E5_FRAME16)
-                       s->frame = (unsigned short) MSG_ReadShort();
+                       s->frame = (unsigned short) MSG_ReadShort(&cl_message);
                else
-                       s->frame = MSG_ReadByte();
+                       s->frame = MSG_ReadByte(&cl_message);
        }
        if (bits & E5_SKIN)
-               s->skin = MSG_ReadByte();
+               s->skin = MSG_ReadByte(&cl_message);
        if (bits & E5_EFFECTS)
        {
                if (bits & E5_EFFECTS32)
-                       s->effects = (unsigned int) MSG_ReadLong();
+                       s->effects = (unsigned int) MSG_ReadLong(&cl_message);
                else if (bits & E5_EFFECTS16)
-                       s->effects = (unsigned short) MSG_ReadShort();
+                       s->effects = (unsigned short) MSG_ReadShort(&cl_message);
                else
-                       s->effects = MSG_ReadByte();
+                       s->effects = MSG_ReadByte(&cl_message);
        }
        if (bits & E5_ALPHA)
-               s->alpha = MSG_ReadByte();
+               s->alpha = MSG_ReadByte(&cl_message);
        if (bits & E5_SCALE)
-               s->scale = MSG_ReadByte();
+               s->scale = MSG_ReadByte(&cl_message);
        if (bits & E5_COLORMAP)
-               s->colormap = MSG_ReadByte();
+               s->colormap = MSG_ReadByte(&cl_message);
        if (bits & E5_ATTACHMENT)
        {
-               s->tagentity = (unsigned short) MSG_ReadShort();
-               s->tagindex = MSG_ReadByte();
+               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();
-               s->light[1] = (unsigned short) MSG_ReadShort();
-               s->light[2] = (unsigned short) MSG_ReadShort();
-               s->light[3] = (unsigned short) MSG_ReadShort();
-               s->lightstyle = MSG_ReadByte();
-               s->lightpflags = MSG_ReadByte();
+               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();
-               s->glowcolor = MSG_ReadByte();
+               s->glowsize = MSG_ReadByte(&cl_message);
+               s->glowcolor = MSG_ReadByte(&cl_message);
        }
        if (bits & E5_COLORMOD)
        {
-               s->colormod[0] = MSG_ReadByte();
-               s->colormod[1] = MSG_ReadByte();
-               s->colormod[2] = MSG_ReadByte();
+               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();
-               s->glowmod[1] = MSG_ReadByte();
-               s->glowmod[2] = MSG_ReadByte();
+               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)
        {
@@ -2403,15 +2435,15 @@ static void EntityState5_ReadUpdate(entity_state_t *s, int number)
                int bonenum;
                int numbones;
                short pose6s[6];
-               type = MSG_ReadByte();
+               type = MSG_ReadByte(&cl_message);
                switch(type)
                {
                case 0:
-                       s->framegroupblend[0].frame = MSG_ReadShort();
+                       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 - (short)MSG_ReadShort() * (1.0f / 1000.0f);
+                       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;
@@ -2421,54 +2453,54 @@ static void EntityState5_ReadUpdate(entity_state_t *s, int number)
                        s->framegroupblend[3].lerp = 0;
                        break;
                case 1:
-                       s->framegroupblend[0].frame = MSG_ReadShort();
-                       s->framegroupblend[1].frame = MSG_ReadShort();
+                       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 - (short)MSG_ReadShort() * (1.0f / 1000.0f);
-                       s->framegroupblend[1].start = cl.time - (short)MSG_ReadShort() * (1.0f / 1000.0f);
+                       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() * (1.0f / 255.0f);
-                       s->framegroupblend[1].lerp = MSG_ReadByte() * (1.0f / 255.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 = 0;
                        s->framegroupblend[3].lerp = 0;
                        break;
                case 2:
-                       s->framegroupblend[0].frame = MSG_ReadShort();
-                       s->framegroupblend[1].frame = MSG_ReadShort();
-                       s->framegroupblend[2].frame = MSG_ReadShort();
+                       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 - (short)MSG_ReadShort() * (1.0f / 1000.0f);
-                       s->framegroupblend[1].start = cl.time - (short)MSG_ReadShort() * (1.0f / 1000.0f);
-                       s->framegroupblend[2].start = cl.time - (short)MSG_ReadShort() * (1.0f / 1000.0f);
+                       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() * (1.0f / 255.0f);
-                       s->framegroupblend[1].lerp = MSG_ReadByte() * (1.0f / 255.0f);
-                       s->framegroupblend[2].lerp = MSG_ReadByte() * (1.0f / 255.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 = 0;
                        break;
                case 3:
-                       s->framegroupblend[0].frame = MSG_ReadShort();
-                       s->framegroupblend[1].frame = MSG_ReadShort();
-                       s->framegroupblend[2].frame = MSG_ReadShort();
-                       s->framegroupblend[3].frame = MSG_ReadShort();
-                       s->framegroupblend[0].start = cl.time - (short)MSG_ReadShort() * (1.0f / 1000.0f);
-                       s->framegroupblend[1].start = cl.time - (short)MSG_ReadShort() * (1.0f / 1000.0f);
-                       s->framegroupblend[2].start = cl.time - (short)MSG_ReadShort() * (1.0f / 1000.0f);
-                       s->framegroupblend[3].start = cl.time - (short)MSG_ReadShort() * (1.0f / 1000.0f);
-                       s->framegroupblend[0].lerp = MSG_ReadByte() * (1.0f / 255.0f);
-                       s->framegroupblend[1].lerp = MSG_ReadByte() * (1.0f / 255.0f);
-                       s->framegroupblend[2].lerp = MSG_ReadByte() * (1.0f / 255.0f);
-                       s->framegroupblend[3].lerp = MSG_ReadByte() * (1.0f / 255.0f);
+                       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();
+                       modelindex = MSG_ReadShort(&cl_message);
                        model = CL_GetModelByIndex(modelindex);
-                       numbones = MSG_ReadByte();
+                       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)
@@ -2480,12 +2512,12 @@ static void EntityState5_ReadUpdate(entity_state_t *s, int number)
                        }
                        for (bonenum = 0;bonenum < numbones;bonenum++)
                        {
-                               pose6s[0] = (short)MSG_ReadShort();
-                               pose6s[1] = (short)MSG_ReadShort();
-                               pose6s[2] = (short)MSG_ReadShort();
-                               pose6s[3] = (short)MSG_ReadShort();
-                               pose6s[4] = (short)MSG_ReadShort();
-                               pose6s[5] = (short)MSG_ReadShort();
+                               pose6s[0] = (short)MSG_ReadShort(&cl_message);
+                               pose6s[1] = (short)MSG_ReadShort(&cl_message);
+                               pose6s[2] = (short)MSG_ReadShort(&cl_message);
+                               pose6s[3] = (short)MSG_ReadShort(&cl_message);
+                               pose6s[4] = (short)MSG_ReadShort(&cl_message);
+                               pose6s[5] = (short)MSG_ReadShort(&cl_message);
                                Matrix4x4_FromBonePose6s(skeleton->relativetransforms + bonenum, 1.0f / 64.0f, pose6s);
                        }
                        s->skeletonobject = *skeleton;
@@ -2496,7 +2528,7 @@ static void EntityState5_ReadUpdate(entity_state_t *s, int number)
                }
        }
        if (bits & E5_TRAILEFFECTNUM)
-               s->traileffectnum = (unsigned short) MSG_ReadShort();
+               s->traileffectnum = (unsigned short) MSG_ReadShort(&cl_message);
 
 
        if (developer_networkentities.integer >= 2)
@@ -2596,7 +2628,25 @@ static int EntityState5_DeltaBits(const entity_state_t *o, const entity_state_t
                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)
-                       bits |= E5_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;
        }
@@ -2612,13 +2662,13 @@ void EntityFrame5_CL_ReadFrame(void)
        entity_t *ent;
        entity_state_t *s;
        // read the number of this frame to echo back in next input packet
-       framenum = MSG_ReadLong();
+       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();
+               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()) != 0x8000 && !msg_badread)
+       while ((n = (unsigned short)MSG_ReadShort(&cl_message)) != 0x8000 && !cl_message.badread)
        {
                // get the entity number
                enumber = n & 0x7FFF;
@@ -2744,6 +2794,7 @@ 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)
 {
+       prvm_prog_t *prog = SVVM_prog;
        const entity_state_t *n;
        int i, num, l, framenum, packetlognumber, priority;
        sizebuf_t buf;
@@ -2978,7 +3029,7 @@ static void QW_TranslateEffects(entity_state_t *s, int qweffects)
 
 void EntityStateQW_ReadPlayerUpdate(void)
 {
-       int slot = MSG_ReadByte();
+       int slot = MSG_ReadByte(&cl_message);
        int enumber = slot + 1;
        int weaponframe;
        int msec;
@@ -2999,9 +3050,9 @@ void EntityStateQW_ReadPlayerUpdate(void)
        s->active = ACTIVE_NETWORK;
        s->number = enumber;
        s->colormap = enumber;
-       playerflags = MSG_ReadShort();
-       MSG_ReadVector(s->origin, cls.protocol);
-       s->frame = MSG_ReadByte();
+       playerflags = MSG_ReadShort(&cl_message);
+       MSG_ReadVector(&cl_message, s->origin, cls.protocol);
+       s->frame = MSG_ReadByte(&cl_message);
 
        VectorClear(viewangles);
        VectorClear(velocity);
@@ -3012,47 +3063,47 @@ void EntityStateQW_ReadPlayerUpdate(void)
                // 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();
+               msec = MSG_ReadByte(&cl_message);
        }
        else
                msec = 0;
        if (playerflags & QW_PF_COMMAND)
        {
-               bits = MSG_ReadByte();
+               bits = MSG_ReadByte(&cl_message);
                if (bits & QW_CM_ANGLE1)
-                       viewangles[0] = MSG_ReadAngle16i(); // cmd->angles[0]
+                       viewangles[0] = MSG_ReadAngle16i(&cl_message); // cmd->angles[0]
                if (bits & QW_CM_ANGLE2)
-                       viewangles[1] = MSG_ReadAngle16i(); // cmd->angles[1]
+                       viewangles[1] = MSG_ReadAngle16i(&cl_message); // cmd->angles[1]
                if (bits & QW_CM_ANGLE3)
-                       viewangles[2] = MSG_ReadAngle16i(); // cmd->angles[2]
+                       viewangles[2] = MSG_ReadAngle16i(&cl_message); // cmd->angles[2]
                if (bits & QW_CM_FORWARD)
-                       MSG_ReadShort(); // cmd->forwardmove
+                       MSG_ReadShort(&cl_message); // cmd->forwardmove
                if (bits & QW_CM_SIDE)
-                       MSG_ReadShort(); // cmd->sidemove
+                       MSG_ReadShort(&cl_message); // cmd->sidemove
                if (bits & QW_CM_UP)
-                       MSG_ReadShort(); // cmd->upmove
+                       MSG_ReadShort(&cl_message); // cmd->upmove
                if (bits & QW_CM_BUTTONS)
-                       (void) MSG_ReadByte(); // cmd->buttons
+                       (void) MSG_ReadByte(&cl_message); // cmd->buttons
                if (bits & QW_CM_IMPULSE)
-                       (void) MSG_ReadByte(); // cmd->impulse
-               (void) MSG_ReadByte(); // cmd->msec
+                       (void) MSG_ReadByte(&cl_message); // cmd->impulse
+               (void) MSG_ReadByte(&cl_message); // cmd->msec
        }
        if (playerflags & QW_PF_VELOCITY1)
-               velocity[0] = MSG_ReadShort();
+               velocity[0] = MSG_ReadShort(&cl_message);
        if (playerflags & QW_PF_VELOCITY2)
-               velocity[1] = MSG_ReadShort();
+               velocity[1] = MSG_ReadShort(&cl_message);
        if (playerflags & QW_PF_VELOCITY3)
-               velocity[2] = MSG_ReadShort();
+               velocity[2] = MSG_ReadShort(&cl_message);
        if (playerflags & QW_PF_MODEL)
-               s->modelindex = MSG_ReadByte();
+               s->modelindex = MSG_ReadByte(&cl_message);
        else
                s->modelindex = cl.qw_modelindex_player;
        if (playerflags & QW_PF_SKINNUM)
-               s->skin = MSG_ReadByte();
+               s->skin = MSG_ReadByte(&cl_message);
        if (playerflags & QW_PF_EFFECTS)
-               QW_TranslateEffects(s, MSG_ReadByte());
+               QW_TranslateEffects(s, MSG_ReadByte(&cl_message));
        if (playerflags & QW_PF_WEAPONFRAME)
-               weaponframe = MSG_ReadByte();
+               weaponframe = MSG_ReadByte(&cl_message);
        else
                weaponframe = 0;
 
@@ -3114,32 +3165,32 @@ static void EntityStateQW_ReadEntityUpdate(entity_state_t *s, int bits)
        s->number = bits & 511;
        bits &= ~511;
        if (bits & QW_U_MOREBITS)
-               bits |= MSG_ReadByte();
+               bits |= MSG_ReadByte(&cl_message);
 
        // store the QW_U_SOLID bit here?
 
        if (bits & QW_U_MODEL)
-               s->modelindex = MSG_ReadByte();
+               s->modelindex = MSG_ReadByte(&cl_message);
        if (bits & QW_U_FRAME)
-               s->frame = MSG_ReadByte();
+               s->frame = MSG_ReadByte(&cl_message);
        if (bits & QW_U_COLORMAP)
-               s->colormap = MSG_ReadByte();
+               s->colormap = MSG_ReadByte(&cl_message);
        if (bits & QW_U_SKIN)
-               s->skin = MSG_ReadByte();
+               s->skin = MSG_ReadByte(&cl_message);
        if (bits & QW_U_EFFECTS)
-               QW_TranslateEffects(s, qweffects = MSG_ReadByte());
+               QW_TranslateEffects(s, qweffects = MSG_ReadByte(&cl_message));
        if (bits & QW_U_ORIGIN1)
-               s->origin[0] = MSG_ReadCoord13i();
+               s->origin[0] = MSG_ReadCoord13i(&cl_message);
        if (bits & QW_U_ANGLE1)
-               s->angles[0] = MSG_ReadAngle8i();
+               s->angles[0] = MSG_ReadAngle8i(&cl_message);
        if (bits & QW_U_ORIGIN2)
-               s->origin[1] = MSG_ReadCoord13i();
+               s->origin[1] = MSG_ReadCoord13i(&cl_message);
        if (bits & QW_U_ANGLE2)
-               s->angles[1] = MSG_ReadAngle8i();
+               s->angles[1] = MSG_ReadAngle8i(&cl_message);
        if (bits & QW_U_ORIGIN3)
-               s->origin[2] = MSG_ReadCoord13i();
+               s->origin[2] = MSG_ReadCoord13i(&cl_message);
        if (bits & QW_U_ANGLE3)
-               s->angles[2] = MSG_ReadAngle8i();
+               s->angles[2] = MSG_ReadAngle8i(&cl_message);
 
        if (developer_networkentities.integer >= 2)
        {
@@ -3209,7 +3260,7 @@ void EntityFrameQW_CL_ReadFrame(qboolean delta)
        oldsnap = NULL;
        if (delta)
        {
-               number = MSG_ReadByte();
+               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");
@@ -3237,8 +3288,8 @@ void EntityFrameQW_CL_ReadFrame(qboolean delta)
        oldindex = 0;
        for (;;)
        {
-               int word = (unsigned short)MSG_ReadShort();
-               if (msg_badread)
+               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;
index c101665d53f93ffb0538ed8a3ac58f0724e36408..9d694f0f10eb397eb9c2e503a237e9c82ed8018f 100644 (file)
@@ -165,6 +165,7 @@ void Protocol_Names(char *buffer, size_t buffersize);
 #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
@@ -332,7 +333,7 @@ void Protocol_Names(char *buffer, size_t buffersize);
 #define RENDER_EXTERIORMODEL 8
 #define RENDER_LOWPRECISION 16 // send as low precision coordinates to save bandwidth
 #define RENDER_COLORMAPPED 32
-#define RENDER_NOCULL 64 // do not cull this entity with r_cullentities
+#define RENDER_WORLDOBJECT 64 // do not cull this entity with r_cullentities
 #define RENDER_COMPLEXANIMATION 128
 
 #define RENDER_SHADOW 65536 // cast shadow
@@ -343,6 +344,7 @@ void Protocol_Names(char *buffer, size_t buffersize);
 #define RENDER_NODEPTHTEST 1048576
 #define RENDER_ADDITIVE 2097152
 #define RENDER_DOUBLESIDED 4194304
+#define RENDER_CUSTOMIZEDMODELLIGHT 4096
 
 #define MAX_FRAMEGROUPBLENDS 4
 typedef struct framegroupblend_s
index c0b34d4a215050728d0e26ba0a9fe5a07a367386..7f1900d9826f6d44d3799b78e01b1803bcd7197a 100644 (file)
 
 #include "cl_collision.h"
 #include "clvm_cmds.h"
+#include "csprogs.h"
 #include "ft2.h"
+#include "mdfour.h"
 
 extern cvar_t prvm_backtraceforwarnings;
 
 // 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(const char *fmt, ...)
+void VM_Warning(prvm_prog_t *prog, const char *fmt, ...)
 {
        va_list argptr;
        char msg[MAX_INPUTLINE];
@@ -27,13 +29,13 @@ void VM_Warning(const char *fmt, ...)
        dpvsnprintf(msg,sizeof(msg),fmt,argptr);
        va_end(argptr);
 
-       Con_DPrint(msg);
+       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();
+               PRVM_PrintState(prog);
                recursive = -1;
        }
 }
@@ -47,13 +49,13 @@ void VM_Warning(const char *fmt, ...)
 // 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 (const char *s)
+void VM_CheckEmptyString(prvm_prog_t *prog, const char *s)
 {
        if (ISWHITESPACE(s[0]))
-               PRVM_ERROR ("%s: Bad string", PRVM_NAME);
+               prog->error_cmd("%s: Bad string", prog->name);
 }
 
-void VM_GenerateFrameGroupBlend(framegroupblend_t *framegroupblend, const prvm_edict_t *ed)
+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
@@ -107,7 +109,8 @@ void VM_FrameBlendFromFrameGroupBlend(frameblend_t *frameblend, const framegroup
                f = g->frame;
                if ((unsigned int)f >= (unsigned int)numframes)
                {
-                       Con_DPrintf("VM_FrameBlendFromFrameGroupBlend: no such frame %d in model %s\n", f, model->name);
+                       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;
@@ -179,11 +182,11 @@ void VM_FrameBlendFromFrameGroupBlend(frameblend_t *frameblend, const framegroup
        }
 }
 
-void VM_UpdateEdictSkeleton(prvm_edict_t *ed, const dp_model_t *edmodel, const frameblend_t *frameblend)
+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(ed);
+               VM_RemoveEdictSkeleton(prog, ed);
                ed->priv.server->skeleton.model = edmodel;
        }
        if (!ed->priv.server->skeleton.model || !ed->priv.server->skeleton.model->num_bones)
@@ -214,7 +217,7 @@ void VM_UpdateEdictSkeleton(prvm_edict_t *ed, const dp_model_t *edmodel, const f
        }
 }
 
-void VM_RemoveEdictSkeleton(prvm_edict_t *ed)
+void VM_RemoveEdictSkeleton(prvm_prog_t *prog, prvm_edict_t *ed)
 {
        if (ed->priv.server->skeleton.relativetransforms)
                Mem_Free(ed->priv.server->skeleton.relativetransforms);
@@ -227,7 +230,7 @@ void VM_RemoveEdictSkeleton(prvm_edict_t *ed)
 //============================================================================
 //BUILT-IN FUNCTIONS
 
-void VM_VarString(int first, char *out, int outlength)
+void VM_VarString(prvm_prog_t *prog, int first, char *out, int outlength)
 {
        int i;
        const char *s;
@@ -254,7 +257,7 @@ checkextension(extensionname)
 */
 
 // kind of helper function
-static qboolean checkextension(const char *name)
+static qboolean checkextension(prvm_prog_t *prog, const char *name)
 {
        int len;
        const char *e, *start;
@@ -280,17 +283,24 @@ static qboolean checkextension(const char *name)
                                return false;
 #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 (void)
+void VM_checkextension(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1,VM_checkextension);
 
-       PRVM_G_FLOAT(OFS_RETURN) = checkextension(PRVM_G_STRING(OFS_PARM0));
+       PRVM_G_FLOAT(OFS_RETURN) = checkextension(prog, PRVM_G_STRING(OFS_PARM0));
 }
 
 /*
@@ -303,17 +313,17 @@ Dumps self.
 error(value)
 =================
 */
-void VM_error (void)
+void VM_error(prvm_prog_t *prog)
 {
        prvm_edict_t    *ed;
        char string[VM_STRINGTEMP_LENGTH];
 
-       VM_VarString(0, string, sizeof(string));
-       Con_Printf("======%s ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
+       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(ed, NULL);
+       PRVM_ED_Print(prog, ed, NULL);
 
-       PRVM_ERROR ("%s: Program error in function %s:\n%s\nTip: read above for entity information\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
+       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);
 }
 
 /*
@@ -326,17 +336,17 @@ removed, but the level can continue.
 objerror(value)
 =================
 */
-void VM_objerror (void)
+void VM_objerror(prvm_prog_t *prog)
 {
        prvm_edict_t    *ed;
        char string[VM_STRINGTEMP_LENGTH];
 
-       VM_VarString(0, string, sizeof(string));
-       Con_Printf("======OBJECT ERROR======\n"); // , PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string); // or include them? FIXME
+       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(ed, NULL);
-       PRVM_ED_Free (ed);
-       Con_Printf("%s OBJECT ERROR in %s:\n%s\nTip: read above for entity information\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
+       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);
 }
 
 /*
@@ -348,11 +358,11 @@ print to console
 print(...[string])
 =================
 */
-void VM_print (void)
+void VM_print(prvm_prog_t *prog)
 {
        char string[VM_STRINGTEMP_LENGTH];
 
-       VM_VarString(0, string, sizeof(string));
+       VM_VarString(prog, 0, string, sizeof(string));
        Con_Print(string);
 }
 
@@ -365,17 +375,17 @@ broadcast print to everyone on server
 bprint(...[string])
 =================
 */
-void VM_bprint (void)
+void VM_bprint(prvm_prog_t *prog)
 {
        char string[VM_STRINGTEMP_LENGTH];
 
        if(!sv.active)
        {
-               VM_Warning("VM_bprint: game is not server(%s) !\n", PRVM_NAME);
+               VM_Warning(prog, "VM_bprint: game is not server(%s) !\n", prog->name);
                return;
        }
 
-       VM_VarString(0, string, sizeof(string));
+       VM_VarString(prog, 0, string, sizeof(string));
        SV_BroadcastPrint(string);
 }
 
@@ -388,7 +398,7 @@ single print to a specific client
 sprint(float clientnum,...[string])
 =================
 */
-void VM_sprint (void)
+void VM_sprint(prvm_prog_t *prog)
 {
        client_t        *client;
        int                     clientnum;
@@ -400,7 +410,7 @@ void VM_sprint (void)
        clientnum = (int)PRVM_G_FLOAT(OFS_PARM0);
        if (!sv.active  || clientnum < 0 || clientnum >= svs.maxclients || !svs.clients[clientnum].active)
        {
-               VM_Warning("VM_sprint: %s: invalid client or server is not active !\n", PRVM_NAME);
+               VM_Warning(prog, "VM_sprint: %s: invalid client or server is not active !\n", prog->name);
                return;
        }
 
@@ -408,7 +418,7 @@ void VM_sprint (void)
        if (!client->netconnection)
                return;
 
-       VM_VarString(1, string, sizeof(string));
+       VM_VarString(prog, 1, string, sizeof(string));
        MSG_WriteChar(&client->netconnection->message,svc_print);
        MSG_WriteString(&client->netconnection->message, string);
 }
@@ -422,12 +432,12 @@ single print to the screen
 centerprint(value)
 =================
 */
-void VM_centerprint (void)
+void VM_centerprint(prvm_prog_t *prog)
 {
        char string[VM_STRINGTEMP_LENGTH];
 
        VM_SAFEPARMCOUNTRANGE(1, 8, VM_centerprint);
-       VM_VarString(0, string, sizeof(string));
+       VM_VarString(prog, 0, string, sizeof(string));
        SCR_CenterPrint(string);
 }
 
@@ -438,7 +448,7 @@ VM_normalize
 vector normalize(vector)
 =================
 */
-void VM_normalize (void)
+void VM_normalize(prvm_prog_t *prog)
 {
        float   *value1;
        vec3_t  newvalue;
@@ -467,7 +477,7 @@ VM_vlen
 scalar vlen(vector)
 =================
 */
-void VM_vlen (void)
+void VM_vlen(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1,VM_vlen);
        PRVM_G_FLOAT(OFS_RETURN) = VectorLength(PRVM_G_VECTOR(OFS_PARM0));
@@ -480,7 +490,7 @@ VM_vectoyaw
 float vectoyaw(vector)
 =================
 */
-void VM_vectoyaw (void)
+void VM_vectoyaw(prvm_prog_t *prog)
 {
        float   *value1;
        float   yaw;
@@ -509,7 +519,7 @@ VM_vectoangles
 vector vectoangles(vector[, vector])
 =================
 */
-void VM_vectoangles (void)
+void VM_vectoangles(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNTRANGE(1, 2,VM_vectoangles);
 
@@ -525,7 +535,7 @@ Returns a number from 0<= num < 1
 float random()
 =================
 */
-void VM_random (void)
+void VM_random(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0,VM_random);
 
@@ -539,7 +549,7 @@ VM_localsound
 localsound(string sample)
 =========
 */
-void VM_localsound(void)
+void VM_localsound(prvm_prog_t *prog)
 {
        const char *s;
 
@@ -550,7 +560,7 @@ void VM_localsound(void)
        if(!S_LocalSound (s))
        {
                PRVM_G_FLOAT(OFS_RETURN) = -4;
-               VM_Warning("VM_localsound: Failed to play %s for %s !\n", s, PRVM_NAME);
+               VM_Warning(prog, "VM_localsound: Failed to play %s for %s !\n", s, prog->name);
                return;
        }
 
@@ -564,9 +574,9 @@ VM_break
 break()
 =================
 */
-void VM_break (void)
+void VM_break(prvm_prog_t *prog)
 {
-       PRVM_ERROR ("%s: break statement", PRVM_NAME);
+       prog->error_cmd("%s: break statement", prog->name);
 }
 
 //============================================================================
@@ -581,11 +591,11 @@ Sends text over to the client's execution buffer
 cmd (string, ...)
 =================
 */
-void VM_localcmd (void)
+void VM_localcmd(prvm_prog_t *prog)
 {
        char string[VM_STRINGTEMP_LENGTH];
        VM_SAFEPARMCOUNTRANGE(1, 8, VM_localcmd);
-       VM_VarString(0, string, sizeof(string));
+       VM_VarString(prog, 0, string, sizeof(string));
        Cbuf_AddText(string);
 }
 
@@ -603,12 +613,12 @@ VM_cvar
 float cvar (string)
 =================
 */
-void VM_cvar (void)
+void VM_cvar(prvm_prog_t *prog)
 {
        char string[VM_STRINGTEMP_LENGTH];
        VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar);
-       VM_VarString(0, string, sizeof(string));
-       VM_CheckEmptyString(string);
+       VM_VarString(prog, 0, string, sizeof(string));
+       VM_CheckEmptyString(prog, string);
        PRVM_G_FLOAT(OFS_RETURN) = PRVM_Cvar_ReadOk(string) ? Cvar_VariableValue(string) : 0;
 }
 
@@ -625,15 +635,15 @@ float CVAR_TYPEFLAG_HASDESCRIPTION = 16;
 float CVAR_TYPEFLAG_READONLY = 32;
 =================
 */
-void VM_cvar_type (void)
+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(0, string, sizeof(string));
-       VM_CheckEmptyString(string);
+       VM_VarString(prog, 0, string, sizeof(string));
+       VM_CheckEmptyString(prog, string);
        cvar = Cvar_FindVar(string);
 
 
@@ -665,13 +675,13 @@ VM_cvar_string
 const string   VM_cvar_string (string, ...)
 =================
 */
-void VM_cvar_string(void)
+void VM_cvar_string(prvm_prog_t *prog)
 {
        char string[VM_STRINGTEMP_LENGTH];
        VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar_string);
-       VM_VarString(0, string, sizeof(string));
-       VM_CheckEmptyString(string);
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(PRVM_Cvar_ReadOk(string) ? Cvar_VariableString(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) : "");
 }
 
 
@@ -682,13 +692,13 @@ VM_cvar_defstring
 const string   VM_cvar_defstring (string, ...)
 ========================
 */
-void VM_cvar_defstring (void)
+void VM_cvar_defstring(prvm_prog_t *prog)
 {
        char string[VM_STRINGTEMP_LENGTH];
        VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar_defstring);
-       VM_VarString(0, string, sizeof(string));
-       VM_CheckEmptyString(string);
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Cvar_VariableDefString(string));
+       VM_VarString(prog, 0, string, sizeof(string));
+       VM_CheckEmptyString(prog, string);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, Cvar_VariableDefString(string));
 }
 
 /*
@@ -698,13 +708,13 @@ VM_cvar_defstring
 const string   VM_cvar_description (string, ...)
 ========================
 */
-void VM_cvar_description (void)
+void VM_cvar_description(prvm_prog_t *prog)
 {
        char string[VM_STRINGTEMP_LENGTH];
        VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar_description);
-       VM_VarString(0, string, sizeof(string));
-       VM_CheckEmptyString(string);
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Cvar_VariableDescription(string));
+       VM_VarString(prog, 0, string, sizeof(string));
+       VM_CheckEmptyString(prog, string);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, Cvar_VariableDescription(string));
 }
 /*
 =================
@@ -713,14 +723,14 @@ VM_cvar_set
 void cvar_set (string,string, ...)
 =================
 */
-void VM_cvar_set (void)
+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(1, string, sizeof(string));
+       VM_VarString(prog, 1, string, sizeof(string));
        name = PRVM_G_STRING(OFS_PARM0);
-       VM_CheckEmptyString(name);
+       VM_CheckEmptyString(prog, name);
        Cvar_Set(name, string);
 }
 
@@ -731,15 +741,15 @@ VM_dprint
 dprint(...[string])
 =========
 */
-void VM_dprint (void)
+void VM_dprint(prvm_prog_t *prog)
 {
        char string[VM_STRINGTEMP_LENGTH];
        VM_SAFEPARMCOUNTRANGE(1, 8, VM_dprint);
-       VM_VarString(0, string, sizeof(string));
+       VM_VarString(prog, 0, string, sizeof(string));
 #if 1
        Con_DPrintf("%s", string);
 #else
-       Con_DPrintf("%s: %s", PRVM_NAME, string);
+       Con_DPrintf("%s: %s", prog->name, string);
 #endif
 }
 
@@ -751,7 +761,7 @@ string      ftos(float)
 =========
 */
 
-void VM_ftos (void)
+void VM_ftos(prvm_prog_t *prog)
 {
        float v;
        char s[128];
@@ -764,7 +774,7 @@ void VM_ftos (void)
                dpsnprintf(s, sizeof(s), "%i", (int)v);
        else
                dpsnprintf(s, sizeof(s), "%f", v);
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(s);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s);
 }
 
 /*
@@ -775,7 +785,7 @@ float       fabs(float)
 =========
 */
 
-void VM_fabs (void)
+void VM_fabs(prvm_prog_t *prog)
 {
        float   v;
 
@@ -793,14 +803,14 @@ string    vtos(vector)
 =========
 */
 
-void VM_vtos (void)
+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(s);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s);
 }
 
 /*
@@ -811,14 +821,14 @@ string    etos(entity)
 =========
 */
 
-void VM_etos (void)
+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(s);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s);
 }
 
 /*
@@ -828,11 +838,11 @@ VM_stof
 float stof(...[string])
 =========
 */
-void VM_stof(void)
+void VM_stof(prvm_prog_t *prog)
 {
        char string[VM_STRINGTEMP_LENGTH];
        VM_SAFEPARMCOUNTRANGE(1, 8, VM_stof);
-       VM_VarString(0, string, sizeof(string));
+       VM_VarString(prog, 0, string, sizeof(string));
        PRVM_G_FLOAT(OFS_RETURN) = atof(string);
 }
 
@@ -843,7 +853,7 @@ VM_itof
 float itof(intt ent)
 ========================
 */
-void VM_itof(void)
+void VM_itof(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_itof);
        PRVM_G_FLOAT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
@@ -856,7 +866,7 @@ VM_ftoe
 entity ftoe(float num)
 ========================
 */
-void VM_ftoe(void)
+void VM_ftoe(prvm_prog_t *prog)
 {
        int ent;
        VM_SAFEPARMCOUNT(1, VM_ftoe);
@@ -875,7 +885,7 @@ VM_etof
 float etof(entity ent)
 ========================
 */
-void VM_etof(void)
+void VM_etof(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_etof);
        PRVM_G_FLOAT(OFS_RETURN) = PRVM_G_EDICTNUM(OFS_PARM0);
@@ -888,7 +898,7 @@ VM_strftime
 string strftime(float uselocaltime, string[, string ...])
 =========
 */
-void VM_strftime(void)
+void VM_strftime(prvm_prog_t *prog)
 {
        time_t t;
 #if _MSC_VER >= 1400
@@ -900,7 +910,7 @@ void VM_strftime(void)
        char fmt[VM_STRINGTEMP_LENGTH];
        char result[VM_STRINGTEMP_LENGTH];
        VM_SAFEPARMCOUNTRANGE(2, 8, VM_strftime);
-       VM_VarString(1, fmt, sizeof(fmt));
+       VM_VarString(prog, 1, fmt, sizeof(fmt));
        t = time(NULL);
 #if _MSC_VER >= 1400
        if (PRVM_G_FLOAT(OFS_PARM0))
@@ -924,7 +934,7 @@ void VM_strftime(void)
 #else
        strftime(result, sizeof(result), fmt, tm);
 #endif
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(result);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, result);
 }
 
 /*
@@ -935,12 +945,12 @@ entity spawn()
 =========
 */
 
-void VM_spawn (void)
+void VM_spawn(prvm_prog_t *prog)
 {
        prvm_edict_t    *ed;
        VM_SAFEPARMCOUNT(0, VM_spawn);
        prog->xfunction->builtinsprofile += 20;
-       ed = PRVM_ED_Alloc();
+       ed = PRVM_ED_Alloc(prog);
        VM_RETURN_EDICT(ed);
 }
 
@@ -952,7 +962,7 @@ remove(entity e)
 =========
 */
 
-void VM_remove (void)
+void VM_remove(prvm_prog_t *prog)
 {
        prvm_edict_t    *ed;
        prog->xfunction->builtinsprofile += 20;
@@ -963,15 +973,15 @@ void VM_remove (void)
        if( PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts )
        {
                if (developer.integer > 0)
-                       VM_Warning( "VM_remove: tried to remove the null entity or a reserved entity!\n" );
+                       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( "VM_remove: tried to remove an already freed entity!\n" );
+                       VM_Warning(prog, "VM_remove: tried to remove an already freed entity!\n" );
        }
        else
-               PRVM_ED_Free (ed);
+               PRVM_ED_Free (prog, ed);
 }
 
 /*
@@ -982,7 +992,7 @@ entity      find(entity start, .string field, string match)
 =========
 */
 
-void VM_find (void)
+void VM_find(prvm_prog_t *prog)
 {
        int             e;
        int             f;
@@ -1027,7 +1037,7 @@ VM_findfloat
 =========
 */
 // LordHavoc: added this for searching float, int, and entity reference fields
-void VM_findfloat (void)
+void VM_findfloat(prvm_prog_t *prog)
 {
        int             e;
        int             f;
@@ -1065,7 +1075,7 @@ entity    findchain(.string field, string match)
 */
 // chained search for strings in entity fields
 // entity(.string field, string match) findchain = #402;
-void VM_findchain (void)
+void VM_findchain(prvm_prog_t *prog)
 {
        int             i;
        int             f;
@@ -1080,7 +1090,7 @@ void VM_findchain (void)
        else
                chainfield = prog->fieldoffsets.chain;
        if (chainfield < 0)
-               PRVM_ERROR("VM_findchain: %s doesnt have the specified chain field !", PRVM_NAME);
+               prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
 
        chain = prog->edicts;
 
@@ -1120,7 +1130,7 @@ 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 (void)
+void VM_findchainfloat(prvm_prog_t *prog)
 {
        int             i;
        int             f;
@@ -1135,7 +1145,7 @@ void VM_findchainfloat (void)
        else
                chainfield = prog->fieldoffsets.chain;
        if (chainfield < 0)
-               PRVM_ERROR("VM_findchain: %s doesnt have the specified chain field !", PRVM_NAME);
+               prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
 
        chain = (prvm_edict_t *)prog->edicts;
 
@@ -1166,7 +1176,7 @@ entity    findflags(entity start, .float field, float match)
 ========================
 */
 // LordHavoc: search for flags in float fields
-void VM_findflags (void)
+void VM_findflags(prvm_prog_t *prog)
 {
        int             e;
        int             f;
@@ -1206,7 +1216,7 @@ entity    findchainflags(.float field, float match)
 ========================
 */
 // LordHavoc: chained search for flags in float fields
-void VM_findchainflags (void)
+void VM_findchainflags(prvm_prog_t *prog)
 {
        int             i;
        int             f;
@@ -1221,7 +1231,7 @@ void VM_findchainflags (void)
        else
                chainfield = prog->fieldoffsets.chain;
        if (chainfield < 0)
-               PRVM_ERROR("VM_findchain: %s doesnt have the specified chain field !", PRVM_NAME);
+               prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
 
        chain = (prvm_edict_t *)prog->edicts;
 
@@ -1253,7 +1263,7 @@ VM_precache_sound
 string precache_sound (string sample)
 =========
 */
-void VM_precache_sound (void)
+void VM_precache_sound(prvm_prog_t *prog)
 {
        const char *s;
 
@@ -1261,11 +1271,11 @@ void VM_precache_sound (void)
 
        s = PRVM_G_STRING(OFS_PARM0);
        PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
-       //VM_CheckEmptyString(s);
+       //VM_CheckEmptyString(prog, s);
 
        if(snd_initialized.integer && !S_PrecacheSound(s, true, true))
        {
-               VM_Warning("VM_precache_sound: Failed to load %s for %s\n", s, PRVM_NAME);
+               VM_Warning(prog, "VM_precache_sound: Failed to load %s for %s\n", s, prog->name);
                return;
        }
 }
@@ -1279,7 +1289,7 @@ returns the same string as output
 does nothing, only used by qcc to build .pak archives
 =================
 */
-void VM_precache_file (void)
+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
@@ -1293,12 +1303,12 @@ VM_coredump
 coredump()
 =========
 */
-void VM_coredump (void)
+void VM_coredump(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0,VM_coredump);
 
        Cbuf_AddText("prvm_edicts ");
-       Cbuf_AddText(PRVM_NAME);
+       Cbuf_AddText(prog->name);
        Cbuf_AddText("\n");
 }
 
@@ -1309,12 +1319,11 @@ VM_stackdump
 stackdump()
 =========
 */
-void PRVM_StackTrace(void);
-void VM_stackdump (void)
+void VM_stackdump(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0, VM_stackdump);
 
-       PRVM_StackTrace();
+       PRVM_StackTrace(prog);
 }
 
 /*
@@ -1325,11 +1334,11 @@ crash()
 =========
 */
 
-void VM_crash(void)
+void VM_crash(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0, VM_crash);
 
-       PRVM_ERROR("Crash called by %s",PRVM_NAME);
+       prog->error_cmd("Crash called by %s",prog->name);
 }
 
 /*
@@ -1339,7 +1348,7 @@ VM_traceon
 traceon()
 =========
 */
-void VM_traceon (void)
+void VM_traceon(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0,VM_traceon);
 
@@ -1353,7 +1362,7 @@ VM_traceoff
 traceoff()
 =========
 */
-void VM_traceoff (void)
+void VM_traceoff(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0,VM_traceoff);
 
@@ -1367,11 +1376,11 @@ VM_eprint
 eprint(entity e)
 =========
 */
-void VM_eprint (void)
+void VM_eprint(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1,VM_eprint);
 
-       PRVM_ED_PrintNum (PRVM_G_EDICTNUM(OFS_PARM0), NULL);
+       PRVM_ED_PrintNum (prog, PRVM_G_EDICTNUM(OFS_PARM0), NULL);
 }
 
 /*
@@ -1381,7 +1390,7 @@ VM_rint
 float  rint(float)
 =========
 */
-void VM_rint (void)
+void VM_rint(prvm_prog_t *prog)
 {
        float f;
        VM_SAFEPARMCOUNT(1,VM_rint);
@@ -1400,7 +1409,7 @@ VM_floor
 float  floor(float)
 =========
 */
-void VM_floor (void)
+void VM_floor(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1,VM_floor);
 
@@ -1414,7 +1423,7 @@ VM_ceil
 float  ceil(float)
 =========
 */
-void VM_ceil (void)
+void VM_ceil(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1,VM_ceil);
 
@@ -1429,7 +1438,7 @@ VM_nextent
 entity nextent(entity)
 =============
 */
-void VM_nextent (void)
+void VM_nextent(prvm_prog_t *prog)
 {
        int             i;
        prvm_edict_t    *ent;
@@ -1465,13 +1474,14 @@ server and menu
 changelevel(string map)
 ==============
 */
-void VM_changelevel (void)
+void VM_changelevel(prvm_prog_t *prog)
 {
+       char vabuf[1024];
        VM_SAFEPARMCOUNT(1, VM_changelevel);
 
        if(!sv.active)
        {
-               VM_Warning("VM_changelevel: game is not server (%s)\n", PRVM_NAME);
+               VM_Warning(prog, "VM_changelevel: game is not server (%s)\n", prog->name);
                return;
        }
 
@@ -1480,7 +1490,7 @@ void VM_changelevel (void)
                return;
        svs.changelevel_issued = true;
 
-       Cbuf_AddText (va("changelevel %s\n",PRVM_G_STRING(OFS_PARM0)));
+       Cbuf_AddText(va(vabuf, sizeof(vabuf), "changelevel %s\n",PRVM_G_STRING(OFS_PARM0)));
 }
 
 /*
@@ -1490,7 +1500,7 @@ VM_sin
 float  sin(float)
 =========
 */
-void VM_sin (void)
+void VM_sin(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1,VM_sin);
        PRVM_G_FLOAT(OFS_RETURN) = sin(PRVM_G_FLOAT(OFS_PARM0));
@@ -1502,7 +1512,7 @@ VM_cos
 float  cos(float)
 =========
 */
-void VM_cos (void)
+void VM_cos(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1,VM_cos);
        PRVM_G_FLOAT(OFS_RETURN) = cos(PRVM_G_FLOAT(OFS_PARM0));
@@ -1515,7 +1525,7 @@ VM_sqrt
 float  sqrt(float)
 =========
 */
-void VM_sqrt (void)
+void VM_sqrt(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1,VM_sqrt);
        PRVM_G_FLOAT(OFS_RETURN) = sqrt(PRVM_G_FLOAT(OFS_PARM0));
@@ -1528,7 +1538,7 @@ VM_asin
 float  asin(float)
 =========
 */
-void VM_asin (void)
+void VM_asin(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1,VM_asin);
        PRVM_G_FLOAT(OFS_RETURN) = asin(PRVM_G_FLOAT(OFS_PARM0));
@@ -1540,7 +1550,7 @@ VM_acos
 float  acos(float)
 =========
 */
-void VM_acos (void)
+void VM_acos(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1,VM_acos);
        PRVM_G_FLOAT(OFS_RETURN) = acos(PRVM_G_FLOAT(OFS_PARM0));
@@ -1552,7 +1562,7 @@ VM_atan
 float  atan(float)
 =========
 */
-void VM_atan (void)
+void VM_atan(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1,VM_atan);
        PRVM_G_FLOAT(OFS_RETURN) = atan(PRVM_G_FLOAT(OFS_PARM0));
@@ -1564,7 +1574,7 @@ VM_atan2
 float  atan2(float,float)
 =========
 */
-void VM_atan2 (void)
+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));
@@ -1576,7 +1586,7 @@ VM_tan
 float  tan(float)
 =========
 */
-void VM_tan (void)
+void VM_tan(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1,VM_tan);
        PRVM_G_FLOAT(OFS_RETURN) = tan(PRVM_G_FLOAT(OFS_PARM0));
@@ -1591,31 +1601,12 @@ Returns a vector of length < 1 and > 0
 vector randomvec()
 =================
 */
-void VM_randomvec (void)
+void VM_randomvec(prvm_prog_t *prog)
 {
-       vec3_t          temp;
-       //float         length;
-
+       vec3_t temp;
        VM_SAFEPARMCOUNT(0, VM_randomvec);
-
-       //// WTF ??
-       do
-       {
-               temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
-               temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
-               temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
-       }
-       while (DotProduct(temp, temp) >= 1);
-       VectorCopy (temp, PRVM_G_VECTOR(OFS_RETURN));
-
-       /*
-       temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
-       temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
-       temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
-       // length returned always > 0
-       length = (rand()&32766 + 1) * (1.0 / 32767.0) / VectorLength(temp);
-       VectorScale(temp,length, temp);*/
-       //VectorCopy(temp, PRVM_G_VECTOR(OFS_RETURN));
+       VectorRandom(temp);
+       VectorCopy(temp, PRVM_G_VECTOR(OFS_RETURN));
 }
 
 //=============================================================================
@@ -1627,7 +1618,7 @@ VM_registercvar
 float  registercvar (string name, string value[, float flags])
 =========
 */
-void VM_registercvar (void)
+void VM_registercvar(prvm_prog_t *prog)
 {
        const char *name, *value;
        int     flags;
@@ -1649,7 +1640,7 @@ void VM_registercvar (void)
 // check for overlap with a command
        if (Cmd_Exists (name))
        {
-               VM_Warning("VM_registercvar: %s is a command\n", name);
+               VM_Warning(prog, "VM_registercvar: %s is a command\n", name);
                return;
        }
 
@@ -1668,7 +1659,7 @@ returns the minimum of two supplied floats
 float min(float a, float b, ...[float])
 =================
 */
-void VM_min (void)
+void VM_min(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNTRANGE(2, 8, VM_min);
        // LordHavoc: 3+ argument enhancement suggested by FrikaC
@@ -1694,7 +1685,7 @@ returns the maximum of two supplied floats
 float  max(float a, float b, ...[float])
 =================
 */
-void VM_max (void)
+void VM_max(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNTRANGE(2, 8, VM_max);
        // LordHavoc: 3+ argument enhancement suggested by FrikaC
@@ -1720,7 +1711,7 @@ returns number bounded by supplied range
 float  bound(float min, float value, float max)
 =================
 */
-void VM_bound (void)
+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));
@@ -1735,26 +1726,26 @@ returns a raised to power b
 float  pow(float a, float b)
 =================
 */
-void VM_pow (void)
+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 (void)
+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(void)
+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(void)
+void VM_Files_CloseAll(prvm_prog_t *prog)
 {
        int i;
        for (i = 0;i < PRVM_MAX_OPENFILES;i++)
@@ -1765,16 +1756,16 @@ void VM_Files_CloseAll(void)
        }
 }
 
-static qfile_t *VM_GetFileHandle( int index )
+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, PRVM_NAME);
+               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, PRVM_NAME);
+               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];
@@ -1790,10 +1781,11 @@ 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(void)
+void VM_fopen(prvm_prog_t *prog)
 {
        int filenum, mode;
        const char *modestring, *filename;
+       char vabuf[1024];
 
        VM_SAFEPARMCOUNT(2,VM_fopen);
 
@@ -1803,7 +1795,7 @@ void VM_fopen(void)
        if (filenum >= PRVM_MAX_OPENFILES)
        {
                PRVM_G_FLOAT(OFS_RETURN) = -2;
-               VM_Warning("VM_fopen: %s ran out of file handles (%i)\n", PRVM_NAME, PRVM_MAX_OPENFILES);
+               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);
@@ -1812,21 +1804,21 @@ void VM_fopen(void)
        {
        case 0: // FILE_READ
                modestring = "rb";
-               prog->openfiles[filenum] = FS_OpenVirtualFile(va("data/%s", filename), false);
+               prog->openfiles[filenum] = FS_OpenVirtualFile(va(vabuf, sizeof(vabuf), "data/%s", filename), false);
                if (prog->openfiles[filenum] == NULL)
-                       prog->openfiles[filenum] = FS_OpenVirtualFile(va("%s", filename), false);
+                       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("data/%s", filename), modestring, false);
+               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("data/%s", filename), modestring, false);
+               prog->openfiles[filenum] = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "data/%s", filename), modestring, false);
                break;
        default:
                PRVM_G_FLOAT(OFS_RETURN) = -3;
-               VM_Warning("VM_fopen: %s: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", PRVM_NAME, mode);
+               VM_Warning(prog, "VM_fopen: %s: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", prog->name, mode);
                return;
        }
 
@@ -1834,14 +1826,14 @@ void VM_fopen(void)
        {
                PRVM_G_FLOAT(OFS_RETURN) = -1;
                if (developer_extra.integer)
-                       VM_Warning("VM_fopen: %s: %s mode %s failed\n", PRVM_NAME, filename, modestring);
+                       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", PRVM_NAME, filename, modestring, filenum);
-               prog->openfiles_origin[filenum] = PRVM_AllocationOrigin();
+                       Con_DPrintf("VM_fopen: %s: %s mode %s opened as #%i\n", prog->name, filename, modestring, filenum);
+               prog->openfiles_origin[filenum] = PRVM_AllocationOrigin(prog);
        }
 }
 
@@ -1853,7 +1845,7 @@ fclose(float fhandle)
 =========
 */
 //void(float fhandle) fclose = #111; // closes a file
-void VM_fclose(void)
+void VM_fclose(prvm_prog_t *prog)
 {
        int filenum;
 
@@ -1862,12 +1854,12 @@ void VM_fclose(void)
        filenum = (int)PRVM_G_FLOAT(OFS_PARM0);
        if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES)
        {
-               VM_Warning("VM_fclose: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
+               VM_Warning(prog, "VM_fclose: invalid file handle %i used in %s\n", filenum, prog->name);
                return;
        }
        if (prog->openfiles[filenum] == NULL)
        {
-               VM_Warning("VM_fclose: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
+               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]);
@@ -1875,7 +1867,7 @@ void VM_fclose(void)
        if(prog->openfiles_origin[filenum])
                PRVM_Free((char *)prog->openfiles_origin[filenum]);
        if (developer_extra.integer)
-               Con_DPrintf("VM_fclose: %s: #%i closed\n", PRVM_NAME, filenum);
+               Con_DPrintf("VM_fclose: %s: #%i closed\n", prog->name, filenum);
 }
 
 /*
@@ -1886,7 +1878,7 @@ 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(void)
+void VM_fgets(prvm_prog_t *prog)
 {
        int c, end;
        char string[VM_STRINGTEMP_LENGTH];
@@ -1900,12 +1892,12 @@ void VM_fgets(void)
        filenum = (int)PRVM_G_FLOAT(OFS_PARM0);
        if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES)
        {
-               VM_Warning("VM_fgets: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
+               VM_Warning(prog, "VM_fgets: invalid file handle %i used in %s\n", filenum, prog->name);
                return;
        }
        if (prog->openfiles[filenum] == NULL)
        {
-               VM_Warning("VM_fgets: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
+               VM_Warning(prog, "VM_fgets: no such file handle %i (or file has been closed) in %s\n", filenum, prog->name);
                return;
        }
        end = 0;
@@ -1926,9 +1918,9 @@ void VM_fgets(void)
                        FS_UnGetc(prog->openfiles[filenum], (unsigned char)c);
        }
        if (developer_extra.integer)
-               Con_DPrintf("fgets: %s: %s\n", PRVM_NAME, string);
+               Con_DPrintf("fgets: %s: %s\n", prog->name, string);
        if (c >= 0 || end)
-               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
 }
 
 /*
@@ -1939,7 +1931,7 @@ 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(void)
+void VM_fputs(prvm_prog_t *prog)
 {
        int stringlength;
        char string[VM_STRINGTEMP_LENGTH];
@@ -1950,19 +1942,19 @@ void VM_fputs(void)
        filenum = (int)PRVM_G_FLOAT(OFS_PARM0);
        if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES)
        {
-               VM_Warning("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
+               VM_Warning(prog, "VM_fputs: invalid file handle %i used in %s\n", filenum, prog->name);
                return;
        }
        if (prog->openfiles[filenum] == NULL)
        {
-               VM_Warning("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
+               VM_Warning(prog, "VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, prog->name);
                return;
        }
-       VM_VarString(1, string, sizeof(string));
+       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", PRVM_NAME, string);
+               Con_DPrintf("fputs: %s: %s\n", prog->name, string);
 }
 
 /*
@@ -1972,28 +1964,28 @@ VM_writetofile
        writetofile(float fhandle, entity ent)
 =========
 */
-void VM_writetofile(void)
+void VM_writetofile(prvm_prog_t *prog)
 {
        prvm_edict_t * ent;
        qfile_t *file;
 
        VM_SAFEPARMCOUNT(2, VM_writetofile);
 
-       file = VM_GetFileHandle( (int)PRVM_G_FLOAT(OFS_PARM0) );
+       file = VM_GetFileHandle(prog, (int)PRVM_G_FLOAT(OFS_PARM0));
        if( !file )
        {
-               VM_Warning("VM_writetofile: invalid or closed file handle\n");
+               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("VM_writetofile: %s: entity %i is free !\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ent));
+               VM_Warning(prog, "VM_writetofile: %s: entity %i is free !\n", prog->name, PRVM_NUM_FOR_EDICT(ent));
                return;
        }
 
-       PRVM_ED_Write (file, ent);
+       PRVM_ED_Write (prog, file, ent);
 }
 
 // KrimZon - DP_QC_ENTITYDATA
@@ -2005,7 +1997,7 @@ float() numentityfields
 Return the number of entity fields - NOT offsets
 =========
 */
-void VM_numentityfields(void)
+void VM_numentityfields(prvm_prog_t *prog)
 {
        PRVM_G_FLOAT(OFS_RETURN) = prog->numfielddefs;
 }
@@ -2019,15 +2011,15 @@ string(float fieldnum) entityfieldname
 Return name of the specified field as a string, or empty if the field is invalid (warning)
 =========
 */
-void VM_entityfieldname(void)
+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("VM_entityfieldname: %s: field index out of bounds\n", PRVM_NAME);
-        PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString("");
+        VM_Warning(prog, "VM_entityfieldname: %s: field index out of bounds\n", prog->name);
+        PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "");
                return;
        }
        
@@ -2043,14 +2035,14 @@ VM_entityfieldtype
 float(float fieldnum) entityfieldtype
 =========
 */
-void VM_entityfieldtype(void)
+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("VM_entityfieldtype: %s: field index out of bounds\n", PRVM_NAME);
+               VM_Warning(prog, "VM_entityfieldtype: %s: field index out of bounds\n", prog->name);
                PRVM_G_FLOAT(OFS_RETURN) = -1.0;
                return;
        }
@@ -2067,7 +2059,7 @@ VM_getentityfieldstring
 string(float fieldnum, entity ent) getentityfieldstring
 =========
 */
-void VM_getentityfieldstring(void)
+void VM_getentityfieldstring(prvm_prog_t *prog)
 {
        // put the data into a string
        ddef_t *d;
@@ -2075,11 +2067,12 @@ void VM_getentityfieldstring(void)
        int *v;
        prvm_edict_t * ent;
        int i = (int)PRVM_G_FLOAT(OFS_PARM0);
+       char valuebuf[MAX_INPUTLINE];
        
        if (i < 0 || i >= prog->numfielddefs)
        {
-        VM_Warning("VM_entityfielddata: %s: field index out of bounds\n", PRVM_NAME);
-               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString("");
+        VM_Warning(prog, "VM_entityfielddata: %s: field index out of bounds\n", prog->name);
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "");
                return;
        }
        
@@ -2089,8 +2082,8 @@ void VM_getentityfieldstring(void)
        ent = PRVM_G_EDICT(OFS_PARM1);
        if(ent->priv.required->free)
        {
-               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString("");
-               VM_Warning("VM_entityfielddata: %s: entity %i is free !\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ent));
+               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;
        }
        v = (int *)((char *)ent->fields.vp + d->ofs*4);
@@ -2102,11 +2095,11 @@ void VM_getentityfieldstring(void)
                        break;
        if (j == prvm_type_size[type])
        {
-               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString("");
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "");
                return;
        }
                
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(PRVM_UglyValueString((etype_t)d->type, (prvm_eval_t *)v));
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, PRVM_UglyValueString(prog, (etype_t)d->type, (prvm_eval_t *)v, valuebuf, sizeof(valuebuf)));
 }
 
 // KrimZon - DP_QC_ENTITYDATA
@@ -2117,7 +2110,7 @@ VM_putentityfieldstring
 float(float fieldnum, entity ent, string s) putentityfieldstring
 =========
 */
-void VM_putentityfieldstring(void)
+void VM_putentityfieldstring(prvm_prog_t *prog)
 {
        ddef_t *d;
        prvm_edict_t * ent;
@@ -2125,7 +2118,7 @@ void VM_putentityfieldstring(void)
 
        if (i < 0 || i >= prog->numfielddefs)
        {
-        VM_Warning("VM_entityfielddata: %s: field index out of bounds\n", PRVM_NAME);
+        VM_Warning(prog, "VM_entityfielddata: %s: field index out of bounds\n", prog->name);
                PRVM_G_FLOAT(OFS_RETURN) = 0.0f;
                return;
        }
@@ -2136,13 +2129,13 @@ void VM_putentityfieldstring(void)
        ent = PRVM_G_EDICT(OFS_PARM1);
        if(ent->priv.required->free)
        {
-               VM_Warning("VM_entityfielddata: %s: entity %i is free !\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ent));
+               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(ent, d, PRVM_G_STRING(OFS_PARM2), false) ) ? 1.0f : 0.0f;
+       PRVM_G_FLOAT(OFS_RETURN) = ( PRVM_ED_ParseEpair(prog, ent, d, PRVM_G_STRING(OFS_PARM2), false) ) ? 1.0f : 0.0f;
 }
 
 /*
@@ -2153,7 +2146,7 @@ float     strlen(string s)
 =========
 */
 //float(string s) strlen = #114; // returns how many characters are in a string
-void VM_strlen(void)
+void VM_strlen(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1,VM_strlen);
 
@@ -2170,7 +2163,7 @@ string    strdecolorize(string s)
 =========
 */
 // string (string s) strdecolorize = #472; // returns the passed in string with color codes stripped
-void VM_strdecolorize(void)
+void VM_strdecolorize(prvm_prog_t *prog)
 {
        char szNewString[VM_STRINGTEMP_LENGTH];
        const char *szString;
@@ -2179,7 +2172,7 @@ void VM_strdecolorize(void)
        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(szNewString);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString);
 }
 
 // DRESK - String Length (not counting color codes)
@@ -2192,7 +2185,7 @@ 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(void)
+void VM_strlennocol(prvm_prog_t *prog)
 {
        const char *szString;
        int nCnt;
@@ -2216,7 +2209,7 @@ string    strtolower(string s)
 =========
 */
 // string (string s) strtolower = #480; // returns passed in string in lowercase form
-void VM_strtolower(void)
+void VM_strtolower(prvm_prog_t *prog)
 {
        char szNewString[VM_STRINGTEMP_LENGTH];
        const char *szString;
@@ -2227,7 +2220,7 @@ void VM_strtolower(void)
 
        COM_ToLowerString(szString, szNewString, sizeof(szNewString) );
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(szNewString);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString);
 }
 
 /*
@@ -2238,7 +2231,7 @@ string    strtoupper(string s)
 =========
 */
 // string (string s) strtoupper = #481; // returns passed in string in uppercase form
-void VM_strtoupper(void)
+void VM_strtoupper(prvm_prog_t *prog)
 {
        char szNewString[VM_STRINGTEMP_LENGTH];
        const char *szString;
@@ -2249,7 +2242,7 @@ void VM_strtoupper(void)
 
        COM_ToUpperString(szString, szNewString, sizeof(szNewString) );
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(szNewString);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString);
 }
 
 /*
@@ -2262,13 +2255,13 @@ 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(void)
+void VM_strcat(prvm_prog_t *prog)
 {
        char s[VM_STRINGTEMP_LENGTH];
        VM_SAFEPARMCOUNTRANGE(1, 8, VM_strcat);
 
-       VM_VarString(0, s, sizeof(s));
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(s);
+       VM_VarString(prog, 0, s, sizeof(s));
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s);
 }
 
 /*
@@ -2280,7 +2273,7 @@ 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(void)
+void VM_substring(prvm_prog_t *prog)
 {
        int start, length;
        int u_slength = 0, u_start;
@@ -2307,7 +2300,7 @@ void VM_substring(void)
 
        memcpy(string, s + start, length);
        string[length] = 0;
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
        */
        
        s = PRVM_G_STRING(OFS_PARM0);
@@ -2332,7 +2325,7 @@ void VM_substring(void)
        u_start = u8_byteofs(s, start, NULL);
        if (u_start < 0)
        {
-               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString("");
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "");
                return;
        }
        u_length = u8_bytelen(s + u_start, length);
@@ -2341,7 +2334,7 @@ void VM_substring(void)
        
        memcpy(string, s + u_start, u_length);
        string[u_length] = 0;
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
 }
 
 /*
@@ -2352,7 +2345,7 @@ 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(void)
+void VM_strreplace(prvm_prog_t *prog)
 {
        int i, j, si;
        const char *search, *replace, *subject;
@@ -2408,7 +2401,7 @@ void VM_strreplace(void)
                        string[si++] = subject[i];
        string[si] = '\0';
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
 }
 
 /*
@@ -2419,7 +2412,7 @@ string(string search, string replace, string subject) strireplace = #485;
 =========
 */
 // case-insensitive version of strreplace
-void VM_strireplace(void)
+void VM_strireplace(prvm_prog_t *prog)
 {
        int i, j, si;
        const char *search, *replace, *subject;
@@ -2475,7 +2468,7 @@ void VM_strireplace(void)
                        string[si++] = subject[i];
        string[si] = '\0';
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
 }
 
 /*
@@ -2486,13 +2479,13 @@ vector  stov(string s)
 =========
 */
 //vector(string s) stov = #117; // returns vector value from a string
-void VM_stov(void)
+void VM_stov(prvm_prog_t *prog)
 {
        char string[VM_STRINGTEMP_LENGTH];
 
        VM_SAFEPARMCOUNT(1,VM_stov);
 
-       VM_VarString(0, string, sizeof(string));
+       VM_VarString(prog, 0, string, sizeof(string));
        Math_atov(string, PRVM_G_VECTOR(OFS_RETURN));
 }
 
@@ -2504,7 +2497,7 @@ 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(void)
+void VM_strzone(prvm_prog_t *prog)
 {
        char *out;
        char string[VM_STRINGTEMP_LENGTH];
@@ -2512,9 +2505,9 @@ void VM_strzone(void)
 
        VM_SAFEPARMCOUNT(1,VM_strzone);
 
-       VM_VarString(0, string, sizeof(string));
+       VM_VarString(prog, 0, string, sizeof(string));
        alloclen = strlen(string) + 1;
-       PRVM_G_INT(OFS_RETURN) = PRVM_AllocString(alloclen, &out);
+       PRVM_G_INT(OFS_RETURN) = PRVM_AllocString(prog, alloclen, &out);
        memcpy(out, string, alloclen);
 }
 
@@ -2526,10 +2519,10 @@ 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(void)
+void VM_strunzone(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1,VM_strunzone);
-       PRVM_FreeString(PRVM_G_INT(OFS_PARM0));
+       PRVM_FreeString(prog, PRVM_G_INT(OFS_PARM0));
 }
 
 /*
@@ -2541,7 +2534,7 @@ 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 (void)
+void VM_clcommand (prvm_prog_t *prog)
 {
        client_t *temp_client;
        int i;
@@ -2551,13 +2544,13 @@ void VM_clcommand (void)
        i = (int)PRVM_G_FLOAT(OFS_PARM0);
        if (!sv.active  || i < 0 || i >= svs.maxclients || !svs.clients[i].active)
        {
-               VM_Warning("VM_clientcommand: %s: invalid client/server is not active !\n", PRVM_NAME);
+               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);
+       Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client, true);
        host_client = temp_client;
 }
 
@@ -2577,7 +2570,7 @@ 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 (void)
+void VM_tokenize (prvm_prog_t *prog)
 {
        const char *p;
 
@@ -2600,7 +2593,7 @@ void VM_tokenize (void)
                if(!COM_ParseToken_VM_Tokenize(&p, false))
                        break;
                tokens_endpos[num_tokens] = p - tokenize_string;
-               tokens[num_tokens] = PRVM_SetTempString(com_token);
+               tokens[num_tokens] = PRVM_SetTempString(prog, com_token);
                ++num_tokens;
        }
 
@@ -2608,7 +2601,7 @@ void VM_tokenize (void)
 }
 
 //float(string s) tokenize = #514; // takes apart a string into individal words (access them with argv), returns how many
-void VM_tokenize_console (void)
+void VM_tokenize_console (prvm_prog_t *prog)
 {
        const char *p;
 
@@ -2631,7 +2624,7 @@ void VM_tokenize_console (void)
                if(!COM_ParseToken_Console(&p))
                        break;
                tokens_endpos[num_tokens] = p - tokenize_string;
-               tokens[num_tokens] = PRVM_SetTempString(com_token);
+               tokens[num_tokens] = PRVM_SetTempString(prog, com_token);
                ++num_tokens;
        }
 
@@ -2652,7 +2645,7 @@ float tokenizebyseparator(string s, string separator1, ...)
 //example:
 //numnumbers = tokenizebyseparator("10.1.2.3", ".");
 //returns 4 and the tokens "10" "1" "2" "3".
-void VM_tokenizebyseparator (void)
+void VM_tokenizebyseparator (prvm_prog_t *prog)
 {
        int j, k;
        int numseparators;
@@ -2708,7 +2701,7 @@ void VM_tokenizebyseparator (void)
                if (j >= (int)sizeof(tokentext))
                        break;
                tokentext[j++] = 0;
-               tokens[num_tokens++] = PRVM_SetTempString(token);
+               tokens[num_tokens++] = PRVM_SetTempString(prog, token);
                if (!*p)
                        break;
        }
@@ -2718,7 +2711,7 @@ void VM_tokenizebyseparator (void)
 
 //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 (void)
+void VM_argv (prvm_prog_t *prog)
 {
        int token_num;
 
@@ -2736,7 +2729,7 @@ void VM_argv (void)
 }
 
 //float(float n) argv_start_index = #515; // returns the start index of a token
-void VM_argv_start_index (void)
+void VM_argv_start_index (prvm_prog_t *prog)
 {
        int token_num;
 
@@ -2754,7 +2747,7 @@ void VM_argv_start_index (void)
 }
 
 //float(float n) argv_end_index = #516; // returns the end index of a token
-void VM_argv_end_index (void)
+void VM_argv_end_index (prvm_prog_t *prog)
 {
        int token_num;
 
@@ -2778,7 +2771,7 @@ VM_isserver
 float  isserver()
 =========
 */
-void VM_isserver(void)
+void VM_isserver(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0,VM_serverstate);
 
@@ -2792,7 +2785,7 @@ VM_clientcount
 float  clientcount()
 =========
 */
-void VM_clientcount(void)
+void VM_clientcount(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0,VM_clientcount);
 
@@ -2806,7 +2799,7 @@ VM_clientstate
 float  clientstate()
 =========
 */
-void VM_clientstate(void)
+void VM_clientstate(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0,VM_clientstate);
 
@@ -2832,10 +2825,10 @@ void VM_clientstate(void)
 =========
 VM_getostype
 
-float  getostype(void)
+float  getostype(prvm_prog_t *prog)
 =========
 */ // not used at the moment -> not included in the common list
-void VM_getostype(void)
+void VM_getostype(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0,VM_getostype);
 
@@ -2858,12 +2851,11 @@ void VM_getostype(void)
 =========
 VM_gettime
 
-float  gettime(void)
+float  gettime(prvm_prog_t *prog)
 =========
 */
-extern double host_starttime;
 float CDAudio_GetPosition(void);
-void VM_gettime(void)
+void VM_gettime(prvm_prog_t *prog)
 {
        int timer_index;
 
@@ -2876,26 +2868,26 @@ void VM_gettime(void)
        else
        {
                timer_index = (int) PRVM_G_FLOAT(OFS_PARM0);
-        switch(timer_index)
-        {
-            case 0: // GETTIME_FRAMESTART
-                PRVM_G_FLOAT(OFS_RETURN) = (float) realtime;
-                break;
-            case 1: // GETTIME_REALTIME
-                PRVM_G_FLOAT(OFS_RETURN) = (float) Sys_DoubleTime();
-                break;
-            case 2: // GETTIME_HIRES
-                PRVM_G_FLOAT(OFS_RETURN) = (float) (Sys_DoubleTime() - realtime);
-                break;
-            case 3: // GETTIME_UPTIME
-                PRVM_G_FLOAT(OFS_RETURN) = (float) (Sys_DoubleTime() - host_starttime);
-                break;
-            case 4: // GETTIME_CDTRACK
-                PRVM_G_FLOAT(OFS_RETURN) = (float) CDAudio_GetPosition();
-                break;
+               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("VM_gettime: %s: unsupported timer specified, returning realtime\n", PRVM_NAME);
-                               PRVM_G_FLOAT(OFS_RETURN) = (float) realtime;
+                               VM_Warning(prog, "VM_gettime: %s: unsupported timer specified, returning realtime\n", prog->name);
+                               PRVM_G_FLOAT(OFS_RETURN) = realtime;
                                break;
                }
        }
@@ -2905,27 +2897,29 @@ void VM_gettime(void)
 =========
 VM_getsoundtime
 
-float  getsoundtime(void)
+float  getsoundtime(prvm_prog_t *prog)
 =========
 */
 
-void VM_getsoundtime (void)
+void VM_getsoundtime (prvm_prog_t *prog)
 {
-       int entnum, entchannel, pnum;
+       int entnum, entchannel;
        VM_SAFEPARMCOUNT(2,VM_getsoundtime);
 
-       pnum = PRVM_GetProgNr();
-       if (pnum == PRVM_MENUPROG)
+       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("VM_getsoundtime: %s: not supported on this progs\n", PRVM_NAME);
+               VM_Warning(prog, "VM_getsoundtime: %s: not supported on this progs\n", prog->name);
                PRVM_G_FLOAT(OFS_RETURN) = -1;
                return;
        }
-       entnum = ((pnum == PRVM_CLIENTPROG) ? MAX_EDICTS : 0) + PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0));
        entchannel = (int)PRVM_G_FLOAT(OFS_PARM1);
        entchannel = CHAN_USER2ENGINE(entchannel);
        if (!IS_CHAN(entchannel))
-               VM_Warning("VM_getsoundtime: %s: bad channel %i\n", PRVM_NAME, entchannel);
+               VM_Warning(prog, "VM_getsoundtime: %s: bad channel %i\n", prog->name, entchannel);
        PRVM_G_FLOAT(OFS_RETURN) = (float)S_GetEntChannelPosition(entnum, entchannel);
 }
 
@@ -2936,7 +2930,7 @@ VM_GetSoundLen
 string soundlength (string sample)
 =========
 */
-void VM_soundlength (void)
+void VM_soundlength (prvm_prog_t *prog)
 {
        const char *s;
 
@@ -2953,11 +2947,11 @@ VM_loadfromdata
 loadfromdata(string data)
 =========
 */
-void VM_loadfromdata(void)
+void VM_loadfromdata(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1,VM_loadentsfromfile);
 
-       PRVM_ED_LoadFromFile(PRVM_G_STRING(OFS_PARM0));
+       PRVM_ED_LoadFromFile(prog, PRVM_G_STRING(OFS_PARM0));
 }
 
 /*
@@ -2967,7 +2961,7 @@ VM_parseentitydata
 parseentitydata(entity ent, string data)
 ========================
 */
-void VM_parseentitydata(void)
+void VM_parseentitydata(prvm_prog_t *prog)
 {
        prvm_edict_t *ent;
        const char *data;
@@ -2977,15 +2971,15 @@ void VM_parseentitydata(void)
        // get edict and test it
        ent = PRVM_G_EDICT(OFS_PARM0);
        if (ent->priv.required->free)
-               PRVM_ERROR ("VM_parseentitydata: %s: Can only set already spawned entities (entity %i is free)!", PRVM_NAME, PRVM_NUM_FOR_EDICT(ent));
+               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) || com_token[0] != '{' )
-               PRVM_ERROR ("VM_parseentitydata: %s: Couldn't parse entity data:\n%s", PRVM_NAME, data );
+       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 (data, ent);
+       PRVM_ED_ParseEdict (prog, data, ent);
 }
 
 /*
@@ -2995,7 +2989,7 @@ VM_loadfromfile
 loadfromfile(string file)
 =========
 */
-void VM_loadfromfile(void)
+void VM_loadfromfile(prvm_prog_t *prog)
 {
        const char *filename;
        char *data;
@@ -3006,7 +3000,7 @@ void VM_loadfromfile(void)
        if (FS_CheckNastyPath(filename, false))
        {
                PRVM_G_FLOAT(OFS_RETURN) = -4;
-               VM_Warning("VM_loadfromfile: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
+               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;
        }
 
@@ -3015,7 +3009,7 @@ void VM_loadfromfile(void)
        if (data == NULL)
                PRVM_G_FLOAT(OFS_RETURN) = -1;
 
-       PRVM_ED_LoadFromFile(data);
+       PRVM_ED_LoadFromFile(prog, data);
 
        if(data)
                Mem_Free(data);
@@ -3029,7 +3023,7 @@ VM_modulo
 float  mod(float val, float m)
 =========
 */
-void VM_modulo(void)
+void VM_modulo(prvm_prog_t *prog)
 {
        int val, m;
        VM_SAFEPARMCOUNT(2,VM_module);
@@ -3040,14 +3034,14 @@ void VM_modulo(void)
        PRVM_G_FLOAT(OFS_RETURN) = (float) (val % m);
 }
 
-void VM_Search_Init(void)
+static void VM_Search_Init(prvm_prog_t *prog)
 {
        int i;
        for (i = 0;i < PRVM_MAX_OPENSEARCHES;i++)
                prog->opensearches[i] = NULL;
 }
 
-void VM_Search_Reset(void)
+static void VM_Search_Reset(prvm_prog_t *prog)
 {
        int i;
        // reset the fssearch list
@@ -3066,7 +3060,7 @@ VM_search_begin
 float search_begin(string pattern, float caseinsensitive, float quiet)
 =========
 */
-void VM_search_begin(void)
+void VM_search_begin(prvm_prog_t *prog)
 {
        int handle;
        const char *pattern;
@@ -3076,7 +3070,7 @@ void VM_search_begin(void)
 
        pattern = PRVM_G_STRING(OFS_PARM0);
 
-       VM_CheckEmptyString(pattern);
+       VM_CheckEmptyString(prog, pattern);
 
        caseinsens = (int)PRVM_G_FLOAT(OFS_PARM1);
        quiet = (int)PRVM_G_FLOAT(OFS_PARM2);
@@ -3088,7 +3082,7 @@ void VM_search_begin(void)
        if(handle >= PRVM_MAX_OPENSEARCHES)
        {
                PRVM_G_FLOAT(OFS_RETURN) = -2;
-               VM_Warning("VM_search_begin: %s ran out of search handles (%i)\n", PRVM_NAME, PRVM_MAX_OPENSEARCHES);
+               VM_Warning(prog, "VM_search_begin: %s ran out of search handles (%i)\n", prog->name, PRVM_MAX_OPENSEARCHES);
                return;
        }
 
@@ -3096,7 +3090,7 @@ void VM_search_begin(void)
                PRVM_G_FLOAT(OFS_RETURN) = -1;
        else
        {
-               prog->opensearches_origin[handle] = PRVM_AllocationOrigin();
+               prog->opensearches_origin[handle] = PRVM_AllocationOrigin(prog);
                PRVM_G_FLOAT(OFS_RETURN) = handle;
        }
 }
@@ -3108,7 +3102,7 @@ VM_search_end
 void   search_end(float handle)
 =========
 */
-void VM_search_end(void)
+void VM_search_end(prvm_prog_t *prog)
 {
        int handle;
        VM_SAFEPARMCOUNT(1, VM_search_end);
@@ -3117,12 +3111,12 @@ void VM_search_end(void)
 
        if(handle < 0 || handle >= PRVM_MAX_OPENSEARCHES)
        {
-               VM_Warning("VM_search_end: invalid handle %i used in %s\n", handle, PRVM_NAME);
+               VM_Warning(prog, "VM_search_end: invalid handle %i used in %s\n", handle, prog->name);
                return;
        }
        if(prog->opensearches[handle] == NULL)
        {
-               VM_Warning("VM_search_end: no such handle %i in %s\n", handle, PRVM_NAME);
+               VM_Warning(prog, "VM_search_end: no such handle %i in %s\n", handle, prog->name);
                return;
        }
 
@@ -3139,7 +3133,7 @@ VM_search_getsize
 float  search_getsize(float handle)
 =========
 */
-void VM_search_getsize(void)
+void VM_search_getsize(prvm_prog_t *prog)
 {
        int handle;
        VM_SAFEPARMCOUNT(1, VM_M_search_getsize);
@@ -3148,12 +3142,12 @@ void VM_search_getsize(void)
 
        if(handle < 0 || handle >= PRVM_MAX_OPENSEARCHES)
        {
-               VM_Warning("VM_search_getsize: invalid handle %i used in %s\n", handle, PRVM_NAME);
+               VM_Warning(prog, "VM_search_getsize: invalid handle %i used in %s\n", handle, prog->name);
                return;
        }
        if(prog->opensearches[handle] == NULL)
        {
-               VM_Warning("VM_search_getsize: no such handle %i in %s\n", handle, PRVM_NAME);
+               VM_Warning(prog, "VM_search_getsize: no such handle %i in %s\n", handle, prog->name);
                return;
        }
 
@@ -3167,7 +3161,7 @@ VM_search_getfilename
 string search_getfilename(float handle, float num)
 =========
 */
-void VM_search_getfilename(void)
+void VM_search_getfilename(prvm_prog_t *prog)
 {
        int handle, filenum;
        VM_SAFEPARMCOUNT(2, VM_search_getfilename);
@@ -3177,21 +3171,21 @@ void VM_search_getfilename(void)
 
        if(handle < 0 || handle >= PRVM_MAX_OPENSEARCHES)
        {
-               VM_Warning("VM_search_getfilename: invalid handle %i used in %s\n", handle, PRVM_NAME);
+               VM_Warning(prog, "VM_search_getfilename: invalid handle %i used in %s\n", handle, prog->name);
                return;
        }
        if(prog->opensearches[handle] == NULL)
        {
-               VM_Warning("VM_search_getfilename: no such handle %i in %s\n", handle, PRVM_NAME);
+               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("VM_search_getfilename: invalid filenum %i in %s\n", filenum, PRVM_NAME);
+               VM_Warning(prog, "VM_search_getfilename: invalid filenum %i in %s\n", filenum, prog->name);
                return;
        }
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog->opensearches[handle]->filenames[filenum]);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, prog->opensearches[handle]->filenames[filenum]);
 }
 
 /*
@@ -3201,7 +3195,7 @@ VM_chr
 string chr(float ascii)
 =========
 */
-void VM_chr(void)
+void VM_chr(prvm_prog_t *prog)
 {
        /*
        char tmp[2];
@@ -3210,7 +3204,7 @@ void VM_chr(void)
        tmp[0] = (unsigned char) PRVM_G_FLOAT(OFS_PARM0);
        tmp[1] = 0;
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(tmp);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, tmp);
        */
        
        char tmp[8];
@@ -3219,7 +3213,7 @@ void VM_chr(void)
 
        len = u8_fromchar((Uchar)PRVM_G_FLOAT(OFS_PARM0), tmp, sizeof(tmp));
        tmp[len] = 0;
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(tmp);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, tmp);
 }
 
 //=============================================================================
@@ -3232,7 +3226,7 @@ VM_iscachedpic
 float  iscachedpic(string pic)
 =========
 */
-void VM_iscachedpic(void)
+void VM_iscachedpic(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1,VM_iscachedpic);
 
@@ -3247,7 +3241,7 @@ VM_precache_pic
 string precache_pic(string pic)
 =========
 */
-void VM_precache_pic(void)
+void VM_precache_pic(prvm_prog_t *prog)
 {
        const char      *s;
 
@@ -3255,7 +3249,7 @@ void VM_precache_pic(void)
 
        s = PRVM_G_STRING(OFS_PARM0);
        PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
-       VM_CheckEmptyString (s);
+       VM_CheckEmptyString(prog, s);
 
        // AK Draw_CachePic is supposed to always return a valid pointer
        if( Draw_CachePic_Flags(s, 0)->tex == r_texture_notexture )
@@ -3269,19 +3263,19 @@ VM_freepic
 freepic(string s)
 =========
 */
-void VM_freepic(void)
+void VM_freepic(prvm_prog_t *prog)
 {
        const char *s;
 
        VM_SAFEPARMCOUNT(1,VM_freepic);
 
        s = PRVM_G_STRING(OFS_PARM0);
-       VM_CheckEmptyString (s);
+       VM_CheckEmptyString(prog, s);
 
        Draw_FreePic(s);
 }
 
-void getdrawfontscale(float *sx, float *sy)
+static void getdrawfontscale(prvm_prog_t *prog, float *sx, float *sy)
 {
        vec3_t v;
        *sx = *sy = 1;
@@ -3293,7 +3287,7 @@ void getdrawfontscale(float *sx, float *sy)
        }
 }
 
-dp_font_t *getdrawfont(void)
+static dp_font_t *getdrawfont(prvm_prog_t *prog)
 {
        int f = (int) PRVM_drawglobalfloat(drawfont);
        if(f < 0 || f >= dp_fonts.maxsize)
@@ -3308,7 +3302,7 @@ VM_drawcharacter
 float  drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag)
 =========
 */
-void VM_drawcharacter(void)
+void VM_drawcharacter(prvm_prog_t *prog)
 {
        float *pos,*scale,*rgb;
        char   character;
@@ -3320,7 +3314,7 @@ void VM_drawcharacter(void)
        if(character == 0)
        {
                PRVM_G_FLOAT(OFS_RETURN) = -1;
-               VM_Warning("VM_drawcharacter: %s passed null character !\n",PRVM_NAME);
+               VM_Warning(prog, "VM_drawcharacter: %s passed null character !\n",prog->name);
                return;
        }
 
@@ -3332,22 +3326,22 @@ void VM_drawcharacter(void)
        if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
        {
                PRVM_G_FLOAT(OFS_RETURN) = -2;
-               VM_Warning("VM_drawcharacter: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
+               VM_Warning(prog, "VM_drawcharacter: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
                return;
        }
 
        if(pos[2] || scale[2])
-               Con_Printf("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")));
+               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("VM_drawcharacter: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
+               VM_Warning(prog, "VM_drawcharacter: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
                return;
        }
 
-       getdrawfontscale(&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());
+       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;
 }
 
@@ -3355,42 +3349,43 @@ void VM_drawcharacter(void)
 =========
 VM_drawstring
 
-float  drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
+float  drawstring(vector position, string text, vector scale, vector rgb, float alpha[, float flag])
 =========
 */
-void VM_drawstring(void)
+void VM_drawstring(prvm_prog_t *prog)
 {
        float *pos,*scale,*rgb;
        const char  *string;
-       int flag;
+       int flag = 0;
        float sx, sy;
-       VM_SAFEPARMCOUNT(6,VM_drawstring);
+       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);
-       flag = (int)PRVM_G_FLOAT(OFS_PARM5);
+       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("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
+               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("VM_drawstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
+               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])
-               Con_Printf("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")));
+               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(&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());
+       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;
 }
@@ -3404,7 +3399,7 @@ float     drawcolorcodedstring(vector position, string text, vector scale, float alp
 float  drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
 =========
 */
-void VM_drawcolorcodedstring(void)
+void VM_drawcolorcodedstring(prvm_prog_t *prog)
 {
        float *pos, *scale;
        const char  *string;
@@ -3438,22 +3433,22 @@ void VM_drawcolorcodedstring(void)
        if(flag < DRAWFLAG_NORMAL || flag >= DRAWFLAG_NUMFLAGS)
        {
                PRVM_G_FLOAT(OFS_RETURN) = -2;
-               VM_Warning("VM_drawcolorcodedstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
+               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("VM_drawcolorcodedstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
+               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])
-               Con_Printf("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")));
+               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(&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());
+       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
@@ -3466,7 +3461,7 @@ VM_stringwidth
 float  stringwidth(string text, float allowColorCodes, float size)
 =========
 */
-void VM_stringwidth(void)
+void VM_stringwidth(prvm_prog_t *prog)
 {
        const char  *string;
        float *szv;
@@ -3476,7 +3471,7 @@ void VM_stringwidth(void)
        size_t maxlen = 0;
        VM_SAFEPARMCOUNTRANGE(2,3,VM_drawstring);
 
-       getdrawfontscale(&sx, &sy);
+       getdrawfontscale(prog, &sx, &sy);
        if(prog->argc == 3)
        {
                szv = PRVM_G_VECTOR(OFS_PARM2);
@@ -3500,7 +3495,7 @@ void VM_stringwidth(void)
        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(), 1000000000) * mult;
+       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)
        {
@@ -3527,7 +3522,7 @@ float findfont(string s)
 =========
 */
 
-float getdrawfontnum(const char *fontname)
+static float getdrawfontnum(const char *fontname)
 {
        int i;
 
@@ -3537,7 +3532,7 @@ float getdrawfontnum(const char *fontname)
        return -1;
 }
 
-void VM_findfont(void)
+void VM_findfont(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1,VM_findfont);
        PRVM_G_FLOAT(OFS_RETURN) = getdrawfontnum(PRVM_G_STRING(OFS_PARM0));
@@ -3551,9 +3546,7 @@ float loadfont(string fontname, string fontmaps, string sizes, float slot)
 =========
 */
 
-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 VM_loadfont(void)
+void VM_loadfont(prvm_prog_t *prog)
 {
        const char *fontname, *filelist, *sizes, *c, *cm;
        char mainfont[MAX_QPATH];
@@ -3655,13 +3648,13 @@ void VM_loadfont(void)
                // detect crap size
                if (sz < 0.001f || sz > 1000.0f)
                {
-                       VM_Warning("VM_loadfont: crap size %s", com_token);
+                       VM_Warning(prog, "VM_loadfont: crap size %s", com_token);
                        continue;
                }
                // check overflow
                if (numsizes == MAX_FONT_SIZES)
                {
-                       VM_Warning("VM_loadfont: MAX_FONT_SIZES = %i exceeded", MAX_FONT_SIZES);
+                       VM_Warning(prog, "VM_loadfont: MAX_FONT_SIZES = %i exceeded", MAX_FONT_SIZES);
                        break;
                }
                f->req_sizes[numsizes] = sz;
@@ -3694,39 +3687,40 @@ VM_drawpic
 float  drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag)
 =========
 */
-void VM_drawpic(void)
+void VM_drawpic(prvm_prog_t *prog)
 {
        const char *picname;
        float *size, *pos, *rgb;
-       int flag;
+       int flag = 0;
 
-       VM_SAFEPARMCOUNT(6,VM_drawpic);
+       VM_SAFEPARMCOUNTRANGE(5,6,VM_drawpic);
 
        picname = PRVM_G_STRING(OFS_PARM1);
-       VM_CheckEmptyString (picname);
+       VM_CheckEmptyString(prog, picname);
 
        // is pic cached ? no function yet for that
        if(!1)
        {
                PRVM_G_FLOAT(OFS_RETURN) = -4;
-               VM_Warning("VM_drawpic: %s: %s not cached !\n", PRVM_NAME, picname);
+               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);
-       flag = (int) PRVM_G_FLOAT(OFS_PARM5);
+       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("VM_drawpic: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
+               VM_Warning(prog, "VM_drawpic: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
                return;
        }
 
        if(pos[2] || size[2])
-               Con_Printf("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")));
+               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;
@@ -3738,7 +3732,7 @@ VM_drawrotpic
 float  drawrotpic(vector position, string pic, vector size, vector org, float angle, vector rgb, float alpha, float flag)
 =========
 */
-void VM_drawrotpic(void)
+void VM_drawrotpic(prvm_prog_t *prog)
 {
        const char *picname;
        float *size, *pos, *org, *rgb;
@@ -3747,13 +3741,13 @@ void VM_drawrotpic(void)
        VM_SAFEPARMCOUNT(8,VM_drawrotpic);
 
        picname = PRVM_G_STRING(OFS_PARM1);
-       VM_CheckEmptyString (picname);
+       VM_CheckEmptyString(prog, picname);
 
        // is pic cached ? no function yet for that
        if(!1)
        {
                PRVM_G_FLOAT(OFS_RETURN) = -4;
-               VM_Warning("VM_drawrotpic: %s: %s not cached !\n", PRVM_NAME, picname);
+               VM_Warning(prog, "VM_drawrotpic: %s: %s not cached !\n", prog->name, picname);
                return;
        }
 
@@ -3766,12 +3760,12 @@ void VM_drawrotpic(void)
        if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
        {
                PRVM_G_FLOAT(OFS_RETURN) = -2;
-               VM_Warning("VM_drawrotpic: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
+               VM_Warning(prog, "VM_drawrotpic: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
                return;
        }
 
        if(pos[2] || size[2] || org[2])
-               Con_Printf("VM_drawrotpic: z value from pos/size/org discarded\n");
+               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;
@@ -3784,7 +3778,7 @@ float     drawsubpic(vector position, vector size, string pic, vector srcPos, vector
 
 =========
 */
-void VM_drawsubpic(void)
+void VM_drawsubpic(prvm_prog_t *prog)
 {
        const char *picname;
        float *size, *pos, *rgb, *srcPos, *srcSize, alpha;
@@ -3793,13 +3787,13 @@ void VM_drawsubpic(void)
        VM_SAFEPARMCOUNT(8,VM_drawsubpic);
 
        picname = PRVM_G_STRING(OFS_PARM2);
-       VM_CheckEmptyString (picname);
+       VM_CheckEmptyString(prog, picname);
 
        // is pic cached ? no function yet for that
        if(!1)
        {
                PRVM_G_FLOAT(OFS_RETURN) = -4;
-               VM_Warning("VM_drawsubpic: %s: %s not cached !\n", PRVM_NAME, picname);
+               VM_Warning(prog, "VM_drawsubpic: %s: %s not cached !\n", prog->name, picname);
                return;
        }
 
@@ -3814,12 +3808,12 @@ void VM_drawsubpic(void)
        if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
        {
                PRVM_G_FLOAT(OFS_RETURN) = -2;
-               VM_Warning("VM_drawsubpic: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
+               VM_Warning(prog, "VM_drawsubpic: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
                return;
        }
 
        if(pos[2] || size[2])
-               Con_Printf("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")));
+               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],
@@ -3838,7 +3832,7 @@ VM_drawfill
 float drawfill(vector position, vector size, vector rgb, float alpha, float flag)
 =========
 */
-void VM_drawfill(void)
+void VM_drawfill(prvm_prog_t *prog)
 {
        float *size, *pos, *rgb;
        int flag;
@@ -3854,12 +3848,12 @@ void VM_drawfill(void)
        if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
        {
                PRVM_G_FLOAT(OFS_RETURN) = -2;
-               VM_Warning("VM_drawfill: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
+               VM_Warning(prog, "VM_drawfill: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
                return;
        }
 
        if(pos[2] || size[2])
-               Con_Printf("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")));
+               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;
@@ -3872,7 +3866,7 @@ VM_drawsetcliparea
 drawsetcliparea(float x, float y, float width, float height)
 =========
 */
-void VM_drawsetcliparea(void)
+void VM_drawsetcliparea(prvm_prog_t *prog)
 {
        float x,y,w,h;
        VM_SAFEPARMCOUNT(4,VM_drawsetcliparea);
@@ -3892,7 +3886,7 @@ VM_drawresetcliparea
 drawresetcliparea()
 =========
 */
-void VM_drawresetcliparea(void)
+void VM_drawresetcliparea(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0,VM_drawresetcliparea);
 
@@ -3906,7 +3900,7 @@ VM_getimagesize
 vector getimagesize(string pic)
 =========
 */
-void VM_getimagesize(void)
+void VM_getimagesize(prvm_prog_t *prog)
 {
        const char *p;
        cachepic_t *pic;
@@ -3914,7 +3908,7 @@ void VM_getimagesize(void)
        VM_SAFEPARMCOUNT(1,VM_getimagesize);
 
        p = PRVM_G_STRING(OFS_PARM0);
-       VM_CheckEmptyString (p);
+       VM_CheckEmptyString(prog, p);
 
        pic = Draw_CachePic_Flags (p, CACHEPICFLAG_NOTPERSISTENT);
 
@@ -3930,11 +3924,12 @@ VM_keynumtostring
 string keynumtostring(float keynum)
 =========
 */
-void VM_keynumtostring (void)
+void VM_keynumtostring (prvm_prog_t *prog)
 {
+       char tinystr[2];
        VM_SAFEPARMCOUNT(1, VM_keynumtostring);
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_KeynumToString((int)PRVM_G_FLOAT(OFS_PARM0)));
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, Key_KeynumToString((int)PRVM_G_FLOAT(OFS_PARM0), tinystr, sizeof(tinystr)));
 }
 
 /*
@@ -3948,13 +3943,14 @@ the returned string is an altstring
 */
 #define FKFC_NUMKEYS 5
 void M_FindKeysForCommand(const char *command, int *keys);
-void VM_findkeysforcommand(void)
+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);
 
@@ -3964,15 +3960,15 @@ void VM_findkeysforcommand(void)
        else
                bindmap = 0; // consistent to "bind"
 
-       VM_CheckEmptyString(cmd);
+       VM_CheckEmptyString(prog, cmd);
 
        Key_FindKeysForCommand(cmd, keys, FKFC_NUMKEYS, bindmap);
 
        ret[0] = 0;
        for(i = 0; i < FKFC_NUMKEYS; i++)
-               strlcat(ret, va(" \'%i\'", keys[i]), sizeof(ret));
+               strlcat(ret, va(vabuf, sizeof(vabuf), " \'%i\'", keys[i]), sizeof(ret));
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(ret);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, ret);
 }
 
 /*
@@ -3982,7 +3978,7 @@ VM_stringtokeynum
 float stringtokeynum(string key)
 =========
 */
-void VM_stringtokeynum (void)
+void VM_stringtokeynum (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT( 1, VM_keynumtostring );
 
@@ -3996,7 +3992,7 @@ VM_getkeybind
 string getkeybind(float key, float bindmap)
 =========
 */
-void VM_getkeybind (void)
+void VM_getkeybind (prvm_prog_t *prog)
 {
        int bindmap;
        VM_SAFEPARMCOUNTRANGE(1, 2, VM_CL_getkeybind);
@@ -4005,7 +4001,7 @@ void VM_getkeybind (void)
        else
                bindmap = 0; // consistent to "bind"
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0), bindmap));
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0), bindmap));
 }
 
 /*
@@ -4015,7 +4011,7 @@ VM_setkeybind
 float setkeybind(float key, string cmd, float bindmap)
 =========
 */
-void VM_setkeybind (void)
+void VM_setkeybind (prvm_prog_t *prog)
 {
        int bindmap;
        VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_setkeybind);
@@ -4036,7 +4032,7 @@ VM_getbindmap
 vector getbindmaps()
 =========
 */
-void VM_getbindmaps (void)
+void VM_getbindmaps (prvm_prog_t *prog)
 {
        int fg, bg;
        VM_SAFEPARMCOUNT(0, VM_CL_getbindmap);
@@ -4053,7 +4049,7 @@ VM_setbindmap
 float setbindmaps(vector bindmap)
 =========
 */
-void VM_setbindmaps (void)
+void VM_setbindmaps (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_CL_setbindmap);
        PRVM_G_FLOAT(OFS_RETURN) = 0;
@@ -4071,7 +4067,7 @@ VM_cin_open
 float cin_open(string file, string name)
 ========================
 */
-void VM_cin_open( void )
+void VM_cin_open(prvm_prog_t *prog)
 {
        const char *file;
        const char *name;
@@ -4081,8 +4077,8 @@ void VM_cin_open( void )
        file = PRVM_G_STRING( OFS_PARM0 );
        name = PRVM_G_STRING( OFS_PARM1 );
 
-       VM_CheckEmptyString( file );
-    VM_CheckEmptyString( name );
+       VM_CheckEmptyString(prog,  file );
+    VM_CheckEmptyString(prog,  name );
 
        if( CL_OpenVideo( file, name, MENUOWNER, "" ) )
                PRVM_G_FLOAT( OFS_RETURN ) = 1;
@@ -4097,14 +4093,14 @@ VM_cin_close
 void cin_close(string name)
 ========================
 */
-void VM_cin_close( void )
+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( name );
+       VM_CheckEmptyString(prog,  name );
 
        CL_CloseVideo( CL_GetVideoByName( name ) );
 }
@@ -4115,7 +4111,7 @@ VM_cin_setstate
 void cin_setstate(string name, float type)
 ========================
 */
-void VM_cin_setstate( void )
+void VM_cin_setstate(prvm_prog_t *prog)
 {
        const char *name;
        clvideostate_t  state;
@@ -4124,7 +4120,7 @@ void VM_cin_setstate( void )
        VM_SAFEPARMCOUNT( 2, VM_cin_netstate );
 
        name = PRVM_G_STRING( OFS_PARM0 );
-       VM_CheckEmptyString( name );
+       VM_CheckEmptyString(prog,  name );
 
        state = (clvideostate_t)((int)PRVM_G_FLOAT( OFS_PARM1 ));
 
@@ -4140,7 +4136,7 @@ VM_cin_getstate
 float cin_getstate(string name)
 ========================
 */
-void VM_cin_getstate( void )
+void VM_cin_getstate(prvm_prog_t *prog)
 {
        const char *name;
        clvideo_t               *video;
@@ -4148,7 +4144,7 @@ void VM_cin_getstate( void )
        VM_SAFEPARMCOUNT( 1, VM_cin_getstate );
 
        name = PRVM_G_STRING( OFS_PARM0 );
-       VM_CheckEmptyString( name );
+       VM_CheckEmptyString(prog,  name );
 
        video = CL_GetVideoByName( name );
        if( video )
@@ -4164,7 +4160,7 @@ VM_cin_restart
 void cin_restart(string name)
 ========================
 */
-void VM_cin_restart( void )
+void VM_cin_restart(prvm_prog_t *prog)
 {
        const char *name;
        clvideo_t               *video;
@@ -4172,39 +4168,13 @@ void VM_cin_restart( void )
        VM_SAFEPARMCOUNT( 1, VM_cin_restart );
 
        name = PRVM_G_STRING( OFS_PARM0 );
-       VM_CheckEmptyString( name );
+       VM_CheckEmptyString(prog,  name );
 
        video = CL_GetVideoByName( name );
        if( video )
                CL_RestartVideo( video );
 }
 
-/*
-========================
-VM_Gecko_Init
-========================
-*/
-void VM_Gecko_Init( void ) {
-       // the prog struct is memset to 0 by Initprog? [12/6/2007 Black]
-       // FIXME: remove the other _Init functions then, too? [12/6/2007 Black]
-}
-
-/*
-========================
-VM_Gecko_Destroy
-========================
-*/
-void VM_Gecko_Destroy( void ) {
-       int i;
-       for( i = 0 ; i < PRVM_MAX_GECKOINSTANCES ; i++ ) {
-               clgecko_t **instance = &prog->opengeckoinstances[ i ];
-               if( *instance ) {
-                       CL_Gecko_DestroyBrowser( *instance );
-               }
-               *instance = NULL;
-       }
-}
-
 /*
 ========================
 VM_gecko_create
@@ -4212,35 +4182,9 @@ VM_gecko_create
 float[bool] gecko_create( string name )
 ========================
 */
-void VM_gecko_create( void ) {
-       const char *name;
-       int i;
-       clgecko_t *instance;
-       
-       VM_SAFEPARMCOUNT( 1, VM_gecko_create );
-
-       name = PRVM_G_STRING( OFS_PARM0 );
-       VM_CheckEmptyString( name );
-
-       // find an empty slot for this gecko browser..
-       for( i = 0 ; i < PRVM_MAX_GECKOINSTANCES ; i++ ) {
-               if( prog->opengeckoinstances[ i ] == NULL ) {
-                       break;
-               }
-       }
-       if( i == PRVM_MAX_GECKOINSTANCES ) {
-                       VM_Warning("VM_gecko_create: %s ran out of gecko handles (%i)\n", PRVM_NAME, PRVM_MAX_GECKOINSTANCES);
-                       PRVM_G_FLOAT( OFS_RETURN ) = 0;
-                       return;
-       }
-
-       instance = prog->opengeckoinstances[ i ] = CL_Gecko_CreateBrowser( name, PRVM_GetProgNr() );
-   if( !instance ) {
-               // TODO: error handling [12/3/2007 Black]
-               PRVM_G_FLOAT( OFS_RETURN ) = 0;
-               return;
-       }
-       PRVM_G_FLOAT( OFS_RETURN ) = 1;
+void VM_gecko_create(prvm_prog_t *prog) {
+       // REMOVED
+       PRVM_G_FLOAT( OFS_RETURN ) = 0;
 }
 
 /*
@@ -4250,19 +4194,8 @@ VM_gecko_destroy
 void gecko_destroy( string name )
 ========================
 */
-void VM_gecko_destroy( void ) {
-       const char *name;
-       clgecko_t *instance;
-
-       VM_SAFEPARMCOUNT( 1, VM_gecko_destroy );
-
-       name = PRVM_G_STRING( OFS_PARM0 );
-       VM_CheckEmptyString( name );
-       instance = CL_Gecko_FindBrowser( name );
-       if( !instance ) {
-               return;
-       }
-       CL_Gecko_DestroyBrowser( instance );
+void VM_gecko_destroy(prvm_prog_t *prog) {
+       // REMOVED
 }
 
 /*
@@ -4272,23 +4205,8 @@ VM_gecko_navigate
 void gecko_navigate( string name, string URI )
 ========================
 */
-void VM_gecko_navigate( void ) {
-       const char *name;
-       const char *URI;
-       clgecko_t *instance;
-
-       VM_SAFEPARMCOUNT( 2, VM_gecko_navigate );
-
-       name = PRVM_G_STRING( OFS_PARM0 );
-       URI = PRVM_G_STRING( OFS_PARM1 );
-       VM_CheckEmptyString( name );
-       VM_CheckEmptyString( URI );
-
-   instance = CL_Gecko_FindBrowser( name );
-       if( !instance ) {
-               return;
-       }
-       CL_Gecko_NavigateToURI( instance, URI );
+void VM_gecko_navigate(prvm_prog_t *prog) {
+       // REMOVED
 }
 
 /*
@@ -4298,43 +4216,9 @@ VM_gecko_keyevent
 float[bool] gecko_keyevent( string name, float key, float eventtype ) 
 ========================
 */
-void VM_gecko_keyevent( void ) {
-       const char *name;
-       unsigned int key;
-       clgecko_buttoneventtype_t eventtype;
-       clgecko_t *instance;
-
-       VM_SAFEPARMCOUNT( 3, VM_gecko_keyevent );
-
-       name = PRVM_G_STRING( OFS_PARM0 );
-       VM_CheckEmptyString( name );
-       key = (unsigned int) PRVM_G_FLOAT( OFS_PARM1 );
-       switch( (unsigned int) PRVM_G_FLOAT( OFS_PARM2 ) ) {
-       case 0:
-               eventtype = CLG_BET_DOWN;
-               break;
-       case 1:
-               eventtype = CLG_BET_UP;
-               break;
-       case 2:
-               eventtype = CLG_BET_PRESS;
-               break;
-       case 3:
-               eventtype = CLG_BET_DOUBLECLICK;
-               break;
-       default:
-               // TODO: console printf? [12/3/2007 Black]
-               PRVM_G_FLOAT( OFS_RETURN ) = 0;
-               return;
-       }
-
-       instance = CL_Gecko_FindBrowser( name );
-       if( !instance ) {
-               PRVM_G_FLOAT( OFS_RETURN ) = 0;
-               return;
-       }
-
-       PRVM_G_FLOAT( OFS_RETURN ) = (CL_Gecko_Event_Key( instance, (keynum_t) key, eventtype ) == true);
+void VM_gecko_keyevent(prvm_prog_t *prog) {
+       // REMOVED
+       PRVM_G_FLOAT( OFS_RETURN ) = 0;
 }
 
 /*
@@ -4344,23 +4228,8 @@ VM_gecko_movemouse
 void gecko_mousemove( string name, float x, float y )
 ========================
 */
-void VM_gecko_movemouse( void ) {
-       const char *name;
-       float x, y;
-       clgecko_t *instance;
-
-       VM_SAFEPARMCOUNT( 3, VM_gecko_movemouse );
-
-       name = PRVM_G_STRING( OFS_PARM0 );
-       VM_CheckEmptyString( name );
-       x = PRVM_G_FLOAT( OFS_PARM1 );
-       y = PRVM_G_FLOAT( OFS_PARM2 );
-       
-       instance = CL_Gecko_FindBrowser( name );
-       if( !instance ) {
-               return;
-       }
-       CL_Gecko_Event_CursorMove( instance, x, y );
+void VM_gecko_movemouse(prvm_prog_t *prog) {
+       // REMOVED
 }
 
 
@@ -4371,23 +4240,8 @@ VM_gecko_resize
 void gecko_resize( string name, float w, float h )
 ========================
 */
-void VM_gecko_resize( void ) {
-       const char *name;
-       float w, h;
-       clgecko_t *instance;
-
-       VM_SAFEPARMCOUNT( 3, VM_gecko_movemouse );
-
-       name = PRVM_G_STRING( OFS_PARM0 );
-       VM_CheckEmptyString( name );
-       w = PRVM_G_FLOAT( OFS_PARM1 );
-       h = PRVM_G_FLOAT( OFS_PARM2 );
-       
-       instance = CL_Gecko_FindBrowser( name );
-       if( !instance ) {
-               return;
-       }
-       CL_Gecko_Resize( instance, (int) w, (int) h );
+void VM_gecko_resize(prvm_prog_t *prog) {
+       // REMOVED
 }
 
 
@@ -4398,24 +4252,10 @@ VM_gecko_get_texture_extent
 vector gecko_get_texture_extent( string name )
 ========================
 */
-void VM_gecko_get_texture_extent( void ) {
-       const char *name;
-       clgecko_t *instance;
-
-       VM_SAFEPARMCOUNT( 1, VM_gecko_movemouse );
-
-       name = PRVM_G_STRING( OFS_PARM0 );
-       VM_CheckEmptyString( name );
-       
-       PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
-       instance = CL_Gecko_FindBrowser( name );
-       if( !instance ) {
-               PRVM_G_VECTOR(OFS_RETURN)[0] = 0;
-               PRVM_G_VECTOR(OFS_RETURN)[1] = 0;
-               return;
-       }
-       CL_Gecko_GetTextureExtent( instance, 
-               PRVM_G_VECTOR(OFS_RETURN), PRVM_G_VECTOR(OFS_RETURN)+1 );
+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;
 }
 
 
@@ -4428,7 +4268,7 @@ Writes new values for v_forward, v_up, and v_right based on angles
 void makevectors(vector angle)
 ==============
 */
-void VM_makevectors (void)
+void VM_makevectors (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_makevectors);
        AngleVectors(PRVM_G_VECTOR(OFS_PARM0), PRVM_gameglobalvector(v_forward), PRVM_gameglobalvector(v_right), PRVM_gameglobalvector(v_up));
@@ -4442,7 +4282,7 @@ Writes new values for v_forward, v_up, and v_right based on the given forward ve
 vectorvectors(vector)
 ==============
 */
-void VM_vectorvectors (void)
+void VM_vectorvectors (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_vectorvectors);
        VectorNormalize2(PRVM_G_VECTOR(OFS_PARM0), PRVM_gameglobalvector(v_forward));
@@ -4456,7 +4296,7 @@ VM_drawline
 void drawline(float width, vector pos1, vector pos2, vector rgb, float alpha, float flags)
 ========================
 */
-void VM_drawline (void)
+void VM_drawline (prvm_prog_t *prog)
 {
        float   *c1, *c2, *rgb;
        float   alpha, width;
@@ -4473,7 +4313,7 @@ void VM_drawline (void)
 }
 
 // float(float number, float quantity) bitshift (EXT_BITSHIFT)
-void VM_bitshift (void)
+void VM_bitshift (prvm_prog_t *prog)
 {
        int n1, n2;
        VM_SAFEPARMCOUNT(2, VM_bitshift);
@@ -4500,7 +4340,7 @@ VM_altstr_count
 float altstr_count(string)
 ========================
 */
-void VM_altstr_count( void )
+void VM_altstr_count(prvm_prog_t *prog)
 {
        const char *altstr, *pos;
        int     count;
@@ -4508,7 +4348,7 @@ void VM_altstr_count( void )
        VM_SAFEPARMCOUNT( 1, VM_altstr_count );
 
        altstr = PRVM_G_STRING( OFS_PARM0 );
-       //VM_CheckEmptyString( altstr );
+       //VM_CheckEmptyString(prog,  altstr );
 
        for( count = 0, pos = altstr ; *pos ; pos++ ) {
                if( *pos == '\\' ) {
@@ -4530,7 +4370,7 @@ VM_altstr_prepare
 string altstr_prepare(string)
 ========================
 */
-void VM_altstr_prepare( void )
+void VM_altstr_prepare(prvm_prog_t *prog)
 {
        char *out;
        const char *instr, *in;
@@ -4550,7 +4390,7 @@ void VM_altstr_prepare( void )
                        *out = *in;
        *out = 0;
 
-       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( outstr );
+       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog,  outstr );
 }
 
 /*
@@ -4560,7 +4400,7 @@ VM_altstr_get
 string altstr_get(string, float)
 ========================
 */
-void VM_altstr_get( void )
+void VM_altstr_get(prvm_prog_t *prog)
 {
        const char *altstr, *pos;
        char *out;
@@ -4598,7 +4438,7 @@ void VM_altstr_get( void )
                        *out = *pos;
 
        *out = 0;
-       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( outstr );
+       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog,  outstr );
 }
 
 /*
@@ -4608,7 +4448,7 @@ VM_altstr_set
 string altstr_set(string altstr, float num, string set)
 ========================
 */
-void VM_altstr_set( void )
+void VM_altstr_set(prvm_prog_t *prog)
 {
     int num;
        const char *altstr, *str;
@@ -4642,7 +4482,7 @@ void VM_altstr_set( void )
                        break;
 
        strlcpy(out, in, outstr + sizeof(outstr) - out);
-       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( outstr );
+       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog,  outstr );
 }
 
 /*
@@ -4652,7 +4492,7 @@ insert after num
 string altstr_ins(string altstr, float num, string set)
 ========================
 */
-void VM_altstr_ins(void)
+void VM_altstr_ins(prvm_prog_t *prog)
 {
        int num;
        const char *set;
@@ -4681,7 +4521,7 @@ void VM_altstr_ins(void)
        *out++ = '\'';
 
        strlcpy(out, in, outstr + sizeof(outstr) - out);
-       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( outstr );
+       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog,  outstr );
 }
 
 
@@ -4692,7 +4532,7 @@ void VM_altstr_ins(void)
 
 static size_t stringbuffers_sortlength;
 
-static void BufStr_Expand(prvm_stringbuffer_t *stringbuffer, int strindex)
+static void BufStr_Expand(prvm_prog_t *prog, prvm_stringbuffer_t *stringbuffer, int strindex)
 {
        if (stringbuffer->max_strings <= strindex)
        {
@@ -4708,7 +4548,7 @@ static void BufStr_Expand(prvm_stringbuffer_t *stringbuffer, int strindex)
        }
 }
 
-static void BufStr_Shrink(prvm_stringbuffer_t *stringbuffer)
+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)
@@ -4748,12 +4588,12 @@ static int BufStr_SortStringsDOWN (const void *in1, const void *in2)
 ========================
 VM_buf_create
 creates new buffer, and returns it's index, returns -1 if failed
-float buf_create(void) = #460;
+float buf_create(prvm_prog_t *prog) = #460;
 float newbuf(string format, float flags) = #460;
 ========================
 */
 
-void VM_buf_create (void)
+void VM_buf_create (prvm_prog_t *prog)
 {
        prvm_stringbuffer_t *stringbuffer;
        int i;
@@ -4768,7 +4608,7 @@ void VM_buf_create (void)
        }
        stringbuffer = (prvm_stringbuffer_t *) Mem_ExpandableArray_AllocRecord(&prog->stringbuffersarray);
        for (i = 0;stringbuffer != Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);i++);
-       stringbuffer->origin = PRVM_AllocationOrigin();
+       stringbuffer->origin = PRVM_AllocationOrigin(prog);
        // optional flags parm
        if (prog->argc >= 2)
                stringbuffer->flags = (int)PRVM_G_FLOAT(OFS_PARM1) & 0xFF;
@@ -4784,7 +4624,7 @@ deletes buffer and all strings in it
 void buf_del(float bufhandle) = #461;
 ========================
 */
-void VM_buf_del (void)
+void VM_buf_del (prvm_prog_t *prog)
 {
        prvm_stringbuffer_t *stringbuffer;
        VM_SAFEPARMCOUNT(1, VM_buf_del);
@@ -4803,7 +4643,7 @@ void VM_buf_del (void)
        }
        else
        {
-               VM_Warning("VM_buf_del: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME);
+               VM_Warning(prog, "VM_buf_del: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name);
                return;
        }
 }
@@ -4815,7 +4655,7 @@ how many strings are stored in buffer
 float buf_getsize(float bufhandle) = #462;
 ========================
 */
-void VM_buf_getsize (void)
+void VM_buf_getsize (prvm_prog_t *prog)
 {
        prvm_stringbuffer_t *stringbuffer;
        VM_SAFEPARMCOUNT(1, VM_buf_getsize);
@@ -4824,7 +4664,7 @@ void VM_buf_getsize (void)
        if(!stringbuffer)
        {
                PRVM_G_FLOAT(OFS_RETURN) = -1;
-               VM_Warning("VM_buf_getsize: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME);
+               VM_Warning(prog, "VM_buf_getsize: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name);
                return;
        }
        else
@@ -4838,7 +4678,7 @@ 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 (void)
+void VM_buf_copy (prvm_prog_t *prog)
 {
        prvm_stringbuffer_t *srcstringbuffer, *dststringbuffer;
        int i;
@@ -4847,19 +4687,19 @@ void VM_buf_copy (void)
        srcstringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0));
        if(!srcstringbuffer)
        {
-               VM_Warning("VM_buf_copy: invalid source buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME);
+               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("VM_buf_copy: source == destination (%i) in %s\n", i, PRVM_NAME);
+               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("VM_buf_copy: invalid destination buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM1), PRVM_NAME);
+               VM_Warning(prog, "VM_buf_copy: invalid destination buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM1), prog->name);
                return;
        }
 
@@ -4892,7 +4732,7 @@ sort buffer by beginnings of strings (cmplength defaults it's length)
 void buf_sort(float bufhandle, float cmplength, float backward) = #464;
 ========================
 */
-void VM_buf_sort (void)
+void VM_buf_sort (prvm_prog_t *prog)
 {
        prvm_stringbuffer_t *stringbuffer;
        VM_SAFEPARMCOUNT(3, VM_buf_sort);
@@ -4900,12 +4740,12 @@ void VM_buf_sort (void)
        stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0));
        if(!stringbuffer)
        {
-               VM_Warning("VM_buf_sort: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME);
+               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("VM_buf_sort: tried to sort empty buffer %i in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME);
+               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);
@@ -4917,7 +4757,7 @@ void VM_buf_sort (void)
        else
                qsort(stringbuffer->strings, stringbuffer->num_strings, sizeof(char*), BufStr_SortStringsDOWN);
 
-       BufStr_Shrink(stringbuffer);
+       BufStr_Shrink(prog, stringbuffer);
 }
 
 /*
@@ -4927,7 +4767,7 @@ concantenates all buffer string into one with "glue" separator and returns it as
 string buf_implode(float bufhandle, string glue) = #465;
 ========================
 */
-void VM_buf_implode (void)
+void VM_buf_implode (prvm_prog_t *prog)
 {
        prvm_stringbuffer_t *stringbuffer;
        char                    k[VM_STRINGTEMP_LENGTH];
@@ -4940,7 +4780,7 @@ void VM_buf_implode (void)
        PRVM_G_INT(OFS_RETURN) = OFS_NULL;
        if(!stringbuffer)
        {
-               VM_Warning("VM_buf_implode: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME);
+               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)
@@ -4958,7 +4798,7 @@ void VM_buf_implode (void)
                        strlcat(k, stringbuffer->strings[i], sizeof(k));
                }
        }
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(k);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, k);
 }
 
 /*
@@ -4968,7 +4808,7 @@ get a string from buffer, returns tempstring, dont str_unzone it!
 string bufstr_get(float bufhandle, float string_index) = #465;
 ========================
 */
-void VM_bufstr_get (void)
+void VM_bufstr_get (prvm_prog_t *prog)
 {
        prvm_stringbuffer_t *stringbuffer;
        int                             strindex;
@@ -4978,17 +4818,17 @@ void VM_bufstr_get (void)
        stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0));
        if(!stringbuffer)
        {
-               VM_Warning("VM_bufstr_get: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME);
+               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("VM_bufstr_get: invalid string index %i used in %s\n", strindex, PRVM_NAME);
+               // 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(stringbuffer->strings[strindex]);
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, stringbuffer->strings[strindex]);
 }
 
 /*
@@ -4998,7 +4838,7 @@ copies a string into selected slot of buffer
 void bufstr_set(float bufhandle, float string_index, string str) = #466;
 ========================
 */
-void VM_bufstr_set (void)
+void VM_bufstr_set (prvm_prog_t *prog)
 {
        size_t alloclen;
        int                             strindex;
@@ -5010,17 +4850,17 @@ void VM_bufstr_set (void)
        stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0));
        if(!stringbuffer)
        {
-               VM_Warning("VM_bufstr_set: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME);
+               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("VM_bufstr_set: invalid string index %i used in %s\n", strindex, PRVM_NAME);
+               VM_Warning(prog, "VM_bufstr_set: invalid string index %i used in %s\n", strindex, prog->name);
                return;
        }
 
-       BufStr_Expand(stringbuffer, strindex);
+       BufStr_Expand(prog, stringbuffer, strindex);
        stringbuffer->num_strings = max(stringbuffer->num_strings, strindex + 1);
 
        if(stringbuffer->strings[strindex])
@@ -5036,7 +4876,7 @@ void VM_bufstr_set (void)
                memcpy(stringbuffer->strings[strindex], news, alloclen);
        }
 
-       BufStr_Shrink(stringbuffer);
+       BufStr_Shrink(prog, stringbuffer);
 }
 
 /*
@@ -5047,7 +4887,7 @@ adds string to buffer in first free slot and returns its index
 float bufstr_add(float bufhandle, string str, float order) = #467;
 ========================
 */
-void VM_bufstr_add (void)
+void VM_bufstr_add (prvm_prog_t *prog)
 {
        int                             order, strindex;
        prvm_stringbuffer_t *stringbuffer;
@@ -5060,12 +4900,12 @@ void VM_bufstr_add (void)
        PRVM_G_FLOAT(OFS_RETURN) = -1;
        if(!stringbuffer)
        {
-               VM_Warning("VM_bufstr_add: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME);
+               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("VM_bufstr_add: can not add an empty string to buffer %i in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME);
+               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);
@@ -5077,7 +4917,7 @@ void VM_bufstr_add (void)
                        if (stringbuffer->strings[strindex] == NULL)
                                break;
 
-       BufStr_Expand(stringbuffer, strindex);
+       BufStr_Expand(prog, stringbuffer, strindex);
 
        stringbuffer->num_strings = max(stringbuffer->num_strings, strindex + 1);
        alloclen = strlen(string) + 1;
@@ -5094,7 +4934,7 @@ delete string from buffer
 void bufstr_free(float bufhandle, float string_index) = #468;
 ========================
 */
-void VM_bufstr_free (void)
+void VM_bufstr_free (prvm_prog_t *prog)
 {
        int                             i;
        prvm_stringbuffer_t     *stringbuffer;
@@ -5103,13 +4943,13 @@ void VM_bufstr_free (void)
        stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0));
        if(!stringbuffer)
        {
-               VM_Warning("VM_bufstr_free: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME);
+               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("VM_bufstr_free: invalid string index %i used in %s\n", i, PRVM_NAME);
+               VM_Warning(prog, "VM_bufstr_free: invalid string index %i used in %s\n", i, prog->name);
                return;
        }
 
@@ -5120,7 +4960,7 @@ void VM_bufstr_free (void)
                stringbuffer->strings[i] = NULL;
        }
 
-       BufStr_Shrink(stringbuffer);
+       BufStr_Shrink(prog, stringbuffer);
 }
 
 
@@ -5129,7 +4969,7 @@ void VM_bufstr_free (void)
 
 
 
-void VM_buf_cvarlist(void)
+void VM_buf_cvarlist(prvm_prog_t *prog)
 {
        cvar_t *cvar;
        const char *partial, *antipartial;
@@ -5143,7 +4983,7 @@ void VM_buf_cvarlist(void)
        stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0));
        if(!stringbuffer)
        {
-               VM_Warning("VM_bufstr_free: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME);
+               VM_Warning(prog, "VM_bufstr_free: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name);
                return;
        }
 
@@ -5217,24 +5057,24 @@ VM_changeyaw
 This was a major timewaster in progs, so it was converted to C
 ==============
 */
-void VM_changeyaw (void)
+void VM_changeyaw (prvm_prog_t *prog)
 {
        prvm_edict_t            *ent;
        float           ideal, current, move, speed;
 
-       // this is called (VERY HACKISHLY) by SV_MoveToGoal, so it can not use any
-       // parameters because they are the parameters to SV_MoveToGoal, not this
+       // 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("changeyaw: can not modify world entity\n");
+               VM_Warning(prog, "changeyaw: can not modify world entity\n");
                return;
        }
        if (ent->priv.server->free)
        {
-               VM_Warning("changeyaw: can not modify free entity\n");
+               VM_Warning(prog, "changeyaw: can not modify free entity\n");
                return;
        }
        current = PRVM_gameedictvector(ent, angles)[1];
@@ -5275,7 +5115,7 @@ void VM_changeyaw (void)
 VM_changepitch
 ==============
 */
-void VM_changepitch (void)
+void VM_changepitch (prvm_prog_t *prog)
 {
        prvm_edict_t            *ent;
        float           ideal, current, move, speed;
@@ -5285,12 +5125,12 @@ void VM_changepitch (void)
        ent = PRVM_G_EDICT(OFS_PARM0);
        if (ent == prog->edicts)
        {
-               VM_Warning("changepitch: can not modify world entity\n");
+               VM_Warning(prog, "changepitch: can not modify world entity\n");
                return;
        }
        if (ent->priv.server->free)
        {
-               VM_Warning("changepitch: can not modify free entity\n");
+               VM_Warning(prog, "changepitch: can not modify free entity\n");
                return;
        }
        current = PRVM_gameedictvector(ent, angles)[0];
@@ -5327,7 +5167,7 @@ void VM_changepitch (void)
 }
 
 
-void VM_uncolorstring (void)
+void VM_uncolorstring (prvm_prog_t *prog)
 {
        char szNewString[VM_STRINGTEMP_LENGTH];
        const char *szString;
@@ -5336,13 +5176,13 @@ void VM_uncolorstring (void)
        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(szNewString);
+       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 (void)
+void VM_strstrofs (prvm_prog_t *prog)
 {
        const char *instr, *match;
        int firstofs;
@@ -5366,7 +5206,7 @@ void VM_strstrofs (void)
 }
 
 //#222 string(string s, float index) str2chr (FTE_STRINGS)
-void VM_str2chr (void)
+void VM_str2chr (prvm_prog_t *prog)
 {
        const char *s;
        Uchar ch;
@@ -5388,7 +5228,7 @@ void VM_str2chr (void)
 }
 
 //#223 string(float c, ...) chr2str (FTE_STRINGS)
-void VM_chr2str (void)
+void VM_chr2str (prvm_prog_t *prog)
 {
        /*
        char    t[9];
@@ -5397,7 +5237,7 @@ void VM_chr2str (void)
        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(t);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, t);
        */
        char t[9 * 4 + 1];
        int i;
@@ -5406,7 +5246,7 @@ void VM_chr2str (void)
        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(t);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, t);
 }
 
 static int chrconv_number(int i, int base, int conv)
@@ -5491,7 +5331,7 @@ static int chrchar_alpha(int i, int basec, int baset, int convc, int convt, int
 }
 // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
 //bulk convert a string. change case or colouring.
-void VM_strconv (void)
+void VM_strconv (prvm_prog_t *prog)
 {
        int ccase, redalpha, rednum, len, i;
        unsigned char resbuf[VM_STRINGTEMP_LENGTH];
@@ -5502,7 +5342,7 @@ void VM_strconv (void)
        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(3, (char *) resbuf, sizeof(resbuf));
+       VM_VarString(prog, 3, (char *) resbuf, sizeof(resbuf));
        len = strlen((char *) resbuf);
 
        for (i = 0; i < len; i++, result++)     //should this be done backwards?
@@ -5534,29 +5374,29 @@ void VM_strconv (void)
        }
        *result = '\0';
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString((char *) resbuf);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, (char *) resbuf);
 }
 
 // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
-void VM_strpad (void)
+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(1, src, sizeof(src));
+       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(destbuf);
+       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 (void)
+void VM_infoadd (prvm_prog_t *prog)
 {
        const char *info, *key;
        char value[VM_STRINGTEMP_LENGTH];
@@ -5565,18 +5405,18 @@ void VM_infoadd (void)
        VM_SAFEPARMCOUNTRANGE(2, 8, VM_infoadd);
        info = PRVM_G_STRING(OFS_PARM0);
        key = PRVM_G_STRING(OFS_PARM1);
-       VM_VarString(2, value, sizeof(value));
+       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(temp);
+       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 (void)
+void VM_infoget (prvm_prog_t *prog)
 {
        const char *info;
        const char *key;
@@ -5588,12 +5428,12 @@ void VM_infoget (void)
 
        InfoString_GetValue(info, key, value, VM_STRINGTEMP_LENGTH);
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(value);
+       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 (void)
+void VM_strncmp (prvm_prog_t *prog)
 {
        const char *s1, *s2;
        VM_SAFEPARMCOUNTRANGE(2, 3, VM_strncmp);
@@ -5611,7 +5451,7 @@ void VM_strncmp (void)
 
 // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
 // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
-void VM_strncasecmp (void)
+void VM_strncasecmp (prvm_prog_t *prog)
 {
        const char *s1, *s2;
        VM_SAFEPARMCOUNTRANGE(2, 3, VM_strncasecmp);
@@ -5628,23 +5468,72 @@ void VM_strncasecmp (void)
 }
 
 // #494 float(float caseinsensitive, string s, ...) crc16
-void VM_crc16(void)
+void VM_crc16(prvm_prog_t *prog)
 {
        float insensitive;
-       static char s[VM_STRINGTEMP_LENGTH];
-       VM_SAFEPARMCOUNTRANGE(2, 8, VM_hash);
+       char s[VM_STRINGTEMP_LENGTH];
+       VM_SAFEPARMCOUNTRANGE(2, 8, VM_crc16);
        insensitive = PRVM_G_FLOAT(OFS_PARM0);
-       VM_VarString(1, s, sizeof(s));
+       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)));
 }
 
-void VM_wasfreed (void)
+// #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(const trace_t *trace)
+void VM_SetTraceGlobals(prvm_prog_t *prog, const trace_t *trace)
 {
        PRVM_gameglobalfloat(trace_allsolid) = trace->allsolid;
        PRVM_gameglobalfloat(trace_startsolid) = trace->startsolid;
@@ -5658,10 +5547,10 @@ void VM_SetTraceGlobals(const trace_t *trace)
        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(trace->hittexture->name) : 0;
+       PRVM_gameglobalstring(trace_dphittexturename) = trace->hittexture ? PRVM_SetTempString(prog, trace->hittexture->name) : 0;
 }
 
-void VM_ClearTraceGlobals(void)
+void VM_ClearTraceGlobals(prvm_prog_t *prog)
 {
        // clean up all trace globals when leaving the VM (anti-triggerbot safeguard)
        PRVM_gameglobalfloat(trace_allsolid) = 0;
@@ -5681,27 +5570,23 @@ void VM_ClearTraceGlobals(void)
 
 //=============
 
-void VM_Cmd_Init(void)
+void VM_Cmd_Init(prvm_prog_t *prog)
 {
        // only init the stuff for the current prog
-       VM_Files_Init();
-       VM_Search_Init();
-       VM_Gecko_Init();
-//     VM_BufStr_Init();
+       VM_Files_Init(prog);
+       VM_Search_Init(prog);
 }
 
-void VM_Cmd_Reset(void)
+void VM_Cmd_Reset(prvm_prog_t *prog)
 {
        CL_PurgeOwner( MENUOWNER );
-       VM_Search_Reset();
-       VM_Files_CloseAll();
-       VM_Gecko_Destroy();
-//     VM_BufStr_ShutDown();
+       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 (void)
+void VM_uri_escape (prvm_prog_t *prog)
 {
        char src[VM_STRINGTEMP_LENGTH];
        char dest[VM_STRINGTEMP_LENGTH];
@@ -5709,7 +5594,7 @@ void VM_uri_escape (void)
        static const char *hex = "0123456789ABCDEF";
 
        VM_SAFEPARMCOUNTRANGE(1, 8, VM_uri_escape);
-       VM_VarString(0, src, sizeof(src));
+       VM_VarString(prog, 0, src, sizeof(src));
 
        for(p = src, q = dest; *p && q < dest + sizeof(dest) - 3; ++p)
        {
@@ -5729,12 +5614,12 @@ void VM_uri_escape (void)
        }
        *q++ = 0;
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(dest);
+       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 (void)
+void VM_uri_unescape (prvm_prog_t *prog)
 {
        char src[VM_STRINGTEMP_LENGTH];
        char dest[VM_STRINGTEMP_LENGTH];
@@ -5742,7 +5627,7 @@ void VM_uri_unescape (void)
        int hi, lo;
 
        VM_SAFEPARMCOUNTRANGE(1, 8, VM_uri_unescape);
-       VM_VarString(0, src, sizeof(src));
+       VM_VarString(prog, 0, src, sizeof(src));
 
        for(p = src, q = dest; *p; ) // no need to check size, because unescape can't expand
        {
@@ -5776,12 +5661,12 @@ nohex:
        }
        *q++ = 0;
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(dest);
+       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 (void)
+void VM_whichpack (prvm_prog_t *prog)
 {
        const char *fn, *pack;
 
@@ -5789,12 +5674,12 @@ void VM_whichpack (void)
        fn = PRVM_G_STRING(OFS_PARM0);
        pack = FS_WhichPack(fn);
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(pack ? pack : "");
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, pack ? pack : "");
 }
 
 typedef struct
 {
-       int prognr;
+       prvm_prog_t *prog;
        double starttime;
        float id;
        char buffer[MAX_INPUTLINE];
@@ -5807,9 +5692,11 @@ 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;
 
-       if(!PRVM_ProgLoaded(handle->prognr))
+       prog = handle->prog;
+       if(!prog->loaded)
        {
                // curl reply came too late... so just drop it
                if(handle->postdata)
@@ -5819,22 +5706,19 @@ static void uri_to_string_callback(int status, size_t length_received, unsigned
                Z_Free(handle);
                return;
        }
-               
-       PRVM_SetProg(handle->prognr);
-       PRVM_Begin;
-               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(handle->buffer);
-                       PRVM_ExecuteProgram(PRVM_allfunction(URI_Get_Callback), "QC function URI_Get_Callback is missing");
-               }
-       PRVM_End;
-       
+
+       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)
@@ -5844,7 +5728,7 @@ static void uri_to_string_callback(int status, size_t length_received, unsigned
 
 // 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 (void)
+void VM_uri_get (prvm_prog_t *prog)
 {
        const char *url;
        float id;
@@ -5858,7 +5742,7 @@ void VM_uri_get (void)
        size_t lq;
 
        if(!PRVM_allfunction(URI_Get_Callback))
-               PRVM_ERROR("uri_get called by %s without URI_Get_Callback defined", PRVM_NAME);
+               prog->error_cmd("uri_get called by %s without URI_Get_Callback defined", prog->name);
 
        VM_SAFEPARMCOUNTRANGE(2, 6, VM_uri_get);
 
@@ -5879,10 +5763,10 @@ void VM_uri_get (void)
                ++query_string;
        lq = query_string ? strlen(query_string) : 0;
 
-       handle->prognr = PRVM_GetProgNr();
+       handle->prog = prog;
        handle->starttime = prog->starttime;
        handle->id = id;
-       if(postseparator)
+       if(postseparator && posttype && *posttype)
        {
                size_t l = strlen(postseparator);
                if(poststringbuffer >= 0)
@@ -5894,7 +5778,7 @@ void VM_uri_get (void)
                        stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, poststringbuffer);
                        if(!stringbuffer)
                        {
-                               VM_Warning("uri_get: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME);
+                               VM_Warning(prog, "uri_get: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name);
                                return;
                        }
                        ltotal = 0;
@@ -5922,7 +5806,7 @@ void VM_uri_get (void)
                                }
                        }
                        if(ltotal != handle->postlen)
-                               PRVM_ERROR ("%s: string buffer content size mismatch, possible overrun", PRVM_NAME);
+                               prog->error_cmd("%s: string buffer content size mismatch, possible overrun", prog->name);
                }
                else
                {
@@ -6006,7 +5890,7 @@ out2:
        }
 }
 
-void VM_netaddress_resolve (void)
+void VM_netaddress_resolve (prvm_prog_t *prog)
 {
        const char *ip;
        char normalized[128];
@@ -6021,13 +5905,13 @@ void VM_netaddress_resolve (void)
                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(normalized);
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, normalized);
        else
-               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString("");
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "");
 }
 
-//string(void) getextresponse = #624; // returns the next extResponse packet that was sent to this client
-void VM_CL_getextresponse (void)
+//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);
 
@@ -6038,11 +5922,11 @@ void VM_CL_getextresponse (void)
                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(cl_net_extresponse[first]);
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, cl_net_extresponse[first]);
        }
 }
 
-void VM_SV_getextresponse (void)
+void VM_SV_getextresponse (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0,VM_argv);
 
@@ -6053,7 +5937,7 @@ void VM_SV_getextresponse (void)
                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(sv_net_extresponse[first]);
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, sv_net_extresponse[first]);
        }
 }
 
@@ -6064,14 +5948,14 @@ Common functions between menu.dat and clsprogs
 */
 
 //#349 float() isdemo 
-void VM_CL_isdemo (void)
+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 (void)
+void VM_CL_videoplaying (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(0, VM_CL_videoplaying);
        PRVM_G_FLOAT(OFS_RETURN) = cl_videoplaying;
@@ -6085,8 +5969,7 @@ VM_M_callfunction
 Extension: pass
 =========
 */
-mfunction_t *PRVM_ED_FindFunction (const char *name);
-void VM_callfunction(void)
+void VM_callfunction(prvm_prog_t *prog)
 {
        mfunction_t *func;
        const char *s;
@@ -6095,26 +5978,26 @@ void VM_callfunction(void)
 
        s = PRVM_G_STRING(OFS_PARM0+(prog->argc - 1)*3);
 
-       VM_CheckEmptyString(s);
+       VM_CheckEmptyString(prog, s);
 
-       func = PRVM_ED_FindFunction(s);
+       func = PRVM_ED_FindFunction(prog, s);
 
        if(!func)
-               PRVM_ERROR("VM_callfunciton: function %s not found !", s);
+               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->builtins[builtinnumber](prog);
                else
-                       PRVM_ERROR("No such builtin #%i in %s; most likely cause: outdated engine build. Try updating!", builtinnumber, PRVM_NAME);
+                       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--;
-               PRVM_ExecuteProgram(func - prog->functions,"");
+               prog->ExecuteProgram(prog, func - prog->functions,"");
                prog->argc++;
        }
 }
@@ -6126,8 +6009,7 @@ VM_isfunction
 float  isfunction(string function_name)
 =========
 */
-mfunction_t *PRVM_ED_FindFunction (const char *name);
-void VM_isfunction(void)
+void VM_isfunction(prvm_prog_t *prog)
 {
        mfunction_t *func;
        const char *s;
@@ -6136,9 +6018,9 @@ void VM_isfunction(void)
 
        s = PRVM_G_STRING(OFS_PARM0);
 
-       VM_CheckEmptyString(s);
+       VM_CheckEmptyString(prog, s);
 
-       func = PRVM_ED_FindFunction(s);
+       func = PRVM_ED_FindFunction(prog, s);
 
        if(!func)
                PRVM_G_FLOAT(OFS_RETURN) = false;
@@ -6154,7 +6036,7 @@ string sprintf(string format, ...)
 =========
 */
 
-void VM_sprintf(void)
+void VM_sprintf(prvm_prog_t *prog)
 {
        const char *s, *s0;
        char outbuf[MAX_INPUTLINE];
@@ -6166,6 +6048,7 @@ void VM_sprintf(void)
        int isfloat;
        static int dummyivec[3] = {0, 0, 0};
        static float dummyvec[3] = {0, 0, 0};
+       char vabuf[1024];
 
 #define PRINTF_ALTERNATE 1
 #define PRINTF_ZEROPAD 2
@@ -6211,7 +6094,7 @@ void VM_sprintf(void)
                                        width = strtol(s, &err, 10);
                                        if(!err)
                                        {
-                                               VM_Warning("VM_sprintf: invalid directive in %s: %s\n", PRVM_NAME, s0);
+                                               VM_Warning(prog, "VM_sprintf: invalid directive in %s: %s\n", prog->name, s0);
                                                goto finished;
                                        }
                                        if(*err == '$')
@@ -6257,7 +6140,7 @@ noflags:
                                                        width = strtol(s, &err, 10);
                                                        if(!err || *err != '$')
                                                        {
-                                                               VM_Warning("VM_sprintf: invalid directive in %s: %s\n", PRVM_NAME, s0);
+                                                               VM_Warning(prog, "VM_sprintf: invalid directive in %s: %s\n", prog->name, s0);
                                                                goto finished;
                                                        }
                                                        s = err + 1;
@@ -6276,7 +6159,7 @@ noflags:
                                                width = strtol(s, &err, 10);
                                                if(!err)
                                                {
-                                                       VM_Warning("VM_sprintf: invalid directive in %s: %s\n", PRVM_NAME, s0);
+                                                       VM_Warning(prog, "VM_sprintf: invalid directive in %s: %s\n", prog->name, s0);
                                                        goto finished;
                                                }
                                                s = err;
@@ -6300,7 +6183,7 @@ noflags:
                                                        precision = strtol(s, &err, 10);
                                                        if(!err || *err != '$')
                                                        {
-                                                               VM_Warning("VM_sprintf: invalid directive in %s: %s\n", PRVM_NAME, s0);
+                                                               VM_Warning(prog, "VM_sprintf: invalid directive in %s: %s\n", prog->name, s0);
                                                                goto finished;
                                                        }
                                                        s = err + 1;
@@ -6314,14 +6197,14 @@ noflags:
                                                precision = strtol(s, &err, 10);
                                                if(!err)
                                                {
-                                                       VM_Warning("VM_sprintf: invalid directive in %s: %s\n", PRVM_NAME, s0);
+                                                       VM_Warning(prog, "VM_sprintf: invalid directive in %s: %s\n", prog->name, s0);
                                                        goto finished;
                                                }
                                                s = err;
                                        }
                                        else
                                        {
-                                               VM_Warning("VM_sprintf: invalid directive in %s: %s\n", PRVM_NAME, s0);
+                                               VM_Warning(prog, "VM_sprintf: invalid directive in %s: %s\n", prog->name, s0);
                                                goto finished;
                                        }
                                }
@@ -6399,13 +6282,13 @@ nolength:
                                                case 'v': case 'V':
                                                        f[-2] += 'g' - 'v';
                                                        if(precision < 0) // not set
-                                                               o += dpsnprintf(o, end - o, va("%s %s %s", /* NESTED SPRINTF IS NESTED */ formatbuf, formatbuf, formatbuf),
+                                                               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("%s %s %s", /* NESTED SPRINTF IS NESTED */ formatbuf, formatbuf, formatbuf),
+                                                               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])
@@ -6422,7 +6305,8 @@ nolength:
                                                        else
                                                        {
                                                                unsigned int c = (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg));
-                                                               const char *buf = u8_encodech(c, NULL);
+                                                               char charbuf16[16];
+                                                               const char *buf = u8_encodech(c, NULL, charbuf16);
                                                                if(!buf)
                                                                        buf = "";
                                                                if(precision < 0) // not set
@@ -6446,7 +6330,7 @@ nolength:
                                                        }
                                                        break;
                                                default:
-                                                       VM_Warning("VM_sprintf: invalid directive in %s: %s\n", PRVM_NAME, s0);
+                                                       VM_Warning(prog, "VM_sprintf: invalid directive in %s: %s\n", prog->name, s0);
                                                        goto finished;
                                        }
                                }
@@ -6461,23 +6345,20 @@ verbatim:
        }
 finished:
        *o = 0;
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(outbuf);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, outbuf);
 }
 
 
 // surface querying
 
-static dp_model_t *getmodel(prvm_edict_t *ed)
+static dp_model_t *getmodel(prvm_prog_t *prog, prvm_edict_t *ed)
 {
-       switch(PRVM_GetProgNr())
-       {
-               case PRVM_SERVERPROG:
-                       return SV_GetModelFromEdict(ed);
-               case PRVM_CLIENTPROG:
-                       return CL_GetModelFromEdict(ed);
-               default:
-                       return NULL;
-       }
+       if (prog == SVVM_prog)
+               return SV_GetModelFromEdict(ed);
+       else if (prog == CLVM_prog)
+               return CL_GetModelFromEdict(ed);
+       else
+               return NULL;
 }
 
 typedef struct
@@ -6500,7 +6381,7 @@ typedef struct
 animatemodel_cache_t;
 static animatemodel_cache_t animatemodel_cache;
 
-void animatemodel(dp_model_t *model, prvm_edict_t *ed)
+static void animatemodel(prvm_prog_t *prog, dp_model_t *model, prvm_edict_t *ed)
 {
        skeleton_t *skeleton;
        int skeletonindex = -1;
@@ -6516,7 +6397,7 @@ void animatemodel(dp_model_t *model, prvm_edict_t *ed)
        if(animatemodel_cache.progid != prog->id)
                memset(&animatemodel_cache, 0, sizeof(animatemodel_cache));
        need |= (animatemodel_cache.model != model);
-       VM_GenerateFrameGroupBlend(ed->priv.server->framegroupblend, ed);
+       VM_GenerateFrameGroupBlend(prog, ed->priv.server->framegroupblend, ed);
        VM_FrameBlendFromFrameGroupBlend(ed->priv.server->frameblend, ed->priv.server->framegroupblend, model);
        need |= (memcmp(&animatemodel_cache.frameblend, &ed->priv.server->frameblend, sizeof(ed->priv.server->frameblend))) != 0;
        skeletonindex = (int)PRVM_gameedictfloat(ed, skeletonindex) - 1;
@@ -6543,7 +6424,7 @@ void animatemodel(dp_model_t *model, prvm_edict_t *ed)
        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(ed, model, ed->priv.server->frameblend);
+       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;
@@ -6553,59 +6434,53 @@ void animatemodel(dp_model_t *model, prvm_edict_t *ed)
                memcpy(&animatemodel_cache.skeleton, skeleton, sizeof(ed->priv.server->skeleton));
 }
 
-static void getmatrix(prvm_edict_t *ed, matrix4x4_t *out)
+static void getmatrix(prvm_prog_t *prog, prvm_edict_t *ed, matrix4x4_t *out)
 {
-       switch(PRVM_GetProgNr())
-       {
-               case PRVM_SERVERPROG:
-                       SV_GetEntityMatrix(ed, out, false);
-                       break;
-               case PRVM_CLIENTPROG:
-                       CL_GetEntityMatrix(ed, out, false);
-                       break;
-               default:
-                       *out = identitymatrix;
-                       break;
-       }
+       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(const vec3_t in, prvm_edict_t *ed, vec3_t out)
+static void applytransform_forward(prvm_prog_t *prog, const vec3_t in, prvm_edict_t *ed, vec3_t out)
 {
        matrix4x4_t m;
-       getmatrix(ed, &m);
+       getmatrix(prog, ed, &m);
        Matrix4x4_Transform(&m, in, out);
 }
 
-static void applytransform_forward_direction(const vec3_t in, prvm_edict_t *ed, vec3_t 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(ed, &m);
+       getmatrix(prog, ed, &m);
        Matrix4x4_Transform3x3(&m, in, out);
 }
 
-static void applytransform_inverted(const vec3_t in, prvm_edict_t *ed, vec3_t 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(ed, &m);
+       getmatrix(prog, ed, &m);
        Matrix4x4_Invert_Full(&n, &m);
        Matrix4x4_Transform3x3(&n, in, out);
 }
 
-static void applytransform_forward_normal(const vec3_t in, prvm_edict_t *ed, vec3_t 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(ed, &m);
+       getmatrix(prog, ed, &m);
        Matrix4x4_TransformPositivePlane(&m, in[0], in[1], in[2], 0, p);
        VectorCopy(p, out);
 }
 
-static void clippointtosurface(prvm_edict_t *ed, dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t 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(model, ed);
+       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)
@@ -6646,13 +6521,13 @@ static msurface_t *getsurface(dp_model_t *model, int surfacenum)
 
 
 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
-void VM_getsurfacenumpoints(void)
+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(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
+       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;
@@ -6662,7 +6537,7 @@ void VM_getsurfacenumpoints(void)
        PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
 }
 //PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
-void VM_getsurfacepoint(void)
+void VM_getsurfacepoint(prvm_prog_t *prog)
 {
        prvm_edict_t *ed;
        dp_model_t *model;
@@ -6671,14 +6546,14 @@ void VM_getsurfacepoint(void)
        VM_SAFEPARMCOUNT(3, VM_getsurfacepoint);
        VectorClear(PRVM_G_VECTOR(OFS_RETURN));
        ed = PRVM_G_EDICT(OFS_PARM0);
-       if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
+       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(model, ed);
-       applytransform_forward(&(animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
+       animatemodel(prog, model, ed);
+       applytransform_forward(prog, &(animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
 }
 //PF_getsurfacepointattribute,     // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
 // float SPA_POSITION = 0;
@@ -6688,7 +6563,7 @@ void VM_getsurfacepoint(void)
 // float SPA_TEXCOORDS0 = 4;
 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
 // float SPA_LIGHTMAP0_COLOR = 6;
-void VM_getsurfacepointattribute(void)
+void VM_getsurfacepointattribute(prvm_prog_t *prog)
 {
        prvm_edict_t *ed;
        dp_model_t *model;
@@ -6699,31 +6574,31 @@ void VM_getsurfacepointattribute(void)
        VM_SAFEPARMCOUNT(4, VM_getsurfacepoint);
        VectorClear(PRVM_G_VECTOR(OFS_RETURN));
        ed = PRVM_G_EDICT(OFS_PARM0);
-       if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
+       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(model, ed);
+       animatemodel(prog, model, ed);
 
        switch( attributetype ) {
                // float SPA_POSITION = 0;
                case 0:
-                       applytransform_forward(&(animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
+                       applytransform_forward(prog, &(animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
                        break;
                // float SPA_S_AXIS = 1;
                case 1:
-                       applytransform_forward_direction(&(animatemodel_cache.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
+                       applytransform_forward_direction(prog, &(animatemodel_cache.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
                        break;
                // float SPA_T_AXIS = 2;
                case 2:
-                       applytransform_forward_direction(&(animatemodel_cache.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
+                       applytransform_forward_direction(prog, &(animatemodel_cache.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
                        break;
                // float SPA_R_AXIS = 3; // same as SPA_NORMAL
                case 3:
-                       applytransform_forward_direction(&(animatemodel_cache.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
+                       applytransform_forward_direction(prog, &(animatemodel_cache.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
                        break;
                // float SPA_TEXCOORDS0 = 4;
                case 4: {
@@ -6754,35 +6629,35 @@ void VM_getsurfacepointattribute(void)
        }
 }
 //PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
-void VM_getsurfacenormal(void)
+void VM_getsurfacenormal(prvm_prog_t *prog)
 {
        dp_model_t *model;
        msurface_t *surface;
        vec3_t normal;
        VM_SAFEPARMCOUNT(2, VM_getsurfacenormal);
        VectorClear(PRVM_G_VECTOR(OFS_RETURN));
-       if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
+       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(model, PRVM_G_EDICT(OFS_PARM0));
+       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(normal, PRVM_G_EDICT(OFS_PARM0), PRVM_G_VECTOR(OFS_RETURN));
+       applytransform_forward_normal(prog, normal, PRVM_G_EDICT(OFS_PARM0), PRVM_G_VECTOR(OFS_RETURN));
        VectorNormalize(PRVM_G_VECTOR(OFS_RETURN));
 }
 //PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
-void VM_getsurfacetexture(void)
+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(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
+       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(surface->texture->name);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, surface->texture->name);
 }
 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
-void VM_getsurfacenearpoint(void)
+void VM_getsurfacenearpoint(prvm_prog_t *prog)
 {
        int surfacenum, best;
        vec3_t clipped, p;
@@ -6798,13 +6673,13 @@ void VM_getsurfacenearpoint(void)
 
        if (!ed || ed->priv.server->free)
                return;
-       model = getmodel(ed);
+       model = getmodel(prog, ed);
        if (!model || !model->num_surfaces)
                return;
 
-       animatemodel(model, ed);
+       animatemodel(prog, model, ed);
 
-       applytransform_inverted(point, ed, p);
+       applytransform_inverted(prog, point, ed, p);
        best = -1;
        bestdist = 1000000000;
        for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
@@ -6818,7 +6693,7 @@ void VM_getsurfacenearpoint(void)
                if (dist < bestdist)
                {
                        // it is, check the nearest point on the actual geometry
-                       clippointtosurface(ed, model, surface, p, clipped);
+                       clippointtosurface(prog, ed, model, surface, p, clipped);
                        VectorSubtract(clipped, p, clipped);
                        dist += VectorLength2(clipped);
                        if (dist < bestdist)
@@ -6832,7 +6707,7 @@ void VM_getsurfacenearpoint(void)
        PRVM_G_FLOAT(OFS_RETURN) = best;
 }
 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
-void VM_getsurfaceclippedpoint(void)
+void VM_getsurfaceclippedpoint(prvm_prog_t *prog)
 {
        prvm_edict_t *ed;
        dp_model_t *model;
@@ -6841,32 +6716,31 @@ void VM_getsurfaceclippedpoint(void)
        VM_SAFEPARMCOUNT(3, VM_te_getsurfaceclippedpoint);
        VectorClear(PRVM_G_VECTOR(OFS_RETURN));
        ed = PRVM_G_EDICT(OFS_PARM0);
-       if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
+       if (!(model = getmodel(prog, ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
                return;
-       animatemodel(model, ed);
-       applytransform_inverted(PRVM_G_VECTOR(OFS_PARM2), ed, p);
-       clippointtosurface(ed, model, surface, p, out);
+       animatemodel(prog, model, ed);
+       applytransform_inverted(prog, PRVM_G_VECTOR(OFS_PARM2), 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(void)
+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(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
+       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_triangles;
 }
 //PF_getsurfacetriangle,     // #??? vector(entity e, float s, float n) getsurfacetriangle = #???;
-void VM_getsurfacetriangle(void)
+void VM_getsurfacetriangle(prvm_prog_t *prog)
 {
        const vec3_t d = {-1, -1, -1};
        prvm_edict_t *ed;
@@ -6876,7 +6750,7 @@ void VM_getsurfacetriangle(void)
        VM_SAFEPARMCOUNT(3, VM_SV_getsurfacetriangle);
        VectorClear(PRVM_G_VECTOR(OFS_RETURN));
        ed = PRVM_G_EDICT(OFS_PARM0);
-       if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
+       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)
@@ -6889,11 +6763,9 @@ void VM_getsurfacetriangle(void)
 // physics builtins
 //
 
-void World_Physics_ApplyCmd(prvm_edict_t *ed, edict_odefunc_t *f);
-
-#define VM_physics_ApplyCmd(ed,f) if (!ed->priv.server->ode_body) VM_physics_newstackfunction(ed, f); else World_Physics_ApplyCmd(ed, f)
+#define VM_physics_ApplyCmd(ed,f) if (!ed->priv.server->ode_body) VM_physics_newstackfunction(prog, ed, f); else World_Physics_ApplyCmd(ed, f)
 
-edict_odefunc_t *VM_physics_newstackfunction(prvm_edict_t *ed, edict_odefunc_t *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;
 
@@ -6911,7 +6783,7 @@ edict_odefunc_t *VM_physics_newstackfunction(prvm_edict_t *ed, edict_odefunc_t *
 }
 
 // void(entity e, float physics_enabled) physics_enable = #;
-void VM_physics_enable(void)
+void VM_physics_enable(prvm_prog_t *prog)
 {
        prvm_edict_t *ed;
        edict_odefunc_t f;
@@ -6921,13 +6793,13 @@ void VM_physics_enable(void)
        if (!ed)
        {
                if (developer.integer > 0)
-                       VM_Warning("VM_physics_enable: null entity!\n");
+                       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("VM_physics_enable: entity is not MOVETYPE_PHYSICS!\n");
+               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;
@@ -6935,7 +6807,7 @@ void VM_physics_enable(void)
 }
 
 // void(entity e, vector force, vector relative_ofs) physics_addforce = #;
-void VM_physics_addforce(void)
+void VM_physics_addforce(prvm_prog_t *prog)
 {
        prvm_edict_t *ed;
        edict_odefunc_t f;
@@ -6945,13 +6817,13 @@ void VM_physics_addforce(void)
        if (!ed)
        {
                if (developer.integer > 0)
-                       VM_Warning("VM_physics_addforce: null entity!\n");
+                       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("VM_physics_addforce: entity is not MOVETYPE_PHYSICS!\n");
+               VM_Warning(prog, "VM_physics_addforce: entity is not MOVETYPE_PHYSICS!\n");
                return;
        }
        f.type = ODEFUNC_RELFORCEATPOS;
@@ -6961,7 +6833,7 @@ void VM_physics_addforce(void)
 }
 
 // void(entity e, vector torque) physics_addtorque = #;
-void VM_physics_addtorque(void)
+void VM_physics_addtorque(prvm_prog_t *prog)
 {
        prvm_edict_t *ed;
        edict_odefunc_t f;
@@ -6971,13 +6843,13 @@ void VM_physics_addtorque(void)
        if (!ed)
        {
                if (developer.integer > 0)
-                       VM_Warning("VM_physics_addtorque: null entity!\n");
+                       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("VM_physics_addtorque: entity is not MOVETYPE_PHYSICS!\n");
+               VM_Warning(prog, "VM_physics_addtorque: entity is not MOVETYPE_PHYSICS!\n");
                return;
        }
        f.type = ODEFUNC_RELTORQUE;
index e8ed3cbc7ea47875a2e3fa8ebe8a4a135c5c8283..7679336738e70c1e039541e8700ad889b4a649a4 100644 (file)
@@ -1,3 +1,7 @@
+
+#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
@@ -194,14 +198,13 @@ float     getserverlistindexforkey(string key)
 #include "mprogdefs.h"
 
 #include "cl_video.h"
-#include "cl_gecko.h"
 
 //============================================================================
 // nice helper macros
 
 #ifndef VM_NOPARMCHECK
-#define VM_SAFEPARMCOUNTRANGE(p1,p2,f) if(prog->argc < p1 || prog->argc > p2) PRVM_ERROR(#f " wrong parameter count %i (" #p1 " to " #p2 " expected ) !", prog->argc)
-#define VM_SAFEPARMCOUNT(p,f)  if(prog->argc != p) PRVM_ERROR(#f " wrong parameter count %i (" #p " expected ) !", prog->argc)
+#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)
@@ -211,270 +214,269 @@ float   getserverlistindexforkey(string key)
 
 #define VM_STRINGTEMP_LENGTH MAX_INPUTLINE
 
+// init code
+void PR_Cmd_Init(void);
+
 // builtins and other general functions
 
-void VM_CheckEmptyString (const char *s);
-void VM_VarString(int first, char *out, int outlength);
-
-void VM_checkextension (void);
-void VM_error (void);
-void VM_objerror (void);
-void VM_print (void);
-void VM_bprint (void);
-void VM_sprint (void);
-void VM_centerprint (void);
-void VM_normalize (void);
-void VM_vlen (void);
-void VM_vectoyaw (void);
-void VM_vectoangles (void);
-void VM_random (void);
-void VM_localsound(void);
-void VM_break (void);
-void VM_localcmd (void);
-void VM_cvar (void);
-void VM_cvar_string(void);
-void VM_cvar_type (void);
-void VM_cvar_defstring (void);
-void VM_cvar_set (void);
-void VM_dprint (void);
-void VM_ftos (void);
-void VM_fabs (void);
-void VM_vtos (void);
-void VM_etos (void);
-void VM_stof(void);
-void VM_itof(void);
-void VM_ftoe(void);
-void VM_strftime(void);
-void VM_spawn (void);
-void VM_remove (void);
-void VM_find (void);
-void VM_findfloat (void);
-void VM_findchain (void);
-void VM_findchainfloat (void);
-void VM_findflags (void);
-void VM_findchainflags (void);
-void VM_precache_file (void);
-void VM_precache_sound (void);
-void VM_coredump (void);
-
-void VM_stackdump (void);
-void VM_crash(void); // REMOVE IT
-void VM_traceon (void);
-void VM_traceoff (void);
-void VM_eprint (void);
-void VM_rint (void);
-void VM_floor (void);
-void VM_ceil (void);
-void VM_nextent (void);
-
-void VM_changelevel (void);
-void VM_sin (void);
-void VM_cos (void);
-void VM_sqrt (void);
-void VM_randomvec (void);
-void VM_registercvar (void);
-void VM_min (void);
-void VM_max (void);
-void VM_bound (void);
-void VM_pow (void);
-void VM_log (void);
-void VM_asin (void);
-void VM_acos (void);
-void VM_atan (void);
-void VM_atan2 (void);
-void VM_tan (void);
-
-void VM_Files_Init(void);
-void VM_Files_CloseAll(void);
-
-void VM_fopen(void);
-void VM_fclose(void);
-void VM_fgets(void);
-void VM_fputs(void);
-void VM_writetofile(void); // only used by menu
-
-void VM_strlen(void);
-void VM_strcat(void);
-void VM_substring(void);
-void VM_stov(void);
-void VM_strzone(void);
-void VM_strunzone(void);
+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(void);
-void VM_entityfieldname(void);
-void VM_entityfieldtype(void);
-void VM_getentityfieldstring(void);
-void VM_putentityfieldstring(void);
-// And declared these ones for VM_getentityfieldstring and VM_putentityfieldstring in prvm_cmds.c
-// the function is from prvm_edict.c
-char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val);
-qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s, qboolean parsebackslash);
+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(void);
+void VM_strlennocol(prvm_prog_t *prog);
 // DRESK - Decolorized String
-void VM_strdecolorize(void);
+void VM_strdecolorize(prvm_prog_t *prog);
 // DRESK - String Uppercase and Lowercase Support
-void VM_strtolower(void);
-void VM_strtoupper(void);
+void VM_strtolower(prvm_prog_t *prog);
+void VM_strtoupper(prvm_prog_t *prog);
 
-void VM_clcommand (void);
+void VM_clcommand (prvm_prog_t *prog);
 
-void VM_tokenize (void);
-void VM_tokenizebyseparator (void);
-void VM_argv (void);
+void VM_tokenize (prvm_prog_t *prog);
+void VM_tokenizebyseparator (prvm_prog_t *prog);
+void VM_argv (prvm_prog_t *prog);
 
-void VM_isserver(void);
-void VM_clientcount(void);
-void VM_clientstate(void);
+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(void);
-void VM_getmousepos(void);
-void VM_gettime(void);
-void VM_getsoundtime(void);
-void VM_soundlength(void);
-void VM_loadfromdata(void);
-void VM_parseentitydata(void);
-void VM_loadfromfile(void);
-void VM_modulo(void);
-
-void VM_search_begin(void);
-void VM_search_end(void);
-void VM_search_getsize(void);
-void VM_search_getfilename(void);
-void VM_chr(void);
-void VM_iscachedpic(void);
-void VM_precache_pic(void);
-void VM_freepic(void);
-void VM_drawcharacter(void);
-void VM_drawstring(void);
-void VM_drawcolorcodedstring(void);
-void VM_stringwidth(void);
-void VM_drawpic(void);
-void VM_drawrotpic(void);
-void VM_drawsubpic(void);
-void VM_drawfill(void);
-void VM_drawsetcliparea(void);
-void VM_drawresetcliparea(void);
-void VM_getimagesize(void);
-
-void VM_findfont(void);
-void VM_loadfont(void);
-
-void VM_makevectors (void);
-void VM_vectorvectors (void);
-
-void VM_keynumtostring (void);
-void VM_getkeybind (void);
-void VM_findkeysforcommand (void);
-void VM_stringtokeynum (void);
-void VM_setkeybind (void);
-void VM_getbindmaps (void);
-void VM_setbindmaps (void);
-
-void VM_cin_open( void );
-void VM_cin_close( void );
-void VM_cin_setstate( void );
-void VM_cin_getstate( void );
-void VM_cin_restart( void );
-
-void VM_gecko_create( void );
-void VM_gecko_destroy( void );
-void VM_gecko_navigate( void );
-void VM_gecko_keyevent( void );
-void VM_gecko_movemouse( void );
-void VM_gecko_resize( void );
-void VM_gecko_get_texture_extent( void );
-
-void VM_drawline (void);
-
-void VM_bitshift (void);
-
-void VM_altstr_count( void );
-void VM_altstr_prepare( void );
-void VM_altstr_get( void );
-void VM_altstr_set( void );
-void VM_altstr_ins(void);
-
-void VM_buf_create(void);
-void VM_buf_del (void);
-void VM_buf_getsize (void);
-void VM_buf_copy (void);
-void VM_buf_sort (void);
-void VM_buf_implode (void);
-void VM_bufstr_get (void);
-void VM_bufstr_set (void);
-void VM_bufstr_add (void);
-void VM_bufstr_free (void);
-
-void VM_changeyaw (void);
-void VM_changepitch (void);
-
-void VM_uncolorstring (void);
-
-void VM_strstrofs (void);
-void VM_str2chr (void);
-void VM_chr2str (void);
-void VM_strconv (void);
-void VM_strpad (void);
-void VM_infoadd (void);
-void VM_infoget (void);
-void VM_strncmp (void);
-void VM_strncmp (void);
-void VM_strncasecmp (void);
-void VM_registercvar (void);
-void VM_wasfreed (void);
-
-void VM_strreplace (void);
-void VM_strireplace (void);
-
-void VM_crc16(void);
-
-void VM_SetTraceGlobals(const trace_t *trace);
-void VM_ClearTraceGlobals(void);
-
-void VM_Cmd_Init(void);
-void VM_Cmd_Reset(void);
-
-void VM_uri_escape (void);
-void VM_uri_unescape (void);
-void VM_whichpack (void);
-
-void VM_etof (void);
-void VM_uri_get (void);
-void VM_netaddress_resolve (void);
-
-void VM_tokenize_console (void);
-void VM_argv_start_index (void);
-void VM_argv_end_index (void);
-
-void VM_buf_cvarlist(void);
-void VM_cvar_description(void);
-
-void VM_CL_getextresponse (void);
-void VM_SV_getextresponse (void);
+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_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 (void);
-void VM_CL_videoplaying (void);
+void VM_CL_isdemo (prvm_prog_t *prog);
+void VM_CL_videoplaying (prvm_prog_t *prog);
 
-void VM_isfunction(void);
-void VM_callfunction(void);
+void VM_isfunction(prvm_prog_t *prog);
+void VM_callfunction(prvm_prog_t *prog);
 
-void VM_sprintf(void);
+void VM_sprintf(prvm_prog_t *prog);
 
-void VM_getsurfacenumpoints(void);
-void VM_getsurfacepoint(void);
-void VM_getsurfacepointattribute(void);
-void VM_getsurfacenormal(void);
-void VM_getsurfacetexture(void);
-void VM_getsurfacenearpoint(void);
-void VM_getsurfaceclippedpoint(void);
-void VM_getsurfacenumtriangles(void);
-void VM_getsurfacetriangle(void);
+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(void);
-void VM_physics_addforce(void);
-void VM_physics_addtorque(void);
+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
index ffe917a8060034737664e089d8cb042321b4740a..25f9899af9f434cbbf1ee15af061596e5e9c72be 100644 (file)
@@ -23,17 +23,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "progsvm.h"
 #include "csprogs.h"
 
-prvm_prog_t *prog;
-
-static prvm_prog_t prog_list[PRVM_MAXPROGS];
+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
 
-ddef_t *PRVM_ED_FieldAtOfs(int ofs);
-qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s, qboolean parsebackslash);
-
 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!)"};
@@ -50,8 +45,6 @@ cvar_t prvm_reuseedicts_neverinsameframe = {0, "prvm_reuseedicts_neverinsamefram
 static double prvm_reuseedicts_always_allow = 0;
 qboolean prvm_runawaycheck = true;
 
-extern sizebuf_t vm_tempstringsbuf;
-
 //============================================================================
 // mempool handling
 
@@ -60,7 +53,7 @@ extern sizebuf_t vm_tempstringsbuf;
 PRVM_MEM_Alloc
 ===============
 */
-void PRVM_MEM_Alloc(void)
+static void PRVM_MEM_Alloc(prvm_prog_t *prog)
 {
        int i;
 
@@ -95,14 +88,14 @@ void PRVM_MEM_Alloc(void)
 PRVM_MEM_IncreaseEdicts
 ===============
 */
-void PRVM_MEM_IncreaseEdicts(void)
+void PRVM_MEM_IncreaseEdicts(prvm_prog_t *prog)
 {
        int             i;
 
        if(prog->max_edicts >= prog->limit_edicts)
                return;
 
-       PRVM_GCALL(begin_increase_edicts)();
+       prog->begin_increase_edicts(prog);
 
        // increase edicts
        prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
@@ -118,91 +111,74 @@ void PRVM_MEM_IncreaseEdicts(void)
                prog->edicts[i].fields.vp = prog->edictsfields + i * prog->entityfields;
        }
 
-       PRVM_GCALL(end_increase_edicts)();
+       prog->end_increase_edicts(prog);
 }
 
 //============================================================================
 // normal prvm
 
-int PRVM_ED_FindFieldOffset(const char *field)
+int PRVM_ED_FindFieldOffset(prvm_prog_t *prog, const char *field)
 {
        ddef_t *d;
-       d = PRVM_ED_FindField(field);
+       d = PRVM_ED_FindField(prog, field);
        if (!d)
                return -1;
        return d->ofs;
 }
 
-int PRVM_ED_FindGlobalOffset(const char *global)
+int PRVM_ED_FindGlobalOffset(prvm_prog_t *prog, const char *global)
 {
        ddef_t *d;
-       d = PRVM_ED_FindGlobal(global);
+       d = PRVM_ED_FindGlobal(prog, global);
        if (!d)
                return -1;
        return d->ofs;
 }
 
-func_t PRVM_ED_FindFunctionOffset(const char *function)
+func_t PRVM_ED_FindFunctionOffset(prvm_prog_t *prog, const char *function)
 {
        mfunction_t *f;
-       f = PRVM_ED_FindFunction(function);
+       f = PRVM_ED_FindFunction(prog, function);
        if (!f)
                return 0;
        return (func_t)(f - prog->functions);
 }
 
-qboolean PRVM_ProgLoaded(int prognr)
-{
-       if(prognr < 0 || prognr >= PRVM_MAXPROGS)
-               return FALSE;
-
-       return (prog_list[prognr].loaded ? TRUE : FALSE);
-}
-
 /*
 =================
-PRVM_SetProgFromString
+PRVM_ProgFromString
 =================
 */
-// perhaps add a return value when the str doesnt exist
-qboolean PRVM_SetProgFromString(const char *str)
-{
-       int i = 0;
-       for(; i < PRVM_MAXPROGS ; i++)
-               if(prog_list[i].name && !strcmp(prog_list[i].name,str))
-               {
-                       if(prog_list[i].loaded)
-                       {
-                               prog = &prog_list[i];
-                               return TRUE;
-                       }
-                       else
-                       {
-                               Con_Printf("%s not loaded !\n",PRVM_NAME);
-                               return FALSE;
-                       }
-               }
-
-       Con_Printf("Invalid program name %s !\n", str);
-       return FALSE;
+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_SetProg
+PRVM_FriendlyProgFromString
 =================
 */
-void PRVM_SetProg(int prognr)
+prvm_prog_t *PRVM_FriendlyProgFromString(const char *str)
 {
-       if(0 <= prognr && prognr < PRVM_MAXPROGS)
+       prvm_prog_t *prog = PRVM_ProgFromString(str);
+       if (!prog)
        {
-               if(prog_list[prognr].loaded)
-                       prog = &prog_list[prognr];
-               else
-                       PRVM_ERROR("%i not loaded !", prognr);
-               return;
+               Con_Printf("%s: unknown program name\n", str);
+               return NULL;
+       }
+       if (!prog->loaded)
+       {
+               Con_Printf("%s: program is not loaded\n", str);
+               return NULL;
        }
-       PRVM_ERROR("Invalid program number %i", prognr);
+       return prog;
 }
 
 /*
@@ -212,23 +188,23 @@ PRVM_ED_ClearEdict
 Sets everything to NULL
 =================
 */
-void PRVM_ED_ClearEdict (prvm_edict_t *e)
+void PRVM_ED_ClearEdict(prvm_prog_t *prog, prvm_edict_t *e)
 {
-       memset (e->fields.vp, 0, prog->entityfields * 4);
+       memset(e->fields.vp, 0, prog->entityfields * 4);
        e->priv.required->free = false;
 
        // AK: Let the init_edict function determine if something needs to be initialized
-       PRVM_GCALL(init_edict)(e);
+       prog->init_edict(prog, e);
 }
 
-const char *PRVM_AllocationOrigin(void)
+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(buf, 128);
+               PRVM_ShortStackTrace(prog, buf, 128);
        }
        return buf;
 }
@@ -240,13 +216,13 @@ PRVM_ED_CanAlloc
 Returns if this particular edict could get allocated by PRVM_ED_Alloc
 =================
 */
-qboolean PRVM_ED_CanAlloc(prvm_edict_t *e)
+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 && prvm_reuseedicts_neverinsameframe.integer)
+       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;
@@ -266,10 +242,10 @@ instead of being removed and recreated, which can cause interpolated
 angles and bad trails.
 =================
 */
-prvm_edict_t *PRVM_ED_Alloc (void)
+prvm_edict_t *PRVM_ED_Alloc(prvm_prog_t *prog)
 {
-       int                     i;
-       prvm_edict_t            *e;
+       int i;
+       prvm_edict_t *e;
 
        // the client qc dont need maxclients
        // thus it doesnt need to use svs.maxclients
@@ -279,25 +255,25 @@ prvm_edict_t *PRVM_ED_Alloc (void)
        for (i = prog->reserved_edicts + 1;i < prog->num_edicts;i++)
        {
                e = PRVM_EDICT_NUM(i);
-               if(PRVM_ED_CanAlloc(e))
+               if(PRVM_ED_CanAlloc(prog, e))
                {
-                       PRVM_ED_ClearEdict (e);
-                       e->priv.required->allocation_origin = PRVM_AllocationOrigin();
+                       PRVM_ED_ClearEdict (prog, e);
+                       e->priv.required->allocation_origin = PRVM_AllocationOrigin(prog);
                        return e;
                }
        }
 
        if (i == prog->limit_edicts)
-               PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
+               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();
+               PRVM_MEM_IncreaseEdicts(prog);
 
        e = PRVM_EDICT_NUM(i);
-       PRVM_ED_ClearEdict (e);
+       PRVM_ED_ClearEdict(prog, e);
 
-       e->priv.required->allocation_origin = PRVM_AllocationOrigin();
+       e->priv.required->allocation_origin = PRVM_AllocationOrigin(prog);
 
        return e;
 }
@@ -310,19 +286,19 @@ Marks the edict as free
 FIXME: walk all entities and NULL out references to this entity
 =================
 */
-void PRVM_ED_Free (prvm_edict_t *ed)
+void PRVM_ED_Free(prvm_prog_t *prog, prvm_edict_t *ed)
 {
        // dont delete the null entity (world) or reserved edicts
-       if(PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts )
+       if (ed - prog->edicts <= prog->reserved_edicts)
                return;
 
-       PRVM_GCALL(free_edict)(ed);
+       prog->free_edict(prog, ed);
 
        ed->priv.required->free = true;
        ed->priv.required->freetime = realtime;
        if(ed->priv.required->allocation_origin)
        {
-               PRVM_Free((char *)ed->priv.required->allocation_origin);
+               Mem_Free((char *)ed->priv.required->allocation_origin);
                ed->priv.required->allocation_origin = NULL;
        }
 }
@@ -334,7 +310,7 @@ void PRVM_ED_Free (prvm_edict_t *ed)
 PRVM_ED_GlobalAtOfs
 ============
 */
-ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
+static ddef_t *PRVM_ED_GlobalAtOfs (prvm_prog_t *prog, int ofs)
 {
        ddef_t          *def;
        int                     i;
@@ -353,7 +329,7 @@ ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
 PRVM_ED_FieldAtOfs
 ============
 */
-ddef_t *PRVM_ED_FieldAtOfs (int ofs)
+ddef_t *PRVM_ED_FieldAtOfs (prvm_prog_t *prog, int ofs)
 {
        ddef_t          *def;
        int                     i;
@@ -372,7 +348,7 @@ ddef_t *PRVM_ED_FieldAtOfs (int ofs)
 PRVM_ED_FindField
 ============
 */
-ddef_t *PRVM_ED_FindField (const char *name)
+ddef_t *PRVM_ED_FindField (prvm_prog_t *prog, const char *name)
 {
        ddef_t *def;
        int i;
@@ -380,7 +356,7 @@ ddef_t *PRVM_ED_FindField (const char *name)
        for (i = 0;i < prog->numfielddefs;i++)
        {
                def = &prog->fielddefs[i];
-               if (!strcmp(PRVM_GetString(def->s_name), name))
+               if (!strcmp(PRVM_GetString(prog, def->s_name), name))
                        return def;
        }
        return NULL;
@@ -391,7 +367,7 @@ ddef_t *PRVM_ED_FindField (const char *name)
 PRVM_ED_FindGlobal
 ============
 */
-ddef_t *PRVM_ED_FindGlobal (const char *name)
+ddef_t *PRVM_ED_FindGlobal (prvm_prog_t *prog, const char *name)
 {
        ddef_t *def;
        int i;
@@ -399,7 +375,7 @@ ddef_t *PRVM_ED_FindGlobal (const char *name)
        for (i = 0;i < prog->numglobaldefs;i++)
        {
                def = &prog->globaldefs[i];
-               if (!strcmp(PRVM_GetString(def->s_name), name))
+               if (!strcmp(PRVM_GetString(prog, def->s_name), name))
                        return def;
        }
        return NULL;
@@ -411,7 +387,7 @@ ddef_t *PRVM_ED_FindGlobal (const char *name)
 PRVM_ED_FindFunction
 ============
 */
-mfunction_t *PRVM_ED_FindFunction (const char *name)
+mfunction_t *PRVM_ED_FindFunction (prvm_prog_t *prog, const char *name)
 {
        mfunction_t             *func;
        int                             i;
@@ -419,7 +395,7 @@ mfunction_t *PRVM_ED_FindFunction (const char *name)
        for (i = 0;i < prog->numfunctions;i++)
        {
                func = &prog->functions[i];
-               if (!strcmp(PRVM_GetString(func->s_name), name))
+               if (!strcmp(PRVM_GetString(prog, func->s_name), name))
                        return func;
        }
        return NULL;
@@ -433,9 +409,8 @@ PRVM_ValueString
 Returns a string describing *data in a type specific manner
 =============
 */
-char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
+static char *PRVM_ValueString (prvm_prog_t *prog, etype_t type, prvm_eval_t *val, char *line, size_t linelength)
 {
-       static char line[MAX_INPUTLINE];
        ddef_t *def;
        mfunction_t *f;
        int n;
@@ -445,39 +420,39 @@ char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
        switch (type)
        {
        case ev_string:
-               strlcpy (line, PRVM_GetString (val->string), sizeof (line));
+               strlcpy (line, PRVM_GetString (prog, val->string), linelength);
                break;
        case ev_entity:
                n = val->edict;
                if (n < 0 || n >= prog->max_edicts)
-                       dpsnprintf (line, sizeof(line), "entity %i (invalid!)", n);
+                       dpsnprintf (line, linelength, "entity %i (invalid!)", n);
                else
-                       dpsnprintf (line, sizeof(line), "entity %i", n);
+                       dpsnprintf (line, linelength, "entity %i", n);
                break;
        case ev_function:
                f = prog->functions + val->function;
-               dpsnprintf (line, sizeof(line), "%s()", PRVM_GetString(f->s_name));
+               dpsnprintf (line, linelength, "%s()", PRVM_GetString(prog, f->s_name));
                break;
        case ev_field:
-               def = PRVM_ED_FieldAtOfs ( val->_int );
-               dpsnprintf (line, sizeof(line), ".%s", PRVM_GetString(def->s_name));
+               def = PRVM_ED_FieldAtOfs ( prog, val->_int );
+               dpsnprintf (line, linelength, ".%s", PRVM_GetString(prog, def->s_name));
                break;
        case ev_void:
-               dpsnprintf (line, sizeof(line), "void");
+               dpsnprintf (line, linelength, "void");
                break;
        case ev_float:
                // LordHavoc: changed from %5.1f to %10.4f
-               dpsnprintf (line, sizeof(line), "%10.4f", val->_float);
+               dpsnprintf (line, linelength, "%10.4f", val->_float);
                break;
        case ev_vector:
                // LordHavoc: changed from %5.1f to %10.4f
-               dpsnprintf (line, sizeof(line), "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
+               dpsnprintf (line, linelength, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
                break;
        case ev_pointer:
-               dpsnprintf (line, sizeof(line), "pointer");
+               dpsnprintf (line, linelength, "pointer");
                break;
        default:
-               dpsnprintf (line, sizeof(line), "bad type %i", (int) type);
+               dpsnprintf (line, linelength, "bad type %i", (int) type);
                break;
        }
 
@@ -492,9 +467,8 @@ Returns a string describing *data in a type specific manner
 Easier to parse than PR_ValueString
 =============
 */
-char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
+char *PRVM_UglyValueString (prvm_prog_t *prog, etype_t type, prvm_eval_t *val, char *line, size_t linelength)
 {
-       static char line[MAX_INPUTLINE];
        int i;
        const char *s;
        ddef_t *def;
@@ -508,8 +482,8 @@ char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
                // 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 (val->string);
-               for (i = 0;i < (int)sizeof(line) - 2 && *s;)
+               s = PRVM_GetString (prog, val->string);
+               for (i = 0;i < (int)linelength - 2 && *s;)
                {
                        if (*s == '\n')
                        {
@@ -538,27 +512,27 @@ char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
                line[i] = '\0';
                break;
        case ev_entity:
-               dpsnprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
+               dpsnprintf (line, linelength, "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
                break;
        case ev_function:
                f = prog->functions + val->function;
-               strlcpy (line, PRVM_GetString (f->s_name), sizeof (line));
+               strlcpy (line, PRVM_GetString (prog, f->s_name), linelength);
                break;
        case ev_field:
-               def = PRVM_ED_FieldAtOfs ( val->_int );
-               dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
+               def = PRVM_ED_FieldAtOfs ( prog, val->_int );
+               dpsnprintf (line, linelength, ".%s", PRVM_GetString(prog, def->s_name));
                break;
        case ev_void:
-               dpsnprintf (line, sizeof (line), "void");
+               dpsnprintf (line, linelength, "void");
                break;
        case ev_float:
-               dpsnprintf (line, sizeof (line), "%.9g", val->_float);
+               dpsnprintf (line, linelength, "%.9g", val->_float);
                break;
        case ev_vector:
-               dpsnprintf (line, sizeof (line), "%.9g %.9g %.9g", val->vector[0], val->vector[1], val->vector[2]);
+               dpsnprintf (line, linelength, "%.9g %.9g %.9g", val->vector[0], val->vector[1], val->vector[2]);
                break;
        default:
-               dpsnprintf (line, sizeof (line), "bad type %i", type);
+               dpsnprintf (line, linelength, "bad type %i", type);
                break;
        }
 
@@ -573,22 +547,22 @@ Returns a string with a description and the contents of a global,
 padded to 20 field width
 ============
 */
-char *PRVM_GlobalString (int ofs)
+char *PRVM_GlobalString (prvm_prog_t *prog, int ofs, char *line, size_t linelength)
 {
        char    *s;
        //size_t        i;
        ddef_t  *def;
        void    *val;
-       static char     line[128];
+       char valuebuf[MAX_INPUTLINE];
 
        val = (void *)&prog->globals.generic[ofs];
-       def = PRVM_ED_GlobalAtOfs(ofs);
+       def = PRVM_ED_GlobalAtOfs(prog, ofs);
        if (!def)
-               dpsnprintf (line, sizeof(line), "GLOBAL%i", ofs);
+               dpsnprintf (line, linelength, "GLOBAL%i", ofs);
        else
        {
-               s = PRVM_ValueString ((etype_t)def->type, (prvm_eval_t *)val);
-               dpsnprintf (line, sizeof(line), "%s (=%s)", PRVM_GetString(def->s_name), s);
+               s = PRVM_ValueString (prog, (etype_t)def->type, (prvm_eval_t *)val, valuebuf, sizeof(valuebuf));
+               dpsnprintf (line, linelength, "%s (=%s)", PRVM_GetString(prog, def->s_name), s);
        }
 
        //i = strlen(line);
@@ -599,17 +573,16 @@ char *PRVM_GlobalString (int ofs)
        return line;
 }
 
-char *PRVM_GlobalStringNoContents (int ofs)
+char *PRVM_GlobalStringNoContents (prvm_prog_t *prog, int ofs, char *line, size_t linelength)
 {
        //size_t        i;
        ddef_t  *def;
-       static char     line[128];
 
-       def = PRVM_ED_GlobalAtOfs(ofs);
+       def = PRVM_ED_GlobalAtOfs(prog, ofs);
        if (!def)
-               dpsnprintf (line, sizeof(line), "GLOBAL%i", ofs);
+               dpsnprintf (line, linelength, "GLOBAL%i", ofs);
        else
-               dpsnprintf (line, sizeof(line), "%s", PRVM_GetString(def->s_name));
+               dpsnprintf (line, linelength, "%s", PRVM_GetString(prog, def->s_name));
 
        //i = strlen(line);
        //for ( ; i<20 ; i++)
@@ -629,7 +602,7 @@ 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_edict_t *ed, const char *wildcard_fieldname)
+void PRVM_ED_Print(prvm_prog_t *prog, prvm_edict_t *ed, const char *wildcard_fieldname)
 {
        size_t  l;
        ddef_t  *d;
@@ -638,19 +611,20 @@ void PRVM_ED_Print(prvm_edict_t *ed, const char *wildcard_fieldname)
        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",PRVM_NAME);
+               Con_Printf("%s: FREE\n",prog->name);
                return;
        }
 
        tempstring[0] = 0;
-       dpsnprintf(tempstring, sizeof(tempstring), "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
+       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(d->s_name);
+               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
 
@@ -683,7 +657,7 @@ void PRVM_ED_Print(prvm_edict_t *ed, const char *wildcard_fieldname)
                        strlcat(tempstring, " ", sizeof(tempstring));
                strlcat(tempstring, " ", sizeof(tempstring));
 
-               name = PRVM_ValueString((etype_t)d->type, (prvm_eval_t *)v);
+               name = PRVM_ValueString(prog, (etype_t)d->type, (prvm_eval_t *)v, valuebuf, sizeof(valuebuf));
                if (strlen(name) > sizeof(tempstring2)-4)
                {
                        memcpy (tempstring2, name, sizeof(tempstring2)-4);
@@ -711,13 +685,15 @@ For savegames
 =============
 */
 extern cvar_t developer_entityparsing;
-void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
+void PRVM_ED_Write (prvm_prog_t *prog, qfile_t *f, prvm_edict_t *ed)
 {
        ddef_t  *d;
        int             *v;
        int             i, j;
        const char      *name;
        int             type;
+       char vabuf[1024];
+       char valuebuf[MAX_INPUTLINE];
 
        FS_Print(f, "{\n");
 
@@ -730,7 +706,7 @@ void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
        for (i = 1;i < prog->numfielddefs;i++)
        {
                d = &prog->fielddefs[i];
-               name = PRVM_GetString(d->s_name);
+               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);
@@ -750,17 +726,17 @@ void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
                        continue;
 
                FS_Printf(f,"\"%s\" ",name);
-               prog->statestring = va("PRVM_ED_Write, ent=%d, name=%s", i, name);
-               FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)d->type, (prvm_eval_t *)v));
+               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, (prvm_eval_t *)v, valuebuf, sizeof(valuebuf)));
                prog->statestring = NULL;
        }
 
        FS_Print(f, "}\n");
 }
 
-void PRVM_ED_PrintNum (int ent, const char *wildcard_fieldname)
+void PRVM_ED_PrintNum (prvm_prog_t *prog, int ent, const char *wildcard_fieldname)
 {
-       PRVM_ED_Print(PRVM_EDICT_NUM(ent), wildcard_fieldname);
+       PRVM_ED_Print(prog, PRVM_EDICT_NUM(ent), wildcard_fieldname);
 }
 
 /*
@@ -772,6 +748,7 @@ 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;
 
@@ -781,8 +758,7 @@ void PRVM_ED_PrintEdicts_f (void)
                return;
        }
 
-       PRVM_Begin;
-       if(!PRVM_SetProgFromString(Cmd_Argv(1)))
+       if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
                return;
 
        if( Cmd_Argc() == 3)
@@ -790,11 +766,9 @@ void PRVM_ED_PrintEdicts_f (void)
        else
                wildcard_fieldname = NULL;
 
-       Con_Printf("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
+       Con_Printf("%s: %i entities\n", prog->name, prog->num_edicts);
        for (i=0 ; i<prog->num_edicts ; i++)
-               PRVM_ED_PrintNum (i, wildcard_fieldname);
-
-       PRVM_End;
+               PRVM_ED_PrintNum (prog, i, wildcard_fieldname);
 }
 
 /*
@@ -804,8 +778,9 @@ PRVM_ED_PrintEdict_f
 For debugging, prints a single edict
 =============
 */
-void PRVM_ED_PrintEdict_f (void)
+static void PRVM_ED_PrintEdict_f (void)
 {
+       prvm_prog_t *prog;
        int             i;
        const char      *wildcard_fieldname;
 
@@ -815,15 +790,13 @@ void PRVM_ED_PrintEdict_f (void)
                return;
        }
 
-       PRVM_Begin;
-       if(!PRVM_SetProgFromString(Cmd_Argv(1)))
+       if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
                return;
 
        i = atoi (Cmd_Argv(2));
        if (i >= prog->num_edicts)
        {
                Con_Print("Bad edict number\n");
-               PRVM_End;
                return;
        }
        if( Cmd_Argc() == 4)
@@ -832,9 +805,7 @@ void PRVM_ED_PrintEdict_f (void)
        else
                // Use All
                wildcard_fieldname = NULL;
-       PRVM_ED_PrintNum (i, wildcard_fieldname);
-
-       PRVM_End;
+       PRVM_ED_PrintNum (prog, i, wildcard_fieldname);
 }
 
 /*
@@ -846,11 +817,9 @@ For debugging
 */
 // 2 possibilities : 1. just displaying the active edict count
 //                                      2. making a function pointer [x]
-void PRVM_ED_Count_f (void)
+static void PRVM_ED_Count_f (void)
 {
-       int             i;
-       prvm_edict_t    *ent;
-       int             active;
+       prvm_prog_t *prog;
 
        if(Cmd_Argc() != 2)
        {
@@ -858,28 +827,10 @@ void PRVM_ED_Count_f (void)
                return;
        }
 
-       PRVM_Begin;
-       if(!PRVM_SetProgFromString(Cmd_Argv(1)))
+       if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
                return;
 
-       if(prog->count_edicts)
-               prog->count_edicts();
-       else
-       {
-               active = 0;
-               for (i=0 ; i<prog->num_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);
-       }
-
-       PRVM_End;
+       prog->count_edicts(prog);
 }
 
 /*
@@ -896,12 +847,14 @@ FIXME: need to tag constants, doesn't really work
 PRVM_ED_WriteGlobals
 =============
 */
-void PRVM_ED_WriteGlobals (qfile_t *f)
+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++)
@@ -915,14 +868,14 @@ void PRVM_ED_WriteGlobals (qfile_t *f)
                if (type != ev_string && type != ev_float && type != ev_entity)
                        continue;
 
-               name = PRVM_GetString(def->s_name);
+               name = PRVM_GetString(prog, def->s_name);
 
                if(developer_entityparsing.integer)
                        Con_Printf("PRVM_ED_WriteGlobals: at global %s\n", name);
 
-               prog->statestring = va("PRVM_ED_WriteGlobals, name=%s", 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((etype_t)type, (prvm_eval_t *)&prog->globals.generic[def->ofs]));
+               FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(prog, (etype_t)type, (prvm_eval_t *)&prog->globals.generic[def->ofs], valuebuf, sizeof(valuebuf)));
                prog->statestring = NULL;
        }
        FS_Print(f,"}\n");
@@ -933,7 +886,7 @@ void PRVM_ED_WriteGlobals (qfile_t *f)
 PRVM_ED_ParseGlobals
 =============
 */
-void PRVM_ED_ParseGlobals (const char *data)
+void PRVM_ED_ParseGlobals (prvm_prog_t *prog, const char *data)
 {
        char keyname[MAX_INPUTLINE];
        ddef_t *key;
@@ -941,8 +894,8 @@ void PRVM_ED_ParseGlobals (const char *data)
        while (1)
        {
                // parse key
-               if (!COM_ParseToken_Simple(&data, false, false))
-                       PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
+               if (!COM_ParseToken_Simple(&data, false, false, true))
+                       prog->error_cmd("PRVM_ED_ParseGlobals: EOF without closing brace");
                if (com_token[0] == '}')
                        break;
 
@@ -952,24 +905,24 @@ void PRVM_ED_ParseGlobals (const char *data)
                strlcpy (keyname, com_token, sizeof(keyname));
 
                // parse value
-               if (!COM_ParseToken_Simple(&data, false, true))
-                       PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
+               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] == '}')
-                       PRVM_ERROR ("PRVM_ED_ParseGlobals: closing brace without data");
+                       prog->error_cmd("PRVM_ED_ParseGlobals: closing brace without data");
 
-               key = PRVM_ED_FindGlobal (keyname);
+               key = PRVM_ED_FindGlobal (prog, keyname);
                if (!key)
                {
-                       Con_DPrintf("'%s' is not a global on %s\n", keyname, PRVM_NAME);
+                       Con_DPrintf("'%s' is not a global on %s\n", keyname, prog->name);
                        continue;
                }
 
-               if (!PRVM_ED_ParseEpair(NULL, key, com_token, true))
-                       PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
+               if (!PRVM_ED_ParseEpair(prog, NULL, key, com_token, true))
+                       prog->error_cmd("PRVM_ED_ParseGlobals: parse error");
        }
 }
 
@@ -984,7 +937,7 @@ Can parse either fields or globals
 returns false if error
 =============
 */
-qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s, qboolean parsebackslash)
+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;
@@ -1000,7 +953,7 @@ qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s, qbool
        {
        case ev_string:
                l = (int)strlen(s) + 1;
-               val->string = PRVM_AllocString(l, &new_p);
+               val->string = PRVM_AllocString(prog, l, &new_p);
                for (i = 0;i < l;i++)
                {
                        if (s[i] == '\\' && s[i+1] && parsebackslash)
@@ -1044,9 +997,9 @@ qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s, qbool
                        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, PRVM_NAME);
+                       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();
+                       PRVM_MEM_IncreaseEdicts(prog);
                // if IncreaseEdicts was called the base pointer needs to be updated
                if (ent)
                        val = (prvm_eval_t *)(ent->fields.vp + key->ofs);
@@ -1056,30 +1009,30 @@ qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s, qbool
        case ev_field:
                if (*s != '.')
                {
-                       Con_DPrintf("PRVM_ED_ParseEpair: Bogus field name %s in %s\n", s, PRVM_NAME);
+                       Con_DPrintf("PRVM_ED_ParseEpair: Bogus field name %s in %s\n", s, prog->name);
                        return false;
                }
-               def = PRVM_ED_FindField(s + 1);
+               def = PRVM_ED_FindField(prog, s + 1);
                if (!def)
                {
-                       Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, PRVM_NAME);
+                       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(s);
+               func = PRVM_ED_FindFunction(prog, s);
                if (!func)
                {
-                       Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, PRVM_NAME);
+                       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(key->s_name), PRVM_NAME);
+               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;
@@ -1101,22 +1054,17 @@ All progs can support this extension; sg calls it in server QC, cg in client
 QC, mg in menu QC.
 =============
 */
-void PRVM_GameCommand(const char *whichprogs, const char *whichcmd)
+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;
        }
 
-       PRVM_Begin;
-       if(!PRVM_SetProgFromString(whichprogs))
-       // note: this is not PRVM_SetProg because that one aborts "hard" using PRVM_Error
-       // also, it makes printing error messages easier!
-       {
-               Con_Printf("%s program not loaded.\n", whichprogs);
+       if (!(prog = PRVM_FriendlyProgFromString(whichprogs)))
                return;
-       }
 
        if(!PRVM_allfunction(GameCommand))
        {
@@ -1129,23 +1077,21 @@ void PRVM_GameCommand(const char *whichprogs, const char *whichcmd)
 
                s = Cmd_Args();
 
-               restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
-               PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(s ? s : "");
-               PRVM_ExecuteProgram (PRVM_allfunction(GameCommand), "QC function GameCommand is missing");
-               vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
+               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;
        }
-
-       PRVM_End;
 }
-void PRVM_GameCommand_Server_f(void)
+static void PRVM_GameCommand_Server_f(void)
 {
        PRVM_GameCommand("server", "sv_cmd");
 }
-void PRVM_GameCommand_Client_f(void)
+static void PRVM_GameCommand_Client_f(void)
 {
        PRVM_GameCommand("client", "cl_cmd");
 }
-void PRVM_GameCommand_Menu_f(void)
+static void PRVM_GameCommand_Menu_f(void)
 {
        PRVM_GameCommand("menu", "menu_cmd");
 }
@@ -1157,12 +1103,14 @@ PRVM_ED_EdictGet_f
 Console command to load a field of a specified edict
 =============
 */
-void PRVM_ED_EdictGet_f(void)
+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)
        {
@@ -1170,23 +1118,19 @@ void PRVM_ED_EdictGet_f(void)
                return;
        }
 
-       PRVM_Begin;
-       if(!PRVM_SetProgFromString(Cmd_Argv(1)))
-       {
-               Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
+       if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
                return;
-       }
 
        ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
 
-       if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
+       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.vp + key->ofs);
-       s = PRVM_UglyValueString((etype_t)key->type, v);
+       s = PRVM_UglyValueString(prog, (etype_t)key->type, v, valuebuf, sizeof(valuebuf));
        if(Cmd_Argc() == 5)
        {
                cvar_t *cvar = Cvar_FindVar(Cmd_Argv(4));
@@ -1201,14 +1145,16 @@ void PRVM_ED_EdictGet_f(void)
                Con_Printf("%s\n", s);
 
 fail:
-       PRVM_End;
+       ;
 }
 
-void PRVM_ED_GlobalGet_f(void)
+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)
        {
@@ -1216,14 +1162,10 @@ void PRVM_ED_GlobalGet_f(void)
                return;
        }
 
-       PRVM_Begin;
-       if(!PRVM_SetProgFromString(Cmd_Argv(1)))
-       {
-               Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
+       if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
                return;
-       }
 
-       key = PRVM_ED_FindGlobal(Cmd_Argv(2));
+       key = PRVM_ED_FindGlobal(prog, Cmd_Argv(2));
        if(!key)
        {
                Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
@@ -1231,7 +1173,7 @@ void PRVM_ED_GlobalGet_f(void)
        }
 
        v = (prvm_eval_t *) &prog->globals.generic[key->ofs];
-       s = PRVM_UglyValueString((etype_t)key->type, v);
+       s = PRVM_UglyValueString(prog, (etype_t)key->type, v, valuebuf, sizeof(valuebuf));
        if(Cmd_Argc() == 4)
        {
                cvar_t *cvar = Cvar_FindVar(Cmd_Argv(3));
@@ -1246,7 +1188,7 @@ void PRVM_ED_GlobalGet_f(void)
                Con_Printf("%s\n", s);
 
 fail:
-       PRVM_End;
+       ;
 }
 
 /*
@@ -1256,8 +1198,9 @@ PRVM_ED_EdictSet_f
 Console command to set a field of a specified edict
 =============
 */
-void PRVM_ED_EdictSet_f(void)
+static void PRVM_ED_EdictSet_f(void)
 {
+       prvm_prog_t *prog;
        prvm_edict_t *ed;
        ddef_t *key;
 
@@ -1267,21 +1210,15 @@ void PRVM_ED_EdictSet_f(void)
                return;
        }
 
-       PRVM_Begin;
-       if(!PRVM_SetProgFromString(Cmd_Argv(1)))
-       {
-               Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
+       if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
                return;
-       }
 
        ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
 
-       if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
+       if((key = PRVM_ED_FindField(prog, Cmd_Argv(3))) == 0)
                Con_Printf("Key %s not found !\n", Cmd_Argv(3));
        else
-               PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4), true);
-
-       PRVM_End;
+               PRVM_ED_ParseEpair(prog, ed, key, Cmd_Argv(4), true);
 }
 
 /*
@@ -1293,7 +1230,7 @@ ed should be a properly initialized empty edict.
 Used for initial level load and for savegames.
 ====================
 */
-const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
+const char *PRVM_ED_ParseEdict (prvm_prog_t *prog, const char *data, prvm_edict_t *ent)
 {
        ddef_t *key;
        qboolean anglehack;
@@ -1307,8 +1244,8 @@ const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
        while (1)
        {
        // parse key
-               if (!COM_ParseToken_Simple(&data, false, false))
-                       PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
+               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] == '}')
@@ -1339,13 +1276,13 @@ const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
                }
 
        // parse value
-               if (!COM_ParseToken_Simple(&data, false, false))
-                       PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
+               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] == '}')
-                       PRVM_ERROR ("PRVM_ED_ParseEdict: closing brace without data");
+                       prog->error_cmd("PRVM_ED_ParseEdict: closing brace without data");
 
                init = true;
 
@@ -1358,10 +1295,10 @@ const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
                if (keyname[0] == '_')
                        continue;
 
-               key = PRVM_ED_FindField (keyname);
+               key = PRVM_ED_FindField (prog, keyname);
                if (!key)
                {
-                       Con_DPrintf("%s: '%s' is not a field\n", PRVM_NAME, keyname);
+                       Con_DPrintf("%s: '%s' is not a field\n", prog->name, keyname);
                        continue;
                }
 
@@ -1372,8 +1309,8 @@ const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
                        dpsnprintf (com_token, sizeof(com_token), "0 %s 0", temp);
                }
 
-               if (!PRVM_ED_ParseEpair(ent, key, com_token, strcmp(keyname, "wad") != 0))
-                       PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
+               if (!PRVM_ED_ParseEpair(prog, ent, key, com_token, strcmp(keyname, "wad") != 0))
+                       prog->error_cmd("PRVM_ED_ParseEdict: parse error");
        }
 
        if (!init)
@@ -1398,12 +1335,13 @@ 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 (const char *data)
+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;
@@ -1416,10 +1354,10 @@ void PRVM_ED_LoadFromFile (const char *data)
        while (1)
        {
 // parse the opening brace
-               if (!COM_ParseToken_Simple(&data, false, false))
+               if (!COM_ParseToken_Simple(&data, false, false, true))
                        break;
                if (com_token[0] != '{')
-                       PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, com_token);
+                       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)
@@ -1428,19 +1366,19 @@ void PRVM_ED_LoadFromFile (const char *data)
                        ent = PRVM_EDICT_NUM(0);
                }
                else
-                       ent = PRVM_ED_Alloc();
+                       ent = PRVM_ED_Alloc(prog);
 
                // clear it
                if (ent != prog->edicts)        // hack
                        memset (ent->fields.vp, 0, prog->entityfields * 4);
 
-               data = PRVM_ED_ParseEdict (data, ent);
+               data = PRVM_ED_ParseEdict (prog, data, ent);
                parsed++;
 
                // remove the entity ?
-               if(prog->load_edict && !prog->load_edict(ent))
+               if(!prog->load_edict(prog, ent))
                {
-                       PRVM_ED_Free(ent);
+                       PRVM_ED_Free(prog, ent);
                        inhibited++;
                        continue;
                }
@@ -1448,8 +1386,9 @@ void PRVM_ED_LoadFromFile (const char *data)
                if (PRVM_serverfunction(SV_OnEntityPreSpawnFunction))
                {
                        // self = ent
+                       PRVM_serverglobalfloat(time) = sv.time;
                        PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
-                       PRVM_ExecuteProgram (PRVM_serverfunction(SV_OnEntityPreSpawnFunction), "QC function SV_OnEntityPreSpawnFunction is missing");
+                       prog->ExecuteProgram(prog, PRVM_serverfunction(SV_OnEntityPreSpawnFunction), "QC function SV_OnEntityPreSpawnFunction is missing");
                }
 
                if(ent->priv.required->free)
@@ -1466,17 +1405,17 @@ void PRVM_ED_LoadFromFile (const char *data)
                        if (!PRVM_alledictstring(ent, classname))
                        {
                                Con_Print("No classname for:\n");
-                               PRVM_ED_Print(ent, NULL);
-                               PRVM_ED_Free (ent);
+                               PRVM_ED_Print(prog, ent, NULL);
+                               PRVM_ED_Free (prog, ent);
                                continue;
                        }
 
                        // look for the spawn function
-                       funcname = PRVM_GetString(PRVM_alledictstring(ent, classname));
-                       func = PRVM_ED_FindFunction (va("spawnfunc_%s", funcname));
+                       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 (funcname);
+                                       func = PRVM_ED_FindFunction (prog, funcname);
 
                        if (!func)
                        {
@@ -1484,25 +1423,27 @@ void PRVM_ED_LoadFromFile (const char *data)
                                if (PRVM_serverfunction(SV_OnEntityNoSpawnFunction))
                                {
                                        // self = ent
+                                       PRVM_serverglobalfloat(time) = sv.time;
                                        PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
-                                       PRVM_ExecuteProgram (PRVM_serverfunction(SV_OnEntityNoSpawnFunction), "QC function SV_OnEntityNoSpawnFunction is missing");
+                                       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(ent, NULL);
+                                               PRVM_ED_Print(prog, ent, NULL);
                                        }
-                                       PRVM_ED_Free (ent);
+                                       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);
-                               PRVM_ExecuteProgram (func - prog->functions, "");
+                               prog->ExecuteProgram(prog, func - prog->functions, "");
                        }
                }
 
@@ -1510,8 +1451,9 @@ void PRVM_ED_LoadFromFile (const char *data)
                if (PRVM_serverfunction(SV_OnEntityPostSpawnFunction))
                {
                        // self = ent
+                       PRVM_serverglobalfloat(time) = sv.time;
                        PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
-                       PRVM_ExecuteProgram (PRVM_serverfunction(SV_OnEntityPostSpawnFunction), "QC function SV_OnEntityPostSpawnFunction is missing");
+                       prog->ExecuteProgram(prog, PRVM_serverfunction(SV_OnEntityPostSpawnFunction), "QC function SV_OnEntityPostSpawnFunction is missing");
                }
 
                spawned++;
@@ -1519,12 +1461,12 @@ void PRVM_ED_LoadFromFile (const char *data)
                        died++;
        }
 
-       Con_DPrintf("%s: %i new entities parsed, %i new inhibited, %i (%i new) spawned (whereas %i removed self, %i stayed)\n", PRVM_NAME, parsed, inhibited, prog->num_edicts, spawned, died, spawned - 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;
 }
 
-void PRVM_FindOffsets(void)
+static void PRVM_FindOffsets(prvm_prog_t *prog)
 {
        // field and global searches use -1 for NULL
        memset(&prog->fieldoffsets, -1, sizeof(prog->fieldoffsets));
@@ -1564,9 +1506,9 @@ void PRVM_FindOffsets(void)
 #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(#x);
-#define PRVM_DECLARE_global(x) prog->globaloffsets.x = PRVM_ED_FindGlobalOffset(#x);
-#define PRVM_DECLARE_function(x) prog->funcoffsets.x = PRVM_ED_FindFunctionOffset(#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
@@ -1640,7 +1582,7 @@ typedef struct po_s
        po_string_t *hashtable[PO_HASHSIZE];
 }
 po_t;
-void PRVM_PO_UnparseString(char *out, const char *in, size_t outsize)
+static void PRVM_PO_UnparseString(char *out, const char *in, size_t outsize)
 {
        for(;;)
        {
@@ -1681,7 +1623,7 @@ void PRVM_PO_UnparseString(char *out, const char *in, size_t outsize)
                ++in;
        }
 }
-void PRVM_PO_ParseString(char *out, const char *in, size_t outsize)
+static void PRVM_PO_ParseString(char *out, const char *in, size_t outsize)
 {
        for(;;)
        {
@@ -1740,7 +1682,7 @@ void PRVM_PO_ParseString(char *out, const char *in, size_t outsize)
                ++in;
        }
 }
-po_t *PRVM_PO_Load(const char *filename, mempool_t *pool)
+static po_t *PRVM_PO_Load(const char *filename, mempool_t *pool)
 {
        po_t *po;
        const char *p, *q;
@@ -1839,7 +1781,7 @@ po_t *PRVM_PO_Load(const char *filename, mempool_t *pool)
        Mem_Free((char *) buf);
        return po;
 }
-const char *PRVM_PO_Lookup(po_t *po, const char *str)
+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];
@@ -1851,7 +1793,7 @@ const char *PRVM_PO_Lookup(po_t *po, const char *str)
        }
        return NULL;
 }
-void PRVM_PO_Destroy(po_t *po)
+static void PRVM_PO_Destroy(po_t *po)
 {
        int i;
        for(i = 0; i < PO_HASHSIZE; ++i)
@@ -1869,16 +1811,15 @@ void PRVM_PO_Destroy(po_t *po)
        Mem_Free(po);
 }
 
-void PRVM_LeakTest(void);
-void PRVM_ResetProg(void)
+void PRVM_LeakTest(prvm_prog_t *prog);
+void PRVM_Prog_Reset(prvm_prog_t *prog)
 {
-       PRVM_LeakTest();
-       PRVM_GCALL(reset_cmd)();
+       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->starttime = Sys_DoubleTime();
 }
 
 /*
@@ -1886,7 +1827,7 @@ void PRVM_ResetProg(void)
 PRVM_LoadLNO
 ===============
 */
-void PRVM_LoadLNO( const char *progname ) {
+static void PRVM_LoadLNO( prvm_prog_t *prog, const char *progname ) {
        fs_offset_t filesize;
        unsigned char *lno;
        unsigned int *header;
@@ -1934,7 +1875,7 @@ void PRVM_LoadLNO( const char *progname ) {
 PRVM_LoadProgs
 ===============
 */
-void PRVM_LoadProgs (const char * filename, 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_Load(prvm_prog_t *prog, const char * filename, 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;
@@ -1950,16 +1891,23 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
        int a;
        int b;
        int c;
+       char vabuf[1024];
 
        if (prog->loaded)
-               PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!", PRVM_NAME );
+               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
 
        dprograms = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
        if (dprograms == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
-               PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
+               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
 
-       Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, (int)(filesize/1024));
+       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++)
@@ -1971,7 +1919,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
        prog->progs_version = LittleLong(dprograms->version);
        prog->progs_crc = LittleLong(dprograms->crc);
        if (prog->progs_version != PROG_VERSION)
-               PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, 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));
@@ -1995,7 +1943,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
        prog->entityfields = prog->progs_entityfields;
 
        if (LittleLong(dprograms->ofs_strings) + prog->progs_numstrings >= (int)filesize)
-               PRVM_ERROR ("%s: %s strings go past end of file", PRVM_NAME, filename);
+               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;
@@ -2028,7 +1976,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                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)
-                       PRVM_ERROR("PRVM_LoadProgs: out of bounds function statement (function %d) in %s", i, PRVM_NAME);
+                       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
        }
 
@@ -2046,7 +1994,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
        {
                prog->globaldefs[prog->numglobaldefs].type = required_global[i].type;
                prog->globaldefs[prog->numglobaldefs].ofs = prog->numglobals;
-               prog->globaldefs[prog->numglobaldefs].s_name = PRVM_SetEngineString(required_global[i].name);
+               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
@@ -2059,7 +2007,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
        {
                prog->fielddefs[i].type = LittleShort(infielddefs[i].type);
                if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
-                       PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
+                       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
@@ -2070,7 +2018,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
        {
                prog->fielddefs[prog->numfielddefs].type = required_field[i].type;
                prog->fielddefs[prog->numfielddefs].ofs = prog->entityfields;
-               prog->fielddefs[prog->numfielddefs].s_name = PRVM_SetEngineString(required_field[i].name);
+               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
@@ -2101,7 +2049,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                case OP_IFNOT:
                        b = (short)b;
                        if (a >= prog->progs_numglobals || b + i < 0 || b + i >= prog->progs_numstatements)
-                               PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, PRVM_NAME);
+                               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;
@@ -2111,7 +2059,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                case OP_GOTO:
                        a = (short)a;
                        if (a + i < 0 || a + i >= prog->progs_numstatements)
-                               PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, PRVM_NAME);
+                               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;
@@ -2119,7 +2067,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                        prog->statements[i].jumpabsolute = i + a;
                        break;
                default:
-                       Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", (int)op, i, PRVM_NAME);
+                       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:
@@ -2156,7 +2104,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                case OP_LOAD_FNC:
                case OP_LOAD_V:
                        if (a >= prog->progs_numglobals || b >= prog->progs_numglobals || c >= prog->progs_numglobals)
-                               PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)", i);
+                               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);
@@ -2170,7 +2118,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                case OP_NOT_FNC:
                case OP_NOT_ENT:
                        if (a >= prog->progs_numglobals || c >= prog->progs_numglobals)
-                               PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
+                               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;
@@ -2192,7 +2140,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                case OP_STOREP_V:
                case OP_STORE_V:
                        if (a >= prog->progs_numglobals || b >= prog->progs_numglobals)
-                               PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
+                               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);
@@ -2212,7 +2160,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                case OP_DONE:
                case OP_RETURN:
                        if ( a >= prog->progs_numglobals)
-                               PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
+                               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;
@@ -2223,7 +2171,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
        }
        if(prog->numstatements < 1)
        {
-               PRVM_ERROR("PRVM_LoadProgs: empty program in %s", PRVM_NAME);
+               prog->error_cmd("PRVM_LoadProgs: empty program in %s", prog->name);
        }
        else switch(prog->statements[prog->numstatements - 1].op)
        {
@@ -2232,7 +2180,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                case OP_DONE:
                        break;
                default:
-                       PRVM_ERROR("PRVM_LoadProgs: program may fall off the edge (does not end with RETURN, GOTO or DONE) in %s", PRVM_NAME);
+                       prog->error_cmd("PRVM_LoadProgs: program may fall off the edge (does not end with RETURN, GOTO or DONE) in %s", prog->name);
                        break;
        }
 
@@ -2242,25 +2190,25 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
 
        // check required functions
        for(i=0 ; i < numrequiredfunc ; i++)
-               if(PRVM_ED_FindFunction(required_func[i]) == 0)
-                       PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_func[i], filename);
+               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(filename);
+       PRVM_LoadLNO(prog, filename);
 
-       PRVM_Init_Exec();
+       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 = !!strcmp(PRVM_NAME, "client");
-               const char *realfilename = (strcmp(PRVM_NAME, "client") ? filename : csqc_progname.string);
+               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 ; i<prog->numglobaldefs ; i++)
                        {
                                const char *name;
-                               name = PRVM_GetString(prog->globaldefs[i].s_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))
                                {
@@ -2271,19 +2219,19 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                }
                if(!strcmp(prvm_language.string, "dump"))
                {
-                       qfile_t *f = FS_OpenRealFile(va("%s.pot", realfilename), "w", false);
+                       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 ; i<prog->numglobaldefs ; i++)
                                {
                                        const char *name;
-                                       name = PRVM_GetString(prog->globaldefs[i].s_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(val->string);
+                                               const char *value = PRVM_GetString(prog, val->string);
                                                if(*value)
                                                {
                                                        char buf[MAX_INPUTLINE];
@@ -2297,23 +2245,23 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                }
                else
                {
-                       po_t *po = PRVM_PO_Load(va("%s.%s.po", realfilename, prvm_language.string), prog->progs_mempool);
+                       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 ; i<prog->numglobaldefs ; i++)
                                {
                                        const char *name;
-                                       name = PRVM_GetString(prog->globaldefs[i].s_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(val->string);
+                                               const char *value = PRVM_GetString(prog, val->string);
                                                if(*value)
                                                {
                                                        value = PRVM_PO_Lookup(po, value);
                                                        if(value)
-                                                               val->string = PRVM_SetEngineString(value);
+                                                               val->string = PRVM_SetEngineString(prog, value);
                                                }
                                        }
                                }
@@ -2324,7 +2272,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
        for (i=0 ; i<prog->numglobaldefs ; i++)
        {
                const char *name;
-               name = PRVM_GetString(prog->globaldefs[i].s_name);
+               name = PRVM_GetString(prog, prog->globaldefs[i].s_name);
                //Con_Printf("found var %s\n", name);
                if(name
                        && !strncmp(name, "autocvar_", 9)
@@ -2333,12 +2281,12 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                {
                        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, PRVM_NAME);
+                       //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, PRVM_NAME);
+                               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:
@@ -2352,22 +2300,22 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                                                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(val->string);
+                                               value = PRVM_GetString(prog, val->string);
                                                break;
                                        default:
-                                               Con_Printf("PRVM_LoadProgs: invalid type of autocvar global %s in %s\n", name, PRVM_NAME);
+                                               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(cvar->string);
-                                       cvar->globaldefindex_stringno[prog - prog_list] = val->string;
+                                       val->string = PRVM_SetEngineString(prog, cvar->string);
+                                       cvar->globaldefindex_stringno[prog - prvm_prog_list] = val->string;
                                }
                                if(!cvar)
-                                       PRVM_ERROR("PRVM_LoadProgs: could not create cvar for autocvar global %s in %s", name, PRVM_NAME);
-                               cvar->globaldefindex_progid[prog - prog_list] = prog->id;
-                               cvar->globaldefindex[prog - prog_list] = i;
+                                       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)
                        {
@@ -2396,18 +2344,18 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                                                }
                                                break;
                                        case ev_string:
-                                               val->string = PRVM_SetEngineString(cvar->string);
-                                               cvar->globaldefindex_stringno[prog - prog_list] = val->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, PRVM_NAME);
+                                               Con_Printf("PRVM_LoadProgs: invalid type of autocvar global %s in %s\n", name, prog->name);
                                                goto fail;
                                }
-                               cvar->globaldefindex_progid[prog - prog_list] = prog->id;
-                               cvar->globaldefindex[prog - prog_list] = i;
+                               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, PRVM_NAME);
+                               Con_Printf("PRVM_LoadProgs: private cvar for autocvar global %s in %s\n", name, prog->name);
                }
 fail:
                ;
@@ -2419,17 +2367,18 @@ fail:
 
        prog->flag = 0;
 
-       PRVM_FindOffsets();
+       PRVM_FindOffsets(prog);
 
-       PRVM_GCALL(init_cmd)();
+       prog->init_cmd(prog);
 
        // init mempools
-       PRVM_MEM_Alloc();
+       PRVM_MEM_Alloc(prog);
 }
 
 
-void PRVM_Fields_f (void)
+static void PRVM_Fields_f (void)
 {
+       prvm_prog_t *prog;
        int i, j, ednum, used, usedamount;
        int *counts;
        char tempstring[MAX_INPUTLINE], tempstring2[260];
@@ -2453,8 +2402,7 @@ void PRVM_Fields_f (void)
                return;
        }
 
-       PRVM_Begin;
-       if(!PRVM_SetProgFromString(Cmd_Argv(1)))
+       if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
                return;
 
        counts = (int *)Mem_Alloc(tempmempool, prog->numfielddefs * sizeof(int));
@@ -2466,7 +2414,7 @@ void PRVM_Fields_f (void)
                for (i = 1;i < prog->numfielddefs;i++)
                {
                        d = &prog->fielddefs[i];
-                       name = PRVM_GetString(d->s_name);
+                       name = PRVM_GetString(prog, d->s_name);
                        if (name[strlen(name)-2] == '_')
                                continue;       // skip _x, _y, _z vars
                        v = (int *)(ed->fields.vp + d->ofs);
@@ -2487,7 +2435,7 @@ void PRVM_Fields_f (void)
        for (i = 0;i < prog->numfielddefs;i++)
        {
                d = &prog->fielddefs[i];
-               name = PRVM_GetString(d->s_name);
+               name = PRVM_GetString(prog, d->s_name);
                if (name[strlen(name)-2] == '_')
                        continue;       // skip _x, _y, _z vars
                switch(d->type & ~DEF_SAVEGLOBAL)
@@ -2546,13 +2494,12 @@ void PRVM_Fields_f (void)
                }
        }
        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", PRVM_NAME, prog->entityfields, used, prog->entityfields * 4, usedamount * 4, prog->max_edicts, prog->entityfields * 4 * prog->max_edicts, usedamount * 4 * prog->max_edicts);
-
-       PRVM_End;
+       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);
 }
 
-void PRVM_Globals_f (void)
+static void PRVM_Globals_f (void)
 {
+       prvm_prog_t *prog;
        int i;
        const char *wildcard;
        int numculled;
@@ -2569,8 +2516,7 @@ void PRVM_Globals_f (void)
                return;
        }
 
-       PRVM_Begin;
-       if(!PRVM_SetProgFromString (Cmd_Argv (1)))
+       if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
                return;
 
        if( Cmd_Argc() == 3)
@@ -2578,21 +2524,19 @@ void PRVM_Globals_f (void)
        else
                wildcard = NULL;
 
-       Con_Printf("%s :", PRVM_NAME);
+       Con_Printf("%s :", prog->name);
 
        for (i = 0;i < prog->numglobaldefs;i++)
        {
                if(wildcard)
-                       if( !matchpattern( PRVM_GetString(prog->globaldefs[i].s_name), wildcard, 1) )
+                       if( !matchpattern( PRVM_GetString(prog, prog->globaldefs[i].s_name), wildcard, 1) )
                        {
                                numculled++;
                                continue;
                        }
-               Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
+               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_End;
 }
 
 /*
@@ -2600,24 +2544,24 @@ void PRVM_Globals_f (void)
 PRVM_Global
 ===============
 */
-void PRVM_Global_f(void)
+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 <program name> <global name>\n" );
                return;
        }
 
-       PRVM_Begin;
-       if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
+       if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
                return;
 
-       global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
+       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( (etype_t)global->type, PRVM_GLOBALFIELDVALUE(global->ofs) ) );
-       PRVM_End;
+               Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( prog, (etype_t)global->type, PRVM_GLOBALFIELDVALUE(global->ofs), valuebuf, sizeof(valuebuf) ) );
 }
 
 /*
@@ -2625,24 +2569,23 @@ void PRVM_Global_f(void)
 PRVM_GlobalSet
 ===============
 */
-void PRVM_GlobalSet_f(void)
+static void PRVM_GlobalSet_f(void)
 {
+       prvm_prog_t *prog;
        ddef_t *global;
        if( Cmd_Argc() != 4 ) {
                Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
                return;
        }
 
-       PRVM_Begin;
-       if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
+       if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
                return;
 
-       global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
+       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( NULL, global, Cmd_Argv(3), true );
-       PRVM_End;
+               PRVM_ED_ParseEpair( prog, NULL, global, Cmd_Argv(3), true );
 }
 
 /*
@@ -2692,68 +2635,30 @@ void PRVM_Init (void)
 PRVM_InitProg
 ===============
 */
-void PRVM_InitProg(int prognr)
+void PRVM_Prog_Init(prvm_prog_t *prog)
 {
-       static unsigned int progid = 0;
-
-       if(prognr < 0 || prognr >= PRVM_MAXPROGS)
-               Sys_Error("PRVM_InitProg: Invalid program number %i",prognr);
-
-       prog = &prog_list[prognr];
-
-       if(prog->loaded)
-               PRVM_ResetProg();
+       if (prog->loaded)
+               PRVM_Prog_Reset(prog);
 
        memset(prog, 0, sizeof(prvm_prog_t));
-       prog->starttime = Sys_DoubleTime();
-       prog->id = ++progid;
-
-       prog->error_cmd = Host_Error;
        prog->leaktest_active = prvm_leaktest.integer != 0;
 }
 
-int PRVM_GetProgNr(void)
-{
-       return prog - prog_list;
-}
-
-void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
-{
-       return _Mem_Alloc(prog->progs_mempool, NULL, buffersize, 16, filename, fileline);
-}
-
-void _PRVM_Free(void *buffer, const char *filename, int fileline)
-{
-       _Mem_Free(buffer, filename, fileline);
-}
-
-void _PRVM_FreeAll(const char *filename, int fileline)
-{
-       prog->functions = NULL;
-       prog->strings = NULL;
-       prog->fielddefs = NULL;
-       prog->globaldefs = NULL;
-       prog->statements = NULL;
-       // FIXME: what about knownstrings?
-       _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
-}
-
 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
-unsigned int PRVM_EDICT_NUM_ERROR(unsigned int n, const char *filename, int fileline)
+unsigned int PRVM_EDICT_NUM_ERROR(prvm_prog_t *prog, unsigned int n, const char *filename, int fileline)
 {
-       PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
+       prog->error_cmd("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", prog->name, n, filename, fileline);
        return 0;
 }
 
-sizebuf_t vm_tempstringsbuf;
 #define PRVM_KNOWNSTRINGBASE 0x40000000
 
-const char *PRVM_GetString(int num)
+const char *PRVM_GetString(prvm_prog_t *prog, int num)
 {
        if (num < 0)
        {
                // invalid
-               VM_Warning("PRVM_GetString: Invalid string offset (%i < 0)\n", num);
+               VM_Warning(prog, "PRVM_GetString: Invalid string offset (%i < 0)\n", num);
                return "";
        }
        else if (num < prog->stringssize)
@@ -2761,15 +2666,15 @@ const char *PRVM_GetString(int num)
                // constant string from progs.dat
                return prog->strings + num;
        }
-       else if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
+       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 < vm_tempstringsbuf.cursize)
-                       return (char *)vm_tempstringsbuf.data + num;
+               if (num < prog->tempstringsbuf.cursize)
+                       return (char *)prog->tempstringsbuf.data + num;
                else
                {
-                       VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)\n", num, vm_tempstringsbuf.cursize);
+                       VM_Warning(prog, "PRVM_GetString: Invalid temp-string offset (%i >= %i prog->tempstringsbuf.cursize)\n", num, prog->tempstringsbuf.cursize);
                        return "";
                }
        }
@@ -2781,48 +2686,48 @@ const char *PRVM_GetString(int num)
                {
                        if (!prog->knownstrings[num])
                        {
-                               VM_Warning("PRVM_GetString: Invalid zone-string offset (%i has been freed)\n", num);
+                               VM_Warning(prog, "PRVM_GetString: Invalid zone-string offset (%i has been freed)\n", num);
                                return "";
                        }
                        return prog->knownstrings[num];
                }
                else
                {
-                       VM_Warning("PRVM_GetString: Invalid zone-string offset (%i >= %i)\n", num, prog->numknownstrings);
+                       VM_Warning(prog, "PRVM_GetString: Invalid zone-string offset (%i >= %i)\n", num, prog->numknownstrings);
                        return "";
                }
        }
        else
        {
                // invalid string offset
-               VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)\n", num, prog->stringssize);
+               VM_Warning(prog, "PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)\n", num, prog->stringssize);
                return "";
        }
 }
 
-const char *PRVM_ChangeEngineString(int i, const char *s)
+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)
-               PRVM_ERROR("PRVM_ChangeEngineString: s is not an engine string");
+               prog->error_cmd("PRVM_ChangeEngineString: s is not an engine string");
        old = prog->knownstrings[i];
        prog->knownstrings[i] = s;
        return old;
 }
 
-int PRVM_SetEngineString(const char *s)
+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)
-               PRVM_ERROR("PRVM_SetEngineString: s in prog->strings area");
+               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 *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
+       if (s >= (char *)prog->tempstringsbuf.data && s < (char *)prog->tempstringsbuf.data + prog->tempstringsbuf.maxsize)
 #if 1
-               return prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
+               return prog->stringssize + (s - (char *)prog->tempstringsbuf.data);
 #endif
        // see if it's a known string address
        for (i = 0;i < prog->numknownstrings;i++)
@@ -2873,7 +2778,7 @@ int PRVM_SetEngineString(const char *s)
 //  buffer)
 // the buffer size is automatically grown as needed
 
-int PRVM_SetTempString(const char *s)
+int PRVM_SetTempString(prvm_prog_t *prog, const char *s)
 {
        int size;
        char *t;
@@ -2881,32 +2786,32 @@ int PRVM_SetTempString(const char *s)
                return 0;
        size = (int)strlen(s) + 1;
        if (developer_insane.integer)
-               Con_DPrintf("PRVM_SetTempString: cursize %i, size %i\n", vm_tempstringsbuf.cursize, size);
-       if (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
-       {
-               sizebuf_t old = vm_tempstringsbuf;
-               if (vm_tempstringsbuf.cursize + size >= 1<<28)
-                       PRVM_ERROR("PRVM_SetTempString: ran out of tempstring memory!  (refusing to grow tempstring buffer over 256MB, cursize %i, size %i)\n", vm_tempstringsbuf.cursize, size);
-               vm_tempstringsbuf.maxsize = max(vm_tempstringsbuf.maxsize, 65536);
-               while (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
-                       vm_tempstringsbuf.maxsize *= 2;
-               if (vm_tempstringsbuf.maxsize != old.maxsize || vm_tempstringsbuf.data == NULL)
+               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, vm_tempstringsbuf.maxsize/1024);
-                       vm_tempstringsbuf.data = (unsigned char *) Mem_Alloc(sv_mempool, vm_tempstringsbuf.maxsize);
+                       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(vm_tempstringsbuf.data, old.data, old.cursize);
+                               memcpy(prog->tempstringsbuf.data, old.data, old.cursize);
                        if (old.data)
                                Mem_Free(old.data);
                }
        }
-       t = (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.cursize;
+       t = (char *)prog->tempstringsbuf.data + prog->tempstringsbuf.cursize;
        memcpy(t, s, size);
-       vm_tempstringsbuf.cursize += size;
-       return PRVM_SetEngineString(t);
+       prog->tempstringsbuf.cursize += size;
+       return PRVM_SetEngineString(prog, t);
 }
 
-int PRVM_AllocString(size_t bufferlength, char **pointer)
+int PRVM_AllocString(prvm_prog_t *prog, size_t bufferlength, char **pointer)
 {
        int i;
        if (!bufferlength)
@@ -2946,25 +2851,25 @@ int PRVM_AllocString(size_t bufferlength, char **pointer)
        prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength);
        prog->knownstrings_freeable[i] = true;
        if(prog->leaktest_active)
-               prog->knownstrings_origin[i] = PRVM_AllocationOrigin();
+               prog->knownstrings_origin[i] = PRVM_AllocationOrigin(prog);
        if (pointer)
                *pointer = (char *)(prog->knownstrings[i]);
        return PRVM_KNOWNSTRINGBASE + i;
 }
 
-void PRVM_FreeString(int num)
+void PRVM_FreeString(prvm_prog_t *prog, int num)
 {
        if (num == 0)
-               PRVM_ERROR("PRVM_FreeString: attempt to free a NULL string");
+               prog->error_cmd("PRVM_FreeString: attempt to free a NULL string");
        else if (num >= 0 && num < prog->stringssize)
-               PRVM_ERROR("PRVM_FreeString: attempt to free a constant string");
+               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])
-                       PRVM_ERROR("PRVM_FreeString: attempt to free a non-existent or already freed string");
+                       prog->error_cmd("PRVM_FreeString: attempt to free a non-existent or already freed string");
                if (!prog->knownstrings_freeable[num])
-                       PRVM_ERROR("PRVM_FreeString: attempt to free a string owned by the engine");
+                       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])
@@ -2974,10 +2879,10 @@ void PRVM_FreeString(int num)
                prog->firstfreeknownstring = min(prog->firstfreeknownstring, num);
        }
        else
-               PRVM_ERROR("PRVM_FreeString: invalid string offset %i", num);
+               prog->error_cmd("PRVM_FreeString: invalid string offset %i", num);
 }
 
-static qboolean PRVM_IsStringReferenced(string_t string)
+static qboolean PRVM_IsStringReferenced(prvm_prog_t *prog, string_t string)
 {
        int i, j;
 
@@ -3008,82 +2913,79 @@ static qboolean PRVM_IsStringReferenced(string_t string)
        return false;
 }
 
-static qboolean PRVM_IsEdictRelevant(prvm_edict_t *edict)
+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
-       switch(prog - prog_list)
+       if (prog == SVVM_prog)
        {
-               case PRVM_SERVERPROG:
-                       {
-                               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(" %s ", prvm_leaktest_ignore_classnames.string), va(" %s ", PRVM_GetString(PRVM_serveredictstring(edict, classname)))))
-                                               return true;
-                               }
-                       }
-                       break;
-               case PRVM_CLIENTPROG:
-                       {
-                               // 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(" %s ", prvm_leaktest_ignore_classnames.string), va(" %s ", PRVM_GetString(PRVM_clientedictstring(edict, classname)))))
-                                               return true;
-                               }
-                       }
-                       break;
-               case PRVM_MENUPROG:
-                       // menu prog does not have classnames
-                       break;
+               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_edict_t *edict, int mark)
+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;
 
-       switch(prog - prog_list)
-       {
-               case PRVM_SERVERPROG:
-                       targetname = PRVM_GetString(PRVM_serveredictstring(edict, targetname));
-                       break;
-       }
+       if (prog == SVVM_prog)
+               targetname = PRVM_GetString(prog, PRVM_serveredictstring(edict, targetname));
 
        if(targetname)
                if(!*targetname) // ""
                        targetname = NULL;
 
-       for (i = 0;i < prog->numglobaldefs;i++)
+       if(mark == 0)
        {
-               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 (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)
@@ -3095,7 +2997,7 @@ static qboolean PRVM_IsEdictReferenced(prvm_edict_t *edict, int mark)
                        continue;
                if(targetname)
                {
-                       const char *target = PRVM_GetString(PRVM_serveredictstring(ed, target));
+                       const char *target = PRVM_GetString(prog, PRVM_serveredictstring(ed, target));
                        if(target)
                                if(!strcmp(target, targetname))
                                        return true;
@@ -3113,7 +3015,7 @@ static qboolean PRVM_IsEdictReferenced(prvm_edict_t *edict, int mark)
        return false;
 }
 
-static void PRVM_MarkReferencedEdicts(void)
+static void PRVM_MarkReferencedEdicts(prvm_prog_t *prog)
 {
        int j;
        qboolean found_new;
@@ -3124,7 +3026,7 @@ static void PRVM_MarkReferencedEdicts(void)
                prvm_edict_t *ed = PRVM_EDICT_NUM(j);
                if(ed->priv.required->free)
                        continue;
-               ed->priv.required->mark = PRVM_IsEdictRelevant(ed) ? 1 : 0;
+               ed->priv.required->mark = PRVM_IsEdictRelevant(prog, ed) ? 1 : 0;
        }
 
        stage = 1;
@@ -3138,7 +3040,7 @@ static void PRVM_MarkReferencedEdicts(void)
                                continue;
                        if(ed->priv.required->mark)
                                continue;
-                       if(PRVM_IsEdictReferenced(ed, stage))
+                       if(PRVM_IsEdictReferenced(prog, ed, stage))
                        {
                                ed->priv.required->mark = stage + 1;
                                found_new = true;
@@ -3150,7 +3052,7 @@ static void PRVM_MarkReferencedEdicts(void)
        Con_DPrintf("leak check used %d stages to find all references\n", stage);
 }
 
-void PRVM_LeakTest(void)
+void PRVM_LeakTest(prvm_prog_t *prog)
 {
        int i, j;
        qboolean leaked = false;
@@ -3164,7 +3066,7 @@ void PRVM_LeakTest(void)
                if(prog->knownstrings[i])
                if(prog->knownstrings_freeable[i])
                if(prog->knownstrings_origin[i])
-               if(!PRVM_IsStringReferenced(PRVM_KNOWNSTRINGBASE + 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;
@@ -3172,7 +3074,7 @@ void PRVM_LeakTest(void)
        }
 
        // 2. Edicts
-       PRVM_MarkReferencedEdicts();
+       PRVM_MarkReferencedEdicts(prog);
        for(j = 0; j < prog->num_edicts; ++j)
        {
                prvm_edict_t *ed = PRVM_EDICT_NUM(j);
@@ -3182,10 +3084,12 @@ void PRVM_LeakTest(void)
                if(ed->priv.required->allocation_origin)
                {
                        Con_Printf("Unreferenced edict found!\n  Allocated at: %s\n", ed->priv.required->allocation_origin);
-                       PRVM_ED_Print(ed, NULL);
+                       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)
index 8fb0d69254722617045db75231ebb23c047bbf99..49142b727a32db211c9737a7fdab7c118e1c065c 100644 (file)
@@ -110,9 +110,6 @@ const char *prvm_opnames[] =
 "BITOR"
 };
 
-char *PRVM_GlobalString (int ofs);
-char *PRVM_GlobalStringNoContents (int ofs);
-extern ddef_t *PRVM_ED_FieldAtOfs(int ofs);
 
 
 //=============================================================================
@@ -124,14 +121,15 @@ PRVM_PrintStatement
 */
 extern cvar_t prvm_statementprofiling;
 extern cvar_t prvm_timeprofiling;
-void PRVM_PrintStatement(mstatement_t *s)
+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->xfunction->s_file ), prog->statement_linenums[ opnum ] );
+               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]);
@@ -146,27 +144,27 @@ void PRVM_PrintStatement(mstatement_t *s)
                for ( ; i<10 ; i++)
                        Con_Print(" ");
        }
-       if (s->operand[0] >= 0) Con_Printf(  "%s", PRVM_GlobalString(s->operand[0]));
-       if (s->operand[1] >= 0) Con_Printf(", %s", PRVM_GlobalString(s->operand[1]));
-       if (s->operand[2] >= 0) Con_Printf(", %s", PRVM_GlobalString(s->operand[2]));
+       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 (const char *name)
+void PRVM_PrintFunctionStatements (prvm_prog_t *prog, const char *name)
 {
        int i, firststatement, endstatement;
        mfunction_t *func;
-       func = PRVM_ED_FindFunction (name);
+       func = PRVM_ED_FindFunction (prog, name);
        if (!func)
        {
-               Con_Printf("%s progs: no function named %s\n", PRVM_NAME, name);
+               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", PRVM_NAME, name, -firststatement);
+               Con_Printf("%s progs: function %s is builtin #%i\n", prog->name, name, -firststatement);
                return;
        }
 
@@ -177,10 +175,11 @@ void PRVM_PrintFunctionStatements (const char *name)
                        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", PRVM_NAME, name, firststatement, endstatement, func->parm_start, func->parm_start + func->locals - 1);
+       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->statements + i);
+               PRVM_PrintStatement(prog, prog->statements + i);
                prog->statement_profile[i] = 0;
        }
 }
@@ -193,19 +192,17 @@ PRVM_PrintFunction_f
 */
 void PRVM_PrintFunction_f (void)
 {
+       prvm_prog_t *prog;
        if (Cmd_Argc() != 3)
        {
                Con_Printf("usage: prvm_printfunction <program name> <function name>\n");
                return;
        }
 
-       PRVM_Begin;
-       if(!PRVM_SetProgFromString(Cmd_Argv(1)))
+       if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
                return;
 
-       PRVM_PrintFunctionStatements(Cmd_Argv(2));
-
-       PRVM_End;
+       PRVM_PrintFunctionStatements(prog, Cmd_Argv(2));
 }
 
 /*
@@ -213,7 +210,7 @@ void PRVM_PrintFunction_f (void)
 PRVM_StackTrace
 ============
 */
-void PRVM_StackTrace (void)
+void PRVM_StackTrace (prvm_prog_t *prog)
 {
        mfunction_t     *f;
        int                     i;
@@ -227,14 +224,15 @@ void PRVM_StackTrace (void)
                if (!f)
                        Con_Print("<NULL FUNCTION>\n");
                else
-                       Con_Printf("%12s : %s : statement %i\n", PRVM_GetString(f->s_file), PRVM_GetString(f->s_name), prog->stack[i].s - f->first_statement);
+                       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(char *buf, size_t bufsize)
+void PRVM_ShortStackTrace(prvm_prog_t *prog, char *buf, size_t bufsize)
 {
        mfunction_t     *f;
        int                     i;
+       char vabuf[1024];
 
        if(prog)
        {
@@ -254,7 +252,7 @@ void PRVM_ShortStackTrace(char *buf, size_t bufsize)
 
                if(strlcat(buf,
                        f
-                               ? va("%s:%s(%i) ", PRVM_GetString(f->s_file), PRVM_GetString(f->s_name), prog->stack[i].s - f->first_statement)
+                               ? 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)
                                : "<NULL> ",
                        bufsize
                ) >= bufsize)
@@ -263,14 +261,15 @@ void PRVM_ShortStackTrace(char *buf, size_t bufsize)
 }
 
 
-void PRVM_CallProfile (void)
+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", PRVM_NAME );
+       Con_Printf( "%s Call Profile:\n", prog->name );
 
        sum = 0;
        do
@@ -289,18 +288,19 @@ void PRVM_CallProfile (void)
                if (best)
                {
                        sum += best->totaltime;
-                       Con_Printf("%9.4f %s\n", best->totaltime, PRVM_GetString(best->s_name));
+                       Con_Printf("%9.4f %s\n", best->totaltime, PRVM_GetString(prog, best->s_name));
                        best->totaltime = 0;
                }
        } while (best);
 
-       Con_Printf("Total time since last profile reset: %9.4f\n", Sys_DoubleTime() - prog->starttime);
+       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->starttime = Sys_DoubleTime();
+       prog->profiletime = newprofiletime;
 }
 
-void PRVM_Profile (int maxfunctions, double mintime, int sortby)
+void PRVM_Profile (prvm_prog_t *prog, int maxfunctions, double mintime, int sortby)
 {
        mfunction_t *f, *best;
        int i, num;
@@ -310,10 +310,10 @@ void PRVM_Profile (int maxfunctions, double mintime, int sortby)
                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", PRVM_NAME );
+               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", PRVM_NAME );
+               Con_Printf( "%s Profile:\n[CallCount] [Statement] [BuiltinCt] [StmtTotal] [BltnTotal] [self]\n", prog->name );
                //                        12345678901 12345678901 12345678901 12345678901 12345678901 123.45%
 
        num = 0;
@@ -381,18 +381,18 @@ void PRVM_Profile (int maxfunctions, double mintime, int sortby)
                                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(best->s_name));
+                                               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(best->s_name));
+                                               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(best->s_name));
+                                               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(best->s_name));
+                                               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++;
@@ -416,19 +416,17 @@ PRVM_CallProfile_f
 */
 void PRVM_CallProfile_f (void)
 {
+       prvm_prog_t *prog;
        if (Cmd_Argc() != 2)
        {
                Con_Print("prvm_callprofile <program name>\n");
                return;
        }
 
-       PRVM_Begin;
-       if(!PRVM_SetProgFromString(Cmd_Argv(1)))
+       if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
                return;
 
-       PRVM_CallProfile();
-
-       PRVM_End;
+       PRVM_CallProfile(prog);
 }
 
 /*
@@ -439,6 +437,7 @@ PRVM_Profile_f
 */
 void PRVM_Profile_f (void)
 {
+       prvm_prog_t *prog;
        int howmany;
 
        howmany = 1<<30;
@@ -450,17 +449,15 @@ void PRVM_Profile_f (void)
                return;
        }
 
-       PRVM_Begin;
-       if(!PRVM_SetProgFromString(Cmd_Argv(1)))
+       if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
                return;
 
-       PRVM_Profile(howmany, 0, 0);
-
-       PRVM_End;
+       PRVM_Profile(prog, howmany, 0, 0);
 }
 
 void PRVM_ChildProfile_f (void)
 {
+       prvm_prog_t *prog;
        int howmany;
 
        howmany = 1<<30;
@@ -472,35 +469,16 @@ void PRVM_ChildProfile_f (void)
                return;
        }
 
-       PRVM_Begin;
-       if(!PRVM_SetProgFromString(Cmd_Argv(1)))
+       if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
                return;
 
-       PRVM_Profile(howmany, 0, 1);
-
-       PRVM_End;
+       PRVM_Profile(prog, howmany, 0, 1);
 }
 
-void PRVM_CrashAll(void)
+void PRVM_PrintState(prvm_prog_t *prog)
 {
        int i;
-       prvm_prog_t *oldprog = prog;
-
-       for(i = 0; i < PRVM_MAXPROGS; i++)
-       {
-               if(!PRVM_ProgLoaded(i))
-                       continue;
-               PRVM_SetProg(i);
-               PRVM_Crash();
-       }
-
-       prog = oldprog;
-}
-
-void PRVM_PrintState(void)
-{
-       int i;
-       if(prog->statestring)
+       if (prog->statestring)
        {
                Con_Printf("Caller-provided information: %s\n", prog->statestring);
        }
@@ -508,33 +486,34 @@ void PRVM_PrintState(void)
        {
                for (i = -7; i <= 0;i++)
                        if (prog->xstatement + i >= prog->xfunction->first_statement)
-                               PRVM_PrintStatement (prog->statements + prog->xstatement + i);
+                               PRVM_PrintStatement(prog, prog->statements + prog->xstatement + i);
        }
        else
                Con_Print("null function executing??\n");
-       PRVM_StackTrace ();
+       PRVM_StackTrace(prog);
 }
 
-extern sizebuf_t vm_tempstringsbuf;
 extern cvar_t prvm_errordump;
-void Host_Savegame_to (const char *name);
-void PRVM_Crash(void)
+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", PRVM_NAME);
-               PRVM_PrintState();
+               Con_Printf("QuakeC crash report for %s:\n", prog->name);
+               PRVM_PrintState(prog);
        }
 
        if(prvm_errordump.integer)
        {
                // make a savegame
-               Host_Savegame_to(va("crash-%s.dmp", PRVM_NAME));
+               Host_Savegame_to(prog, va(vabuf, sizeof(vabuf), "crash-%s.dmp", prog->name));
        }
 
        // dump the stack so host_error can shutdown functions
@@ -542,7 +521,7 @@ void PRVM_Crash(void)
        prog->localstack_used = 0;
 
        // delete all tempstrings (FIXME: is this safe in VM->engine->VM recursion?)
-       vm_tempstringsbuf.cursize = 0;
+       prog->tempstringsbuf.cursize = 0;
 
        // reset the prog pointer
        prog = NULL;
@@ -563,12 +542,12 @@ PRVM_EnterFunction
 Returns the new program statement counter
 ====================
 */
-int PRVM_EnterFunction (mfunction_t *f)
+static int PRVM_EnterFunction (prvm_prog_t *prog, mfunction_t *f)
 {
        int             i, j, c, o;
 
        if (!f)
-               PRVM_ERROR ("PRVM_EnterFunction: NULL function in %s", PRVM_NAME);
+               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;
@@ -577,12 +556,12 @@ int PRVM_EnterFunction (mfunction_t *f)
        prog->stack[prog->depth].builtinsprofile_acc = -f->builtinsprofile;
        prog->depth++;
        if (prog->depth >=PRVM_MAX_STACK_DEPTH)
-               PRVM_ERROR ("stack overflow");
+               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)
-               PRVM_ERROR ("PRVM_ExecuteProgram: locals stack overflow in %s", PRVM_NAME);
+               prog->error_cmd("PRVM_ExecuteProgram: locals stack overflow in %s", prog->name);
 
        for (i=0 ; i < c ; i++)
                prog->localstack[prog->localstack_used+i] = ((int *)prog->globals.generic)[f->parm_start + i];
@@ -609,21 +588,21 @@ int PRVM_EnterFunction (mfunction_t *f)
 PRVM_LeaveFunction
 ====================
 */
-int PRVM_LeaveFunction (void)
+static int PRVM_LeaveFunction (prvm_prog_t *prog)
 {
        int             i, c;
        mfunction_t *f;
 
        if (prog->depth <= 0)
-               PRVM_ERROR ("prog stack underflow in %s", PRVM_NAME);
+               prog->error_cmd("prog stack underflow in %s", prog->name);
 
        if (!prog->xfunction)
-               PRVM_ERROR ("PR_LeaveFunction: NULL function in %s", PRVM_NAME);
+               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)
-               PRVM_ERROR ("PRVM_ExecuteProgram: locals stack underflow in %s", PRVM_NAME);
+               prog->error_cmd("PRVM_ExecuteProgram: locals stack underflow in %s", prog->name);
 
        for (i=0 ; i < c ; i++)
                ((int *)prog->globals.generic)[prog->xfunction->parm_start + i] = prog->localstack[prog->localstack_used+i];
@@ -656,7 +635,7 @@ int PRVM_LeaveFunction (void)
        return prog->stack[prog->depth].s;
 }
 
-void PRVM_Init_Exec(void)
+void PRVM_Init_Exec(prvm_prog_t *prog)
 {
        // dump the stack
        prog->depth = 0;
@@ -670,7 +649,6 @@ void PRVM_Init_Exec(void)
 #define OPC ((prvm_eval_t *)&prog->globals.generic[st->operand[2]])
 extern cvar_t prvm_traceqc;
 extern cvar_t prvm_statementprofiling;
-extern sizebuf_t vm_tempstringsbuf;
 extern qboolean prvm_runawaycheck;
 
 #ifdef PROFILING
@@ -679,7 +657,7 @@ extern qboolean prvm_runawaycheck;
 MVM_ExecuteProgram
 ====================
 */
-void MVM_ExecuteProgram (func_t fnum, const char *errormessage)
+void MVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
 {
        mstatement_t    *st, *startst;
        mfunction_t     *f, *newf;
@@ -690,19 +668,19 @@ void MVM_ExecuteProgram (func_t fnum, const char *errormessage)
        double  calltime;
        double tm, starttm;
 
-       calltime = Sys_DoubleTime();
+       calltime = Sys_DirtyTime();
 
        if (!fnum || fnum >= (unsigned int)prog->numfunctions)
        {
                if (PRVM_allglobaledict(self))
-                       PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
-               PRVM_ERROR ("MVM_ExecuteProgram: %s", errormessage);
+                       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 = vm_tempstringsbuf.cursize;
+       restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
 
        prog->trace = prvm_traceqc.integer;
 
@@ -710,7 +688,7 @@ void MVM_ExecuteProgram (func_t fnum, const char *errormessage)
        exitdepth = prog->depth;
 
 // make a stack frame
-       st = &prog->statements[PRVM_EnterFunction (f)];
+       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)
@@ -753,14 +731,16 @@ chooseexecprogram:
        }
 
 cleanup:
-       if (developer_insane.integer && vm_tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
-               Con_DPrintf("MVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog->functions[fnum].s_name), vm_tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize);
+       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
-       vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
+       prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
 
-       f->totaltime += (Sys_DoubleTime() - calltime);
+       tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
+       f->totaltime += tm;
 
-       SV_FlushBroadcastMessages();
+       if (prog == SVVM_prog)
+               SV_FlushBroadcastMessages();
 }
 
 /*
@@ -768,7 +748,7 @@ cleanup:
 CLVM_ExecuteProgram
 ====================
 */
-void CLVM_ExecuteProgram (func_t fnum, const char *errormessage)
+void CLVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage)
 {
        mstatement_t    *st, *startst;
        mfunction_t     *f, *newf;
@@ -779,19 +759,19 @@ void CLVM_ExecuteProgram (func_t fnum, const char *errormessage)
        double  calltime;
        double tm, starttm;
 
-       calltime = Sys_DoubleTime();
+       calltime = Sys_DirtyTime();
 
        if (!fnum || fnum >= (unsigned int)prog->numfunctions)
        {
                if (PRVM_allglobaledict(self))
-                       PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
-               PRVM_ERROR ("CLVM_ExecuteProgram: %s", errormessage);
+                       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 = vm_tempstringsbuf.cursize;
+       restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
 
        prog->trace = prvm_traceqc.integer;
 
@@ -799,7 +779,7 @@ void CLVM_ExecuteProgram (func_t fnum, const char *errormessage)
        exitdepth = prog->depth;
 
 // make a stack frame
-       st = &prog->statements[PRVM_EnterFunction (f)];
+       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)
@@ -842,14 +822,16 @@ chooseexecprogram:
        }
 
 cleanup:
-       if (developer_insane.integer && vm_tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
-               Con_DPrintf("CLVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog->functions[fnum].s_name), vm_tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize);
+       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
-       vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
+       prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
 
-       f->totaltime += (Sys_DoubleTime() - calltime);
+       tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
+       f->totaltime += tm;
 
-       SV_FlushBroadcastMessages();
+       if (prog == SVVM_prog)
+               SV_FlushBroadcastMessages();
 }
 #endif
 
@@ -858,7 +840,11 @@ cleanup:
 SVVM_ExecuteProgram
 ====================
 */
-void SVVM_ExecuteProgram (func_t fnum, const char *errormessage)
+#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;
@@ -869,19 +855,19 @@ void SVVM_ExecuteProgram (func_t fnum, const char *errormessage)
        double  calltime;
        double tm, starttm;
 
-       calltime = Sys_DoubleTime();
+       calltime = Sys_DirtyTime();
 
        if (!fnum || fnum >= (unsigned int)prog->numfunctions)
        {
                if (PRVM_allglobaledict(self))
-                       PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
-               PRVM_ERROR ("SVVM_ExecuteProgram: %s", errormessage);
+                       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 = vm_tempstringsbuf.cursize;
+       restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
 
        prog->trace = prvm_traceqc.integer;
 
@@ -889,7 +875,7 @@ void SVVM_ExecuteProgram (func_t fnum, const char *errormessage)
        exitdepth = prog->depth;
 
 // make a stack frame
-       st = &prog->statements[PRVM_EnterFunction (f)];
+       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)
@@ -932,12 +918,14 @@ chooseexecprogram:
        }
 
 cleanup:
-       if (developer_insane.integer && vm_tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
-               Con_DPrintf("SVVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog->functions[fnum].s_name), vm_tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize);
+       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
-       vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
+       prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
 
-       f->totaltime += (Sys_DoubleTime() - calltime);
+       tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0;
+       f->totaltime += tm;
 
-       SV_FlushBroadcastMessages();
+       if (prog == SVVM_prog)
+               SV_FlushBroadcastMessages();
 }
index 4d872f64bf4e72c09d0afba93c0910e6b24aa488..3ae82b335c3ba44dcc33575a6c45ff95b681e707 100644 (file)
@@ -1,9 +1,9 @@
 #ifdef PRVMTIMEPROFILING 
 #define PreError() \
        prog->xstatement = st - prog->statements; \
-       tm = Sys_DoubleTime(); \
+       tm = Sys_DirtyTime(); \
        prog->xfunction->profile += (st - startst); \
-       prog->xfunction->tprofile += (tm - starttm);
+       prog->xfunction->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0;
 #else
 #define PreError() \
        prog->xstatement = st - prog->statements; \
@@ -18,7 +18,7 @@
 
 #if PRVMSLOWINTERPRETER
                        if (prog->trace)
-                               PRVM_PrintStatement(st);
+                               PRVM_PrintStatement(prog, st);
                        prog->statement_profile[st - prog->statements]++;
 #endif
 
@@ -68,7 +68,7 @@
                                                prog->xfunction->profile += (st - startst);
                                                startst = st;
                                                prog->xstatement = st - prog->statements;
-                                               VM_Warning( "Attempted division by zero in %s\n", PRVM_NAME );
+                                               VM_Warning(prog, "Attempted division by zero in %s\n", prog->name );
                                        }
                                        OPC->_float = 0.0f;
                                }
                                OPC->_float = !OPA->vector[0] && !OPA->vector[1] && !OPA->vector[2];
                                break;
                        case OP_NOT_S:
-                               OPC->_float = !OPA->string || !*PRVM_GetString(OPA->string);
+                               OPC->_float = !OPA->string || !*PRVM_GetString(prog, OPA->string);
                                break;
                        case OP_NOT_FNC:
                                OPC->_float = !OPA->function;
                                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(OPA->string),PRVM_GetString(OPB->string));
+                               OPC->_float = !strcmp(PRVM_GetString(prog, OPA->string),PRVM_GetString(prog, OPB->string));
                                break;
                        case OP_EQ_E:
                                OPC->_float = OPA->_int == OPB->_int;
                                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(OPA->string),PRVM_GetString(OPB->string));
+                               OPC->_float = strcmp(PRVM_GetString(prog, OPA->string),PRVM_GetString(prog, OPB->string));
                                break;
                        case OP_NE_E:
                                OPC->_float = OPA->_int != OPB->_int;
                                if (OPB->_int < 0 || OPB->_int + 1 > prog->entityfieldsarea)
                                {
                                        PreError();
-                                       PRVM_ERROR("%s attempted to write to an out of bounds edict (%i)", PRVM_NAME, OPB->_int);
+                                       prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, OPB->_int);
                                        goto cleanup;
                                }
                                if (OPB->_int < prog->entityfields && !prog->allowworldwrites)
                                {
                                        prog->xstatement = st - prog->statements;
-                                       VM_Warning("assignment to world.%s (field %i) in %s\n", PRVM_GetString(PRVM_ED_FieldAtOfs(OPB->_int)->s_name), OPB->_int, PRVM_NAME);
+                                       VM_Warning(prog, "assignment to world.%s (field %i) in %s\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, OPB->_int)->s_name), OPB->_int, prog->name);
                                }
                                ptr = (prvm_eval_t *)(prog->edictsfields + OPB->_int);
                                ptr->_int = OPA->_int;
                                if (OPB->_int < 0 || OPB->_int + 3 > prog->entityfieldsarea)
                                {
                                        PreError();
-                                       PRVM_ERROR("%s attempted to write to an out of bounds edict (%i)", PRVM_NAME, OPB->_int);
+                                       prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, OPB->_int);
                                        goto cleanup;
                                }
                                if (OPB->_int < prog->entityfields && !prog->allowworldwrites)
                                {
                                        prog->xstatement = st - prog->statements;
-                                       VM_Warning("assignment to world.%s (field %i) in %s\n", PRVM_GetString(PRVM_ED_FieldAtOfs(OPB->_int)->s_name), OPB->_int, PRVM_NAME);
+                                       VM_Warning(prog, "assignment to world.%s (field %i) in %s\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, OPB->_int)->s_name), OPB->_int, prog->name);
                                }
                                ptr = (prvm_eval_t *)(prog->edictsfields + OPB->_int);
                                ptr->ivector[0] = OPA->ivector[0];
                                if (OPA->edict < 0 || OPA->edict >= prog->max_edicts)
                                {
                                        PreError();
-                                       PRVM_ERROR ("%s Progs attempted to address an out of bounds edict number", PRVM_NAME);
+                                       prog->error_cmd("%s Progs attempted to address an out of bounds edict number", prog->name);
                                        goto cleanup;
                                }
                                if ((unsigned int)(OPB->_int) >= (unsigned int)(prog->entityfields))
                                {
                                        PreError();
-                                       PRVM_ERROR("%s attempted to address an invalid field (%i) in an edict", PRVM_NAME, OPB->_int);
+                                       prog->error_cmd("%s attempted to address an invalid field (%i) in an edict", prog->name, OPB->_int);
                                        goto cleanup;
                                }
 #if 0
                                if (OPA->edict == 0 && !prog->allowworldwrites)
                                {
                                        PreError();
-                                       PRVM_ERROR("forbidden assignment to null/world entity in %s", PRVM_NAME);
+                                       prog->error_cmd("forbidden assignment to null/world entity in %s", prog->name);
                                        goto cleanup;
                                }
 #endif
                                if (OPA->edict < 0 || OPA->edict >= prog->max_edicts)
                                {
                                        PreError();
-                                       PRVM_ERROR ("%s Progs attempted to read an out of bounds edict number", PRVM_NAME);
+                                       prog->error_cmd("%s Progs attempted to read an out of bounds edict number", prog->name);
                                        goto cleanup;
                                }
                                if ((unsigned int)(OPB->_int) >= (unsigned int)(prog->entityfields))
                                {
                                        PreError();
-                                       PRVM_ERROR("%s attempted to read an invalid field in an edict (%i)", PRVM_NAME, OPB->_int);
+                                       prog->error_cmd("%s attempted to read an invalid field in an edict (%i)", prog->name, OPB->_int);
                                        goto cleanup;
                                }
                                ed = PRVM_PROG_TO_EDICT(OPA->edict);
                                if (OPA->edict < 0 || OPA->edict >= prog->max_edicts)
                                {
                                        PreError();
-                                       PRVM_ERROR ("%s Progs attempted to read an out of bounds edict number", PRVM_NAME);
+                                       prog->error_cmd("%s Progs attempted to read an out of bounds edict number", prog->name);
                                        goto cleanup;
                                }
                                if (OPB->_int < 0 || OPB->_int + 2 >= prog->entityfields)
                                {
                                        PreError();
-                                       PRVM_ERROR("%s attempted to read an invalid field in an edict (%i)", PRVM_NAME, OPB->_int);
+                                       prog->error_cmd("%s attempted to read an invalid field in an edict (%i)", prog->name, OPB->_int);
                                        goto cleanup;
                                }
                                ed = PRVM_PROG_TO_EDICT(OPA->edict);
                                        if (++jumpcount == 10000000 && prvm_runawaycheck)
                                        {
                                                prog->xstatement = st - prog->statements;
-                                               PRVM_Profile(1<<30, 1000000, 0);
-                                               PRVM_ERROR("%s runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", PRVM_NAME, jumpcount);
+                                               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;
                                        if (++jumpcount == 10000000 && prvm_runawaycheck)
                                        {
                                                prog->xstatement = st - prog->statements;
-                                               PRVM_Profile(1<<30, 0.01, 0);
-                                               PRVM_ERROR("%s runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", PRVM_NAME, jumpcount);
+                                               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;
                                if (++jumpcount == 10000000 && prvm_runawaycheck)
                                {
                                        prog->xstatement = st - prog->statements;
-                                       PRVM_Profile(1<<30, 0.01, 0);
-                                       PRVM_ERROR("%s runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", PRVM_NAME, jumpcount);
+                                       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_CALL7:
                        case OP_CALL8:
 #ifdef PRVMTIMEPROFILING 
-                               tm = Sys_DoubleTime();
-                               prog->xfunction->tprofile += (tm - starttm);
+                               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 - prog->statements;
                                prog->argc = st->op - OP_CALL0;
                                if (!OPA->function)
-                                       PRVM_ERROR("NULL function in %s", PRVM_NAME);
+                                       prog->error_cmd("NULL function in %s", prog->name);
 
                                if(!OPA->function || OPA->function >= (unsigned int)prog->numfunctions)
                                {
                                        PreError();
-                                       PRVM_ERROR("%s CALL outside the program", PRVM_NAME);
+                                       prog->error_cmd("%s CALL outside the program", prog->name);
                                        goto cleanup;
                                }
 
                                        prog->xfunction->builtinsprofile++;
                                        if (builtinnumber < prog->numbuiltins && prog->builtins[builtinnumber])
                                        {
-                                               prog->builtins[builtinnumber]();
+                                               prog->builtins[builtinnumber](prog);
 #ifdef PRVMTIMEPROFILING 
-                                               tm = Sys_DoubleTime();
-                                               newf->tprofile += (tm - starttm);
-                                               prog->xfunction->tbprofile += (tm - starttm);
+                                               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
                                        }
                                        else
-                                               PRVM_ERROR("No such builtin #%i in %s; most likely cause: outdated engine build. Try updating!", builtinnumber, PRVM_NAME);
+                                               prog->error_cmd("No such builtin #%i in %s; most likely cause: outdated engine build. Try updating!", builtinnumber, prog->name);
                                }
                                else
-                                       st = prog->statements + PRVM_EnterFunction(newf);
+                                       st = prog->statements + PRVM_EnterFunction(prog, newf);
                                startst = st;
                                break;
 
                        case OP_DONE:
                        case OP_RETURN:
 #ifdef PRVMTIMEPROFILING 
-                               tm = Sys_DoubleTime();
-                               prog->xfunction->tprofile += (tm - starttm);
+                               tm = Sys_DirtyTime();
+                               prog->xfunction->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0;
                                starttm = tm;
 #endif
                                prog->xfunction->profile += (st - startst);
                                prog->globals.generic[OFS_RETURN+1] = prog->globals.generic[st->operand[0]+1];
                                prog->globals.generic[OFS_RETURN+2] = prog->globals.generic[st->operand[0]+2];
 
-                               st = prog->statements + PRVM_LeaveFunction();
+                               st = prog->statements + PRVM_LeaveFunction(prog);
                                startst = st;
                                if (prog->depth <= exitdepth)
                                        goto cleanup; // all done
                                {
                                        PreError();
                                        prog->xstatement = st - prog->statements;
-                                       PRVM_ERROR("OP_STATE not supported by %s", PRVM_NAME);
+                                       prog->error_cmd("OP_STATE not supported by %s", prog->name);
                                }
                                break;
 
                                if (OPB->_int < 0 || OPB->_int + 4 > pr_edictareasize)
                                {
                                        PreError();
-                                       PRVM_ERROR ("%s Progs attempted to write to an out of bounds edict", PRVM_NAME);
+                                       prog->error_cmd("%s Progs attempted to write to an out of bounds edict", prog->name);
                                        goto cleanup;
                                }
 #endif
                                if (OPA->edict < 0 || OPA->edict >= prog->max_edicts)
                                {
                                        PreError();
-                                       PRVM_ERROR ("%s Progs attempted to read an out of bounds edict number", PRVM_NAME);
+                                       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();
-                                       PRVM_ERROR ("%s Progs attempted to read an invalid field in an edict", PRVM_NAME);
+                                       prog->error_cmd("%s Progs attempted to read an invalid field in an edict", prog->name);
                                        goto cleanup;
                                }
 #endif
                                if (OPB->_int < 0 || OPB->_int >= pr_globaldefs)
                                {
                                        PreError();
-                                       PRVM_ERROR ("%s Progs attempted to write to an invalid indexed global", PRVM_NAME);
+                                       prog->error_cmd("%s Progs attempted to write to an invalid indexed global", prog->name);
                                        goto cleanup;
                                }
 #endif
                                if (OPB->_int < 0 || OPB->_int + 2 >= pr_globaldefs)
                                {
                                        PreError();
-                                       PRVM_ERROR ("%s Progs attempted to write to an invalid indexed global", PRVM_NAME);
+                                       prog->error_cmd("%s Progs attempted to write to an invalid indexed global", prog->name);
                                        goto cleanup;
                                }
 #endif
                                if (i < 0 || i >= pr_globaldefs)
                                {
                                        PreError();
-                                       PRVM_ERROR ("%s Progs attempted to address an out of bounds global", PRVM_NAME);
+                                       prog->error_cmd("%s Progs attempted to address an out of bounds global", prog->name);
                                        goto cleanup;
                                }
 #endif
                                if (OPA->_int < 0 || OPA->_int >= pr_globaldefs)
                                {
                                        PreError();
-                                       PRVM_ERROR ("%s Progs attempted to read an invalid indexed global", PRVM_NAME);
+                                       prog->error_cmd("%s Progs attempted to read an invalid indexed global", prog->name);
                                        goto cleanup;
                                }
 #endif
                                if (OPA->_int < 0 || OPA->_int + 2 >= pr_globaldefs)
                                {
                                        PreError();
-                                       PRVM_ERROR ("%s Progs attempted to read an invalid indexed global", PRVM_NAME);
+                                       prog->error_cmd("%s Progs attempted to read an invalid indexed global", prog->name);
                                        goto cleanup;
                                }
 #endif
                                if (OPA->_int < 0 || OPA->_int >= st->b)
                                {
                                        PreError();
-                                       PRVM_ERROR ("%s Progs boundcheck failed at line number %d, value is < 0 or >= %d", PRVM_NAME, st->b, st->c);
+                                       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();
-                               PRVM_ERROR ("Bad opcode %i in %s", st->op, PRVM_NAME);
+                               prog->error_cmd("Bad opcode %i in %s", st->op, prog->name);
                                goto cleanup;
                        }
                }
index 1bd6c5e16f197bc79d1af5b0ffbb59a4d93a3d94..09ac75edcc95298ae85aba795704ffcc443cfc39 100644 (file)
@@ -29,10 +29,13 @@ 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(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_clientfieldfloat(shadertime)
@@ -68,6 +71,9 @@ 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)
@@ -83,7 +89,6 @@ PRVM_DECLARE_clientfunction(CSQC_Parse_TempEntity)
 PRVM_DECLARE_clientfunction(CSQC_Shutdown)
 PRVM_DECLARE_clientfunction(CSQC_UpdateView)
 PRVM_DECLARE_clientfunction(GameCommand)
-PRVM_DECLARE_clientfunction(Gecko_Query)
 PRVM_DECLARE_clientfunction(URI_Get_Callback)
 PRVM_DECLARE_clientglobaledict(other)
 PRVM_DECLARE_clientglobaledict(self)
@@ -97,6 +102,9 @@ 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)
@@ -299,6 +307,8 @@ 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(max_health)
 PRVM_DECLARE_field(maxs)
 PRVM_DECLARE_field(message)
@@ -329,6 +339,7 @@ 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)
@@ -361,6 +372,9 @@ 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)
@@ -389,7 +403,6 @@ PRVM_DECLARE_function(ClientDisconnect)
 PRVM_DECLARE_function(ClientKill)
 PRVM_DECLARE_function(EndFrame)
 PRVM_DECLARE_function(GameCommand)
-PRVM_DECLARE_function(Gecko_Query)
 PRVM_DECLARE_function(PlayerPostThink)
 PRVM_DECLARE_function(PlayerPreThink)
 PRVM_DECLARE_function(PutClientInServer)
@@ -432,6 +445,9 @@ 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)
@@ -545,7 +561,6 @@ PRVM_DECLARE_global(world)
 PRVM_DECLARE_global(worldstatus)
 PRVM_DECLARE_menufieldstring(classname)
 PRVM_DECLARE_menufunction(GameCommand)
-PRVM_DECLARE_menufunction(Gecko_Query)
 PRVM_DECLARE_menufunction(URI_Get_Callback)
 PRVM_DECLARE_menufunction(m_draw)
 PRVM_DECLARE_menufunction(m_init)
@@ -649,6 +664,8 @@ 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(max_health)
 PRVM_DECLARE_serverfieldfloat(modelflags)
 PRVM_DECLARE_serverfieldfloat(modelindex)
@@ -809,4 +826,4 @@ 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)
\ No newline at end of file
+PRVM_DECLARE_serverglobalvector(v_up)
index 2310bc2062e0143336e2c0b1e60de3583d2e96f0..65f241590335bffd34d37b7bbe89ae4193a9872d 100644 (file)
@@ -95,7 +95,6 @@ extern char engineversion[128];
 #define        MAX_PARTICLEEFFECTINFO  1024
 #define        MAX_PARTICLETEXTURES    256
 #define        MAXCLVIDEOS                             1
-#define        MAX_GECKO_INSTANCES             1
 #define        MAX_DYNAMIC_TEXTURE_COUNT       2
 #define        MAX_MAP_LEAFS                   8192
 
@@ -116,6 +115,9 @@ extern char engineversion[128];
 #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
@@ -162,7 +164,6 @@ extern char engineversion[128];
 #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_GECKO_INSTANCES             16 ///< maximum number of web browser textures active at once
 #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)
 
@@ -186,6 +187,9 @@ extern char engineversion[128];
 #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
 
 
@@ -391,10 +395,7 @@ extern char engineversion[128];
 #include "keys.h"
 #include "console.h"
 #include "menu.h"
-
-#include "glquake.h"
-
-#include "palette.h"
+#include "csprogs.h"
 
 extern qboolean noclip_anglehack;
 
@@ -404,6 +405,8 @@ extern cvar_t developer_insane;
 extern cvar_t developer_loadfile;
 extern cvar_t developer_loading;
 
+extern cvar_t sessionid;
+
 #define STARTCONFIGFILENAME "quake.rc"
 #define CONFIGFILENAME "config.cfg"
 
@@ -493,10 +496,16 @@ qboolean Sys_HaveSSE2(void);
 #define Sys_HaveSSE2() false
 #endif
 
+#include "glquake.h"
+
+#include "palette.h"
+
 /// incremented every frame, never reset
 extern int host_framecount;
 /// not bounded in any way, changed at start of every frame, never reset
 extern double realtime;
+/// equal to Sys_DirtyTime() at the start of this host frame
+extern double host_dirtytime;
 
 void Host_InitCommands(void);
 void Host_Main(void);
@@ -508,6 +517,8 @@ void Host_ClientCommands(const char *fmt, ...) DP_FUNC_PRINTF(1);
 void Host_ShutdownServer(void);
 void Host_Reconnect_f(void);
 void Host_NoOperation_f(void);
+void Host_LockSession(void);
+void Host_UnlockSession(void);
 
 void Host_AbortCurrentFrame(void);
 
index 3789d8d88b9b8e9174d4ff50eed532bc468dfe85..b8f8152f89316fd3f2b64708d519130e857a3b96 100644 (file)
@@ -213,7 +213,7 @@ static void R_DrawExplosion_TransparentCallback(const entity_render_t *ent, cons
        R_EntityMatrix(&identitymatrix);
 
 //     R_Mesh_ResetTextureState();
-       R_SetupShader_Generic(explosiontexture, NULL, GL_MODULATE, 1, false);
+       R_SetupShader_Generic(explosiontexture, NULL, GL_MODULATE, 1, false, false, false);
        for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
        {
                const explosion_t *e = explosion + surfacelist[surfacelistindex];
@@ -275,7 +275,7 @@ void R_DrawExplosions(void)
                {
                        R_MoveExplosion(&explosion[i]);
                        if (explosion[i].alpha)
-                               R_MeshQueue_AddTransparent(explosion[i].origin, R_DrawExplosion_TransparentCallback, NULL, i, NULL);
+                               R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, explosion[i].origin, R_DrawExplosion_TransparentCallback, NULL, i, NULL);
                }
        }
        while (numexplosions > 0 && explosion[i-1].alpha <= 0)
index 67d32ae80fbae5b79ed097b8ff88fcd91f5d00bb..5ef3ed144534841a4e08219a35435f9b65e7175f 100644 (file)
@@ -16,20 +16,20 @@ 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};
 
-void r_lightningbeams_start(void)
+static void r_lightningbeams_start(void)
 {
        r_lightningbeamtexture = NULL;
        r_lightningbeamqmbtexture = NULL;
 }
 
-void r_lightningbeams_setupqmbtexture(void)
+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);
 }
 
-void r_lightningbeams_setuptexture(void)
+static void r_lightningbeams_setuptexture(void)
 {
 #if 0
 #define BEAMWIDTH 128
@@ -103,7 +103,7 @@ void r_lightningbeams_setuptexture(void)
                        }
                }
 
-               Image_WriteTGABGRA(va("lightningbeam%i.tga", imagenumber), BEAMWIDTH, BEAMHEIGHT, pixels);
+               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);
@@ -151,13 +151,13 @@ void r_lightningbeams_setuptexture(void)
 #endif
 }
 
-void r_lightningbeams_shutdown(void)
+static void r_lightningbeams_shutdown(void)
 {
        r_lightningbeamtexture = NULL;
        r_lightningbeamqmbtexture = NULL;
 }
 
-void r_lightningbeams_newmap(void)
+static void r_lightningbeams_newmap(void)
 {
        if (r_lightningbeamtexture)
                R_SkinFrame_MarkUsed(r_lightningbeamtexture);
@@ -177,7 +177,7 @@ void R_LightningBeams_Init(void)
        R_RegisterModule("R_LightningBeams", r_lightningbeams_start, r_lightningbeams_shutdown, r_lightningbeams_newmap, NULL, NULL);
 }
 
-void R_CalcLightningBeamPolygonVertex3f(float *v, const float *start, const float *end, const float *offset)
+static void R_CalcLightningBeamPolygonVertex3f(float *v, const float *start, const float *end, const float *offset)
 {
        // near right corner
        VectorAdd     (start, offset, (v + 0));
@@ -189,7 +189,7 @@ void R_CalcLightningBeamPolygonVertex3f(float *v, const float *start, const floa
        VectorAdd     (end  , offset, (v + 9));
 }
 
-void R_CalcLightningBeamPolygonTexCoord2f(float *tc, float t1, float t2)
+static void R_CalcLightningBeamPolygonTexCoord2f(float *tc, float t1, float t2)
 {
        if (r_lightningbeam_qmbtexture.integer)
        {
@@ -217,7 +217,7 @@ void R_CalcLightningBeamPolygonTexCoord2f(float *tc, float t1, float t2)
 
 float beamrepeatscale;
 
-void R_DrawLightningBeam_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
+static void R_DrawLightningBeam_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
 {
        int surfacelistindex;
        float vertex3f[12*3];
@@ -320,7 +320,7 @@ void R_DrawLightningBeams(void)
                        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(org, R_DrawLightningBeam_TransparentCallback, NULL, i, NULL);
+                       R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, org, R_DrawLightningBeam_TransparentCallback, NULL, i, NULL);
                }
        }
 }
index c11668d4b1cab340a1d0a62d7271db7d97e93956..adec83e15b337ff8a42e49981fdb8679e53a3be1 100644 (file)
@@ -146,7 +146,7 @@ demonstrated by the game Doom3.
 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
 #endif
 
-extern void R_Shadow_EditLights_Init(void);
+static void R_Shadow_EditLights_Init(void);
 
 typedef enum r_shadow_rendermode_e
 {
@@ -244,8 +244,8 @@ rtexture_t *r_shadow_attenuationgradienttexture;
 rtexture_t *r_shadow_attenuation2dtexture;
 rtexture_t *r_shadow_attenuation3dtexture;
 skinframe_t *r_shadow_lightcorona;
-rtexture_t *r_shadow_shadowmap2dtexture;
-rtexture_t *r_shadow_shadowmap2dcolortexture;
+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
@@ -255,26 +255,26 @@ GLuint r_shadow_prepasslightingdiffusespecularfbo;
 GLuint r_shadow_prepasslightingdiffusefbo;
 int r_shadow_prepass_width;
 int r_shadow_prepass_height;
-rtexture_t *r_shadow_prepassgeometrydepthtexture;
-rtexture_t *r_shadow_prepassgeometrydepthcolortexture;
+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;
 
-static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
-
 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_deferred_8bitrange = {CVAR_SAVE, "r_shadow_deferred_8bitrange", "4", "dynamic range of image-based lighting when using 32bit color (does not apply to fp)"};
-//cvar_t r_shadow_deferred_fp = {CVAR_SAVE, "r_shadow_deferred_fp", "0", "use 16bit (1) or 32bit (2) floating point for accumulation of image-based lighting"};
 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)"};
@@ -422,7 +422,7 @@ skinframe_t *r_editlights_sprcubemaplight;
 skinframe_t *r_editlights_sprcubemapnoshadowlight;
 skinframe_t *r_editlights_sprselection;
 
-void R_Shadow_SetShadowMode(void)
+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;
@@ -441,7 +441,9 @@ void R_Shadow_SetShadowMode(void)
                case RENDERPATH_GL20:
                        if(r_shadow_shadowmapfilterquality < 0)
                        {
-                               if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
+                               if (!r_fb.usedepthtextures)
+                                       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, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) 
                                {
@@ -472,6 +474,8 @@ void R_Shadow_SetShadowMode(void)
                                        break;
                                }
                        }
+                       if (!r_fb.usedepthtextures)
+                               r_shadow_shadowmapsampler = false;
                        r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
                        break;
                case RENDERPATH_D3D9:
@@ -502,7 +506,7 @@ qboolean R_Shadow_ShadowMappingEnabled(void)
        }
 }
 
-void R_Shadow_FreeShadowMaps(void)
+static void R_Shadow_FreeShadowMaps(void)
 {
        R_Shadow_SetShadowMode();
 
@@ -510,20 +514,20 @@ void R_Shadow_FreeShadowMaps(void)
 
        r_shadow_fbo2d = 0;
 
-       if (r_shadow_shadowmap2dtexture)
-               R_FreeTexture(r_shadow_shadowmap2dtexture);
-       r_shadow_shadowmap2dtexture = NULL;
+       if (r_shadow_shadowmap2ddepthtexture)
+               R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
+       r_shadow_shadowmap2ddepthtexture = NULL;
 
-       if (r_shadow_shadowmap2dcolortexture)
-               R_FreeTexture(r_shadow_shadowmap2dcolortexture);
-       r_shadow_shadowmap2dcolortexture = 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;
 }
 
-void r_shadow_start(void)
+static void r_shadow_start(void)
 {
        // allocate vertex processing arrays
        r_shadow_bouncegridpixels = NULL;
@@ -535,8 +539,8 @@ void r_shadow_start(void)
        r_shadow_attenuation2dtexture = NULL;
        r_shadow_attenuation3dtexture = NULL;
        r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
-       r_shadow_shadowmap2dtexture = NULL;
-       r_shadow_shadowmap2dcolortexture = NULL;
+       r_shadow_shadowmap2ddepthtexture = NULL;
+       r_shadow_shadowmap2ddepthbuffer = NULL;
        r_shadow_shadowmapvsdcttexture = NULL;
        r_shadow_shadowmapmaxsize = 0;
        r_shadow_shadowmapsize = 0;
@@ -589,7 +593,7 @@ void r_shadow_start(void)
 }
 
 static void R_Shadow_FreeDeferred(void);
-void r_shadow_shutdown(void)
+static void r_shadow_shutdown(void)
 {
        CHECKGLERROR
        R_Shadow_UncompileWorldLights();
@@ -672,7 +676,7 @@ void r_shadow_shutdown(void)
                Mem_Free(r_shadow_buffer_lighttrispvs);
 }
 
-void r_shadow_newmap(void)
+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);
@@ -694,8 +698,6 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_usenormalmap);
        Cvar_RegisterVariable(&r_shadow_debuglight);
        Cvar_RegisterVariable(&r_shadow_deferred);
-       Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
-//     Cvar_RegisterVariable(&r_shadow_deferred_fp);
        Cvar_RegisterVariable(&r_shadow_gloss);
        Cvar_RegisterVariable(&r_shadow_gloss2intensity);
        Cvar_RegisterVariable(&r_shadow_glossintensity);
@@ -819,7 +821,7 @@ matrix4x4_t matrix_attenuationz =
        }
 };
 
-void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
+static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
 {
        numvertices = ((numvertices + 255) & ~255) * vertscale;
        numtriangles = ((numtriangles + 255) & ~255) * triscale;
@@ -1294,7 +1296,7 @@ void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *inv
        }
 }
 
-qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
+static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
 {
 #if 1
        return false;
@@ -1449,7 +1451,7 @@ int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t
        return mask;
 }
 
-int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
+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;
@@ -1518,7 +1520,7 @@ int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
     return mask;
 }
 
-int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
+static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
 {
        int i;
        vec3_t p, n;
@@ -2013,10 +2015,10 @@ void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
 
 void R_Shadow_RenderMode_Reset(void)
 {
-       R_Mesh_SetMainRenderTargets();
+       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]);
-       R_Mesh_ResetTextureState();
        GL_DepthRange(0, 1);
        GL_DepthTest(true);
        GL_DepthMask(false);
@@ -2028,7 +2030,7 @@ void R_Shadow_RenderMode_Reset(void)
        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(NULL, NULL, GL_MODULATE, 1, false);
+       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);
@@ -2050,7 +2052,7 @@ void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
        GL_ColorMask(0, 0, 0, 0);
        GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
        GL_CullFace(GL_NONE);
-       R_SetupShader_DepthOrShadow(false);
+       R_SetupShader_DepthOrShadow(false, false);
        r_shadow_rendermode = mode;
        switch(mode)
        {
@@ -2092,49 +2094,31 @@ static void R_Shadow_MakeShadowMap(int side, int size)
        switch (r_shadow_shadowmode)
        {
        case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
-               if (r_shadow_shadowmap2dtexture) return;
-               r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
-               r_shadow_shadowmap2dcolortexture = NULL;
-               switch(vid.renderpath)
+               if (r_shadow_shadowmap2ddepthtexture) return;
+               if (r_fb.usedepthtextures)
                {
-#ifdef SUPPORTD3D
-               case RENDERPATH_D3D9:
-                       r_shadow_shadowmap2dcolortexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), NULL, TEXTYPE_BGRA, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
-                       r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
-                       break;
-#endif
-               default:
-                       r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
-                       break;
+                       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), false);
+                       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;
        }
-
-       // render depth into the fbo, do not render color at all
-       // validate the fbo now
-       if (qglDrawBuffer)
-       {
-               int status;
-               qglDrawBuffer(GL_NONE);CHECKGLERROR
-               qglReadBuffer(GL_NONE);CHECKGLERROR
-               status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
-               if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
-               {
-                       Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
-                       Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
-                       Cvar_SetValueQuick(&r_shadow_deferred, 0);
-               }
-       }
 }
 
-void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
+static void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
 {
        float nearclip, farclip, bias;
        r_viewport_t viewport;
        int flipped;
-       GLuint fbo = 0;
+       GLuint fbo2d = 0;
        float clearcolor[4];
        nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
        farclip = 1.0f;
@@ -2152,17 +2136,20 @@ void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
        // complex unrolled cube approach (more flexible)
        if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
                R_Shadow_MakeVSDCT();
-       if (!r_shadow_shadowmap2dtexture)
+       if (!r_shadow_shadowmap2ddepthtexture)
                R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
-       if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
-       r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
-       r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
+       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();
-       R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
-       R_SetupShader_DepthOrShadow(true);
+       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);
        GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
        GL_DepthMask(true);
        GL_DepthTest(true);
@@ -2172,6 +2159,17 @@ init_done:
        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:
@@ -2190,33 +2188,30 @@ init_done:
                        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);
-                       GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
+                       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:
-               Vector4Set(clearcolor, 1,1,1,1);
-               // completely different meaning than in OpenGL path
-               r_shadow_shadowmap_parameters[1] = 0;
-               r_shadow_shadowmap_parameters[3] = -bias;
                // 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 (r_shadow_shadowmapsampler)
-               {
-                       GL_ColorMask(0,0,0,0);
-                       if (clear)
-                               GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
-               }
-               else
+               if (clear)
                {
-                       GL_ColorMask(1,1,1,1);
-                       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;
        }
@@ -2225,7 +2220,6 @@ init_done:
 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
 {
        R_Mesh_ResetTextureState();
-       R_Mesh_SetMainRenderTargets();
        if (transparent)
        {
                r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
@@ -2286,9 +2280,9 @@ void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadow
        // 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_prepassgeometrydepthtexture, 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);
        else
-               R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
+               R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
 
        r_shadow_usingshadowmap2d = shadowmapping;
 
@@ -2694,10 +2688,16 @@ void R_Shadow_UpdateBounceGridTexture(void)
                                r_refdef.stats.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)
-                               //      Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask, true);
-                               //else
+                               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)
@@ -3167,8 +3167,8 @@ static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numve
        int *newe;
        const int *e;
        float *c;
-       int maxtriangles = 4096;
-       static int newelements[4096*3];
+       int maxtriangles = 1024;
+       int newelements[1024*3];
        R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
        for (renders = 0;renders < 4;renders++)
        {
@@ -3321,8 +3321,8 @@ void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **textures
        qboolean negated;
        float lightcolor[3];
        VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
-       ambientscale = rsurface.rtlight->ambientscale;
-       diffusescale = rsurface.rtlight->diffusescale;
+       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)
        {
@@ -3556,7 +3556,7 @@ void R_Shadow_UncompileWorldLights(void)
        }
 }
 
-void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
+static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
 {
        int i, j;
        mplane_t plane;
@@ -3725,7 +3725,7 @@ void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
 #endif
 }
 
-void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
+static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
 {
        shadowmesh_t *mesh;
 
@@ -3755,7 +3755,7 @@ void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }
 
-void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
+static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
 {
        qboolean zpass = false;
        shadowmesh_t *mesh;
@@ -3830,7 +3830,7 @@ void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, co
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }
 
-void R_Shadow_DrawEntityShadow(entity_render_t *ent)
+static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
 {
        vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
        vec_t relativeshadowradius;
@@ -3866,7 +3866,7 @@ void R_Shadow_SetupEntityLight(const entity_render_t *ent)
        Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
 }
 
-void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
+static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
 {
        if (!r_refdef.scene.worldmodel->DrawLight)
                return;
@@ -3883,7 +3883,7 @@ void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned c
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }
 
-void R_Shadow_DrawEntityLight(entity_render_t *ent)
+static void R_Shadow_DrawEntityLight(entity_render_t *ent)
 {
        dp_model_t *model = ent->model;
        if (!model->DrawLight)
@@ -3896,7 +3896,7 @@ void R_Shadow_DrawEntityLight(entity_render_t *ent)
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }
 
-void R_Shadow_PrepareLight(rtlight_t *rtlight)
+static void R_Shadow_PrepareLight(rtlight_t *rtlight)
 {
        int i;
        float f;
@@ -4130,7 +4130,7 @@ void R_Shadow_PrepareLight(rtlight_t *rtlight)
        }
 }
 
-void R_Shadow_DrawLight(rtlight_t *rtlight)
+static void R_Shadow_DrawLight(rtlight_t *rtlight)
 {
        int i;
        int numsurfaces;
@@ -4379,13 +4379,9 @@ static void R_Shadow_FreeDeferred(void)
        R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
        r_shadow_prepasslightingdiffusefbo = 0;
 
-       if (r_shadow_prepassgeometrydepthtexture)
-               R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
-       r_shadow_prepassgeometrydepthtexture = NULL;
-
-       if (r_shadow_prepassgeometrydepthcolortexture)
-               R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
-       r_shadow_prepassgeometrydepthcolortexture = NULL;
+       if (r_shadow_prepassgeometrydepthbuffer)
+               R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
+       r_shadow_prepassgeometrydepthbuffer = NULL;
 
        if (r_shadow_prepassgeometrynormalmaptexture)
                R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
@@ -4417,7 +4413,7 @@ void R_Shadow_DrawPrepass(void)
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_Color(1,1,1,1);
        GL_DepthTest(true);
-       R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
+       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)
@@ -4444,7 +4440,7 @@ void R_Shadow_DrawPrepass(void)
        GL_ColorMask(1,1,1,1);
        GL_Color(1,1,1,1);
        GL_DepthTest(true);
-       R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, 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);
        Vector4Set(clearcolor, 0, 0, 0, 0);
        GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
        if (r_timereport_active)
@@ -4475,8 +4471,6 @@ void R_Shadow_DrawPrepass(void)
                        if (r_refdef.scene.lights[lnum]->draw)
                                R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
 
-       R_Mesh_SetMainRenderTargets();
-
        R_Shadow_RenderMode_End();
 
        if (r_timereport_active)
@@ -4484,7 +4478,7 @@ void R_Shadow_DrawPrepass(void)
 }
 
 void R_Shadow_DrawLightSprites(void);
-void R_Shadow_PrepareLights(void)
+void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
        int flag;
        int lnum;
@@ -4492,7 +4486,6 @@ void R_Shadow_PrepareLights(void)
        dlight_t *light;
        size_t range;
        float f;
-       GLenum status;
 
        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) ||
@@ -4502,6 +4495,10 @@ void R_Shadow_PrepareLights(void)
                r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
                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)
@@ -4511,7 +4508,7 @@ void R_Shadow_PrepareLights(void)
        case RENDERPATH_D3D10:
        case RENDERPATH_D3D11:
        case RENDERPATH_SOFT:
-       case RENDERPATH_GLES2:
+#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;
@@ -4528,78 +4525,36 @@ void R_Shadow_PrepareLights(void)
                        r_shadow_usingdeferredprepass = true;
                        r_shadow_prepass_width = vid.width;
                        r_shadow_prepass_height = vid.height;
-                       r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
-                       switch (vid.renderpath)
-                       {
-                       case RENDERPATH_D3D9:
-                               r_shadow_prepassgeometrydepthcolortexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrydepthcolormap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
-                               break;
-                       default:
-                               break;
-                       }
-                       r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, 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_COLORBUFFER, 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_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
+                       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_COLORBUFFER16F, 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_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
-                       R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
-                       // render depth into one texture and normalmap into the other
-                       if (qglDrawBuffersARB)
-                       {
-                               qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
-                               qglReadBuffer(GL_NONE);CHECKGLERROR
-                               status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
-                               if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
-                               {
-                                       Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
-                                       Cvar_SetValueQuick(&r_shadow_deferred, 0);
-                                       r_shadow_usingdeferredprepass = false;
-                               }
-                       }
+                       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_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
-                       R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
+                       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
-                       if (qglDrawBuffersARB)
-                       {
-                               qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
-                               qglReadBuffer(GL_NONE);CHECKGLERROR
-                               status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
-                               if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
-                               {
-                                       Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
-                                       Cvar_SetValueQuick(&r_shadow_deferred, 0);
-                                       r_shadow_usingdeferredprepass = false;
-                               }
-                       }
 
                        // set up the lighting pass fbo (diffuse)
-                       r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
-                       R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
+                       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
-                       if (qglDrawBuffersARB)
-                       {
-                               qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
-                               qglReadBuffer(GL_NONE);CHECKGLERROR
-                               status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
-                               if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
-                               {
-                                       Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
-                                       Cvar_SetValueQuick(&r_shadow_deferred, 0);
-                                       r_shadow_usingdeferredprepass = false;
-                               }
-                       }
                }
+#endif
                break;
        case RENDERPATH_GL11:
        case RENDERPATH_GL13:
        case RENDERPATH_GLES1:
+       case RENDERPATH_GLES2:
                r_shadow_usingdeferredprepass = false;
                break;
        }
@@ -4684,19 +4639,6 @@ void R_Shadow_DrawLights(void)
        R_Shadow_RenderMode_End();
 }
 
-extern const float r_screenvertex3f[12];
-extern void R_SetupView(qboolean allowwaterclippingplane);
-extern void R_ResetViewRendering3D(void);
-extern void R_ResetViewRendering2D(void);
-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;
-
 void R_Shadow_PrepareModelShadows(void)
 {
        int i;
@@ -4766,7 +4708,7 @@ void R_Shadow_PrepareModelShadows(void)
        }
 }
 
-void R_DrawModelShadowMaps(void)
+void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
        int i;
        float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
@@ -4778,7 +4720,7 @@ void R_DrawModelShadowMaps(void)
        float m[12];
        matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
        r_viewport_t viewport;
-       GLuint fbo = 0;
+       GLuint shadowfbo = 0;
        float clearcolor[4];
 
        if (!r_refdef.scene.numentities)
@@ -4792,18 +4734,22 @@ void R_DrawModelShadowMaps(void)
                return;
        }
 
-       R_ResetViewRendering3D();
+       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_shadowmap2dtexture)
+               if (!r_shadow_shadowmap2ddepthtexture)
                        R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
-               fbo = r_shadow_fbo2d;
-               r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
-               r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
+               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:
@@ -4851,8 +4797,11 @@ void R_DrawModelShadowMaps(void)
 
        VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
 
-       R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
-       R_SetupShader_DepthOrShadow(true);
+       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);
        GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
        GL_DepthMask(true);
        GL_DepthTest(true);
@@ -4861,7 +4810,7 @@ void R_DrawModelShadowMaps(void)
        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_shadowmap2dtexture)
+       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);
@@ -4872,7 +4821,7 @@ void R_DrawModelShadowMaps(void)
 
 #if 0
        // debugging
-       R_Mesh_SetMainRenderTargets();
+       R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
        R_SetupShader_ShowDepth(true);
        GL_ColorMask(1,1,1,1);
        GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
@@ -4961,7 +4910,7 @@ void R_DrawModelShadowMaps(void)
        }
 }
 
-void R_DrawModelShadows(void)
+void R_DrawModelShadows(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
 {
        int i;
        float relativethrowdistance;
@@ -4974,7 +4923,11 @@ void R_DrawModelShadows(void)
        if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
                return;
 
-       R_ResetViewRendering3D();
+       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();
@@ -5059,7 +5012,7 @@ void R_DrawModelShadows(void)
        //GL_ScissorTest(true);
        //R_EntityMatrix(&identitymatrix);
        //R_Mesh_ResetTextureState();
-       R_ResetViewRendering2D();
+       R_ResetViewRendering2D(fbo, depthtexture, colortexture);
 
        // set up a darkening blend on shadowed areas
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -5074,7 +5027,7 @@ void R_DrawModelShadows(void)
 
        // apply the blend to the shadowed areas
        R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, true);
+       R_SetupShader_Generic_NoTexture(false, true);
        R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
 
        // restore the viewport
@@ -5084,7 +5037,7 @@ void R_DrawModelShadows(void)
        //R_Shadow_RenderMode_End();
 }
 
-void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
+static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
 {
        float zdist;
        vec3_t centerorigin;
@@ -5109,6 +5062,7 @@ void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
                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);
@@ -5124,6 +5078,7 @@ void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
                        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__);
@@ -5144,7 +5099,7 @@ void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
 
 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
 
-void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
+static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
 {
        vec3_t color;
        GLint allpixels = 0, visiblepixels = 0;
@@ -5158,10 +5113,12 @@ void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
                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__);
@@ -5216,7 +5173,7 @@ void R_Shadow_DrawCoronas(void)
        size_t range;
        if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
                return;
-       if (r_waterstate.renderingscene)
+       if (r_fb.water.renderingscene)
                return;
        flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
        R_EntityMatrix(&identitymatrix);
@@ -5235,6 +5192,7 @@ void R_Shadow_DrawCoronas(void)
        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);
@@ -5256,8 +5214,9 @@ void R_Shadow_DrawCoronas(void)
                        GL_PolygonOffset(0, 0);
                        GL_DepthTest(true);
                        R_Mesh_ResetTextureState();
-                       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false);
+                       R_SetupShader_Generic_NoTexture(false, false);
                }
+#endif
                break;
        case RENDERPATH_D3D9:
                usequery = false;
@@ -5331,12 +5290,12 @@ void R_Shadow_DrawCoronas(void)
 
 
 
-dlight_t *R_Shadow_NewWorldLight(void)
+static dlight_t *R_Shadow_NewWorldLight(void)
 {
        return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
 }
 
-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)
+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
@@ -5377,7 +5336,7 @@ void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, ve
        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);
 }
 
-void R_Shadow_FreeWorldLight(dlight_t *light)
+static void R_Shadow_FreeWorldLight(dlight_t *light)
 {
        if (r_shadow_selectedlight == light)
                r_shadow_selectedlight = NULL;
@@ -5399,7 +5358,7 @@ void R_Shadow_ClearWorldLights(void)
        r_shadow_selectedlight = NULL;
 }
 
-void R_Shadow_SelectLight(dlight_t *light)
+static void R_Shadow_SelectLight(dlight_t *light)
 {
        if (r_shadow_selectedlight)
                r_shadow_selectedlight->selected = false;
@@ -5408,7 +5367,7 @@ void R_Shadow_SelectLight(dlight_t *light)
                r_shadow_selectedlight->selected = true;
 }
 
-void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
+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];
@@ -5417,7 +5376,7 @@ void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const r
        R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
 }
 
-void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
+static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
 {
        float intensity;
        float s;
@@ -5470,10 +5429,10 @@ void R_Shadow_DrawLightSprites(void)
        {
                light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
                if (light)
-                       R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
+                       R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
        }
        if (!r_editlights_lockcursor)
-               R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
+               R_MeshQueue_AddTransparent(MESHQUEUE_SORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
 }
 
 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
@@ -5496,7 +5455,7 @@ int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radiu
        return 1;
 }
 
-void R_Shadow_SelectLightInView(void)
+static void R_Shadow_SelectLightInView(void)
 {
        float bestrating, rating, temp[3];
        dlight_t *best;
@@ -5751,6 +5710,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
        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)
        {
@@ -5765,7 +5725,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                data = cl.worldmodel->brush.entities;
        if (!data)
                return;
-       for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
+       for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
        {
                type = LIGHTTYPE_MINUSX;
                origin[0] = origin[1] = origin[2] = 0;
@@ -5783,7 +5743,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                islight = false;
                while (1)
                {
-                       if (!COM_ParseToken_Simple(&data, false, false))
+                       if (!COM_ParseToken_Simple(&data, false, false, true))
                                break; // error
                        if (com_token[0] == '}')
                                break; // end of entity
@@ -5793,7 +5753,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                                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))
+                       if (!COM_ParseToken_Simple(&data, false, false, true))
                                break; // error
                        strlcpy(value, com_token, sizeof(value));
 
@@ -5954,14 +5914,14 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                }
                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("cubemaps/%i", skin) : NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
+                       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);
 }
 
 
-void R_Shadow_SetCursorLocationForView(void)
+static void R_Shadow_SetCursorLocationForView(void)
 {
        vec_t dist, push;
        vec3_t dest, endpos;
@@ -5998,7 +5958,7 @@ void R_Shadow_UpdateWorldLightSelection(void)
                R_Shadow_SelectLight(NULL);
 }
 
-void R_Shadow_EditLights_Clear_f(void)
+static void R_Shadow_EditLights_Clear_f(void)
 {
        R_Shadow_ClearWorldLights();
 }
@@ -6018,26 +5978,26 @@ void R_Shadow_EditLights_Reload_f(void)
        }
 }
 
-void R_Shadow_EditLights_Save_f(void)
+static void R_Shadow_EditLights_Save_f(void)
 {
        if (!cl.worldmodel)
                return;
        R_Shadow_SaveWorldLights();
 }
 
-void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
+static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
 {
        R_Shadow_ClearWorldLights();
        R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
 }
 
-void R_Shadow_EditLights_ImportLightsFile_f(void)
+static void R_Shadow_EditLights_ImportLightsFile_f(void)
 {
        R_Shadow_ClearWorldLights();
        R_Shadow_LoadLightsFile();
 }
 
-void R_Shadow_EditLights_Spawn_f(void)
+static void R_Shadow_EditLights_Spawn_f(void)
 {
        vec3_t color;
        if (!r_editlights.integer)
@@ -6054,7 +6014,7 @@ void R_Shadow_EditLights_Spawn_f(void)
        R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
 }
 
-void R_Shadow_EditLights_Edit_f(void)
+static void R_Shadow_EditLights_Edit_f(void)
 {
        vec3_t origin, angles, color;
        vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
@@ -6380,7 +6340,7 @@ void R_Shadow_EditLights_Edit_f(void)
        R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
 }
 
-void R_Shadow_EditLights_EditAll_f(void)
+static void R_Shadow_EditLights_EditAll_f(void)
 {
        size_t lightindex;
        dlight_t *light, *oldselected;
@@ -6453,7 +6413,7 @@ void R_Shadow_EditLights_DrawSelectedLightProperties(void)
        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;
 }
 
-void R_Shadow_EditLights_ToggleShadow_f(void)
+static void R_Shadow_EditLights_ToggleShadow_f(void)
 {
        if (!r_editlights.integer)
        {
@@ -6468,7 +6428,7 @@ void R_Shadow_EditLights_ToggleShadow_f(void)
        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);
 }
 
-void R_Shadow_EditLights_ToggleCorona_f(void)
+static void R_Shadow_EditLights_ToggleCorona_f(void)
 {
        if (!r_editlights.integer)
        {
@@ -6483,7 +6443,7 @@ void R_Shadow_EditLights_ToggleCorona_f(void)
        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);
 }
 
-void R_Shadow_EditLights_Remove_f(void)
+static void R_Shadow_EditLights_Remove_f(void)
 {
        if (!r_editlights.integer)
        {
@@ -6499,7 +6459,7 @@ void R_Shadow_EditLights_Remove_f(void)
        r_shadow_selectedlight = NULL;
 }
 
-void R_Shadow_EditLights_Help_f(void)
+static void R_Shadow_EditLights_Help_f(void)
 {
        Con_Print(
 "Documentation on r_editlights system:\n"
@@ -6556,7 +6516,7 @@ void R_Shadow_EditLights_Help_f(void)
        );
 }
 
-void R_Shadow_EditLights_CopyInfo_f(void)
+static void R_Shadow_EditLights_CopyInfo_f(void)
 {
        if (!r_editlights.integer)
        {
@@ -6585,7 +6545,7 @@ void R_Shadow_EditLights_CopyInfo_f(void)
        r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
 }
 
-void R_Shadow_EditLights_PasteInfo_f(void)
+static void R_Shadow_EditLights_PasteInfo_f(void)
 {
        if (!r_editlights.integer)
        {
@@ -6600,7 +6560,7 @@ void R_Shadow_EditLights_PasteInfo_f(void)
        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);
 }
 
-void R_Shadow_EditLights_Lock_f(void)
+static void R_Shadow_EditLights_Lock_f(void)
 {
        if (!r_editlights.integer)
        {
@@ -6620,7 +6580,7 @@ void R_Shadow_EditLights_Lock_f(void)
        r_editlights_lockcursor = true;
 }
 
-void R_Shadow_EditLights_Init(void)
+static void R_Shadow_EditLights_Init(void)
 {
        Cvar_RegisterVariable(&r_editlights);
        Cvar_RegisterVariable(&r_editlights_cursordistance);
@@ -6828,6 +6788,7 @@ void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const
                        intensity *= VectorLength(color);
                        VectorMA(sample + 12, intensity, relativepoint, sample + 12);
                }
+               // FIXME: sample bouncegrid too!
        }
 
        if (flags & LP_DYNLIGHT)
index c595fbe9f02e9232e1255dd4c586dcedbff07fbd..d4d4b078f2db3bc5f173047e2eb1fa12f6433a04 100644 (file)
@@ -78,7 +78,7 @@ void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec
 void R_RTLight_Compile(rtlight_t *rtlight);
 void R_RTLight_Uncompile(rtlight_t *rtlight);
 
-void R_Shadow_PrepareLights(void);
+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);
@@ -104,4 +104,7 @@ void R_Shadow_PrepareModelShadows(void);
 void R_LightPoint(vec3_t color, const vec3_t p, const int flags);
 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t 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
index 0f019bbb25b5ab2dfd26d40148b44daf84768eb7..97b2dafe6fae404f48df7744575ee01106a6632e 100644 (file)
@@ -74,7 +74,7 @@ void R_SkyStartFrame(void)
 R_SetSkyBox
 ==================
 */
-void R_UnloadSkyBox(void)
+static void R_UnloadSkyBox(void)
 {
        int i;
        int c = 0;
@@ -91,13 +91,14 @@ void R_UnloadSkyBox(void)
                Con_Printf("unloading skybox\n");
 }
 
-int R_LoadSkyBox(void)
+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();
 
@@ -122,7 +123,7 @@ int R_LoadSkyBox(void)
                        }
                        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("skyboxside%d", i), TEXF_CLAMP | (gl_texturecompression_sky.integer ? TEXF_COMPRESS : 0), temp, image_width, image_height, vid.sRGB3D);
+                       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++;
@@ -158,7 +159,7 @@ int R_SetSkyBox(const char *sky)
 }
 
 // LordHavoc: added LoadSky console command
-void LoadSky_f (void)
+static void LoadSky_f (void)
 {
        switch (Cmd_Argc())
        {
index 486b119f5271367b04278049bbbf47b97442cfb0..9ab013f31fbd48e2fb8c51a21ea6a5c35803d1cb 100644 (file)
@@ -35,7 +35,7 @@ extern cvar_t r_overheadsprites_scaley;
 #define SIDE_BOTTOM 3
 #define SIDE_RIGHT 4
 
-void R_TrackSprite(const entity_render_t *ent, vec3_t origin, vec3_t left, vec3_t up, int *edge, float *dir_angle)
+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
@@ -141,7 +141,7 @@ void R_TrackSprite(const entity_render_t *ent, vec3_t origin, vec3_t left, vec3_
        }
 }
 
-void R_RotateSprite(const mspriteframe_t *frame, vec3_t origin, vec3_t left, vec3_t up, int edge, float dir_angle)
+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))
        {
@@ -205,7 +205,7 @@ void R_RotateSprite(const mspriteframe_t *frame, vec3_t origin, vec3_t left, vec
 
 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
 
-void R_Model_Sprite_Draw_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
+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;
@@ -258,7 +258,7 @@ void R_Model_Sprite_Draw_TransparentCallback(const entity_render_t *ent, const r
                // honors scale
                // honors a global label scaling cvar
        
-               if(r_waterstate.renderingscene) // labels are considered HUD items, and don't appear in reflections
+               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
@@ -281,7 +281,7 @@ void R_Model_Sprite_Draw_TransparentCallback(const entity_render_t *ent, const r
                // 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_waterstate.renderingscene) // labels are considered HUD items, and don't appear in reflections
+               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
@@ -424,6 +424,6 @@ void R_Model_Sprite_Draw(entity_render_t *ent)
                return;
 
        Matrix4x4_OriginFromMatrix(&ent->matrix, org);
-       R_MeshQueue_AddTransparent(ent->flags & RENDER_NODEPTHTEST ? r_refdef.view.origin : org, R_Model_Sprite_Draw_TransparentCallback, ent, 0, rsurface.rtlight);
+       R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? MESHQUEUE_SORT_HUD : ((ent->flags & RENDER_WORLDOBJECT) ? MESHQUEUE_SORT_SKY : MESHQUEUE_SORT_DISTANCE), org, R_Model_Sprite_Draw_TransparentCallback, ent, 0, rsurface.rtlight);
 }
 
index 8c59f72ff5c276bd3a202ca776b04919c316735d..594fcad2a654f7d07fefcbd6740045a21e638f99 100644 (file)
@@ -34,6 +34,8 @@
 #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
 {
@@ -75,8 +77,20 @@ typedef enum textype_e
        TEXTYPE_COLORBUFFER16F,
        // this represents an RGBA float texture (4 32bit floats)
        TEXTYPE_COLORBUFFER32F,
-       // 16bit D16 (16bit depth) or 32bit S8D24 (24bit depth, 8bit stencil unused)
-       TEXTYPE_SHADOWMAP
+       // 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;
 
@@ -94,13 +108,17 @@ textype_t;
 typedef struct rtexture_s
 {
        // this is exposed (rather than private) for speed reasons only
-       int texnum;
-       qboolean dirty;
-       int gltexturetypeenum; // exposed for use in R_Mesh_TexBind
+       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 d3disdepthsurface; // for depth/stencil surfaces
+       qboolean d3disrendertargetsurface;
+       qboolean d3disdepthstencilsurface;
        int d3dformat;
        int d3dusage;
        int d3dpool;
@@ -152,8 +170,9 @@ extern cvar_t r_texture_dds_save;
 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, int precision, qboolean filter);
-rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel);
+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);
 
 // saves a texture to a DDS file
 int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha);
@@ -177,6 +196,9 @@ 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);
@@ -194,5 +216,7 @@ 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
 
index 9ef7403cd46832aac733e3d6fdb414f18199ab98..c869615a2fed6362c19e6e2acbe3ce38253bd4c6 100644 (file)
@@ -27,22 +27,22 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 extern float ixtable[4096];
 
 // fog stuff
-extern void FOG_clear(void);
+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;
-extern int R_SetSkyBox(const char *sky);
-extern void R_SkyStartFrame(void);
-extern void R_Sky(void);
-extern void R_ResetSkyBox(void);
+int R_SetSkyBox(const char *sky);
+void R_SkyStartFrame(void);
+void R_Sky(void);
+void R_ResetSkyBox(void);
 
 // SHOWLMP stuff (Nehahra)
-extern void SHOWLMP_decodehide(void);
-extern void SHOWLMP_decodeshow(void);
-extern void SHOWLMP_drawall(void);
+void SHOWLMP_decodehide(void);
+void SHOWLMP_decodeshow(void);
+void SHOWLMP_drawall(void);
 
 // render profiling stuff
 extern int r_timereport_active;
@@ -113,9 +113,6 @@ extern cvar_t r_showcollisionbrushes_polygonfactor;
 extern cvar_t r_showcollisionbrushes_polygonoffset;
 extern cvar_t r_showdisabledepthtest;
 
-//
-// view origin
-//
 extern cvar_t r_drawentities;
 extern cvar_t r_draw2d;
 extern qboolean r_draw2d_force;
@@ -129,6 +126,7 @@ 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(void); // 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,
@@ -191,6 +189,8 @@ 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;
@@ -441,17 +441,21 @@ typedef enum rsurfacepass_e
 }
 rsurfacepass_t;
 
-void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale, qboolean notrippy);
-void R_SetupShader_DepthOrShadow(qboolean notrippy);
+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);
 void R_SetupShader_ShowDepth(qboolean notrippy);
 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;
-       rtexture_t *texture_reflection;
-       rtexture_t *texture_camera;
+       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
@@ -463,14 +467,10 @@ r_waterstate_waterplane_t;
 
 typedef struct r_waterstate_s
 {
-       qboolean enabled;
-
-       qboolean renderingscene; // true while rendering a refraction or reflection texture, disables water surfaces
-       qboolean renderingrefraction;
-
        int waterwidth, waterheight;
        int texturewidth, textureheight;
        int camerawidth, cameraheight;
+       rtexture_t *depthtexture;
 
        int maxwaterplanes; // same as MAX_WATERPLANES
        int numwaterplanes;
@@ -478,10 +478,105 @@ typedef struct r_waterstate_s
 
        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;
 
-extern r_waterstate_t r_waterstate;
+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_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(void);
+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);
 
 #endif
 
index 80c6330fa3019202a7d89d9fa23b0dcb2a449ebc..fd242066fc8e6759f2418307f301a834f018bbf4 100644 (file)
@@ -21,6 +21,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 #include "time.h"
+#include "cl_collision.h"
+#include "csprogs.h"
 
 cachepic_t *sb_disc;
 
@@ -97,6 +99,7 @@ cvar_t showtime = {CVAR_SAVE, "showtime", "0", "shows current time of day (usefu
 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)"};
@@ -115,12 +118,11 @@ cvar_t crosshair_color_blue = {CVAR_SAVE, "crosshair_color_blue", "0", "customiz
 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"};
 
-void Sbar_MiniDeathmatchOverlay (int x, int y);
-void Sbar_DeathmatchOverlay (void);
-void Sbar_IntermissionOverlay (void);
-void Sbar_FinaleOverlay (void);
+static void Sbar_MiniDeathmatchOverlay (int x, int y);
+static void Sbar_DeathmatchOverlay (void);
+static void Sbar_IntermissionOverlay (void);
+static void Sbar_FinaleOverlay (void);
 
-void CL_VM_UpdateShowingScoresState (int showingscores);
 
 
 /*
@@ -130,7 +132,7 @@ Sbar_ShowScores
 Tab key down
 ===============
 */
-void Sbar_ShowScores (void)
+static void Sbar_ShowScores (void)
 {
        if (sb_showscores)
                return;
@@ -145,14 +147,15 @@ Sbar_DontShowScores
 Tab key up
 ===============
 */
-void Sbar_DontShowScores (void)
+static void Sbar_DontShowScores (void)
 {
        sb_showscores = false;
        CL_VM_UpdateShowingScoresState(sb_showscores);
 }
 
-void sbar_start(void)
+static void sbar_start(void)
 {
+       char vabuf[1024];
        int i;
 
        if (gamemode == GAME_DELUXEQUAKE || gamemode == GAME_BLOODOMNICIDE)
@@ -163,7 +166,7 @@ void sbar_start(void)
                sb_disc = Draw_CachePic_Flags ("gfx/disc", CACHEPICFLAG_QUIET);
 
                for (i = 0;i < 10;i++)
-                       sb_nums[0][i] = Draw_CachePic_Flags (va("gfx/num_%i",i), CACHEPICFLAG_QUIET);
+                       sb_nums[0][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/num_%i",i), CACHEPICFLAG_QUIET);
 
                somsb_health = Draw_CachePic_Flags ("gfx/hud_health", CACHEPICFLAG_QUIET);
                somsb_ammo[0] = Draw_CachePic_Flags ("gfx/sb_shells", CACHEPICFLAG_QUIET);
@@ -177,7 +180,7 @@ void sbar_start(void)
        else if (gamemode == GAME_NEXUIZ)
        {
                for (i = 0;i < 10;i++)
-                       sb_nums[0][i] = Draw_CachePic_Flags (va("gfx/num_%i",i), CACHEPICFLAG_QUIET);
+                       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);
 
@@ -210,7 +213,7 @@ void sbar_start(void)
                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("gfx/inv_weapon%i",i), CACHEPICFLAG_QUIET);
+                       sb_weapons[0][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inv_weapon%i",i), CACHEPICFLAG_QUIET);
        }
        else if (gamemode == GAME_ZYMOTIC)
        {
@@ -230,8 +233,8 @@ void sbar_start(void)
 
                for (i = 0;i < 10;i++)
                {
-                       sb_nums[0][i] = Draw_CachePic_Flags (va("gfx/num_%i",i), CACHEPICFLAG_QUIET);
-                       sb_nums[1][i] = Draw_CachePic_Flags (va("gfx/anum_%i",i), CACHEPICFLAG_QUIET);
+                       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);
@@ -258,13 +261,13 @@ void sbar_start(void)
 
                for (i = 0;i < 5;i++)
                {
-                       sb_weapons[2+i][0] = Draw_CachePic_Flags (va("gfx/inva%i_shotgun",i+1), CACHEPICFLAG_QUIET);
-                       sb_weapons[2+i][1] = Draw_CachePic_Flags (va("gfx/inva%i_sshotgun",i+1), CACHEPICFLAG_QUIET);
-                       sb_weapons[2+i][2] = Draw_CachePic_Flags (va("gfx/inva%i_nailgun",i+1), CACHEPICFLAG_QUIET);
-                       sb_weapons[2+i][3] = Draw_CachePic_Flags (va("gfx/inva%i_snailgun",i+1), CACHEPICFLAG_QUIET);
-                       sb_weapons[2+i][4] = Draw_CachePic_Flags (va("gfx/inva%i_rlaunch",i+1), CACHEPICFLAG_QUIET);
-                       sb_weapons[2+i][5] = Draw_CachePic_Flags (va("gfx/inva%i_srlaunch",i+1), CACHEPICFLAG_QUIET);
-                       sb_weapons[2+i][6] = Draw_CachePic_Flags (va("gfx/inva%i_lightng",i+1), CACHEPICFLAG_QUIET);
+                       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);
@@ -325,11 +328,11 @@ void sbar_start(void)
 
                        for (i = 0;i < 5;i++)
                        {
-                               hsb_weapons[2+i][0] = Draw_CachePic_Flags (va("gfx/inva%i_laser",i+1), CACHEPICFLAG_QUIET);
-                               hsb_weapons[2+i][1] = Draw_CachePic_Flags (va("gfx/inva%i_mjolnir",i+1), CACHEPICFLAG_QUIET);
-                               hsb_weapons[2+i][2] = Draw_CachePic_Flags (va("gfx/inva%i_gren_prox",i+1), CACHEPICFLAG_QUIET);
-                               hsb_weapons[2+i][3] = Draw_CachePic_Flags (va("gfx/inva%i_prox_gren",i+1), CACHEPICFLAG_QUIET);
-                               hsb_weapons[2+i][4] = Draw_CachePic_Flags (va("gfx/inva%i_prox",i+1), CACHEPICFLAG_QUIET);
+                               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);
@@ -365,11 +368,11 @@ void sbar_start(void)
        sb_finale = Draw_CachePic_Flags ("gfx/finale", CACHEPICFLAG_QUIET);
 }
 
-void sbar_shutdown(void)
+static void sbar_shutdown(void)
 {
 }
 
-void sbar_newmap(void)
+static void sbar_newmap(void)
 {
 }
 
@@ -386,6 +389,7 @@ void Sbar_Init (void)
        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);
@@ -419,17 +423,17 @@ int sbar_x, sbar_y;
 Sbar_DrawPic
 =============
 */
-void Sbar_DrawStretchPic (int x, int y, cachepic_t *pic, float alpha, float overridewidth, float overrideheight)
+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);
 }
 
-void Sbar_DrawPic (int x, int y, cachepic_t *pic)
+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);
 }
 
-void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha)
+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);
 }
@@ -441,9 +445,10 @@ Sbar_DrawCharacter
 Draws one solid graphics character
 ================
 */
-void Sbar_DrawCharacter (int x, int y, int num)
+static void Sbar_DrawCharacter (int x, int y, int num)
 {
-       DrawQ_String (sbar_x + x + 4 , sbar_y + y, va("%c", num), 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, true, FONT_SBAR);
+       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);
 }
 
 /*
@@ -451,7 +456,7 @@ void Sbar_DrawCharacter (int x, int y, int num)
 Sbar_DrawString
 ================
 */
-void Sbar_DrawString (int x, int y, char *str)
+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);
 }
@@ -461,7 +466,7 @@ void Sbar_DrawString (int x, int y, char *str)
 Sbar_DrawNum
 =============
 */
-void Sbar_DrawNum (int x, int y, int num, int digits, int color)
+static void Sbar_DrawNum (int x, int y, int num, int digits, int color)
 {
        char str[32], *ptr;
        int l, frame;
@@ -493,7 +498,7 @@ Sbar_DrawXNum
 =============
 */
 
-void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags)
+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;
@@ -528,7 +533,7 @@ void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r,
 //=============================================================================
 
 
-int Sbar_IsTeammatch(void)
+static int Sbar_IsTeammatch(void)
 {
        // currently only nexuiz uses the team score board
        return ((gamemode == GAME_NEXUIZ)
@@ -658,13 +663,14 @@ void Sbar_SortFrags (void)
 Sbar_SoloScoreboard
 ===============
 */
-void Sbar_SoloScoreboard (void)
+static void Sbar_SoloScoreboard (void)
 {
 #if 1
        char    str[80], timestr[40];
        int             max, timelen;
        int             minutes, seconds;
        double  t;
+       char vabuf[1024];
 
        t = (cl.intermission ? cl.completed_time : cl.time);
        minutes = (int)(t / 60);
@@ -672,14 +678,14 @@ void Sbar_SoloScoreboard (void)
 
        // monsters and secrets are now both on the top row
        if (cl.stats[STAT_TOTALMONSTERS])
-               Sbar_DrawString(8, 4, va("Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]));
+               Sbar_DrawString(8, 4, va(vabuf, sizeof(vabuf), "Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]));
        else if (cl.stats[STAT_MONSTERS]) // LA: Display something if monsters_killed is non-zero, but total_monsters is zero
-               Sbar_DrawString(8, 4, va("Monsters:%3i", cl.stats[STAT_MONSTERS]));
+               Sbar_DrawString(8, 4, va(vabuf, sizeof(vabuf), "Monsters:%3i", cl.stats[STAT_MONSTERS]));
 
        if (cl.stats[STAT_TOTALSECRETS])
-               Sbar_DrawString(8+22*8, 4, va("Secrets:%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]));
+               Sbar_DrawString(8+22*8, 4, va(vabuf, sizeof(vabuf), "Secrets:%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]));
        else if (cl.stats[STAT_SECRETS]) // LA: And similarly for secrets
-               Sbar_DrawString(8+22*8, 4, va("Secrets:%3i", cl.stats[STAT_SECRETS]));
+               Sbar_DrawString(8+22*8, 4, va(vabuf, sizeof(vabuf), "Secrets:%3i", cl.stats[STAT_SECRETS]));
 
        // format is like this: e1m1:The Sligpate Complex
        dpsnprintf(str, sizeof(str), "%s:%s", cl.worldbasename, cl.worldmessage);
@@ -739,7 +745,7 @@ void Sbar_SoloScoreboard (void)
 Sbar_DrawScoreboard
 ===============
 */
-void Sbar_DrawScoreboard (void)
+static void Sbar_DrawScoreboard (void)
 {
        Sbar_SoloScoreboard ();
        // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode
@@ -753,6 +759,7 @@ void Sbar_DrawScoreboard (void)
 // 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
@@ -760,7 +767,7 @@ static void Sbar_DrawWeapon(int nr, float fade, int active)
 
                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("%i",nr+1), 0, font_size, font_size, 1, 1, 0, sbar_alpha_fg.value, 0, NULL, true, FONT_DEFAULT);
+               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
        {
@@ -769,7 +776,7 @@ static void Sbar_DrawWeapon(int nr, float fade, int active)
                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("%i",nr+1), 0, font_size, font_size, 1, 0, 0, fade, 0, NULL, true, FONT_DEFAULT);
+               //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);
        }
 }
 
@@ -778,7 +785,7 @@ static void Sbar_DrawWeapon(int nr, float fade, int active)
 Sbar_DrawInventory
 ===============
 */
-void Sbar_DrawInventory (void)
+static void Sbar_DrawInventory (void)
 {
        int i;
        char num[6];
@@ -929,7 +936,7 @@ void Sbar_DrawInventory (void)
 Sbar_DrawFrags
 ===============
 */
-void Sbar_DrawFrags (void)
+static void Sbar_DrawFrags (void)
 {
        int i, k, l, x, f;
        char num[12];
@@ -978,7 +985,7 @@ void Sbar_DrawFrags (void)
 Sbar_DrawFace
 ===============
 */
-void Sbar_DrawFace (void)
+static void Sbar_DrawFace (void)
 {
        int f;
 
@@ -1114,6 +1121,7 @@ void Sbar_ShowFPS(void)
        char speedstring[32];
        char blurstring[32];
        char topspeedstring[48];
+       char texstring[MAX_QPATH];
        qboolean red = false;
        soundstring[0] = 0;
        fpsstring[0] = 0;
@@ -1123,6 +1131,7 @@ void Sbar_ShowFPS(void)
        datestring[0] = 0;
        speedstring[0] = 0;
        blurstring[0] = 0;
+       texstring[0] = 0;
        topspeedstring[0] = 0;
        if (showfps.integer)
        {
@@ -1200,6 +1209,26 @@ void Sbar_ShowFPS(void)
                        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;
@@ -1275,10 +1304,17 @@ void Sbar_ShowFPS(void)
                        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 - DrawQ_TextWidth(texstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR);
+                       DrawQ_Fill(fps_x, fps_y, vid_conwidth.integer - fps_x, fps_scaley, 0, 0, 0, 0.5, 0);
+                       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;
+               }
        }
 }
 
-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)
+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);
@@ -1309,6 +1345,7 @@ void Sbar_Score (int margin);
 void Sbar_Draw (void)
 {
        cachepic_t *pic;
+       char vabuf[1024];
 
        if(cl.csqc_vidvars.drawenginesbar)      //[515]: csqc drawsbar
        {
@@ -1753,12 +1790,12 @@ void Sbar_Draw (void)
 
        if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && !cl.intermission && !r_letterbox.value)
        {
-               pic = Draw_CachePic (va("gfx/crosshair%i", crosshair.integer));
+               pic = Draw_CachePic (va(vabuf, sizeof(vabuf), "gfx/crosshair%i", crosshair.integer));
                DrawQ_Pic((vid_conwidth.integer - pic->width * crosshair_size.value) * 0.5f, (vid_conheight.integer - pic->height * crosshair_size.value) * 0.5f, 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("gfx/prydoncursor%03i", cl_prydoncursor.integer)), 0, 0, 1, 1, 1, 1, 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);
 }
 
 //=============================================================================
@@ -1769,11 +1806,12 @@ Sbar_DeathmatchOverlay
 
 ==================
 */
-float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
+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)
@@ -1787,9 +1825,9 @@ float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
                if (s->qw_spectator)
                {
                        if (s->qw_ping || s->qw_packetloss)
-                               DrawQ_String(x, y, va("%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 );
+                               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("         %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 );
+                               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
                {
@@ -1804,11 +1842,11 @@ float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
                        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("%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);
+                       //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("%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 );
+                               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("         %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 );
+                               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
@@ -1816,9 +1854,9 @@ float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
                if (s->qw_spectator)
                {
                        if (s->qw_ping || s->qw_packetloss)
-                               DrawQ_String(x, y, va("%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 );
+                               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("         spect %c%s", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
+                               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
                {
@@ -1828,11 +1866,11 @@ float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
                        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("%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);
+                       //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("%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 );
+                               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("         %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 );
+                               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;
@@ -1841,6 +1879,7 @@ float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y)
 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)
@@ -1898,11 +1937,11 @@ void Sbar_DeathmatchOverlay (void)
        y = 40;
        if (cls.protocol == PROTOCOL_QUAKEWORLD)
        {
-               DrawQ_String(xmin, y, va("ping pl%% time frags team  name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
+               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("ping pl%% frags  name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR );
+               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;
 
@@ -2002,7 +2041,7 @@ void Sbar_MiniDeathmatchOverlay (int x, int y)
        }
 }
 
-int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
+static int Sbar_TeamColorCompare(const void *t1_, const void *t2_)
 {
        static int const sortorder[16] =
        {
index 4b566b6df162ffd947a21657e04ed1e3af22a394..0739756abb16f3a528fe10226bba7bf3df49f9fc 100644 (file)
@@ -32,5 +32,8 @@ void Sbar_Init (void);
 /// called every frame by screen
 void Sbar_Draw (void);
 
+int Sbar_GetSortedPlayerIndex (int index);
+void Sbar_SortFrags (void);
+
 #endif
 
index cb32fe422f2c21f93c7c17c6cccdc92c552e7b80..5d399607ca1ea7717ded40dce8dbd944f0e160a3 100644 (file)
@@ -53,6 +53,12 @@ typedef struct server_static_s
        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;
 
 //=============================================================================
@@ -317,6 +323,7 @@ typedef struct client_s
 #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
@@ -330,6 +337,8 @@ typedef struct client_s
 #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
@@ -449,6 +458,9 @@ 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;
@@ -470,6 +482,7 @@ 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;
@@ -490,13 +503,13 @@ 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);
-void SV_StartPointSound (vec3_t origin, const char *sample, int volume, float attenuation);
+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_SendClientMessages(void);
 
 void SV_ReadClientMessage(void);
 
@@ -550,6 +563,7 @@ int SV_GenericHitSuperContentsMask(const prvm_edict_t *edict);
 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);
 
@@ -558,7 +572,7 @@ 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 SV_MoveToGoal (void);
+void VM_SV_MoveToGoal(prvm_prog_t *prog);
 
 void SV_ApplyClientMove (void);
 void SV_SaveSpawnparms (void);
@@ -568,13 +582,20 @@ void SV_CheckVelocity (prvm_edict_t *ent);
 
 void SV_SetupVM(void);
 
-void SV_VM_Begin(void);
-void SV_VM_End(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);
 
-const char *Host_TimingReport(void); ///< for output in Host_Status_f
+void SV_StartThread(void);
+void SV_StopThread(void);
+#define SV_LockThreadMutex() (svs.threaded ? Thread_LockMutex(svs.threadmutex),1 : 0)
+#define SV_UnlockThreadMutex() (svs.threaded ? Thread_UnlockMutex(svs.threadmutex),1 : 0)
 
-int SV_GetPitchSign(prvm_edict_t *ent);
-void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix);
+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
 
index b02bd3c0a59cfea2031e7b2dc8acdb162d7870c8..c133ba280471c088e5831bea5c5aae3fea232a1e 100644 (file)
 "# 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) texture(a,b)\n"
+"# define dp_shadow2D(a,b) float(texture(a,b))\n"
 "#else\n"
 "# ifdef FRAGMENT_SHADER\n"
 "#  define dp_FragColor gl_FragColor\n"
@@ -29,6 +30,7 @@
 "# 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 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"
@@ -57,7 +65,7 @@
 "#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)\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 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"
 "#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 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"
 "#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"
 "      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"
 "      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"
 "}\n"
 "#endif\n"
 "#else // !MODE_GENERIC\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(myhalf3(normal))).xy * DistortScaleRefractReflect.xy;\n"
+"              vec2 ScreenTexCoord = SafeScreenTexCoord + vec3(normalize(cast_myhalf3(normal))).xy * DistortScaleRefractReflect.xy;\n"
 "      #else\n"
-"              vec2 ScreenTexCoord = SafeScreenTexCoord + vec3(normalize(myhalf3(dp_texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5))).xy * DistortScaleRefractReflect.xy;\n"
+"              vec2 ScreenTexCoord = SafeScreenTexCoord + vec3(normalize(cast_myhalf3(dp_texture2D(Texture_Normal, TexCoord)) - cast_myhalf3(0.5))).xy * DistortScaleRefractReflect.xy;\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"
 "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"
 "#endif\n"
 "\n"
 "#ifdef MODE_DEFERREDLIGHTSOURCE\n"
-"uniform sampler2D Texture_ScreenDepth;\n"
 "uniform sampler2D Texture_ScreenNormalMap;\n"
 "#endif\n"
 "#ifdef USEDEFERREDLIGHTMAP\n"
 "uniform highp float FogHeightFade;\n"
 "vec3 FogVertex(vec4 surfacecolor)\n"
 "{\n"
-"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_DEFERREDGEOMETRY) || defined(USEREFLECTCUBE)\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"
 "#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, myhalf2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0)).r);\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, myhalf2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0)).r);\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"
+"#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) * OffsetMapping_ScaleSteps.x) * vec2(-1, 1), -1);\n"
-"      //vec3 OffsetVector = vec3(normalize(EyeVectorFogDepth.xy) * OffsetMapping_ScaleSteps.x * vec2(-1, 1), -1);\n"
-"      vec3 OffsetVector = vec3(normalize(EyeVectorFogDepth.xyz).xy * OffsetMapping_ScaleSteps.x * vec2(-1, 1), -1);\n"
-"      vec3 RT = vec3(TexCoord, 1);\n"
-"      OffsetVector *= OffsetMapping_ScaleSteps.z;\n"
-"      for(i = 1.0; i < OffsetMapping_ScaleSteps.y; ++i)\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 < OffsetMapping_ScaleSteps.w; ++i, f *= 0.5)\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) * OffsetMapping_ScaleSteps.x) * vec2(-1, 1));\n"
-"      //vec2 OffsetVector = vec2(normalize(EyeVectorFogDepth.xy) * OffsetMapping_ScaleSteps.x * vec2(-1, 1));\n"
-"      vec2 OffsetVector = vec2(normalize(EyeVectorFogDepth.xyz).xy * OffsetMapping_ScaleSteps.x * vec2(-1, 1));\n"
-"      OffsetVector *= OffsetMapping_ScaleSteps.z;\n"
-"      for(i = 0.0; i < OffsetMapping_ScaleSteps.y; ++i)\n"
-"              TexCoord += OffsetVector * (1.0 - dp_textureGrad(Texture_Normal, TexCoord, dPdx, dPdy).a);\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"
 "vec3 GetShadowMapTC2D(vec3 dir)\n"
 "{\n"
 "      vec3 adir = abs(dir);\n"
-"      vec2 aparams = ShadowMap_Parameters.xy / max(max(adir.x, adir.y), adir.z);\n"
+"      float m = max(max(adir.x, adir.y), adir.z);\n"
+"      vec2 mparams = ShadowMap_Parameters.xy / m;\n"
 "      vec4 proj = dp_textureCube(Texture_CubeProjection, dir);\n"
-"      return vec3(mix(dir.xy, dir.zz, proj.xy) * aparams.x + proj.zw * ShadowMap_Parameters.z, aparams.y + ShadowMap_Parameters.w);\n"
+"#ifdef USEDEPTHRGB\n"
+"      return vec3(mix(dir.xy, dir.zz, proj.xy) * mparams.x + proj.zw * ShadowMap_Parameters.z, m + 64 * ShadowMap_Parameters.w);\n"
+"#else\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 ma = adir.z;\n"
-"      vec4 proj = vec4(dir, 2.5);\n"
-"      if (adir.x > ma) { ma = adir.x; proj = vec4(dir.zyx, 0.5); }\n"
-"      if (adir.y > ma) { ma = adir.y; proj = vec4(dir.xzy, 1.5); }\n"
-"      vec2 aparams = ShadowMap_Parameters.xy / ma;\n"
-"      return vec3(proj.xy * aparams.x + vec2(proj.z < 0.0 ? 1.5 : 0.5, proj.w) * ShadowMap_Parameters.z, aparams.y + ShadowMap_Parameters.w);\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 * 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"
 "      vec3 shadowmaptc = GetShadowMapTC2D(dir);\n"
 "      float f;\n"
 "\n"
-"#  ifdef USESHADOWSAMPLER\n"
-"#    ifdef USESHADOWMAPPCF\n"
-"#      define texval(x, y) dp_shadow2D(Texture_ShadowMap2D, vec3(center + vec2(x, y)*ShadowMap_TextureScale, shadowmaptc.z))  \n"
-"      vec2 center = shadowmaptc.xy*ShadowMap_TextureScale;\n"
-"      f = dot(vec4(0.25), vec4(texval(-0.4, 1.0), texval(-1.0, -0.4), texval(0.4, -1.0), texval(1.0, 0.4)));\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"
-"      f = dp_shadow2D(Texture_ShadowMap2D, vec3(shadowmaptc.xy*ShadowMap_TextureScale, shadowmaptc.z));\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 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"
+"#   ifdef USESHADOWSAMPLER\n"
+"#     ifdef USESHADOWMAPPCF\n"
+"#       define texval(x, y) dp_shadow2D(Texture_ShadowMap2D, vec3(center + vec2(x, y)*ShadowMap_TextureScale, shadowmaptc.z))  \n"
+"      vec2 center = shadowmaptc.xy*ShadowMap_TextureScale;\n"
+"      f = dot(vec4(0.25), vec4(texval(-0.4, 1.0), texval(-1.0, -0.4), texval(0.4, -1.0), texval(1.0, 0.4)));\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"
+"#       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 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) texture2DOffset(Texture_ShadowMap2D, center, ivec2(x, y)).r\n"
+"#       endif\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"
+"#       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 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"
+"#       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"
-"#     endif\n"
-"#    else\n"
+"#     else\n"
 "      f = step(shadowmaptc.z, dp_texture2D(Texture_ShadowMap2D, shadowmaptc.xy*ShadowMap_TextureScale).r);\n"
-"#    endif\n"
+"#     endif\n"
+"#   endif\n"
 "#  endif\n"
 "#  ifdef USESHADOWMAPORTHO\n"
 "      return mix(ShadowMap_Parameters.w, 1.0, f);\n"
 "#ifdef USETRIPPY\n"
 "      gl_Position = TrippyVertex(gl_Position);\n"
 "#endif\n"
+"      Depth = (ModelViewMatrix * Attrib_Position).z;\n"
 "}\n"
 "#endif // VERTEX_SHADER\n"
 "\n"
 "      float a = offsetMappedTexture2D(Texture_Gloss).a;\n"
 "#endif\n"
 "\n"
-"      dp_FragColor = vec4(normalize(surfacenormal.x * VectorS.xyz + surfacenormal.y * VectorT.xyz + surfacenormal.z * VectorR.xyz) * 0.5 + vec3(0.5, 0.5, 0.5), a);\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"
 "      // calculate viewspace pixel position\n"
 "      vec2 ScreenTexCoord = gl_FragCoord.xy * PixelToScreenTexCoord;\n"
 "      vec3 position;\n"
-"      position.z = ScreenToDepth.y / (dp_texture2D(Texture_ScreenDepth, ScreenTexCoord).r + ScreenToDepth.x);\n"
-"      position.xy = ModelViewPosition.xy * (position.z / ModelViewPosition.z);\n"
-"      // decode viewspace pixel normal\n"
+"      // get the geometry information (depth, normal, specular exponent)\n"
 "      myhalf4 normalmap = dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord);\n"
-"      myhalf3 surfacenormal = normalize(normalmap.rgb - myhalf3(0.5,0.5,0.5));\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 = position in lightspace\n"
+"      // CubeVector = pixel in lightspace\n"
 "      // eyevector = pixel to view in viewspace\n"
 "      vec3 CubeVector = vec3(ViewToLight * vec4(position,1));\n"
-"      myhalf fade = myhalf(dp_texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\n"
+"      myhalf fade = cast_myhalf(dp_texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\n"
 "#ifdef USEDIFFUSE\n"
 "      // calculate diffuse shading\n"
-"      myhalf3 lightnormal = myhalf3(normalize(LightPosition - position));\n"
-"      myhalf diffuse = myhalf(max(float(dot(surfacenormal, lightnormal)), 0.0));\n"
+"      myhalf3 lightnormal = cast_myhalf3(normalize(LightPosition - position));\n"
+"      myhalf diffuse = cast_myhalf(max(float(dot(surfacenormal, lightnormal)), 0.0));\n"
 "#endif\n"
 "#ifdef USESPECULAR\n"
 "      // calculate directional shading\n"
 "      vec3 eyevector = position * -1.0;\n"
 "#  ifdef USEEXACTSPECULARMATH\n"
-"      myhalf specular = pow(myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(eyevector)))*-1.0, 0.0)), SpecularPower * normalmap.a);\n"
+"      myhalf specular = pow(cast_myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(eyevector)))*-1.0, 0.0)), 1.0 + SpecularPower * normalmap.a);\n"
 "#  else\n"
-"      myhalf3 specularnormal = normalize(lightnormal + myhalf3(normalize(eyevector)));\n"
-"      myhalf specular = pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower * normalmap.a);\n"
+"      myhalf3 specularnormal = normalize(lightnormal + cast_myhalf3(normalize(eyevector)));\n"
+"      myhalf specular = pow(cast_myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), 1.0 + SpecularPower * normalmap.a);\n"
 "#  endif\n"
 "#endif\n"
 "\n"
 "      gl_FragColor.rgb *= cubecolor;\n"
 "# endif\n"
 "#endif\n"
-"      \n"
 "}\n"
 "#endif // FRAGMENT_SHADER\n"
 "#else // !MODE_DEFERREDLIGHTSOURCE\n"
 "#endif\n"
 "void main(void)\n"
 "{\n"
-"#if defined(MODE_VERTEXCOLOR) || defined(USEVERTEXTEXTUREBLEND)\n"
+"#if defined(MODE_VERTEXCOLOR) || defined(USEVERTEXTEXTUREBLEND) || defined(MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR)\n"
 "      VertexColor = Attrib_Color;\n"
 "#endif\n"
 "      // copy the surface texcoord\n"
 "#endif\n"
 "\n"
 "      // combine the diffuse textures (base, pants, shirt)\n"
-"      myhalf4 color = myhalf4(offsetMappedTexture2D(Texture_Color));\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 += myhalf3(offsetMappedTexture2D(Texture_Pants)) * Color_Pants + myhalf3(offsetMappedTexture2D(Texture_Shirt)) * Color_Shirt;\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 = myhalf4(dp_texture2D(Texture_SecondaryColor, TexCoord2));\n"
-"      myhalf terrainblend = clamp(myhalf(VertexColor.a) * color.a, myhalf(1.0 - color2.a), myhalf(1.0));\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(myhalf(VertexColor.a) * color.a * 2.0 - 0.5, myhalf(0.0), myhalf(1.0));\n"
-"      //myhalf terrainblend = min(myhalf(VertexColor.a) * color.a * 2.0, myhalf(1.0));\n"
-"      //myhalf terrainblend = myhalf(VertexColor.a) * color.a > 0.5;\n"
-"      color.rgb = mix(myhalf3(dp_texture2D(Texture_SecondaryColor, TexCoord2)), color.rgb, terrainblend);\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(myhalf4(1, 0, 0, 1), color, terrainblend);\n"
+"      //color = mix(cast_myhalf4(1, 0, 0, 1), color, terrainblend);\n"
 "#endif\n"
 "\n"
 "      // get the surface normal\n"
 "#ifdef USEVERTEXTEXTUREBLEND\n"
-"      myhalf3 surfacenormal = normalize(mix(myhalf3(dp_texture2D(Texture_SecondaryNormal, TexCoord2)), myhalf3(offsetMappedTexture2D(Texture_Normal)), terrainblend) - myhalf3(0.5, 0.5, 0.5));\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(myhalf3(offsetMappedTexture2D(Texture_Normal)) - myhalf3(0.5, 0.5, 0.5));\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(myhalf4(dp_texture2D(Texture_SecondaryGloss, TexCoord2)), myhalf4(offsetMappedTexture2D(Texture_Gloss)), terrainblend);\n"
+"      myhalf4 glosstex = mix(cast_myhalf4(dp_texture2D(Texture_SecondaryGloss, TexCoord2)), cast_myhalf4(offsetMappedTexture2D(Texture_Gloss)), terrainblend);\n"
 "# else\n"
-"      myhalf4 glosstex = myhalf4(offsetMappedTexture2D(Texture_Gloss));\n"
+"      myhalf4 glosstex = cast_myhalf4(offsetMappedTexture2D(Texture_Gloss));\n"
 "# endif\n"
 "#endif\n"
 "\n"
 "      vec3 TangentReflectVector = reflect(-EyeVectorFogDepth.xyz, surfacenormal);\n"
 "      vec3 ModelReflectVector = TangentReflectVector.x * VectorS.xyz + TangentReflectVector.y * VectorT.xyz + TangentReflectVector.z * VectorR.xyz;\n"
 "      vec3 ReflectCubeTexCoord = vec3(ModelToReflectCube * vec4(ModelReflectVector, 0));\n"
-"      diffusetex += myhalf3(offsetMappedTexture2D(Texture_ReflectMask)) * myhalf3(dp_textureCube(Texture_ReflectCube, ReflectCubeTexCoord));\n"
+"      diffusetex += cast_myhalf3(offsetMappedTexture2D(Texture_ReflectMask)) * cast_myhalf3(dp_textureCube(Texture_ReflectCube, ReflectCubeTexCoord));\n"
 "#endif\n"
 "\n"
 "\n"
 "#ifdef MODE_LIGHTSOURCE\n"
 "      // light source\n"
 "#ifdef USEDIFFUSE\n"
-"      myhalf3 lightnormal = myhalf3(normalize(LightVector));\n"
-"      myhalf diffuse = myhalf(max(float(dot(surfacenormal, lightnormal)), 0.0));\n"
+"      myhalf3 lightnormal = cast_myhalf3(normalize(LightVector));\n"
+"      myhalf diffuse = cast_myhalf(max(float(dot(surfacenormal, lightnormal)), 0.0));\n"
 "      color.rgb = diffusetex * (Color_Ambient + diffuse * Color_Diffuse);\n"
 "#ifdef USESPECULAR\n"
 "#ifdef USEEXACTSPECULARMATH\n"
-"      myhalf specular = pow(myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVectorFogDepth.xyz)))*-1.0, 0.0)), SpecularPower * glosstex.a);\n"
+"      myhalf specular = pow(cast_myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVectorFogDepth.xyz)))*-1.0, 0.0)), 1.0 + SpecularPower * glosstex.a);\n"
 "#else\n"
-"      myhalf3 specularnormal = normalize(lightnormal + myhalf3(normalize(EyeVectorFogDepth.xyz)));\n"
-"      myhalf specular = pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower * glosstex.a);\n"
+"      myhalf3 specularnormal = normalize(lightnormal + cast_myhalf3(normalize(EyeVectorFogDepth.xyz)));\n"
+"      myhalf specular = pow(cast_myhalf(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"
 "      color.rgb = diffusetex * Color_Ambient;\n"
 "#endif\n"
 "      color.rgb *= LightColor;\n"
-"      color.rgb *= myhalf(dp_texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\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 *= myhalf3(dp_textureCube(Texture_Cube, CubeVector));\n"
+"      color.rgb *= cast_myhalf3(dp_textureCube(Texture_Cube, CubeVector));\n"
 "# endif\n"
 "#endif // MODE_LIGHTSOURCE\n"
 "\n"
 "\n"
 "\n"
 "#ifdef MODE_LIGHTDIRECTION\n"
-"#define SHADING\n"
-"#ifdef USEDIFFUSE\n"
-"      myhalf3 lightnormal = myhalf3(normalize(LightVector));\n"
-"#endif\n"
-"#define lightcolor LightColor\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"
+"   #define SHADING\n"
 "      // deluxemap lightmapping using light vectors in modelspace (q3map2 -light -deluxe)\n"
-"      myhalf3 lightnormal_modelspace = myhalf3(dp_texture2D(Texture_Deluxemap, TexCoordSurfaceLightmap.zw)) * 2.0 + myhalf3(-1.0, -1.0, -1.0);\n"
-"      myhalf3 lightcolor = myhalf3(dp_texture2D(Texture_Lightmap, TexCoordSurfaceLightmap.zw));\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, myhalf3(VectorS));\n"
-"      lightnormal.y = dot(lightnormal_modelspace, myhalf3(VectorT));\n"
-"      lightnormal.z = dot(lightnormal_modelspace, myhalf3(VectorR));\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"
 "      lightcolor *= 1.0 / max(0.25, lightnormal.z);\n"
 "#endif // MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
 "#ifdef MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n"
-"#define SHADING\n"
+"   #define SHADING\n"
 "      // deluxemap lightmapping using light vectors in tangentspace (hmap2 -light)\n"
-"      myhalf3 lightnormal = myhalf3(dp_texture2D(Texture_Deluxemap, TexCoordSurfaceLightmap.zw)) * 2.0 + myhalf3(-1.0, -1.0, -1.0);\n"
-"      myhalf3 lightcolor = myhalf3(dp_texture2D(Texture_Lightmap, TexCoordSurfaceLightmap.zw));\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"
-"\n"
-"\n"
-"\n"
-"\n"
 "#ifdef MODE_FAKELIGHT\n"
-"#define SHADING\n"
-"myhalf3 lightnormal = myhalf3(normalize(EyeVectorFogDepth.xyz));\n"
-"myhalf3 lightcolor = myhalf3(1.0);\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 + myhalf3(dp_texture2D(Texture_Lightmap, TexCoordSurfaceLightmap.zw)) * Color_Diffuse);\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 + myhalf3(VertexColor.rgb) * Color_Diffuse);\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"
 "\n"
 "#ifdef SHADING\n"
 "# ifdef USEDIFFUSE\n"
-"      myhalf diffuse = myhalf(max(float(dot(surfacenormal, lightnormal)), 0.0));\n"
+"      myhalf diffuse = cast_myhalf(max(float(dot(surfacenormal, lightnormal)), 0.0));\n"
 "#  ifdef USESPECULAR\n"
 "#   ifdef USEEXACTSPECULARMATH\n"
-"      myhalf specular = pow(myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVectorFogDepth.xyz)))*-1.0, 0.0)), SpecularPower * glosstex.a);\n"
+"      myhalf specular = pow(cast_myhalf(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVectorFogDepth.xyz)))*-1.0, 0.0)), 1.0 + SpecularPower * glosstex.a);\n"
 "#   else\n"
-"      myhalf3 specularnormal = normalize(lightnormal + myhalf3(normalize(EyeVectorFogDepth.xyz)));\n"
-"      myhalf specular = pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower * glosstex.a);\n"
+"      myhalf3 specularnormal = normalize(lightnormal + cast_myhalf3(normalize(EyeVectorFogDepth.xyz)));\n"
+"      myhalf specular = pow(cast_myhalf(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"
 "\n"
 "#ifdef USEDEFERREDLIGHTMAP\n"
 "      vec2 ScreenTexCoord = gl_FragCoord.xy * PixelToScreenTexCoord;\n"
-"      color.rgb += diffusetex * myhalf3(dp_texture2D(Texture_ScreenDiffuse, ScreenTexCoord)) * DeferredMod_Diffuse;\n"
-"      color.rgb += glosstex.rgb * myhalf3(dp_texture2D(Texture_ScreenSpecular, ScreenTexCoord)) * DeferredMod_Specular;\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 = myhalf4(dp_texture3D(Texture_BounceGrid, BounceGridTexCoord                        ));\n"
-"//    myhalf4 bouncegrid_coeff2 = myhalf4(dp_texture3D(Texture_BounceGrid, BounceGridTexCoord + vec3(0.0, 0.0, 0.125))) * 2.0 + myhalf4(-1.0, -1.0, -1.0, -1.0);\n"
-"      myhalf4 bouncegrid_coeff3 = myhalf4(dp_texture3D(Texture_BounceGrid, BounceGridTexCoord + vec3(0.0, 0.0, 0.250)));\n"
-"      myhalf4 bouncegrid_coeff4 = myhalf4(dp_texture3D(Texture_BounceGrid, BounceGridTexCoord + vec3(0.0, 0.0, 0.375)));\n"
-"      myhalf4 bouncegrid_coeff5 = myhalf4(dp_texture3D(Texture_BounceGrid, BounceGridTexCoord + vec3(0.0, 0.0, 0.500)));\n"
-"      myhalf4 bouncegrid_coeff6 = myhalf4(dp_texture3D(Texture_BounceGrid, BounceGridTexCoord + vec3(0.0, 0.0, 0.625)));\n"
-"      myhalf4 bouncegrid_coeff7 = myhalf4(dp_texture3D(Texture_BounceGrid, BounceGridTexCoord + vec3(0.0, 0.0, 0.750)));\n"
-"      myhalf4 bouncegrid_coeff8 = myhalf4(dp_texture3D(Texture_BounceGrid, BounceGridTexCoord + vec3(0.0, 0.0, 0.875)));\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(myhalf3(0.0, 0.0, 0.0), bouncegrid_dir);\n"
-"      myhalf3 bouncegrid_dirn = max(myhalf3(0.0, 0.0, 0.0), -bouncegrid_dir);\n"
-"//    bouncegrid_dirp  = bouncegrid_dirn = myhalf3(1.0,1.0,1.0);\n"
-"      myhalf3 bouncegrid_light = myhalf3(\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 * myhalf3(dp_texture3D(Texture_BounceGrid, BounceGridTexCoord)) * BounceGridIntensity;\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(myhalf3(dp_texture2D(Texture_SecondaryGlow, TexCoord2)), myhalf3(offsetMappedTexture2D(Texture_Glow)), terrainblend) * Color_Glow;\n"
+"      color.rgb += mix(cast_myhalf3(dp_texture2D(Texture_SecondaryGlow, TexCoord2)), cast_myhalf3(offsetMappedTexture2D(Texture_Glow)), terrainblend) * Color_Glow;\n"
 "#else\n"
-"      color.rgb += myhalf3(offsetMappedTexture2D(Texture_Glow)) * Color_Glow;\n"
+"      color.rgb += cast_myhalf3(offsetMappedTexture2D(Texture_Glow)) * Color_Glow;\n"
 "#endif\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(myhalf3(offsetMappedTexture2D(Texture_Normal)) - myhalf3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\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_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(myhalf3(normal))).xy * DistortScaleRefractReflect.zw;\n"
+"              vec2 ScreenTexCoord = SafeScreenTexCoord + vec3(normalize(cast_myhalf3(normal))).xy * DistortScaleRefractReflect.zw;\n"
 "      #else\n"
-"              vec2 ScreenTexCoord = SafeScreenTexCoord + vec3(normalize(myhalf3(offsetMappedTexture2D(Texture_Normal)) - myhalf3(0.5))).xy * DistortScaleRefractReflect.zw;\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"
 "      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, myhalf3(dp_texture2D(Texture_Reflection, ScreenTexCoord)) * ReflectColor.rgb, ReflectColor.a);\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"
index c93d4724ddcf2934344e261e34ccac0a2aa1af2a..f20f8329e7ad7d45a651175e789ad3fb857b84e3 100644 (file)
@@ -10,7 +10,7 @@
 "#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)\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"
 "void main\n"
 "(\n"
 "float Depth : TEXCOORD0,\n"
-"out float4 gl_FragColor : COLOR\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"
-"      gl_FragColor = temp;\n"
-"//    gl_FragColor = float4(Depth,0,0,0);\n"
+"      dp_FragColor = temp;\n"
+"//    dp_FragColor = float4(Depth,0,0,0);\n"
 "}\n"
 "#endif\n"
-"#else // !MODE_DEPTH_ORSHADOW\n"
+"#else // !MODE_DEPTH_OR_SHADOW\n"
 "\n"
 "\n"
 "\n"
 "void main\n"
 "(\n"
 "float4 gl_FrontColor : COLOR0,\n"
-"out float4 gl_FragColor : COLOR\n"
+"out float4 dp_FragColor : COLOR\n"
 ")\n"
 "{\n"
-"      gl_FragColor = gl_FrontColor;\n"
+"      dp_FragColor = gl_FrontColor;\n"
 "}\n"
 "#endif\n"
 "#else // !MODE_SHOWDEPTH\n"
 "uniform float ClientTime : register(c2),\n"
 "uniform float2 PixelSize : register(c25),\n"
 "uniform float4 BloomColorSubtract : register(c43),\n"
-"out float4 gl_FragColor : COLOR\n"
+"out float4 dp_FragColor : COLOR\n"
 ")\n"
 "{\n"
-"      gl_FragColor = tex2D(Texture_First, TexCoord1);\n"
+"      dp_FragColor = tex2D(Texture_First, TexCoord1);\n"
 "#ifdef USEBLOOM\n"
-"      gl_FragColor += max(float4(0,0,0,0), tex2D(Texture_Second, TexCoord2) - BloomColorSubtract);\n"
+"      dp_FragColor += max(float4(0,0,0,0), tex2D(Texture_Second, TexCoord2) - BloomColorSubtract);\n"
 "#endif\n"
 "#ifdef USEVIEWTINT\n"
-"      gl_FragColor = lerp(gl_FragColor, ViewTintColor, ViewTintColor.a);\n"
+"      dp_FragColor = lerp(dp_FragColor, ViewTintColor, ViewTintColor.a);\n"
 "#endif\n"
 "\n"
 "#ifdef USEPOSTPROCESSING\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"
-"      gl_FragColor += tex2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*float2(-0.987688, -0.156434)) * UserVec1.y;\n"
-"      gl_FragColor += tex2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*float2(-0.156434, -0.891007)) * UserVec1.y;\n"
-"      gl_FragColor += tex2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*float2( 0.891007, -0.453990)) * UserVec1.y;\n"
-"      gl_FragColor += tex2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*float2( 0.707107,  0.707107)) * UserVec1.y;\n"
-"      gl_FragColor += tex2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*float2(-0.453990,  0.891007)) * UserVec1.y;\n"
-"      gl_FragColor /= (1.0 + 5.0 * UserVec1.y);\n"
-"      gl_FragColor.rgb = gl_FragColor.rgb * (1.0 + UserVec2.x) + float3(1,1,1)*max(0.0, sobel - UserVec2.z)*UserVec2.y;\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 USESATURATION\n"
 "      //apply saturation BEFORE gamma ramps, so v_glslgamma value does not matter\n"
-"      float y = dot(gl_FragColor.rgb, float3(0.299, 0.587, 0.114));\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, (gl_FragColor.r - max(gl_FragColor.g, gl_FragColor.b))*(1.0 - Saturation));\n"
-"              gl_FragColor.rgb = lerp(float3(y,y,y), gl_FragColor.rgb, Saturation);\n"
-"              gl_FragColor.r += r;\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"
-"              //gl_FragColor = float3(y,y,y) + (gl_FragColor.rgb - float3(y)) * Saturation;\n"
-"              gl_FragColor.rgb = lerp(float3(y,y,y), gl_FragColor.rgb, Saturation);\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"
-"      gl_FragColor.r = tex2D(Texture_GammaRamps, float2(gl_FragColor.r, 0)).r;\n"
-"      gl_FragColor.g = tex2D(Texture_GammaRamps, float2(gl_FragColor.g, 0)).g;\n"
-"      gl_FragColor.b = tex2D(Texture_GammaRamps, float2(gl_FragColor.b, 0)).b;\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"
 "#ifdef USESPECULAR\n"
 "uniform sampler Texture_Second : register(s1),\n"
 "#endif\n"
-"out float4 gl_FragColor : COLOR\n"
+"#ifdef USEGAMMARAMPS\n"
+"uniform sampler Texture_GammaRamps : register(s2),\n"
+"#endif\n"
+"out float4 dp_FragColor : COLOR\n"
 ")\n"
 "{\n"
 "#ifdef USEVIEWTINT\n"
-"      gl_FragColor = gl_FrontColor;\n"
+"      dp_FragColor = gl_FrontColor;\n"
 "#else\n"
-"      gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
+"      dp_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
 "#endif\n"
 "#ifdef USEDIFFUSE\n"
-"      gl_FragColor *= tex2D(Texture_First, TexCoord1);\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"
-"      gl_FragColor *= tex2;\n"
+"      dp_FragColor *= tex2;\n"
 "# endif\n"
 "# ifdef USEGLOW\n"
-"      gl_FragColor += tex2;\n"
+"      dp_FragColor += tex2;\n"
 "# endif\n"
 "# ifdef USEVERTEXTEXTUREBLEND\n"
-"      gl_FragColor = lerp(gl_FragColor, tex2, tex2.a);\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"
 "}\n"
 "#endif\n"
 "#else // !MODE_GENERIC\n"
 "float2 TexCoord : TEXCOORD0,\n"
 "uniform sampler Texture_First : register(s0),\n"
 "uniform float4 BloomBlur_Parameters : register(c1),\n"
-"out float4 gl_FragColor : COLOR\n"
+"out float4 dp_FragColor : COLOR\n"
 ")\n"
 "{\n"
 "      int i;\n"
 "              color += tex2D(Texture_First, tc).rgb;\n"
 "              tc += BloomBlur_Parameters.xy;\n"
 "      }\n"
-"      gl_FragColor = float4(color * BloomBlur_Parameters.z + float3(BloomBlur_Parameters.w), 1);\n"
+"      dp_FragColor = float4(color * BloomBlur_Parameters.z + float3(BloomBlur_Parameters.w), 1);\n"
 "}\n"
 "#endif\n"
 "#else // !MODE_BLOOMBLUR\n"
 "uniform float4 ScreenScaleRefractReflect : register(c32),\n"
 "uniform float4 ScreenCenterRefractReflect : register(c31),\n"
 "uniform float4 RefractColor : register(c29),\n"
-"out float4 gl_FragColor : COLOR\n"
+"out float4 dp_FragColor : COLOR\n"
 ")\n"
 "{\n"
 "      float2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\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"
-"      gl_FragColor = float4(tex2D(Texture_Refraction, ScreenTexCoord).rgb, 1) * RefractColor;\n"
+"      dp_FragColor = float4(tex2D(Texture_Refraction, ScreenTexCoord).rgb, 1) * RefractColor;\n"
 "}\n"
 "#endif\n"
 "#else // !MODE_REFRACTION\n"
 "{\n"
 "      TexCoord = mul(TexMatrix, gl_MultiTexCoord0).xy;\n"
 "      float3 EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
-"      EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
-"      EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
-"      EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.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"
 "uniform float4 ReflectColor : register(c26),\n"
 "uniform float ReflectFactor : register(c27),\n"
 "uniform float ReflectOffset : register(c28),\n"
-"out float4 gl_FragColor : COLOR\n"
+"out float4 dp_FragColor : COLOR\n"
 ")\n"
 "{\n"
 "      float4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\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"
-"      gl_FragColor = lerp(float4(tex2D(Texture_Refraction, ScreenTexCoord.xy).rgb, 1) * RefractColor, float4(tex2D(Texture_Reflection, ScreenTexCoord.zw).rgb, 1) * ReflectColor, Fresnel);\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"
 "#endif\n"
 "\n"
 "#ifdef USEOFFSETMAPPING\n"
-"float2 OffsetMapping(float2 TexCoord, float4 OffsetMapping_ScaleSteps, float3 EyeVector, sampler Texture_Normal, float2 dPdx, float2 dPdy)\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"
+"      mediump vec4 ScaleSteps = float4(OffsetMapping_ScaleSteps.x, OffsetMapping_ScaleSteps.y * LODFactor, OffsetMapping_ScaleSteps.z / LODFactor, 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) * OffsetMapping_ScaleSteps.x) * float2(-1, 1), -1);\n"
-"      //float3 OffsetVector = float3(normalize(EyeVector.xy) * OffsetMapping_ScaleSteps.x * float2(-1, 1), -1);\n"
-"      float3 OffsetVector = float3(normalize(EyeVector).xy * OffsetMapping_ScaleSteps.x * float2(-1, 1), -1);\n"
-"      float3 RT = float3(TexCoord, 1);\n"
-"      OffsetVector *= OffsetMapping_ScaleSteps.z;\n"
-"      for(i = 1.0; i < OffsetMapping_ScaleSteps.y; ++i)\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 < OffsetMapping_ScaleSteps.w; ++i, f *= 0.5)\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) * OffsetMapping_ScaleSteps.x) * float2(-1, 1));\n"
-"      //float2 OffsetVector = float2(normalize(EyeVector.xy) * OffsetMapping_ScaleSteps.x * float2(-1, 1));\n"
-"      float2 OffsetVector = float2(normalize(EyeVector).xy * OffsetMapping_ScaleSteps.x * float2(-1, 1));\n"
-"      OffsetVector *= OffsetMapping_ScaleSteps.z;\n"
-"      for(i = 0.0; i < OffsetMapping_ScaleSteps.y; ++i)\n"
-"              TexCoord += OffsetVector * (1.0 - tex2Dgrad(Texture_Normal, TexCoord, dPdx, dPdy).a);\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"
 "float3 GetShadowMapTC2D(float3 dir, float4 ShadowMap_Parameters, samplerCUBE Texture_CubeProjection)\n"
 "{\n"
 "      float3 adir = abs(dir);\n"
-"      float2 aparams = ShadowMap_Parameters.xy / max(max(adir.x, adir.y), adir.z);\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) * aparams.x + proj.zw * ShadowMap_Parameters.z, aparams.y + ShadowMap_Parameters.w);\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 ma = adir.z;\n"
-"      float4 proj = float4(dir, 2.5);\n"
-"      if (adir.x > ma) { ma = adir.x; proj = float4(dir.zyx, 0.5); }\n"
-"      if (adir.y > ma) { ma = adir.y; proj = float4(dir.xzy, 1.5); }\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 / ma + float2(0.5,0.5) + float2(proj.z < 0.0 ? 1.5 : 0.5, proj.w) * ShadowMap_Parameters.z, ma + 64 * ShadowMap_Parameters.w);\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 aparams = ShadowMap_Parameters.xy / ma;\n"
-"      return float3(proj.xy * aparams.x + float2(proj.z < 0.0 ? 1.5 : 0.5, proj.w) * ShadowMap_Parameters.z, aparams.y + ShadowMap_Parameters.w);\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"
 "      // transform unnormalized eye direction into tangent space\n"
 "#ifdef USEOFFSETMAPPING\n"
 "      float3 EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
-"      EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
-"      EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
-"      EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.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"
 "#ifdef USETRIPPY\n"
 "      gl_Position = TrippyVertex(gl_Position);\n"
 "#endif\n"
-"      VectorR.w = gl_Position.z;\n"
+"      VectorR.w = mul(ModelViewMatrix, gl_Vertex).z;\n"
 "}\n"
 "#endif // VERTEX_SHADER\n"
 "\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"
-"#ifdef HLSL\n"
-"out float4 gl_FragData0 : COLOR0,\n"
-"out float4 gl_FragData1 : COLOR1\n"
-"#else\n"
-"out float4 gl_FragColor : COLOR\n"
-"#endif\n"
+"out float4 dp_FragColor : COLOR\n"
 ")\n"
 "{\n"
 "      float2 TexCoord = TexCoordBoth.xy;\n"
 "      // apply offsetmapping\n"
 "      float2 dPdx = ddx(TexCoord);\n"
 "      float2 dPdy = ddy(TexCoord);\n"
-"      float2 TexCoordOffset = OffsetMapping(TexCoord, OffsetMapping_ScaleSteps, EyeVector, Texture_Normal, dPdx, dPdy);\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"
 "      float a = offsetMappedTexture2D(Texture_Gloss).a;\n"
 "#endif\n"
 "\n"
-"#ifdef HLSL\n"
-"      gl_FragData0 = float4(normalize(surfacenormal.x * VectorS + surfacenormal.y * VectorT + surfacenormal.z * VectorR.xyz) * 0.5 + float3(0.5, 0.5, 0.5), a);\n"
-"      float Depth = VectorR.w / 256.0;\n"
-"      float4 depthcolor = float4(Depth,Depth*65536.0/255.0,Depth*16777216.0/255.0,0.0);\n"
-"//    float4 depthcolor = float4(Depth,Depth*256.0,Depth*65536.0,0.0);\n"
-"      depthcolor.yz -= floor(depthcolor.yz);\n"
-"      gl_FragData1 = depthcolor;\n"
-"#else\n"
-"      gl_FragColor = float4(normalize(surfacenormal.x * VectorS + surfacenormal.y * VectorT + surfacenormal.z * VectorR) * 0.5 + float3(0.5, 0.5, 0.5), a);\n"
-"#endif\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"
 "      // calculate viewspace pixel position\n"
 "      float2 ScreenTexCoord = Pixel * PixelToScreenTexCoord;\n"
-"      //ScreenTexCoord.y = ScreenTexCoord.y * -1 + 1; // Cg is opposite?\n"
 "      float3 position;\n"
-"#ifdef HLSL\n"
-"      position.z = texDepth2D(Texture_ScreenDepth, ScreenTexCoord) * 256.0;\n"
-"#else\n"
-"      position.z = ScreenToDepth.y / (texDepth2D(Texture_ScreenDepth, ScreenTexCoord) + ScreenToDepth.x);\n"
-"#endif\n"
-"      position.xy = ModelViewPosition.xy * (position.z / ModelViewPosition.z);\n"
-"      // decode viewspace pixel normal\n"
+"      // get the geometry information (depth, normal, specular exponent)\n"
 "      half4 normalmap = half4(tex2D(Texture_ScreenNormalMap, ScreenTexCoord));\n"
-"      half3 surfacenormal = half3(normalize(normalmap.rgb - half3(0.5,0.5,0.5)));\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"
 "      // 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)), SpecularPower * normalmap.a));\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)), SpecularPower * normalmap.a));\n"
+"      half specular = half(pow(half(max(float(dot(surfacenormal, specularnormal)), 0.0)), 1.0 + SpecularPower * normalmap.a));\n"
 "#  endif\n"
 "#endif\n"
 "\n"
 "(\n"
 "float4 gl_Vertex : POSITION,\n"
 "uniform float4x4 ModelViewProjectionMatrix : register(c8),\n"
-"#if defined(USEVERTEXTEXTUREBLEND) || defined(MODE_VERTEXCOLOR)\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"
 "      // (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.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
-"      LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
-"      LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.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.x = dot(LightDir, gl_MultiTexCoord1.xyz);\n"
-"      LightVector.y = dot(LightDir, gl_MultiTexCoord2.xyz);\n"
-"      LightVector.z = dot(LightDir, gl_MultiTexCoord3.xyz);\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.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
-"      EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
-"      EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.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"
 "\n"
 "#ifdef USEOFFSETMAPPING\n"
 "uniform float4 OffsetMapping_ScaleSteps : register(c24),\n"
+"uniform float OffsetMapping_Bias : register(c54),\n"
 "#endif\n"
 "\n"
 "#ifdef USEDEFERREDLIGHTMAP\n"
 "#endif\n"
 "#endif // !defined(MODE_LIGHTSOURCE) && !defined(MODE_DEFERREDLIGHTSOURCE) && !defined(USESHADOWMAPORTHO)\n"
 "\n"
-"out float4 gl_FragColor : COLOR\n"
+"out float4 dp_FragColor : COLOR\n"
 ")\n"
 "{\n"
 "      float2 TexCoord = TexCoordBoth.xy;\n"
 "      // apply offsetmapping\n"
 "      float2 dPdx = ddx(TexCoord);\n"
 "      float2 dPdy = ddy(TexCoord);\n"
-"      float2 TexCoordOffset = OffsetMapping(TexCoord, OffsetMapping_ScaleSteps, EyeVector, Texture_Normal, dPdx, dPdy);\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"
 "      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)), SpecularPower * glosstex.a));\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)), SpecularPower * glosstex.a));\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"
 "\n"
 "\n"
 "#ifdef MODE_LIGHTDIRECTION\n"
-"#define SHADING\n"
-"#ifdef USEDIFFUSE\n"
-"      half3 lightnormal = half3(normalize(LightVector));\n"
-"#endif\n"
-"#define lightcolor LightColor\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"
+"      #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;\n"
-"      lightnormal.x = dot(lightnormal_modelspace, half3(VectorS));\n"
-"      lightnormal.y = dot(lightnormal_modelspace, half3(VectorT));\n"
-"      lightnormal.z = dot(lightnormal_modelspace, half3(VectorR));\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"
 "      lightcolor *= 1.0 / max(0.25, lightnormal.z);\n"
 "#endif // MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
 "#ifdef MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n"
-"#define SHADING\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"
-"\n"
-"\n"
-"\n"
-"\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"
+"      #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"
 "      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)), SpecularPower * glosstex.a));\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)), SpecularPower * glosstex.a));\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 = lerp(color.rgb, half3(tex2D(Texture_Reflection, ScreenTexCoord).rgb) * ReflectColor.rgb, ReflectColor.a);\n"
 "#endif\n"
 "\n"
-"      gl_FragColor = float4(color);\n"
+"      dp_FragColor = float4(color);\n"
 "}\n"
 "#endif // FRAGMENT_SHADER\n"
 "\n"
index e537d8388661b63d0c35345d6ff1568d9ffdff5b..71f8b4d73e80c6612f7c3c32677ba22a440bf4b0 100644 (file)
@@ -26,10 +26,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "snd_modplug.h"
 #include "csprogs.h"
 #include "cl_collision.h"
+#include "cdaudio.h"
 
 
 #define SND_MIN_SPEED 8000
-#define SND_MAX_SPEED 96000
+#define SND_MAX_SPEED 192000
 #define SND_MIN_WIDTH 1
 #define SND_MAX_WIDTH 2
 #define SND_MIN_CHANNELS 1
@@ -165,6 +166,8 @@ 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"};
@@ -177,11 +180,15 @@ cvar_t snd_spatialization_occlusion = {CVAR_SAVE, "snd_spatialization_occlusion"
 
 // 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)"};
+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)"};
@@ -240,6 +247,10 @@ static cvar_t snd_channels = {CVAR_SAVE, "snd_channels", "2", "number of channel
 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" };
@@ -314,16 +325,15 @@ static void S_SoundList_f (void)
                if (sfx->fetcher != NULL)
                {
                        unsigned int size;
-                       const snd_format_t* format;
 
                        size = sfx->memsize;
-                       format = sfx->fetcher->getfmt(sfx);
-                       Con_Printf ("%c%c%c(%2db, %6s) %8i : %s\n",
+                       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' : ' ',
-                                               format->width * 8,
-                                               (format->channels == 1) ? "mono" : "stereo",
+                                               sfx->format.speed,
+                                               sfx->format.width * 8,
+                                               (sfx->format.channels == 1) ? "mono" : "stereo",
                                                size,
                                                sfx->name);
                        total += size;
@@ -335,7 +345,7 @@ static void S_SoundList_f (void)
 }
 
 
-void S_SoundInfo_f(void)
+static void S_SoundInfo_f(void)
 {
        if (snd_renderbuffer == NULL)
        {
@@ -614,6 +624,8 @@ void S_Startup (void)
                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)
        {
@@ -625,6 +637,7 @@ void S_Startup (void)
                        chosen_fmt.speed = prev_render_format.speed;
                }
        }
+#endif
 
        // Sanity checks
        if (chosen_fmt.speed < SND_MIN_SPEED)
@@ -764,7 +777,7 @@ void S_Shutdown(void)
        sound_spatialized = false;
 }
 
-void S_Restart_f(void)
+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.
@@ -830,6 +843,9 @@ void S_Init(void)
        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);
@@ -844,10 +860,15 @@ void S_Init(void)
        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"))
        {
@@ -876,6 +897,7 @@ void S_Init(void)
        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);
@@ -977,6 +999,15 @@ sfx_t *S_FindName (const char *name)
                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));
@@ -1036,8 +1067,8 @@ void S_FreeSfx (sfx_t *sfx, qboolean force)
        }
 
        // Free it
-       if (sfx->fetcher != NULL && sfx->fetcher->free != NULL)
-               sfx->fetcher->free (sfx->fetcher_data);
+       if (sfx->fetcher != NULL && sfx->fetcher->freesfx != NULL)
+               sfx->fetcher->freesfx(sfx);
        Mem_Free (sfx);
 }
 
@@ -1064,7 +1095,8 @@ void S_ClearUsed (void)
                        channels[i].sfx = ambient_sfxs[i];
                        channels[i].sfx->flags |= SFXFLAG_MENUSOUND;
                        channels[i].flags |= CHANNELFLAG_FORCELOOP;
-                       channels[i].master_vol = 0;
+                       channels[i].basevolume = 0.0f;
+                       channels[i].basespeed = channels[i].mixspeed = 1.0f;
                }
        }
 
@@ -1189,7 +1221,7 @@ SND_PickChannel
 Picks a channel based on priorities, empty slots, number of channels
 =================
 */
-channel_t *SND_PickChannel(int entnum, int entchannel)
+static channel_t *SND_PickChannel(int entnum, int entchannel)
 {
        int ch_idx;
        int first_to_die;
@@ -1236,7 +1268,7 @@ channel_t *SND_PickChannel(int entnum, int entchannel)
                // don't override looped sounds
                if ((ch->flags & CHANNELFLAG_FORCELOOP) || sfx->loopstart < sfx->total_length)
                        continue;
-               life_left = sfx->total_length - ch->pos;
+               life_left = (int)((double)sfx->total_length - ch->position);
 
                if (life_left < first_life_left)
                {
@@ -1262,13 +1294,14 @@ Spatializes a channel
 =================
 */
 extern cvar_t cl_gameplayfix_soundsmovewithentities;
-void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx)
+static void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx)
 {
        int i;
        double f;
-       float angle_side, angle_front, angle_factor;
-       vec_t dist, mastervol, intensity, vol;
+       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)
@@ -1291,9 +1324,19 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx)
                        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->master_vol;
+       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)
@@ -1372,7 +1415,7 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx)
                        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("snd_channel%dvolume", CHAN_ENGINE2CVAR(ch->entchannel)), 1.0); break;
+                       default: mastervol *= Cvar_VariableValueOr(va(vabuf, sizeof(vabuf), "snd_channel%dvolume", CHAN_ENGINE2CVAR(ch->entchannel)), 1.0); break;
                }
        }
 
@@ -1380,8 +1423,11 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx)
        if (!(ch->flags & CHANNELFLAG_FULLVOLUME))
                mastervol *= volume.value;
 
-       // 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, mastervol, 655360);
+       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;
@@ -1393,35 +1439,40 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx)
                // Replaygain support
                // Con_DPrintf("Setting volume on ReplayGain-enabled track... %f -> ", fvol);
                mastervol *= sfx->volume_mult;
-               if(mastervol * sfx->volume_peak > 65536)
-                       mastervol = 65536 / sfx->volume_peak;
+               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);
        }
 
-       // clamp HERE to keep relative volumes of the channels correct
-       mastervol = bound(0, mastervol, 65536);
+       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->dist_mult == 0)
+       if (ch->entnum == cl.viewentity || ch->distfade == 0)
        {
                ch->prologic_invert = 1;
                if (snd_spatialization_prologic.integer != 0)
                {
-                       vol = mastervol * snd_speakerlayout.listeners[0].ambientvolume * sqrt(0.5);
-                       ch->listener_volume[0] = (int)bound(0, vol, 65536);
-                       vol = mastervol * snd_speakerlayout.listeners[1].ambientvolume * sqrt(0.5);
-                       ch->listener_volume[1] = (int)bound(0, vol, 65536);
+                       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->listener_volume[i] = 0;
+                               ch->volume[i] = 0;
                }
                else
                {
                        for (i = 0;i < SND_LISTENERS;i++)
-                       {
-                               vol = mastervol * snd_speakerlayout.listeners[i].ambientvolume;
-                               ch->listener_volume[i] = (int)bound(0, vol, 65536);
-                       }
+                               ch->volume[i] = mastervol * snd_speakerlayout.listeners[i].ambientvolume;
                }
        }
        else
@@ -1429,7 +1480,14 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx)
                // calculate stereo seperation and distance attenuation
                VectorSubtract(listener_origin, ch->origin, source_vec);
                dist = VectorLength(source_vec);
-               intensity = mastervol * (1.0 - dist * ch->dist_mult);
+               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;
@@ -1449,13 +1507,13 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx)
                                                        occluded = true;
                        }
                        if(occluded)
-                               intensity *= 0.5;
+                               intensity *= 0.5f;
 
                        ch->prologic_invert = 1;
                        if (snd_spatialization_prologic.integer != 0)
                        {
                                if (dist == 0)
-                                       angle_factor = 0.5;
+                                       angle_factor = 0.5f;
                                else
                                {
                                        Matrix4x4_Transform(&listener_basematrix, ch->origin, source_vec);
@@ -1504,12 +1562,10 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx)
                                                //angle_factor is between 0 and 1 and represents the angle range from the front left to the center to the front right speaker
                                }
 
-                               vol = intensity * sqrt(angle_factor);
-                               ch->listener_volume[0] = (int)bound(0, vol, 65536);
-                               vol = intensity * sqrt(1 - angle_factor);
-                               ch->listener_volume[1] = (int)bound(0, vol, 65536);
+                               ch->volume[0] = intensity * sqrt(angle_factor);
+                               ch->volume[1] = intensity * sqrt(1 - angle_factor);
                                for (i = 2;i < SND_LISTENERS;i++)
-                                       ch->listener_volume[i] = 0;
+                                       ch->volume[i] = 0;
                        }
                        else
                        {
@@ -1541,18 +1597,16 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx)
                                                        break;
                                        }
 
-                                       vol = intensity * max(0, source_vec[0] * snd_speakerlayout.listeners[i].dotscale + snd_speakerlayout.listeners[i].dotbias);
-
-                                       ch->listener_volume[i] = (int)bound(0, vol, 65536);
+                                       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->listener_volume[i] = 0;
+                               ch->volume[i] = 0;
        }
 }
-void SND_Spatialize(channel_t *ch, qboolean isstatic)
+static void SND_Spatialize(channel_t *ch, qboolean isstatic)
 {
        sfx_t *sfx = ch->sfx;
        SND_Spatialize_WithSfx(ch, isstatic, sfx);
@@ -1563,7 +1617,7 @@ void SND_Spatialize(channel_t *ch, qboolean isstatic)
 // Start a sound effect
 // =======================================================================
 
-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)
+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)
        {
@@ -1595,7 +1649,7 @@ void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags,
        memset (target_chan, 0, sizeof (*target_chan));
        VectorCopy (origin, target_chan->origin);
        target_chan->flags = flags;
-       target_chan->pos = startpos; // start of the sound
+       target_chan->position = startpos; // start of the sound
        target_chan->entnum = entnum;
        target_chan->entchannel = entchannel;
 
@@ -1604,13 +1658,14 @@ void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags,
        {
                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->dist_mult = attenuation / (64.0f * snd_soundradius.value);
+               target_chan->distfade = attenuation / (64.0f * snd_soundradius.value);
        }
        else
-               target_chan->dist_mult = attenuation / snd_soundradius.value;
+               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
@@ -1619,7 +1674,7 @@ void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags,
 }
 
 
-int S_StartSound_StartPosition_Flags (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float startposition, int flags)
+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;
@@ -1637,7 +1692,8 @@ int S_StartSound_StartPosition_Flags (int entnum, int entchannel, sfx_t *sfx, ve
                        if (ch->entnum == entnum && ch->entchannel == entchannel)
                        {
                                S_SetChannelVolume(ch_idx, fvol);
-                               ch->dist_mult = attenuation / snd_soundradius.value;
+                               S_SetChannelSpeed(ch_idx, fspeed);
+                               ch->distfade = attenuation / snd_soundradius.value;
                                SND_Spatialize(ch, false);
                                return ch_idx;
                        }
@@ -1656,35 +1712,40 @@ int S_StartSound_StartPosition_Flags (int entnum, int entchannel, sfx_t *sfx, ve
        // 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 * S_GetSoundRate());
+       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->pos == 0)
+                       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 = (int)lhrandom(0, -0.1 * snd_renderbuffer->format.speed);
+                               startpos = lhrandom(0, maxdelta * sfx->format.speed);
                                break;
                        }
                }
        }
 
-       S_PlaySfxOnChannel (sfx, target_chan, flags, origin, fvol, attenuation, false, entnum, entchannel, startpos);
+       S_PlaySfxOnChannel (sfx, target_chan, flags, origin, fvol, attenuation, false, entnum, entchannel, startpos, fspeed);
 
        return (target_chan - channels);
 }
 
-int S_StartSound_StartPosition (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float startposition)
-{
-       return S_StartSound_StartPosition_Flags(entnum, entchannel, sfx, origin, fvol, attenuation, startposition, CHANNELFLAG_NONE);
-}
-
 int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
 {
-       return S_StartSound_StartPosition(entnum, entchannel, sfx, origin, fvol, attenuation, 0);
+       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)
@@ -1706,13 +1767,8 @@ void S_StopChannel (unsigned int channel_ind, qboolean lockmutex, qboolean frees
        sfx = ch->sfx;
        if (ch->sfx != NULL)
        {
-               if (sfx->fetcher != NULL)
-               {
-                       snd_fetcher_endsb_t fetcher_endsb = sfx->fetcher->endsb;
-                       if (fetcher_endsb != NULL)
-                               fetcher_endsb (ch->fetcher_data);
-               }
-
+               if (sfx->fetcher != NULL && sfx->fetcher->stopchannel != NULL)
+                       sfx->fetcher->stopchannel(ch);
                ch->fetcher_data = NULL;
                ch->sfx = NULL;
        }
@@ -1754,7 +1810,6 @@ void S_StopSound(int entnum, int entchannel)
                }
 }
 
-extern void CDAudio_Stop(void);
 void S_StopAllSounds (void)
 {
        unsigned int i;
@@ -1804,24 +1859,29 @@ void S_PauseGameSounds (qboolean toggle)
 
 void S_SetChannelVolume(unsigned int ch_ind, float fvol)
 {
-       channels[ch_ind].master_vol = (int)(fvol * 65536.0f);
+       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
-       int s;
+       double s;
        channel_t *ch = &channels[ch_ind];
        sfx_t *sfx = ch->sfx;
        if (!sfx)
                return -1;
 
-       s = ch->pos;
+       s = ch->position / sfx->format.speed;
        /*
        if(!snd_usethreadedmixing)
-               s += _snd_mixahead.value * S_GetSoundRate();
+               s += _snd_mixahead.value;
        */
-       return (s % sfx->total_length) / (float) S_GetSoundRate();
+       return (float)s;
 }
 
 float S_GetEntChannelPosition(int entnum, int entchannel)
@@ -1862,7 +1922,7 @@ void S_StaticSound (sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
        }
 
        target_chan = &channels[total_channels++];
-       S_PlaySfxOnChannel (sfx, target_chan, CHANNELFLAG_FORCELOOP, origin, fvol, attenuation, true, 0, 0, 0);
+       S_PlaySfxOnChannel (sfx, target_chan, CHANNELFLAG_FORCELOOP, origin, fvol, attenuation, true, 0, 0, 0, 1.0f);
 }
 
 
@@ -1871,10 +1931,11 @@ void S_StaticSound (sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
 S_UpdateAmbientSounds
 ===================
 */
-void S_UpdateAmbientSounds (void)
+static void S_UpdateAmbientSounds (void)
 {
        int                     i;
-       int                     vol;
+       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];
@@ -1892,40 +1953,36 @@ void S_UpdateAmbientSounds (void)
                if (sfx == NULL || sfx->fetcher == NULL)
                        continue;
 
-               vol = (int)ambientlevels[ambient_channel];
-               if (vol < 8)
-                       vol = 0;
-               vol *= 256;
+               i = ambientlevels[ambient_channel];
+               if (i < 8)
+                       i = 0;
+               vol = i * (1.0f / 256.0f);
 
                // Don't adjust volume too fast
-               // FIXME: this rounds off to an int each frame, meaning there is little to no fade at extremely high framerates!
-               if (cl.time > cl.oldtime)
+               if (chan->basevolume < vol)
                {
-                       if (chan->master_vol < vol)
-                       {
-                               chan->master_vol += (int)((cl.time - cl.oldtime) * 256.0 * ambient_fade.value);
-                               if (chan->master_vol > vol)
-                                       chan->master_vol = vol;
-                       }
-                       else if (chan->master_vol > vol)
-                       {
-                               chan->master_vol -= (int)((cl.time - cl.oldtime) * 256.0 * ambient_fade.value);
-                               if (chan->master_vol < vol)
-                                       chan->master_vol = 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->listener_volume[0] = (int)bound(0, chan->master_vol * ambient_level.value * volume.value * mastervolume.value * snd_speakerlayout.listeners[0].ambientvolume * sqrt(0.5), 65536);
-                       chan->listener_volume[1] = (int)bound(0, chan->master_vol * ambient_level.value * volume.value * mastervolume.value * snd_speakerlayout.listeners[1].ambientvolume * sqrt(0.5), 65536);
+                       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->listener_volume[i] = 0;
+                               chan->volume[i] = 0.0f;
                }
                else
                {
                        for (i = 0;i < SND_LISTENERS;i++)
-                               chan->listener_volume[i] = (int)bound(0, chan->master_vol * ambient_level.value * volume.value * mastervolume.value * snd_speakerlayout.listeners[i].ambientvolume, 65536);
+                               chan->volume[i] = chan->basevolume * ambient_level.value * volume.value * mastervolume.value * snd_speakerlayout.listeners[i].ambientvolume;
                }
        }
 }
@@ -2200,7 +2257,7 @@ void S_Update(const matrix4x4_t *listenermatrix)
                {
                        // no need to merge silent channels
                        for (j = 0;j < SND_LISTENERS;j++)
-                               if (ch->listener_volume[j])
+                               if (ch->volume[j])
                                        break;
                        if (j == SND_LISTENERS)
                                continue;
@@ -2222,13 +2279,13 @@ void S_Update(const matrix4x4_t *listenermatrix)
                        {
                                for (j = 0;j < SND_LISTENERS;j++)
                                {
-                                       combine->listener_volume[j] = bound(0, combine->listener_volume[j] + ch->listener_volume[j], 65536);
-                                       ch->listener_volume[j] = 0;
+                                       combine->volume[j] += ch->volume[j];
+                                       ch->volume[j] = 0;
                                }
                        }
                }
                for (k = 0;k < SND_LISTENERS;k++)
-                       if (ch->listener_volume[k])
+                       if (ch->volume[k])
                                break;
                if (k < SND_LISTENERS)
                        cls.soundstats.mixedsounds++;
index a166aba259e38fc336cd058dcd7e965c87310ce3..527ce49fc4241b5c6b1343dd1ac247af56a56fcf 100644 (file)
@@ -64,6 +64,7 @@ struct sfx_s
        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
@@ -79,31 +80,39 @@ struct sfx_s
 
 typedef struct channel_s
 {
-       int                     listener_volume [SND_LISTENERS];        // 0-65536 volume per speaker
-       int                             master_vol;             // 0-65536 master volume
+       // 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                             pos;                    // sample position in sfx, negative values delay the start of the sound playback
-       int                             entnum;                 // to allow overriding a specific sound
-       int                             entchannel;
+       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                   dist_mult;              // distance multiplier (attenuation/clipK)
+       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 const snd_buffer_t* (*snd_fetcher_getsb_t) (void *sfxfetcher, void **chfetcherpointer, unsigned int *start, unsigned int nbsampleframes);
-typedef void (*snd_fetcher_endsb_t) (void *chfetcherdata);
-typedef void (*snd_fetcher_free_t) (void *sfxfetcherdata);
-typedef const snd_format_t* (*snd_fetcher_getfmt_t) (sfx_t* sfx);
+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_getsb_t             getsb;
-       snd_fetcher_endsb_t             endsb;
-       snd_fetcher_free_t              free;
-       snd_fetcher_getfmt_t    getfmt;
+       snd_fetcher_getsamplesfloat_t           getsamplesfloat;
+       snd_fetcher_stopchannel_t               stopchannel;
+       snd_fetcher_freesfx_t           freesfx;
 };
 
 extern unsigned int total_channels;
@@ -116,6 +125,7 @@ extern qboolean snd_usethreadedmixing; // if true, the main thread does not mix
 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
@@ -132,13 +142,7 @@ extern mempool_t *snd_mempool;
 extern qboolean simsound;
 
 
-#define STREAM_BUFFER_DURATION 0.3f // in seconds
-#define STREAM_BUFFER_FILL 0.2f // in seconds
-#define STREAM_BUFFER_SIZE(format_ptr) ((int)ceil (STREAM_BUFFER_DURATION * (format_ptr)->speed) * (format_ptr)->width * (format_ptr)->channels)
-
-// We work with 1 sec sequences, so this buffer must be able to contain
-// 1 sec of sound of the highest quality (48 KHz, 16 bit samples, stereo)
-extern unsigned char resampling_buffer [48000 * 2 * 2];
+#define STREAM_BUFFERSIZE 16384 // in sampleframes
 
 
 // ====================================================================
@@ -186,7 +190,7 @@ void SndSys_SendKeyEvents(void);
 // exported for capturevideo so ogg can see all channels
 typedef struct portable_samplepair_s
 {
-       int sample[SND_LISTENERS];
+       float sample[SND_LISTENERS];
 } portable_sampleframe_t;
 
 typedef struct listener_s
index 11b0a9d9a9a22a394497c627ff8293a9cb8e2824..635bdd3ffb63407d8a27378fb83756a6b73b8c46 100644 (file)
@@ -26,8 +26,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "snd_wav.h"
 #include "snd_modplug.h"
 
-unsigned char resampling_buffer [48000 * 2 * 2];
-
 
 /*
 ====================
index 6bec880eae3974665dcc699feff687b8a84779fb..4f3310bfcf1a83b3ef3eaad472b70fa7e850ceae 100644 (file)
@@ -21,14 +21,14 @@ 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
 
-extern void SCR_CaptureVideo_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length);
-static void S_CaptureAVISound(size_t length)
+static void S_CaptureAVISound(const portable_sampleframe_t *paintbuffer, size_t length)
 {
        size_t i;
        unsigned int j;
@@ -47,9 +47,88 @@ static void S_CaptureAVISound(size_t length)
        SCR_CaptureVideo_SoundFrame(paintbuffer_unswapped, length);
 }
 
-static void S_ConvertPaintBuffer(const portable_sampleframe_t *painted_ptr, void *rb_ptr, int nbframes, int width, int channels)
+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;
@@ -57,52 +136,51 @@ static void S_ConvertPaintBuffer(const portable_sampleframe_t *painted_ptr, void
                {
                        for (i = 0;i < nbframes;i++, painted_ptr++)
                        {
-                               *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
-                               *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
-                               *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
-                               *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
-                               *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767);
-                               *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767);
-                               *snd_out++ = bound(-32768, painted_ptr->sample[6], 32767);
-                               *snd_out++ = bound(-32768, painted_ptr->sample[7], 32767);
+                               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++)
                        {
-                               *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
-                               *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
-                               *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
-                               *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
-                               *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767);
-                               *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767);
+                               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++)
                        {
-                               *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
-                               *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
-                               *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
-                               *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
+                               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++)
                        {
-                               *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
-                               *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
+                               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 = (painted_ptr->sample[0] + painted_ptr->sample[1]) >> 1;
-                               *snd_out++ = bound(-32768, val, 32767);
+                               val = (int)((painted_ptr->sample[0] + painted_ptr->sample[1]) * 16384.0f);*snd_out++ = bound(-32768, val, 32767);
                        }
                }
 
@@ -117,52 +195,51 @@ static void S_ConvertPaintBuffer(const portable_sampleframe_t *painted_ptr, void
                {
                        for (i = 0; i < nbframes; i++, painted_ptr++)
                        {
-                               val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
-                               val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
-                               val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
-                               val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
-                               val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255);
-                               val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255);
-                               val = (painted_ptr->sample[6] >> 8) + 128; *snd_out++ = bound(0, val, 255);
-                               val = (painted_ptr->sample[7] >> 8) + 128; *snd_out++ = bound(0, val, 255);
+                               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 = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
-                               val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
-                               val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
-                               val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
-                               val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255);
-                               val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255);
+                               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 = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
-                               val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
-                               val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
-                               val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
+                               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 = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
-                               val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
+                               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 = ((painted_ptr->sample[0] + painted_ptr->sample[1]) >> 9) + 128;
-                               *snd_out++ = bound(0, val, 255);
+                               val = (int)((painted_ptr->sample[0] + painted_ptr->sample[1]) * 64.0f) + 128; *snd_out++ = bound(0, val, 255);
                        }
                }
 
@@ -181,326 +258,52 @@ CHANNEL MIXING
 ===============================================================================
 */
 
-static qboolean SND_PaintChannel (channel_t *ch, portable_sampleframe_t *paint, unsigned int count)
-{
-       int vol[SND_LISTENERS];
-       const snd_buffer_t *sb;
-       unsigned int i, sb_offset;
-       sfx_t *sfx;
-
-       sfx = ch->sfx; // fetch the volatile variable
-       if (!sfx) // given that this is called by the mixer thread, this never happens, but...
-               return false;
-
-       // move to the stack (do we need to?)
-       for (i = 0;i < SND_LISTENERS;i++)
-               vol[i] = ch->listener_volume[i];
-
-       // if volumes are all zero, just return
-       for (i = 0;i < SND_LISTENERS;i++)
-               if (vol[i])
-                       break;
-       if (i == SND_LISTENERS)
-               return false;
-
-       sb_offset = ch->pos;
-       sb = sfx->fetcher->getsb (sfx->fetcher_data, &ch->fetcher_data, &sb_offset, count);
-       if (sb == NULL)
-       {
-               Con_DPrintf("SND_PaintChannel: ERROR: can't get sound buffer from sfx \"%s\"\n",
-                                       sfx->name); // , count); // or add this? FIXME
-               return false;
-       }
-       else
-       {
-#if SND_LISTENERS != 8
-#              error the following code only supports up to 8 channels, update it
-#endif
-               if (sb->format.width == 1)
-               {
-                       const signed char *samples = (signed char*)sb->samples + (ch->pos - sb_offset) * sb->format.channels;
-
-                       // Stereo sound support
-                       if (sb->format.channels == 2)
-                       {
-                               if (vol[6] + vol[7] > 0)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 8;
-                                               paint[i].sample[1] += (samples[1] * vol[1]) >> 8;
-                                               paint[i].sample[2] += (samples[0] * vol[2]) >> 8;
-                                               paint[i].sample[3] += (samples[1] * vol[3]) >> 8;
-                                               paint[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9;
-                                               paint[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9;
-                                               paint[i].sample[6] += (samples[0] * vol[6]) >> 8;
-                                               paint[i].sample[7] += (samples[1] * vol[7]) >> 8;
-                                               samples += 2;
-                                       }
-                               }
-                               else if (vol[4] + vol[5] > 0)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 8;
-                                               paint[i].sample[1] += (samples[1] * vol[1]) >> 8;
-                                               paint[i].sample[2] += (samples[0] * vol[2]) >> 8;
-                                               paint[i].sample[3] += (samples[1] * vol[3]) >> 8;
-                                               paint[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9;
-                                               paint[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9;
-                                               samples += 2;
-                                       }
-                               }
-                               else if (vol[2] + vol[3] > 0)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 8;
-                                               paint[i].sample[1] += (samples[1] * vol[1]) >> 8;
-                                               paint[i].sample[2] += (samples[0] * vol[2]) >> 8;
-                                               paint[i].sample[3] += (samples[1] * vol[3]) >> 8;
-                                               samples += 2;
-                                       }
-                               }
-                               else if (vol[0] + vol[1] > 0 && ch->prologic_invert == -1)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 8;
-                                               paint[i].sample[1] -= (samples[1] * vol[1]) >> 8;
-                                               samples += 2;
-                                       }
-                               }
-                               else if (vol[0] + vol[1] > 0)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 8;
-                                               paint[i].sample[1] += (samples[1] * vol[1]) >> 8;
-                                               samples += 2;
-                                       }
-                               }
-                       }
-                       else if (sb->format.channels == 1)
-                       {
-                               if (vol[6] + vol[7] > 0)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 8;
-                                               paint[i].sample[1] += (samples[0] * vol[1]) >> 8;
-                                               paint[i].sample[2] += (samples[0] * vol[2]) >> 8;
-                                               paint[i].sample[3] += (samples[0] * vol[3]) >> 8;
-                                               paint[i].sample[4] += (samples[0] * vol[4]) >> 8;
-                                               paint[i].sample[5] += (samples[0] * vol[5]) >> 8;
-                                               paint[i].sample[6] += (samples[0] * vol[6]) >> 8;
-                                               paint[i].sample[7] += (samples[0] * vol[7]) >> 8;
-                                               samples += 1;
-                                       }
-                               }
-                               else if (vol[4] + vol[5] > 0)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 8;
-                                               paint[i].sample[1] += (samples[0] * vol[1]) >> 8;
-                                               paint[i].sample[2] += (samples[0] * vol[2]) >> 8;
-                                               paint[i].sample[3] += (samples[0] * vol[3]) >> 8;
-                                               paint[i].sample[4] += (samples[0] * vol[4]) >> 8;
-                                               paint[i].sample[5] += (samples[0] * vol[5]) >> 8;
-                                               samples += 1;
-                                       }
-                               }
-                               else if (vol[2] + vol[3] > 0)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 8;
-                                               paint[i].sample[1] += (samples[0] * vol[1]) >> 8;
-                                               paint[i].sample[2] += (samples[0] * vol[2]) >> 8;
-                                               paint[i].sample[3] += (samples[0] * vol[3]) >> 8;
-                                               samples += 1;
-                                       }
-                               }
-                               else if (vol[0] + vol[1] > 0 && ch->prologic_invert == -1)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 8;
-                                               paint[i].sample[1] -= (samples[0] * vol[1]) >> 8;
-                                               samples += 1;
-                                       }
-                               }
-                               else if (vol[0] + vol[1] > 0)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 8;
-                                               paint[i].sample[1] += (samples[0] * vol[1]) >> 8;
-                                               samples += 1;
-                                       }
-                               }
-                       }
-                       else
-                               return false; // unsupported number of channels in sound
-               }
-               else if (sb->format.width == 2)
-               {
-                       const signed short *samples = (signed short*)sb->samples + (ch->pos - sb_offset) * sb->format.channels;
-
-                       // Stereo sound support
-                       if (sb->format.channels == 2)
-                       {
-                               if (vol[6] + vol[7] > 0)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 16;
-                                               paint[i].sample[1] += (samples[1] * vol[1]) >> 16;
-                                               paint[i].sample[2] += (samples[0] * vol[2]) >> 16;
-                                               paint[i].sample[3] += (samples[1] * vol[3]) >> 16;
-                                               paint[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17;
-                                               paint[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17;
-                                               paint[i].sample[6] += (samples[0] * vol[6]) >> 16;
-                                               paint[i].sample[7] += (samples[1] * vol[7]) >> 16;
-                                               samples += 2;
-                                       }
-                               }
-                               else if (vol[4] + vol[5] > 0)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 16;
-                                               paint[i].sample[1] += (samples[1] * vol[1]) >> 16;
-                                               paint[i].sample[2] += (samples[0] * vol[2]) >> 16;
-                                               paint[i].sample[3] += (samples[1] * vol[3]) >> 16;
-                                               paint[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17;
-                                               paint[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17;
-                                               samples += 2;
-                                       }
-                               }
-                               else if (vol[2] + vol[3] > 0)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 16;
-                                               paint[i].sample[1] += (samples[1] * vol[1]) >> 16;
-                                               paint[i].sample[2] += (samples[0] * vol[2]) >> 16;
-                                               paint[i].sample[3] += (samples[1] * vol[3]) >> 16;
-                                               samples += 2;
-                                       }
-                               }
-                               else if (vol[0] + vol[1] > 0 && ch->prologic_invert == -1)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 16;
-                                               paint[i].sample[1] -= (samples[1] * vol[1]) >> 16;
-                                               samples += 2;
-                                       }
-                               }
-                               else if (vol[0] + vol[1] > 0)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 16;
-                                               paint[i].sample[1] += (samples[1] * vol[1]) >> 16;
-                                               samples += 2;
-                                       }
-                               }
-                       }
-                       else if (sb->format.channels == 1)
-                       {
-                               if (vol[6] + vol[7] > 0)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 16;
-                                               paint[i].sample[1] += (samples[0] * vol[1]) >> 16;
-                                               paint[i].sample[2] += (samples[0] * vol[2]) >> 16;
-                                               paint[i].sample[3] += (samples[0] * vol[3]) >> 16;
-                                               paint[i].sample[4] += (samples[0] * vol[4]) >> 16;
-                                               paint[i].sample[5] += (samples[0] * vol[5]) >> 16;
-                                               paint[i].sample[6] += (samples[0] * vol[6]) >> 16;
-                                               paint[i].sample[7] += (samples[0] * vol[7]) >> 16;
-                                               samples += 1;
-                                       }
-                               }
-                               else if (vol[4] + vol[5] > 0)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 16;
-                                               paint[i].sample[1] += (samples[0] * vol[1]) >> 16;
-                                               paint[i].sample[2] += (samples[0] * vol[2]) >> 16;
-                                               paint[i].sample[3] += (samples[0] * vol[3]) >> 16;
-                                               paint[i].sample[4] += (samples[0] * vol[4]) >> 16;
-                                               paint[i].sample[5] += (samples[0] * vol[5]) >> 16;
-                                               samples += 1;
-                                       }
-                               }
-                               else if (vol[2] + vol[3] > 0)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 16;
-                                               paint[i].sample[1] += (samples[0] * vol[1]) >> 16;
-                                               paint[i].sample[2] += (samples[0] * vol[2]) >> 16;
-                                               paint[i].sample[3] += (samples[0] * vol[3]) >> 16;
-                                               samples += 1;
-                                       }
-                               }
-                               else if (vol[0] + vol[1] > 0 && ch->prologic_invert == -1)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 16;
-                                               paint[i].sample[1] -= (samples[0] * vol[1]) >> 16;
-                                               samples += 1;
-                                       }
-                               }
-                               else if (vol[0] + vol[1] > 0)
-                               {
-                                       for (i = 0;i < count;i++)
-                                       {
-                                               paint[i].sample[0] += (samples[0] * vol[0]) >> 16;
-                                               paint[i].sample[1] += (samples[0] * vol[1]) >> 16;
-                                               samples += 1;
-                                       }
-                               }
-                       }
-                       else
-                               return false; // unsupported number of channels in sound
-               }
-       }
-       return true;
-}
-
 void S_MixToBuffer(void *stream, unsigned int bufferframes)
 {
-       unsigned int i;
+       int channelindex;
        channel_t *ch;
-       unsigned int frames;
+       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
-               frames = min(bufferframes, PAINTBUFFER_SIZE);
+               totalmixframes = min(bufferframes, PAINTBUFFER_SIZE);
 
                // clear the paint buffer
-               memset (paintbuffer, 0, frames * sizeof (paintbuffer[0]));
+               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;
-               for (i = 0; i < total_channels ; i++, ch++)
+               for (channelindex = 0;channelindex < (int)total_channels;channelindex++, ch++)
                {
-                       sfx_t *sfx;
-                       int ltime;
-                       int count;
-
                        sfx = ch->sfx;
                        if (sfx == NULL)
                                continue;
@@ -510,53 +313,221 @@ void S_MixToBuffer(void *stream, unsigned int bufferframes)
                                continue;
                        if (!sfx->total_length)
                                continue;
-                       if (sfx->total_length > 1<<30)
-                               Sys_Error("S_MixToBuffer: sfx corrupt\n");
 
-                       ltime = 0;
-                       if (ch->pos < 0)
+                       // 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)
                        {
-                               count = -ch->pos;
-                               count = min(count, (int)frames - ltime);
-                               ch->pos += count;
-                               ltime += count;
+                               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;
                        }
 
-                       while (ltime < (int)frames)
+                       // 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;
+                       wantframes = totalmixframes;
+                       istartframe = 0;
+                       for (wantframes = totalmixframes;wantframes > 0;posd += count * speedd, wantframes -= count)
                        {
-                               // paint up to end of buffer or of input, whichever is lower
-                               count = sfx->total_length - ch->pos;
-                               count = bound(0, count, (int)frames - ltime);
-                               // mix the remaining samples
-                               if (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 (;;)
                                {
-                                       SND_PaintChannel (ch, paintbuffer + ltime, count);
-                                       ch->pos += count;
-                                       ltime += count;
+                                       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;
                                }
-                               // if at end of sfx, loop or stop the channel
-                               else
+
+                               // 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 (;;)
                                {
-                                       if (sfx->loopstart < sfx->total_length)
-                                               ch->pos = sfx->loopstart;
-                                       else if (ch->flags & CHANNELFLAG_FORCELOOP)
-                                               ch->pos = 0;
+                                       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
                                        {
-                                               S_StopChannel (ch - channels, false, false);
                                                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(frames);
+                       S_CaptureAVISound(paintbuffer, totalmixframes);
 
-               S_ConvertPaintBuffer(paintbuffer, outbytes, frames, snd_renderbuffer->format.width, snd_renderbuffer->format.channels);
+               S_ConvertPaintBuffer(paintbuffer, outbytes, totalmixframes, snd_renderbuffer->format.width, snd_renderbuffer->format.channels);
 
                // advance the output pointer
-               outbytes += frames * snd_renderbuffer->format.width * snd_renderbuffer->format.channels;
-               bufferframes -= frames;
+               outbytes += totalmixframes * snd_renderbuffer->format.width * snd_renderbuffer->format.channels;
+               bufferframes -= totalmixframes;
        }
 }
index 596b38ff75ab7d8e3a85da14a225dc285c6bd2b9..6dc3fce277d922737191a481ba5ba167a7836be9 100644 (file)
@@ -205,57 +205,46 @@ typedef struct
 {
        unsigned char   *file;
        size_t                  filesize;
-       snd_format_t    format;
-       unsigned int    total_length;
-       char                    name[128];
-       sfx_t           *sfx;
 } modplug_stream_persfx_t;
 
 // Per-channel data structure
 typedef struct
 {
        ModPlugFile     *mf;
-       unsigned int    sb_offset;
        int                             bs;
-       snd_buffer_t    sb;             // must be at the end due to its dynamically allocated size
+       int                             buffer_firstframe;
+       int                             buffer_numframes;
+       unsigned char   buffer[STREAM_BUFFERSIZE*4];
 } modplug_stream_perchannel_t;
 
 
 /*
 ====================
-ModPlug_FetchSound
+ModPlug_GetSamplesFloat
 ====================
 */
-static const snd_buffer_t* ModPlug_FetchSound (void *sfxfetcher, void **chfetcherpointer, unsigned int *start, unsigned int nbsampleframes)
+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 *)*chfetcherpointer;
-       modplug_stream_persfx_t* per_sfx = (modplug_stream_persfx_t *)sfxfetcher;
-       snd_buffer_t* sb;
+       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;
-       unsigned int real_start;
-       unsigned int factor;
+       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)
        {
-               size_t buff_len, memsize;
-               snd_format_t sb_format;
-
-               sb_format.speed = snd_renderbuffer->format.speed;
-               sb_format.width = per_sfx->format.width;
-               sb_format.channels = per_sfx->format.channels;
-
-               buff_len = STREAM_BUFFER_SIZE(&sb_format);
-               memsize = sizeof (*per_ch) - sizeof (per_ch->sb.samples) + buff_len;
-               per_ch = (modplug_stream_perchannel_t *)Mem_Alloc (snd_mempool, memsize);
+               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)
                {
-                       Con_Printf("error while reading ModPlug stream \"%s\"\n", per_sfx->name);
-                       Mem_Free (per_ch);
-                       return NULL;
+                       // 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
@@ -265,130 +254,88 @@ static const snd_buffer_t* ModPlug_FetchSound (void *sfxfetcher, void **chfetche
 
                per_ch->bs = 0;
 
-               per_ch->sb_offset = 0;
-               per_ch->sb.format = sb_format;
-               per_ch->sb.nbframes = 0;
-               per_ch->sb.maxframes = buff_len / (per_ch->sb.format.channels * per_ch->sb.format.width);
-
-               *chfetcherpointer = per_ch;
+               per_ch->buffer_firstframe = 0;
+               per_ch->buffer_numframes = 0;
+               ch->fetcher_data = per_ch;
        }
 
-       real_start = *start;
-
-       sb = &per_ch->sb;
-       factor = per_sfx->format.width * per_sfx->format.channels;
-
-       // If the stream buffer can't contain that much samples anyway
-       if (nbsampleframes > sb->maxframes)
+       // if the request is too large for our buffer, loop...
+       while (numsampleframes * f > (int)sizeof(per_ch->buffer))
        {
-               Con_Printf ("ModPlug_FetchSound: stream buffer too small (%u sample frames required)\n", nbsampleframes);
-               return NULL;
+               done = sizeof(per_ch->buffer) / f;
+               ModPlug_GetSamplesFloat(ch, sfx, firstsampleframe, done, outsamplesfloat);
+               firstsampleframe += done;
+               numsampleframes -= done;
+               outsamplesfloat += done * sfx->format.channels;
        }
 
-       // If the data we need has already been decompressed in the sfxbuffer, just return it
-       if (per_ch->sb_offset <= real_start && per_ch->sb_offset + sb->nbframes >= real_start + nbsampleframes)
+       // 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)
        {
-               *start = per_ch->sb_offset;
-               return sb;
+               // 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);
        }
 
-       newlength = (int)(per_ch->sb_offset + sb->nbframes) - real_start;
-
-       // If we need to skip some data before decompressing the rest, or if the stream has looped
-       if (newlength < 0 || per_ch->sb_offset > real_start)
+       // decompress the file as needed
+       if (firstsampleframe + numsampleframes > per_ch->buffer_firstframe + per_ch->buffer_numframes)
        {
-               unsigned int time_start;
-               unsigned int modplug_start;
-
-               /*
-               MODs loop on their own, so any position is valid!
-               if (real_start > (unsigned int)per_sfx->total_length)
-               {
-                       Con_Printf ("ModPlug_FetchSound: asked for a start position after the end of the sfx! (%u > %u)\n",
-                                               real_start, per_sfx->total_length);
-                       return NULL;
-               }
-               */
-
-               // We work with 200ms (1/5 sec) steps to avoid rounding errors
-               time_start = real_start * 5 / snd_renderbuffer->format.speed;
-               modplug_start = time_start * (1000 / 5);
-
-               Con_DPrintf("warning: mod file needed to seek (to %d)\n", modplug_start);
-
-               qModPlug_Seek(per_ch->mf, modplug_start);
-               sb->nbframes = 0;
-
-               real_start = (unsigned int) ((float)modplug_start / 1000 * snd_renderbuffer->format.speed);
-               if (*start - real_start + nbsampleframes > sb->maxframes)
+               // 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)
                {
-                       Con_Printf ("ModPlug_FetchSound: stream buffer too small after seek (%u sample frames required)\n",
-                                               *start - real_start + nbsampleframes);
-                       per_ch->sb_offset = real_start;
-                       return NULL;
+                       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;
        }
-       // Else, move forward the samples we need to keep in the sound buffer
-       else
-       {
-               memmove (sb->samples, sb->samples + (real_start - per_ch->sb_offset) * factor, newlength * factor);
-               sb->nbframes = newlength;
-       }
-
-       per_ch->sb_offset = real_start;
 
-       // We add more than one frame of sound to the buffer:
-       // 1- to ensure we won't lose many samples during the resampling process
-       // 2- to reduce calls to ModPlug_FetchSound to regulate workload
-       newlength = (int)(per_sfx->format.speed*STREAM_BUFFER_FILL);
-       if ((size_t) ((double) newlength * (double)sb->format.speed / (double)per_sfx->format.speed) + sb->nbframes > sb->maxframes)
-       {
-               Con_Printf ("ModPlug_FetchSound: stream buffer overflow (%u + %u = %u sample frames / %u)\n",
-                                       (unsigned int) ((double) newlength * (double)sb->format.speed / (double)per_sfx->format.speed), sb->nbframes, (unsigned int) ((double) newlength * (double)sb->format.speed / (double)per_sfx->format.speed) + sb->nbframes, sb->maxframes);
-               return NULL;
-       }
-       newlength *= factor; // convert from sample frames to bytes
-       if(newlength > (int)sizeof(resampling_buffer))
-               newlength = sizeof(resampling_buffer);
-
-       // Decompress in the resampling_buffer
-       done = 0;
-       while ((ret = qModPlug_Read (per_ch->mf, (char *)&resampling_buffer[done], (int)(newlength - done))) > 0)
-               done += ret;
-       if(done < newlength)
-       {
-               // 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...
-               per_sfx->sfx->total_length = (real_start + ((size_t)done / (size_t)factor));
-               per_sfx->sfx->loopstart = 0;
-
-               if(newlength != done)
-                       Con_DPrintf("ModPlug_Fetch: wanted: %d, got: %d\n", newlength, done);
-       }
-
-       Snd_AppendToSndBuffer (sb, resampling_buffer, (size_t)done / (size_t)factor, &per_sfx->format);
-
-       *start = per_ch->sb_offset;
-       return sb;
+       // 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_FetchEnd
+ModPlug_StopChannel
 ====================
 */
-static void ModPlug_FetchEnd (void *chfetcherdata)
+static void ModPlug_StopChannel(channel_t *ch)
 {
-       modplug_stream_perchannel_t* per_ch = (modplug_stream_perchannel_t *)chfetcherdata;
+       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);
+               qModPlug_Unload(per_ch->mf);
 
-               Mem_Free (per_ch);
+               Mem_Free(per_ch);
        }
 }
 
@@ -398,9 +345,9 @@ static void ModPlug_FetchEnd (void *chfetcherdata)
 ModPlug_FreeSfx
 ====================
 */
-static void ModPlug_FreeSfx (void *sfxfetcherdata)
+static void ModPlug_FreeSfx (sfx_t *sfx)
 {
-       modplug_stream_persfx_t* per_sfx = (modplug_stream_persfx_t *)sfxfetcherdata;
+       modplug_stream_persfx_t* per_sfx = (modplug_stream_persfx_t *)sfx->fetcher_data;
 
        // Free the modplug file
        Mem_Free(per_sfx->file);
@@ -410,18 +357,7 @@ static void ModPlug_FreeSfx (void *sfxfetcherdata)
 }
 
 
-/*
-====================
-ModPlug_GetFormat
-====================
-*/
-static const snd_format_t* qModPlug_GetFormat (sfx_t* sfx)
-{
-       modplug_stream_persfx_t* per_sfx = (modplug_stream_persfx_t *)sfx->fetcher_data;
-       return &per_sfx->format;
-}
-
-static const snd_fetcher_t modplug_fetcher = { ModPlug_FetchSound, ModPlug_FetchEnd, ModPlug_FreeSfx, qModPlug_GetFormat };
+static const snd_fetcher_t modplug_fetcher = { ModPlug_GetSamplesFloat, ModPlug_StopChannel, ModPlug_FreeSfx };
 
 
 /*
@@ -479,21 +415,17 @@ qboolean ModPlug_LoadModPlugFile (const char *filename, sfx_t *sfx)
        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));
-       strlcpy(per_sfx->name, sfx->name, sizeof(per_sfx->name));
-       sfx->memsize += sizeof (*per_sfx);
        per_sfx->file = data;
        per_sfx->filesize = filesize;
+       sfx->memsize += sizeof(*per_sfx);
        sfx->memsize += filesize;
-
-       per_sfx->format.speed = 44100; // modplug always works at that rate
-       per_sfx->format.width = 2;  // We always work with 16 bits samples
-       per_sfx->format.channels = 2; // stereo rulez ;) (MAYBE default to mono because Amiga MODs sound better then?)
-       per_sfx->sfx = sfx;
-
+       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 = 2147384647; // they always loop
+       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;
index 8385964425053d17c5f7a18f664b6bb219ba2101..47548e0a807d4a3173d4ca227516f8fc6902607e 100644 (file)
@@ -69,12 +69,7 @@ int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f
        return -1;
 }
 
-int S_StartSound_StartPosition (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float startposition)
-{
-       return -1;
-}
-
-int S_StartSound_StartPosition_Flags (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float startposition, int flags)
+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)
 {
        return -1;
 }
index 0ee16bab4bd7f70cfd64d7310b6b9ba8f72001d9..683d4213215f4496ab7bbd74a7b6e4500b496520 100644 (file)
@@ -399,9 +399,6 @@ typedef struct
 {
        unsigned char   *file;
        size_t                  filesize;
-       snd_format_t    format;
-       unsigned int    total_length;
-       char                    name[128];
 } ogg_stream_persfx_t;
 
 // Per-channel data structure
@@ -409,9 +406,10 @@ typedef struct
 {
        OggVorbis_File  vf;
        ov_decode_t             ov_decode;
-       unsigned int    sb_offset;
        int                             bs;
-       snd_buffer_t    sb;             // must be at the end due to its dynamically allocated size
+       int                             buffer_firstframe;
+       int                             buffer_numframes;
+       unsigned char   buffer[STREAM_BUFFERSIZE*4];
 } ogg_stream_perchannel_t;
 
 
@@ -419,159 +417,110 @@ static const ov_callbacks callbacks = {ovcb_read, ovcb_seek, ovcb_close, ovcb_te
 
 /*
 ====================
-OGG_FetchSound
+OGG_GetSamplesFloat
 ====================
 */
-static const snd_buffer_t* OGG_FetchSound (void *sfxfetcher, void **chfetcherpointer, unsigned int *start, unsigned int nbsampleframes)
+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 *)*chfetcherpointer;
-       ogg_stream_persfx_t* per_sfx = (ogg_stream_persfx_t *)sfxfetcher;
-       snd_buffer_t* sb;
+       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;
-       unsigned int real_start;
-       unsigned int factor;
 
-       // If there's no fetcher structure attached to the channel yet
+       // if this channel does not yet have a channel fetcher, make one
        if (per_ch == NULL)
        {
-               size_t buff_len, memsize;
-               snd_format_t sb_format;
-
-               sb_format.speed = snd_renderbuffer->format.speed;
-               sb_format.width = per_sfx->format.width;
-               sb_format.channels = per_sfx->format.channels;
-
-               buff_len = STREAM_BUFFER_SIZE(&sb_format);
-               memsize = sizeof (*per_ch) - sizeof (per_ch->sb.samples) + buff_len;
-               per_ch = (ogg_stream_perchannel_t *)Mem_Alloc (snd_mempool, memsize);
-
-               // Open it with the VorbisFile API
+               // 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)
+               if (qov_open_callbacks(&per_ch->ov_decode, &per_ch->vf, NULL, 0, callbacks) < 0)
                {
-                       Con_Printf("error while reading Ogg Vorbis stream \"%s\"\n", per_sfx->name);
-                       Mem_Free (per_ch);
-                       return NULL;
+                       // this never happens - this function succeeded earlier on the same data
+                       Mem_Free(per_ch);
+                       return;
                }
                per_ch->bs = 0;
-
-               per_ch->sb_offset = 0;
-               per_ch->sb.format = sb_format;
-               per_ch->sb.nbframes = 0;
-               per_ch->sb.maxframes = buff_len / (per_ch->sb.format.channels * per_ch->sb.format.width);
-
-               *chfetcherpointer = per_ch;
-       }
-
-       real_start = *start;
-
-       sb = &per_ch->sb;
-       factor = per_sfx->format.width * per_sfx->format.channels;
-
-       // If the stream buffer can't contain that much samples anyway
-       if (nbsampleframes > sb->maxframes)
-       {
-               Con_Printf ("OGG_FetchSound: stream buffer too small (%u sample frames required)\n", nbsampleframes);
-               return NULL;
+               per_ch->buffer_firstframe = 0;
+               per_ch->buffer_numframes = 0;
+               // attach the struct to our channel
+               ch->fetcher_data = (void *)per_ch;
        }
 
-       // If the data we need has already been decompressed in the sfxbuffer, just return it
-       if (per_ch->sb_offset <= real_start && per_ch->sb_offset + sb->nbframes >= real_start + nbsampleframes)
+       // if the request is too large for our buffer, loop...
+       while (numsampleframes * f > (int)sizeof(per_ch->buffer))
        {
-               *start = per_ch->sb_offset;
-               return sb;
+               done = sizeof(per_ch->buffer) / f;
+               OGG_GetSamplesFloat(ch, sfx, firstsampleframe, done, outsamplesfloat);
+               firstsampleframe += done;
+               numsampleframes -= done;
+               outsamplesfloat += done * sfx->format.channels;
        }
 
-       newlength = (int)(per_ch->sb_offset + sb->nbframes) - real_start;
-
-       // If we need to skip some data before decompressing the rest, or if the stream has looped
-       if (newlength < 0 || per_ch->sb_offset > real_start)
+       // 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)
        {
-               unsigned int time_start;
-               ogg_int64_t ogg_start;
-               int err;
-
-               if (real_start > (unsigned int)per_sfx->total_length)
+               // 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)
                {
-                       Con_Printf ("OGG_FetchSound: asked for a start position after the end of the sfx! (%u > %u)\n",
-                                               real_start, per_sfx->total_length);
-                       return NULL;
+                       // LordHavoc: we can't Con_Printf here, not thread safe...
+                       //Con_Printf("OGG_FetchSound: qov_pcm_seek(..., %d) returned %d\n", firstsampleframe, ret);
+                       return;
                }
-
-               // We work with 200ms (1/5 sec) steps to avoid rounding errors
-               time_start = real_start * 5 / snd_renderbuffer->format.speed;
-               ogg_start = time_start * (per_sfx->format.speed / 5);
-               err = qov_pcm_seek (&per_ch->vf, ogg_start);
-               if (err != 0)
-               {
-                       Con_Printf ("OGG_FetchSound: qov_pcm_seek(..., %d) returned %d\n",
-                                               real_start, err);
-                       return NULL;
-               }
-               sb->nbframes = 0;
-
-               real_start = (unsigned int) ((float)ogg_start / per_sfx->format.speed * snd_renderbuffer->format.speed);
-               if (*start - real_start + nbsampleframes > sb->maxframes)
-               {
-                       Con_Printf ("OGG_FetchSound: stream buffer too small after seek (%u sample frames required)\n",
-                                               *start - real_start + nbsampleframes);
-                       per_ch->sb_offset = real_start;
-                       return NULL;
-               }
-       }
-       // Else, move forward the samples we need to keep in the sound buffer
-       else
-       {
-               memmove (sb->samples, sb->samples + (real_start - per_ch->sb_offset) * factor, newlength * factor);
-               sb->nbframes = newlength;
        }
 
-       per_ch->sb_offset = real_start;
-
-       // We add more than one frame of sound to the buffer:
-       // 1- to ensure we won't lose many samples during the resampling process
-       // 2- to reduce calls to OGG_FetchSound to regulate workload
-       newlength = (int)(per_sfx->format.speed*STREAM_BUFFER_FILL);
-       // this is how much we FETCH...
-       if ((size_t) ((double) newlength * (double)sb->format.speed / (double)per_sfx->format.speed) + sb->nbframes > sb->maxframes)
+       // decompress the file as needed
+       if (firstsampleframe + numsampleframes > per_ch->buffer_firstframe + per_ch->buffer_numframes)
        {
-               Con_Printf ("OGG_FetchSound: stream buffer overflow (%u + %u = %u sample frames / %u)\n",
-                                       (unsigned int) ((double) newlength * (double)sb->format.speed / (double)per_sfx->format.speed), sb->nbframes, (unsigned int) ((double) newlength * (double)sb->format.speed / (double)per_sfx->format.speed) + sb->nbframes, sb->maxframes);
-               return NULL;
+               // 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;
        }
-       newlength *= factor; // convert from sample frames to bytes
-       if(newlength > (int)sizeof(resampling_buffer))
-               newlength = sizeof(resampling_buffer);
 
-       // Decompress in the resampling_buffer
-       done = 0;
-       while ((ret = qov_read (&per_ch->vf, (char *)&resampling_buffer[done], (int)(newlength - done), mem_bigendian, 2, 1, &per_ch->bs)) > 0)
-               done += ret;
-
-       Snd_AppendToSndBuffer (sb, resampling_buffer, (size_t)done / (size_t)factor, &per_sfx->format);
-
-       *start = per_ch->sb_offset;
-       return sb;
+       // 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_FetchEnd
+OGG_StopChannel
 ====================
 */
-static void OGG_FetchEnd (void *chfetcherdata)
+static void OGG_StopChannel(channel_t *ch)
 {
-       ogg_stream_perchannel_t* per_ch = (ogg_stream_perchannel_t *)chfetcherdata;
-
+       ogg_stream_perchannel_t *per_ch = (ogg_stream_perchannel_t *)ch->fetcher_data;
        if (per_ch != NULL)
        {
-               // Free the ogg vorbis decoder
-               qov_clear (&per_ch->vf);
-
-               Mem_Free (per_ch);
+               // release the vorbis decompressor
+               qov_clear(&per_ch->vf);
+               Mem_Free(per_ch);
        }
 }
 
@@ -581,32 +530,19 @@ static void OGG_FetchEnd (void *chfetcherdata)
 OGG_FreeSfx
 ====================
 */
-static void OGG_FreeSfx (void *sfxfetcherdata)
+static void OGG_FreeSfx(sfx_t *sfx)
 {
-       ogg_stream_persfx_t* per_sfx = (ogg_stream_persfx_t *)sfxfetcherdata;
-
-       // Free the Ogg Vorbis file
+       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 stream structure
+       // free the file information structure
        Mem_Free(per_sfx);
 }
 
 
-/*
-====================
-OGG_GetFormat
-====================
-*/
-static const snd_format_t* OGG_GetFormat (sfx_t* sfx)
-{
-       ogg_stream_persfx_t* per_sfx = (ogg_stream_persfx_t *)sfx->fetcher_data;
-       return &per_sfx->format;
-}
-
-static const snd_fetcher_t ogg_fetcher = { OGG_FetchSound, OGG_FetchEnd, OGG_FreeSfx, OGG_GetFormat };
+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, double samplesfactor, unsigned int numsamples, double *peak, double *gaindb)
+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;
 
@@ -649,11 +585,11 @@ static void OGG_DecodeTags(vorbis_comment *vc, unsigned int *start, unsigned int
 
        if(startcomment)
        {
-               *start = (unsigned int) bound(0, atof(startcomment) * samplesfactor, numsamples);
+               *start = (unsigned int) bound(0, atof(startcomment), numsamples);
                if(endcomment)
-                       *length = (unsigned int) bound(0, atof(endcomment) * samplesfactor, numsamples);
+                       *length = (unsigned int) bound(0, atof(endcomment), numsamples);
                else if(lengthcomment)
-                       *length = (unsigned int) bound(0, *start + atof(lengthcomment) * samplesfactor, numsamples);
+                       *length = (unsigned int) bound(0, *start + atof(lengthcomment), numsamples);
        }
 }
 
@@ -664,7 +600,7 @@ OGG_LoadVorbisFile
 Load an Ogg Vorbis file into memory
 ====================
 */
-qboolean OGG_LoadVorbisFile (const char *filename, sfx_t *sfx)
+qboolean OGG_LoadVorbisFile(const char *filename, sfx_t *sfx)
 {
        unsigned char *data;
        fs_offset_t filesize;
@@ -672,7 +608,6 @@ qboolean OGG_LoadVorbisFile (const char *filename, sfx_t *sfx)
        OggVorbis_File vf;
        vorbis_info *vi;
        vorbis_comment *vc;
-       ogg_int64_t len, buff_len;
        double peak, gaindb;
 
 #ifndef LINK_TO_LIBVORBIS
@@ -680,31 +615,31 @@ qboolean OGG_LoadVorbisFile (const char *filename, sfx_t *sfx)
                return false;
 #endif
 
-       // Already loaded?
+       // Return if already loaded
        if (sfx->fetcher != NULL)
                return true;
 
-       // Load the file
-       data = FS_LoadFile (filename, snd_mempool, false, &filesize);
+       // 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);
+               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)
+       if (qov_open_callbacks(&ov_decode, &vf, NULL, 0, callbacks) < 0)
        {
-               Con_Printf ("error while opening Ogg Vorbis file \"%s\"\n", filename);
+               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);
+       vi = qov_info(&vf, -1);
        if (vi->channels < 1 || vi->channels > 2)
        {
                Con_Printf("%s has an unsupported number of channels (%i)\n",
@@ -714,81 +649,54 @@ qboolean OGG_LoadVorbisFile (const char *filename, sfx_t *sfx)
                return false;
        }
 
-       len = qov_pcm_total (&vf, -1) * vi->channels * 2;  // 16 bits => "* 2"
+       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);
 
-       // Decide if we go for a stream or a simple PCM cache
-       buff_len = (int)ceil (STREAM_BUFFER_DURATION * snd_renderbuffer->format.speed) * 2 * vi->channels;
-       if (snd_streaming.integer && (len > (ogg_int64_t)filesize + 3 * buff_len || snd_streaming.integer >= 2))
+       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));
-               strlcpy(per_sfx->name, sfx->name, sizeof(per_sfx->name));
+                       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;
-
-               per_sfx->format.speed = vi->rate;
-               per_sfx->format.width = 2;  // We always work with 16 bits samples
-               per_sfx->format.channels = vi->channels;
-
                sfx->fetcher_data = per_sfx;
                sfx->fetcher = &ogg_fetcher;
                sfx->flags |= SFXFLAG_STREAMED;
-               sfx->total_length = (int)((size_t)len / (per_sfx->format.channels * 2) * ((double)snd_renderbuffer->format.speed / per_sfx->format.speed));
                vc = qov_comment(&vf, -1);
-               OGG_DecodeTags(vc, &sfx->loopstart, &sfx->total_length, (double)snd_renderbuffer->format.speed / (double)per_sfx->format.speed, sfx->total_length, &peak, &gaindb);
-               per_sfx->total_length = sfx->total_length;
-               qov_clear (&vf);
+               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;
-               snd_buffer_t *sb;
-               snd_format_t ogg_format;
-
                if (developer_loading.integer >= 2)
                        Con_Printf ("Ogg sound file \"%s\" will be cached\n", filename);
-
-               // Decode it
-               buff = (char *)Mem_Alloc (snd_mempool, (int)len);
+               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)
+               while ((ret = qov_read(&vf, &buff[done], (int)(len - done), mem_bigendian, 2, 1, &bs)) > 0)
                        done += ret;
-
-               // Build the sound buffer
-               ogg_format.speed = vi->rate;
-               ogg_format.channels = vi->channels;
-               ogg_format.width = 2;  // We always work with 16 bits samples
-               sb = Snd_CreateSndBuffer ((unsigned char *)buff, (size_t)done / (vi->channels * 2), &ogg_format, snd_renderbuffer->format.speed);
-               if (sb == NULL)
-               {
-                       qov_clear (&vf);
-                       Mem_Free (data);
-                       Mem_Free (buff);
-                       return false;
-               }
-
-               sfx->fetcher = &wav_fetcher;
-               sfx->fetcher_data = sb;
-
-               sfx->total_length = sb->nbframes;
-               sfx->memsize += sb->maxframes * sb->format.channels * sb->format.width + sizeof (*sb) - sizeof (sb->samples);
-
-               sfx->flags &= ~SFXFLAG_STREAMED;
                vc = qov_comment(&vf, -1);
-               OGG_DecodeTags(vc, &sfx->loopstart, &sfx->total_length, (double)snd_renderbuffer->format.speed / (double)sb->format.speed, sfx->total_length, &peak, &gaindb);
-               sb->nbframes = sfx->total_length;
-               qov_clear (&vf);
-               Mem_Free (data);
-               Mem_Free (buff);
+               OGG_DecodeTags(vc, &sfx->loopstart, &sfx->total_length, sfx->total_length, &peak, &gaindb);
+               qov_clear(&vf);
+               Mem_Free(data);
        }
 
        if(peak)
@@ -798,6 +706,13 @@ qboolean OGG_LoadVorbisFile (const char *filename, sfx_t *sfx)
                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;
 }
index b55c36653358524b8dd636f341323c92dfeb41a8..258b501c4d7cf08c6e132f7987f481147c6bb5b5 100644 (file)
@@ -226,13 +226,24 @@ static wavinfo_t GetWavinfo (char *name, unsigned char *wav, int wavlength)
 
 /*
 ====================
-WAV_FetchSound
+WAV_GetSamplesFloat
 ====================
 */
-static const snd_buffer_t* WAV_FetchSound (void *sfxfetcher, void **chfetcherpointer, unsigned int *start, unsigned int nbsampleframes)
+static void WAV_GetSamplesFloat(channel_t *ch, sfx_t *sfx, int firstsampleframe, int numsampleframes, float *outsamplesfloat)
 {
-       *start = 0;
-       return (snd_buffer_t *)sfxfetcher;
+       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);
+       }
 }
 
 /*
@@ -240,25 +251,13 @@ static const snd_buffer_t* WAV_FetchSound (void *sfxfetcher, void **chfetcherpoi
 WAV_FreeSfx
 ====================
 */
-static void WAV_FreeSfx (void *sfxfetcherdata)
+static void WAV_FreeSfx(sfx_t *sfx)
 {
-       snd_buffer_t* sb = (snd_buffer_t *)sfxfetcherdata;
-       // Free the sound buffer
-       Mem_Free(sb);
+       // free the loaded sound data
+       Mem_Free(sfx->fetcher_data);
 }
 
-/*
-====================
-WAV_GetFormat
-====================
-*/
-static const snd_format_t* WAV_GetFormat (sfx_t* sfx)
-{
-       snd_buffer_t* sb = (snd_buffer_t *)sfx->fetcher_data;
-       return &sb->format;
-}
-
-const snd_fetcher_t wav_fetcher = { WAV_FetchSound, NULL, WAV_FreeSfx, WAV_GetFormat };
+const snd_fetcher_t wav_fetcher = { WAV_GetSamplesFloat, NULL, WAV_FreeSfx };
 
 
 /*
@@ -271,8 +270,9 @@ qboolean S_LoadWavFile (const char *filename, sfx_t *sfx)
        fs_offset_t filesize;
        unsigned char *data;
        wavinfo_t info;
-       snd_format_t wav_format;
-       snd_buffer_t* sb;
+       int i, len;
+       const unsigned char *inb;
+       unsigned char *outb;
 
        // Already loaded?
        if (sfx->fetcher != NULL)
@@ -316,28 +316,46 @@ qboolean S_LoadWavFile (const char *filename, sfx_t *sfx)
                        ptr[i] = LittleShort (ptr[i]);
        }
 
-       wav_format.speed = info.rate;
-       wav_format.width = info.width;
-       wav_format.channels = info.channels;
-       sb = Snd_CreateSndBuffer (data + info.dataofs, info.samples, &wav_format, snd_renderbuffer->format.speed);
-       if (sb == NULL)
+       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)
        {
-               Mem_Free(data);
-               return false;
+               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;
        }
-       sfx->fetcher = &wav_fetcher;
-       sfx->fetcher_data = sb;
-
-       sfx->total_length = sb->nbframes;
-       sfx->memsize += sb->maxframes * sb->format.channels * sb->format.width + sizeof (*sb) - sizeof (sb->samples);
 
        if (info.loopstart < 0)
                sfx->loopstart = sfx->total_length;
        else
-               sfx->loopstart = (unsigned int) ((double)info.loopstart * (double)sb->format.speed / (double)info.rate);
+               sfx->loopstart = info.loopstart;
        sfx->loopstart = min(sfx->loopstart, sfx->total_length);
        sfx->flags &= ~SFXFLAG_STREAMED;
 
-       Mem_Free (data);
        return true;
 }
index ff1e918767332683861acfac6c37414c5f29d93d..0162c37c72923a83a3494774e7fae5d55b6f54b6 100644 (file)
@@ -72,6 +72,7 @@ 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);
 
 // for sound() builtins
 #define CHANFLAG_RELIABLE 1
@@ -97,8 +98,7 @@ qboolean S_IsSoundPrecached (const sfx_t *sfx);
 
 // 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 (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float startposition);
-int S_StartSound_StartPosition_Flags (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float startposition, int flags);
+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);
@@ -109,6 +109,7 @@ 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);
 
index f6f00d33102ec3c30968a30ff05e0c9a3e446b5a..cc94a2c05aa5d1e6d41b04031651060d41bdc77e 100644 (file)
@@ -5,6 +5,7 @@ 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)
@@ -30,6 +31,7 @@ void SV_StartDemoRecording(client_t *client, const char *filename, int forcetrac
 
 void SV_WriteDemoMessage(client_t *client, sizebuf_t *sendbuffer, qboolean clienttoserver)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int len, i;
        float f;
        int temp;
@@ -52,6 +54,7 @@ void SV_WriteDemoMessage(client_t *client, sizebuf_t *sendbuffer, qboolean clien
 
 void SV_StopDemoRecording(client_t *client)
 {
+       prvm_prog_t *prog = SVVM_prog;
        sizebuf_t buf;
        unsigned char bufdata[64];
 
index bc6eaf0ad59db131b13eb1013c12a4ddd1c36ecb..27befbcfcea47edb3f5cf4a20589c50a9a3bee7c 100644 (file)
@@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #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);
@@ -30,21 +31,19 @@ static void SV_Download_f(void);
 static void SV_VM_Setup(void);
 extern cvar_t net_connecttimeout;
 
-void VM_CustomStats_Clear (void);
-void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats);
-
 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"};
+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)"};
@@ -121,6 +120,9 @@ cvar_t sv_gameplayfix_swiminbmodels = {0, "sv_gameplayfix_swiminbmodels", "1", "
 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 (sv_gameplayfix_stepwhilejumping must also be 1)"};
@@ -148,9 +150,11 @@ cvar_t sv_warsowbunny_topspeed = {0, "sv_warsowbunny_topspeed", "925", "soft spe
 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"};
@@ -409,7 +413,7 @@ prvm_required_field_t sv_reqglobals[] =
 
 //============================================================================
 
-void SV_AreaStats_f(void)
+static void SV_AreaStats_f(void)
 {
        World_PrintAreaStats(&sv.world, "server");
 }
@@ -426,6 +430,7 @@ void SV_Init (void)
        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);
@@ -435,12 +440,14 @@ void SV_Init (void)
        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);
@@ -523,6 +530,9 @@ void SV_Init (void)
        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);
@@ -550,9 +560,11 @@ void SV_Init (void)
        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);
@@ -599,12 +611,13 @@ void SV_Init (void)
 
 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("%s.ent", sv.worldnamenoextension), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
+       FS_WriteFile(va(vabuf, sizeof(vabuf), "%s.ent", sv.worldnamenoextension), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
 }
 
 
@@ -693,10 +706,11 @@ 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)
+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;
+       int sound_num, field_mask, i, ent, speed4000;
 
        dest = (reliable ? &sv.reliable_datagram : &sv.datagram);
 
@@ -730,11 +744,14 @@ void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int v
 
        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)
@@ -747,6 +764,8 @@ void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int v
                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);
@@ -779,9 +798,9 @@ function, therefore the check for it is omitted.
 
 ==================
 */
-void SV_StartPointSound (vec3_t origin, const char *sample, int volume, float attenuation)
+void SV_StartPointSound (vec3_t origin, const char *sample, int volume, float attenuation, float speed)
 {
-       int sound_num, field_mask, i;
+       int sound_num, field_mask, i, speed4000;
 
        if (volume < 0 || volume > 255)
        {
@@ -803,6 +822,7 @@ void SV_StartPointSound (vec3_t origin, const char *sample, int volume, float at
        if (!sound_num)
                return;
 
+       speed4000 = (int)(speed * 40.0f);
        field_mask = 0;
        if (volume != DEFAULT_SOUND_PACKET_VOLUME)
                field_mask |= SND_VOLUME;
@@ -810,6 +830,8 @@ void SV_StartPointSound (vec3_t origin, const char *sample, int volume, float at
                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);
@@ -818,6 +840,8 @@ void SV_StartPointSound (vec3_t origin, const char *sample, int volume, float at
                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)
@@ -847,8 +871,10 @@ 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
 
@@ -927,11 +953,11 @@ void SV_SendServerinfo (client_t *client)
        {
                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("csqc_progname %s\n", sv.csqc_progname));
+               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("csqc_progsize %i\n", sv.csqc_progsize));
+               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("csqc_progcrc %i\n", sv.csqc_progcrc));
+               MSG_WriteString (&client->netconnection->message, va(vabuf, sizeof(vabuf), "csqc_progcrc %i\n", sv.csqc_progcrc));
 
                if(client->sv_demo_file != NULL)
                {
@@ -947,10 +973,10 @@ void SV_SendServerinfo (client_t *client)
                }
 
                //[515]: init stufftext string (it is sent before svc_serverinfo)
-               if (PRVM_GetString(PRVM_serverglobalstring(SV_InitCmd)))
+               if (PRVM_GetString(prog, PRVM_serverglobalstring(SV_InitCmd)))
                {
                        MSG_WriteByte (&client->netconnection->message, svc_stufftext);
-                       MSG_WriteString (&client->netconnection->message, va("%s\n", PRVM_GetString(PRVM_serverglobalstring(SV_InitCmd))));
+                       MSG_WriteString (&client->netconnection->message, va(vabuf, sizeof(vabuf), "%s\n", PRVM_GetString(prog, PRVM_serverglobalstring(SV_InitCmd))));
                }
        }
 
@@ -980,7 +1006,7 @@ void SV_SendServerinfo (client_t *client)
        else
                MSG_WriteByte (&client->netconnection->message, GAME_COOP);
 
-       MSG_WriteString (&client->netconnection->message,PRVM_GetString(PRVM_serveredictstring(prog->edicts, message)));
+       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]);
@@ -1033,6 +1059,7 @@ 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;
 
@@ -1085,13 +1112,14 @@ void SV_ConnectClient (int clientnum, netconn_t *netconnection)
        {
                // 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;
-               PRVM_ExecuteProgram (PRVM_serverfunction(SetNewParms), "QC function SetNewParms is missing");
+               prog->ExecuteProgram(prog, PRVM_serverfunction(SetNewParms), "QC function SetNewParms is missing");
                for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
                        client->spawn_parms[i] = (&PRVM_serverglobalfloat(parm1))[i];
 
                // set up the entity for this client (including .colormap, .team, etc)
-               PRVM_ED_ClearEdict(client->edict);
+               PRVM_ED_ClearEdict(prog, client->edict);
        }
 
        // don't call SendServerinfo for a fresh botclient because its fields have
@@ -1124,6 +1152,7 @@ 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;
@@ -1154,7 +1183,7 @@ static qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *c
        // 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(PRVM_serveredictstring(ent, model)) && sv.models[i]) ? i : 0;
+       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);
@@ -1333,6 +1362,7 @@ static qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *c
                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];
@@ -1428,8 +1458,9 @@ static qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *c
        return true;
 }
 
-void SV_PrepareEntitiesForSending(void)
+static void SV_PrepareEntitiesForSending(void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int e;
        prvm_edict_t *ent;
        // send all entities that touch the pvs
@@ -1450,6 +1481,7 @@ void SV_PrepareEntitiesForSending(void)
 
 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];
@@ -1495,7 +1527,7 @@ qboolean SV_CanSeeBox(int numtraces, vec_t enlarge, vec3_t eye, vec3_t entboxmin
 
        // get the list of entities in the sweep box
        if (sv_cullentities_trace_entityocclusion.integer)
-               numtouchedicts = World_EntitiesInBox(&sv.world, clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
+               numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
        if (numtouchedicts > MAX_EDICTS)
        {
                // this never happens
@@ -1539,7 +1571,7 @@ qboolean SV_CanSeeBox(int numtraces, vec_t enlarge, vec3_t eye, vec3_t entboxmin
                        if(model && model->brush.TraceLineOfSight)
                        {
                                // get the entity matrix
-                               pitchsign = SV_GetPitchSign(touch);
+                               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
@@ -1563,8 +1595,9 @@ qboolean SV_CanSeeBox(int numtraces, vec_t enlarge, vec3_t eye, vec3_t entboxmin
        return false;
 }
 
-void SV_MarkWriteEntityStateToClient(entity_state_t *s)
+static void SV_MarkWriteEntityStateToClient(entity_state_t *s)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int isbmodel;
        dp_model_t *model;
        prvm_edict_t *ed;
@@ -1575,9 +1608,10 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s)
 
        if (s->customizeentityforclient)
        {
+               PRVM_serverglobalfloat(time) = sv.time;
                PRVM_serverglobaledict(self) = s->number;
                PRVM_serverglobaledict(other) = sv.writeentitiestoclient_cliententitynumber;
-               PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
+               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;
        }
@@ -1691,8 +1725,9 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s)
 
 #if MAX_LEVELNETWORKEYES > 0
 #define MAX_EYE_RECURSION 1 // increase if recursion gets supported by portals
-void SV_AddCameraEyes(void)
+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];
@@ -1711,12 +1746,13 @@ void SV_AddCameraEyes(void)
                {
                        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));
-                               PRVM_ExecuteProgram(PRVM_serveredictfunction(ed, camera_transform), "QC function e.camera_transform is missing");
+                               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]);
@@ -1763,8 +1799,9 @@ void SV_AddCameraEyes(void)
 }
 #endif
 
-void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int maxsize)
+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;
@@ -1893,6 +1930,7 @@ SV_CleanupEnts
 */
 static void SV_CleanupEnts (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int             e;
        prvm_edict_t    *ent;
 
@@ -1909,6 +1947,7 @@ 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;
@@ -1962,7 +2001,10 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
 
        // stuff the sigil bits into the high bits of items for sbar, or else
        // mix in items2
-       if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
+       // LordHavoc: detecting items2 turned out to be tricky, check if the field
+       // was forcefully declared, we want to override serverflags if it was
+       // declared by the qc intentionally, but not if we added it in the engine.
+       if (prog->fieldoffsets.items2 < (int)(prog->numfielddefs - SV_REQGLOBALS))
                items = (int)PRVM_serveredictfloat(ent, items) | ((int)PRVM_serveredictfloat(ent, items2) << 23);
        else
                items = (int)PRVM_serveredictfloat(ent, items) | ((int)PRVM_serverglobalfloat(serverflags) << 28);
@@ -1971,7 +2013,7 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
 
        // cache weapon model name and index in client struct to save time
        // (this search can be almost 1% of cpu time!)
-       s = PRVM_GetString(PRVM_serveredictstring(ent, weaponmodel));
+       s = PRVM_GetString(prog, PRVM_serveredictstring(ent, weaponmodel));
        if (strcmp(s, client->weaponmodel))
        {
                strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
@@ -2328,7 +2370,7 @@ static void SV_SendClientDatagram (client_t *client)
                // 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);
+               VM_SV_UpdateCustomStats(client, client->edict, &msg, stats);
                // set host_client->statsdeltabits
                Protocol_UpdateClientStats (stats);
 
@@ -2391,6 +2433,7 @@ SV_UpdateToReliableMessages
 */
 static void SV_UpdateToReliableMessages (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int i, j;
        client_t *client;
        const char *name;
@@ -2405,12 +2448,12 @@ static void SV_UpdateToReliableMessages (void)
                host_client->edict = PRVM_EDICT_NUM(i+1);
 
                // DP_SV_CLIENTNAME
-               name = PRVM_GetString(PRVM_serveredictstring(host_client->edict, netname));
+               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(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->spawned)
@@ -2435,20 +2478,20 @@ static void SV_UpdateToReliableMessages (void)
                }
 
                // NEXUIZ_PLAYERMODEL
-               model = PRVM_GetString(PRVM_serveredictstring(host_client->edict, 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(host_client->playermodel);
+               PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, host_client->playermodel);
 
                // NEXUIZ_PLAYERSKIN
-               skin = PRVM_GetString(PRVM_serveredictstring(host_client->edict, 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(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);
@@ -2459,7 +2502,7 @@ static void SV_UpdateToReliableMessages (void)
                                clientcamera = PRVM_NUM_FOR_EDICT(host_client->edict);
                        host_client->clientcamera = clientcamera;
 
-                       if (oldclientcamera != host_client->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);
@@ -2494,7 +2537,7 @@ static void SV_UpdateToReliableMessages (void)
 SV_SendClientMessages
 =======================
 */
-void SV_SendClientMessages (void)
+void SV_SendClientMessages(void)
 {
        int i, prepared = false;
 
@@ -2526,7 +2569,7 @@ void SV_SendClientMessages (void)
                        // only prepare entities once per frame
                        SV_PrepareEntitiesForSending();
                }
-               SV_SendClientDatagram (host_client);
+               SV_SendClientDatagram(host_client);
        }
 
 // clear muzzle flashes
@@ -2808,9 +2851,23 @@ int SV_ModelIndex(const char *s, int precachemode)
                                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]));
-                               sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, s[0] == '*' ? sv.worldname : NULL);
-                               if (sv.state != ss_loading)
+                               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);
@@ -2917,7 +2974,7 @@ int SV_ParticleEffectIndex(const char *name)
                                argc = 0;
                                for (;;)
                                {
-                                       if (!COM_ParseToken_Simple(&text, true, false) || !strcmp(com_token, "\n"))
+                                       if (!COM_ParseToken_Simple(&text, true, false, true) || !strcmp(com_token, "\n"))
                                                break;
                                        if (argc < 16)
                                        {
@@ -2973,6 +3030,7 @@ dp_model_t *SV_GetModelByIndex(int modelindex)
 
 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;
@@ -2988,6 +3046,7 @@ SV_CreateBaseline
 */
 static void SV_CreateBaseline (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int i, entnum, large;
        prvm_edict_t *svent;
 
@@ -3069,7 +3128,7 @@ Load csprogs.dat and comperss it so it doesn't need to be
 reloaded on request.
 ================
 */
-void SV_Prepare_CSQC(void)
+static void SV_Prepare_CSQC(void)
 {
        fs_offset_t progsize;
 
@@ -3120,6 +3179,7 @@ transition to another level
 */
 void SV_SaveSpawnparms (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int             i, j;
 
        svs.serverflags = (int)PRVM_serverglobalfloat(serverflags);
@@ -3130,8 +3190,9 @@ void SV_SaveSpawnparms (void)
                        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);
-               PRVM_ExecuteProgram (PRVM_serverfunction(SetChangeParms), "QC function SetChangeParms is missing");
+               prog->ExecuteProgram(prog, PRVM_serverfunction(SetChangeParms), "QC function SetChangeParms is missing");
                for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
                        host_client->spawn_parms[j] = (&PRVM_serverglobalfloat(parm1))[j];
        }
@@ -3147,11 +3208,13 @@ 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);
 
@@ -3167,6 +3230,11 @@ void SV_SpawnServer (const char *server)
                }
        }
 
+//     SV_LockThreadMutex();
+
+       if(cls.state == ca_dedicated)
+               Sys_MakeProcessNice();
+
        if (cls.state != ca_dedicated)
        {
                SCR_BeginLoadingPlaque();
@@ -3175,15 +3243,14 @@ void SV_SpawnServer (const char *server)
 
        if(sv.active)
        {
-               SV_VM_Begin();
                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
-                       PRVM_ExecuteProgram(s,"SV_Shutdown() required");
+                       prog->ExecuteProgram(prog, s,"SV_Shutdown() required");
                }
-               SV_VM_End();
        }
 
        // free q3 shaders so that any newly downloaded shaders will be active
@@ -3193,6 +3260,12 @@ void SV_SpawnServer (const char *server)
        if (!worldmodel || !worldmodel->TraceBox)
        {
                Con_Printf("Couldn't load map %s\n", modelname);
+
+               if(cls.state == ca_dedicated)
+                       Sys_MakeProcessMean();
+
+//             SV_UnlockThreadMutex();
+
                return;
        }
 
@@ -3279,8 +3352,6 @@ void SV_SpawnServer (const char *server)
                sv.protocol = PROTOCOL_QUAKE;
        }
 
-       SV_VM_Begin();
-
 // load progs to get entity field count
        //PR_LoadProgs ( sv_progs.string );
 
@@ -3303,7 +3374,7 @@ void SV_SpawnServer (const char *server)
        prog->allowworldwrites = true;
        sv.paused = false;
 
-       PRVM_serverglobalfloat(time) = sv.time = 1.0;
+       sv.time = 1.0;
 
        Mod_ClearUsed();
        worldmodel->used = true;
@@ -3314,7 +3385,7 @@ void SV_SpawnServer (const char *server)
 //
 // clear world interaction links
 //
-       World_SetSize(&sv.world, sv.worldname, sv.worldmodel->normalmins, sv.worldmodel->normalmaxs);
+       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]));
@@ -3336,7 +3407,7 @@ void SV_SpawnServer (const char *server)
        ent = PRVM_EDICT_NUM(0);
        memset (ent->fields.vp, 0, prog->entityfields * 4);
        ent->priv.server->free = false;
-       PRVM_serveredictstring(ent, model) = PRVM_SetEngineString(sv.worldname);
+       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;
@@ -3350,7 +3421,7 @@ void SV_SpawnServer (const char *server)
        else
                PRVM_serverglobalfloat(deathmatch) = deathmatch.integer;
 
-       PRVM_serverglobalstring(mapname) = PRVM_SetEngineString(sv.name);
+       PRVM_serverglobalstring(mapname) = PRVM_SetEngineString(prog, sv.name);
 
 // serverflags are for cross level information (sigils)
        PRVM_serverglobalfloat(serverflags) = svs.serverflags;
@@ -3363,18 +3434,18 @@ void SV_SpawnServer (const char *server)
        {
                host_client->spawned = false;
                host_client->edict = PRVM_EDICT_NUM(i + 1);
-               PRVM_ED_ClearEdict(host_client->edict);
+               PRVM_ED_ClearEdict(prog, host_client->edict);
        }
 
        // load replacement entity file if found
-       if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("%s.ent", sv.worldnamenoextension), tempmempool, true, NULL)))
+       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 (entities);
+               PRVM_ED_LoadFromFile(prog, entities);
                Mem_Free(entities);
        }
        else
-               PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
+               PRVM_ED_LoadFromFile(prog, sv.worldmodel->brush.entities);
 
 
        // LordHavoc: clear world angles (to fix e3m3.bsp)
@@ -3385,7 +3456,7 @@ void SV_SpawnServer (const char *server)
        prog->allowworldwrites = false;
 
 // run two frames to allow everything to settle
-       PRVM_serverglobalfloat(time) = sv.time = 1.0001;
+       sv.time = 1.0001;
        for (i = 0;i < 2;i++)
        {
                sv.frametime = 0.1;
@@ -3401,9 +3472,6 @@ void SV_SpawnServer (const char *server)
 
        sv.state = ss_active; // LordHavoc: workaround for svc_precache bug
 
-       // to prevent network timeouts
-       realtime = Sys_DoubleTime();
-       
 // 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++)
        {
@@ -3426,32 +3494,35 @@ void SV_SpawnServer (const char *server)
                        host_client->clientconnectcalled = true;
                        PRVM_serverglobalfloat(time) = sv.time;
                        PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
-                       PRVM_ExecuteProgram (PRVM_serverfunction(ClientConnect), "QC function ClientConnect is missing");
-                       PRVM_ExecuteProgram (PRVM_serverfunction(PutClientInServer), "QC function PutClientInServer is missing");
+                       prog->ExecuteProgram(prog, PRVM_serverfunction(ClientConnect), "QC function ClientConnect is missing");
+                       prog->ExecuteProgram(prog, PRVM_serverfunction(PutClientInServer), "QC function PutClientInServer is missing");
                        host_client->spawned = true;
                }
        }
 
        // update the map title cvar
-       strlcpy(sv.worldmessage, PRVM_GetString(PRVM_serveredictstring(prog->edicts, message)), sizeof(sv.worldmessage)); // map title (not related to filename)
+       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);
 
-       SV_VM_End();
+       if(cls.state == ca_dedicated)
+               Sys_MakeProcessMean();
+
+//     SV_UnlockThreadMutex();
 }
 
 /////////////////////////////////////////////////////
 // SV VM stuff
 
-static void SV_VM_CB_BeginIncreaseEdicts(void)
+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 SV_VM_CB_EndIncreaseEdicts(void)
+static void SVVM_end_increase_edicts(prvm_prog_t *prog)
 {
        int i;
        prvm_edict_t *ent;
@@ -3462,7 +3533,7 @@ static void SV_VM_CB_EndIncreaseEdicts(void)
                        SV_LinkEdict(ent);
 }
 
-static void SV_VM_CB_InitEdict(prvm_edict_t *e)
+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;
@@ -3477,44 +3548,44 @@ static void SV_VM_CB_InitEdict(prvm_edict_t *e)
                // 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(svs.clients[num].name);
+               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(svs.clients[num].playermodel);
-               PRVM_serveredictstring(e, playerskin) = PRVM_SetEngineString(svs.clients[num].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(svs.clients[num].netaddress);
+                       PRVM_serveredictstring(e, netaddress) = PRVM_SetEngineString(prog, svs.clients[num].netaddress);
                }
                else
-                       PRVM_serveredictstring(e, netaddress) = PRVM_SetEngineString("null/botclient");
+                       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(svs.clients[num].netconnection->crypto.client_idfp);
+                       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(svs.clients[num].netconnection->crypto.client_keyfp);
+                       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(svs.clients[num].netconnection->crypto.server_keyfp);
+                       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("AES128");
+                       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("HMAC-SHA256");
+                       PRVM_serveredictstring(e, crypto_signmethod) = PRVM_SetEngineString(prog, "HMAC-SHA256");
                else
                        PRVM_serveredictstring(e, crypto_signmethod) = 0;
        }
 }
 
-static void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
+static void SVVM_free_edict(prvm_prog_t *prog, prvm_edict_t *ed)
 {
        int i;
        int e;
@@ -3532,7 +3603,7 @@ static void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
        PRVM_serveredictfloat(ed, nextthink) = -1;
        PRVM_serveredictfloat(ed, solid) = 0;
 
-       VM_RemoveEdictSkeleton(ed);
+       VM_RemoveEdictSkeleton(prog, ed);
        World_Physics_RemoveFromEntity(&sv.world, ed);
        World_Physics_RemoveJointFromEntity(&sv.world, ed);
 
@@ -3547,7 +3618,7 @@ static void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
        }
 }
 
-static void SV_VM_CB_CountEdicts(void)
+static void SVVM_count_edicts(prvm_prog_t *prog)
 {
        int             i;
        prvm_edict_t    *ent;
@@ -3575,7 +3646,7 @@ static void SV_VM_CB_CountEdicts(void)
        Con_Printf("step      :%3i\n", step);
 }
 
-static qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
+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
@@ -3599,8 +3670,8 @@ static qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
 
 static void SV_VM_Setup(void)
 {
-       PRVM_Begin;
-       PRVM_InitProg( PRVM_SERVERPROG );
+       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]
@@ -3624,18 +3695,19 @@ static void SV_VM_Setup(void)
        prog->extensionstring = vm_sv_extensions;
        prog->loadintoworld = true;
 
-       prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
-       prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
-       prog->init_edict = SV_VM_CB_InitEdict;
-       prog->free_edict = SV_VM_CB_FreeEdict;
-       prog->count_edicts = SV_VM_CB_CountEdicts;
-       prog->load_edict = SV_VM_CB_LoadEdict;
-       prog->init_cmd = VM_SV_Cmd_Init;
-       prog->reset_cmd = VM_SV_Cmd_Reset;
-       prog->error_cmd = Host_Error;
-       prog->ExecuteProgram = SVVM_ExecuteProgram;
+       // 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_LoadProgs( sv_progs.string, SV_REQFUNCS, sv_reqfuncs, SV_REQFIELDS, sv_reqfields, SV_REQGLOBALS, sv_reqglobals);
+       PRVM_Prog_Load(prog, sv_progs.string, 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"
@@ -3776,27 +3848,176 @@ static void SV_VM_Setup(void)
 //             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", PRVM_NAME, sv_progs.string, prog->progs_crc, PROGHEADER_CRC);
+               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
 
-       PRVM_End;
-
        SV_Prepare_CSQC();
 }
 
-void SV_VM_Begin(void)
+extern cvar_t host_maxwait;
+extern cvar_t host_framerate;
+static int SV_ThreadFunc(void *voiddata)
 {
-       PRVM_Begin;
-       PRVM_SetProg( PRVM_SERVERPROG );
+       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->spawned)
+                                       if(host_client->netconnection)
+                                               playing = true;
+               if(!playing)
+               {
+                       // Nobody is looking? Then we won't do timing...
+                       // Instead, reset it to zero
+                       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)
+                               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;
+               }
 
-       PRVM_serverglobalfloat(time) = (float) sv.time;
+               // 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.generic[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_VM_End(void)
+void SV_StartThread(void)
 {
-       PRVM_End;
+       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;
 }
index d93d1f8b2b6fbc948b30515f9776fac46e1fccc8..eb577c77721975b6e27e945fb8d73434ae50a662 100644 (file)
@@ -35,6 +35,7 @@ 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;
@@ -107,6 +108,7 @@ 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;
        trace_t         trace;
@@ -249,14 +251,14 @@ facing it.
 
 ======================
 */
-void VM_changeyaw (void);
-qboolean SV_StepDirection (prvm_edict_t *ent, float yaw, float dist)
+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();
+       VM_changeyaw(prog);
 
        yaw = yaw*M_PI*2 / 360;
        move[0] = cos(yaw)*dist;
@@ -287,8 +289,9 @@ SV_FixCheckBottom
 
 ======================
 */
-void SV_FixCheckBottom (prvm_edict_t *ent)
+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;
 }
 
@@ -301,8 +304,9 @@ SV_NewChaseDir
 ================
 */
 #define        DI_NODIR        -1
-void SV_NewChaseDir (prvm_edict_t *actor, prvm_edict_t *enemy, float dist)
+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;
@@ -390,7 +394,7 @@ SV_CloseEnough
 
 ======================
 */
-qboolean SV_CloseEnough (prvm_edict_t *ent, prvm_edict_t *goal, float dist)
+static qboolean SV_CloseEnough (prvm_edict_t *ent, prvm_edict_t *goal, float dist)
 {
        int             i;
 
@@ -410,7 +414,7 @@ SV_MoveToGoal
 
 ======================
 */
-void SV_MoveToGoal (void)
+void VM_SV_MoveToGoal(prvm_prog_t *prog)
 {
        prvm_edict_t            *ent, *goal;
        float           dist;
index 0e3ac3305cc673140d82847c27920aaa9382de5c..c88ff4c452193c721fa782bb2844169c824ff836 100644 (file)
@@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // sv_phys.c
 
 #include "quakedef.h"
+#include "prvm_cmds.h"
 
 /*
 
@@ -43,7 +44,7 @@ solid_edge items only clip against bsp models.
 
 void SV_Physics_Toss (prvm_edict_t *ent);
 
-int SV_GetPitchSign(prvm_edict_t *ent)
+int SV_GetPitchSign(prvm_prog_t *prog, prvm_edict_t *ent)
 {
        dp_model_t *model;
        if (
@@ -71,6 +72,7 @@ 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);
@@ -101,6 +103,7 @@ 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;
@@ -174,7 +177,7 @@ trace_t SV_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int
        // 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 = World_EntitiesInBox(&sv.world, clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
+       numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
        if (numtouchedicts > MAX_EDICTS)
        {
                // this never happens
@@ -213,16 +216,16 @@ trace_t SV_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int
                if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
                {
                        model = SV_GetModelFromEdict(touch);
-                       pitchsign = SV_GetPitchSign(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(touch->priv.server->framegroupblend, touch);
+               VM_GenerateFrameGroupBlend(prog, touch->priv.server->framegroupblend, touch);
                VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model);
-               VM_UpdateEdictSkeleton(touch, model, touch->priv.server->frameblend);
+               VM_UpdateEdictSkeleton(prog, touch, model, touch->priv.server->frameblend);
                if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)
                        Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipstart, hitsupercontentsmask);
                else
@@ -246,6 +249,7 @@ trace_t SV_TraceLine(const vec3_t start, const vec3_t pEnd, int type, prvm_edict
 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;
@@ -340,7 +344,7 @@ trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
        // 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 = World_EntitiesInBox(&sv.world, clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
+       numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
        if (numtouchedicts > MAX_EDICTS)
        {
                // this never happens
@@ -379,16 +383,16 @@ trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
                if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
                {
                        model = SV_GetModelFromEdict(touch);
-                       pitchsign = SV_GetPitchSign(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(touch->priv.server->framegroupblend, touch);
+               VM_GenerateFrameGroupBlend(prog, touch->priv.server->framegroupblend, touch);
                VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model);
-               VM_UpdateEdictSkeleton(touch, model, touch->priv.server->frameblend);
+               VM_UpdateEdictSkeleton(prog, touch, model, touch->priv.server->frameblend);
                if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)
                        Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
                else
@@ -424,6 +428,7 @@ trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
 #endif
 #endif
 {
+       prvm_prog_t *prog = SVVM_prog;
        vec3_t hullmins, hullmaxs;
        int i, bodysupercontents;
        int passedictprog;
@@ -553,7 +558,7 @@ trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
        // 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 = World_EntitiesInBox(&sv.world, clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
+       numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
        if (numtouchedicts > MAX_EDICTS)
        {
                // this never happens
@@ -592,16 +597,16 @@ trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
                if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
                {
                        model = SV_GetModelFromEdict(touch);
-                       pitchsign = SV_GetPitchSign(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(touch->priv.server->framegroupblend, touch);
+               VM_GenerateFrameGroupBlend(prog, touch->priv.server->framegroupblend, touch);
                VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model);
-               VM_UpdateEdictSkeleton(touch, model, touch->priv.server->frameblend);
+               VM_UpdateEdictSkeleton(prog, touch, model, touch->priv.server->frameblend);
                if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)
                        Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
                else
@@ -640,6 +645,7 @@ trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
 
 int SV_PointSuperContents(const vec3_t point)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int supercontents = 0;
        int i;
        prvm_edict_t *touch;
@@ -662,7 +668,7 @@ int SV_PointSuperContents(const vec3_t point)
                return supercontents;
 
        // get list of entities at this point
-       numtouchedicts = World_EntitiesInBox(&sv.world, point, point, MAX_EDICTS, touchedicts);
+       numtouchedicts = SV_EntitiesInBox(point, point, MAX_EDICTS, touchedicts);
        if (numtouchedicts > MAX_EDICTS)
        {
                // this never happens
@@ -699,8 +705,38 @@ 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;
+       VectorSet(paddedmins, mins[0] - 10, mins[1] - 10, mins[2] - 1);
+       VectorSet(paddedmaxs, maxs[0] + 10, maxs[1] + 10, maxs[2] + 1);
+       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;
@@ -717,11 +753,12 @@ void SV_LinkEdict_TouchAreaGrid_Call(prvm_edict_t *touch, prvm_edict_t *ent)
        PRVM_serverglobalfloat(trace_dphitcontents) = 0;
        PRVM_serverglobalfloat(trace_dphitq3surfaceflags) = 0;
        PRVM_serverglobalstring(trace_dphittexturename) = 0;
-       PRVM_ExecuteProgram (PRVM_serveredictfunction(touch, touch), "QC function self.touch is missing");
+       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];
@@ -737,7 +774,7 @@ void SV_LinkEdict_TouchAreaGrid(prvm_edict_t *ent)
 
        // build a list of edicts to touch, because the link loop can be corrupted
        // by IncreaseEdicts called during touch functions
-       numtouchedicts = World_EntitiesInBox(&sv.world, ent->priv.server->areamins, ent->priv.server->areamaxs, MAX_EDICTS, touchedicts);
+       numtouchedicts = SV_EntitiesInBox(ent->priv.server->areamins, ent->priv.server->areamaxs, MAX_EDICTS, touchedicts);
        if (numtouchedicts > MAX_EDICTS)
        {
                // this never happens
@@ -798,6 +835,7 @@ SV_LinkEdict
 */
 void SV_LinkEdict (prvm_edict_t *ent)
 {
+       prvm_prog_t *prog = SVVM_prog;
        dp_model_t *model;
        vec3_t mins, maxs;
        int modelindex;
@@ -816,9 +854,9 @@ void SV_LinkEdict (prvm_edict_t *ent)
        }
        model = SV_GetModelByIndex(modelindex);
 
-       VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
+       VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
        VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
-       VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
+       VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
 
 // set the abs box
 
@@ -914,12 +952,13 @@ 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;
        trace_t trace;
        contents = SV_GenericHitSuperContentsMask(ent);
        VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
-       trace = SV_TraceBox(org, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, origin), MOVE_NOMONSTERS, ent, contents);
+       trace = SV_TraceBox(org, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, origin), ((PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), ent, contents);
        if (trace.startsupercontents & contents)
                return true;
        else
@@ -968,33 +1007,6 @@ static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
        return false;
 }
 
-/*
-================
-SV_CheckAllEnts
-================
-*/
-void SV_CheckAllEnts (void)
-{
-       int e;
-       prvm_edict_t *check;
-
-       // see if any solid entities are inside the final position
-       check = PRVM_NEXT_EDICT(prog->edicts);
-       for (e = 1;e < prog->num_edicts;e++, check = PRVM_NEXT_EDICT(check))
-       {
-               if (check->priv.server->free)
-                       continue;
-               if (PRVM_serveredictfloat(check, movetype) == MOVETYPE_PUSH
-                || PRVM_serveredictfloat(check, movetype) == MOVETYPE_NONE
-                || PRVM_serveredictfloat(check, movetype) == MOVETYPE_FOLLOW
-                || PRVM_serveredictfloat(check, movetype) == MOVETYPE_NOCLIP)
-                       continue;
-
-               if (SV_TestEntityPosition (check, vec3_origin))
-                       Con_Print("entity in invalid position\n");
-       }
-}
-
 // DRESK - Support for Entity Contents Transition Event
 /*
 ================
@@ -1003,8 +1015,9 @@ SV_CheckContentsTransition
 returns true if entity had a valid contentstransition function call
 ================
 */
-int SV_CheckContentsTransition(prvm_edict_t *ent, const int nContents)
+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
@@ -1018,14 +1031,16 @@ int SV_CheckContentsTransition(prvm_edict_t *ent, const int nContents)
                        // 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);
+                       // 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
-                       PRVM_ExecuteProgram(PRVM_serveredictfunction(ent, contentstransition), "contentstransition: NULL function");
+                       prog->ExecuteProgram(prog, PRVM_serveredictfunction(ent, contentstransition), "contentstransition: NULL function");
                }
        }
 
@@ -1041,6 +1056,7 @@ SV_CheckVelocity
 */
 void SV_CheckVelocity (prvm_edict_t *ent)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int i;
        float wishspeed;
 
@@ -1051,12 +1067,12 @@ void SV_CheckVelocity (prvm_edict_t *ent)
        {
                if (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(PRVM_serveredictstring(ent, classname)));
+                       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 (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(PRVM_serveredictstring(ent, classname)));
+                       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;
                }
        }
@@ -1088,8 +1104,9 @@ in a frame.  Not used for pushmove objects, because they must be exact.
 Returns false if the entity removed itself.
 =============
 */
-qboolean SV_RunThink (prvm_edict_t *ent)
+static qboolean SV_RunThink (prvm_edict_t *ent)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int iterations;
 
        // don't let things stay in the past.
@@ -1103,7 +1120,7 @@ qboolean SV_RunThink (prvm_edict_t *ent)
                PRVM_serveredictfloat(ent, nextthink) = 0;
                PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
                PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
-               PRVM_ExecuteProgram (PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
+               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
@@ -1121,30 +1138,30 @@ SV_Impact
 Two entities have touched, so run their touch functions
 ==================
 */
-extern void VM_SetTraceGlobals(const trace_t *trace);
-extern sizebuf_t vm_tempstringsbuf;
-void SV_Impact (prvm_edict_t *e1, trace_t *trace)
+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 = vm_tempstringsbuf.cursize;
+       restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
 
-       VM_SetTraceGlobals(trace);
+       VM_SetTraceGlobals(prog, trace);
 
-       PRVM_serverglobalfloat(time) = sv.time;
        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);
-               PRVM_ExecuteProgram (PRVM_serveredictfunction(e1, touch), "QC function self.touch is missing");
+               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));
@@ -1155,12 +1172,12 @@ void SV_Impact (prvm_edict_t *e1, trace_t *trace)
                PRVM_serverglobalfloat(trace_dphitcontents) = 0;
                PRVM_serverglobalfloat(trace_dphitq3surfaceflags) = 0;
                PRVM_serverglobalstring(trace_dphittexturename) = 0;
-               PRVM_ExecuteProgram (PRVM_serveredictfunction(e2, touch), "QC function self.touch is missing");
+               prog->ExecuteProgram(prog, PRVM_serveredictfunction(e2, touch), "QC function self.touch is missing");
        }
 
        PRVM_serverglobaledict(self) = old_self;
        PRVM_serverglobaledict(other) = old_other;
-       vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
+       prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
 }
 
 
@@ -1173,7 +1190,7 @@ returns the blocked flags (1 = floor, 2 = step / wall)
 ==================
 */
 #define STOP_EPSILON 0.1
-void ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
+static void ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
 {
        int i;
        float backoff;
@@ -1205,6 +1222,7 @@ static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, q
 #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;
@@ -1432,6 +1450,7 @@ 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);
@@ -1449,6 +1468,122 @@ 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;
+}
+
+static qboolean SV_NudgeOutOfSolid(prvm_edict_t *ent)
+{
+       prvm_prog_t *prog = SVVM_prog;
+       int bump;
+       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, origin), stuckorigin);
+       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;
+       for (bump = 0;bump < 10;bump++)
+       {
+               stucktrace = SV_TraceBox(stuckorigin, stuckmins, stuckmaxs, stuckorigin, 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
@@ -1460,12 +1595,11 @@ Returns true if the push did not result in the entity being teleported by QC cod
 */
 static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int solid;
        int movetype;
        int type;
-       int bump;
        vec3_t mins, maxs;
-       vec3_t original, original_velocity;
        vec3_t start;
        vec3_t end;
 
@@ -1477,34 +1611,7 @@ static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, q
        // move start position out of solids
        if (sv_gameplayfix_nudgeoutofsolid.integer && sv_gameplayfix_nudgeoutofsolid_separation.value >= 0)
        {
-               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, origin), stuckorigin);
-               VectorCopy(mins, stuckmins);
-               VectorCopy(maxs, stuckmaxs);
-               stuckmins[0] -= separation;
-               stuckmins[1] -= separation;
-               stuckmins[2] -= separation;
-               stuckmaxs[0] += separation;
-               stuckmaxs[1] += separation;
-               stuckmaxs[2] += separation;
-               for (bump = 0;bump < 10;bump++)
-               {
-                       stucktrace = SV_TraceBox(stuckorigin, stuckmins, stuckmaxs, stuckorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
-                       if (!stucktrace.bmodelstartsolid || stucktrace.startdepth >= 0)
-                       {
-                               // found a good location, use it
-                               VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin));
-                               break;
-                       }
-                       nudge = -stucktrace.startdepth;
-                       VectorMA(stuckorigin, nudge, stucktrace.startdepthnormal, stuckorigin);
-               }
+               SV_NudgeOutOfSolid(ent);
        }
 
        VectorCopy(PRVM_serveredictvector(ent, origin), start);
@@ -1512,6 +1619,8 @@ static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, q
 
        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
@@ -1523,8 +1632,7 @@ static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, q
 
        VectorCopy(trace->endpos, PRVM_serveredictvector(ent, origin));
 
-       VectorCopy(PRVM_serveredictvector(ent, origin), original);
-       VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
+       ent->priv.required->mark = PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN; // -2: setorigin running
 
        SV_LinkEdict(ent);
 
@@ -1542,7 +1650,21 @@ static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, q
        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);
 
-       return VectorCompare(PRVM_serveredictvector(ent, origin), original) && VectorCompare(PRVM_serveredictvector(ent, velocity), original_velocity);
+       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;
+       }
 }
 
 
@@ -1552,8 +1674,9 @@ SV_PushMove
 
 ============
 */
-void SV_PushMove (prvm_edict_t *pusher, float movetime)
+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;
@@ -1567,6 +1690,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
        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])
        {
@@ -1684,7 +1808,10 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
 // see if any solid entities are inside the final position
        num_moved = 0;
 
-       numcheckentities = World_EntitiesInBox(&sv.world, mins, maxs, MAX_EDICTS, checkentities);
+       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];
@@ -1695,7 +1822,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                case MOVETYPE_PUSH:
                case MOVETYPE_FOLLOW:
                case MOVETYPE_NOCLIP:
-               case MOVETYPE_FAKEPUSH:
+               case MOVETYPE_FLY_WORLDONLY:
                        continue;
                default:
                        break;
@@ -1728,10 +1855,14 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                        }
                }
 
+               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);
@@ -1780,72 +1911,56 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, PRVM_serveredictvector(pusher, mins), PRVM_serveredictvector(pusher, maxs), SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), checkcontents);
                if (trace.startsolid)
                {
-                       // try moving the contacted entity a tiny bit further to account for precision errors
                        vec3_t move2;
-                       PRVM_serveredictfloat(pusher, solid) = SOLID_NOT;
-                       VectorScale(move, 1.1, move2);
-                       VectorCopy (check->priv.server->moved_from, PRVM_serveredictvector(check, origin));
-                       VectorCopy (check->priv.server->moved_fromangles, PRVM_serveredictvector(check, angles));
-                       if(!SV_PushEntity (&trace2, check, move2, true, true))
-                       {
-                               // entity "check" got teleported
-                               continue;
-                       }
-                       PRVM_serveredictfloat(pusher, solid) = savesolid;
-                       Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, PRVM_serveredictvector(pusher, mins), PRVM_serveredictvector(pusher, maxs), SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), checkcontents);
-                       if (trace.startsolid)
+                       if(SV_NudgeOutOfSolid_PivotIsKnownGood(check, pivot))
                        {
-                               // try moving the contacted entity a tiny bit less to account for precision errors
-                               PRVM_serveredictfloat(pusher, solid) = SOLID_NOT;
-                               VectorScale(move, 0.9, move2);
-                               VectorCopy (check->priv.server->moved_from, PRVM_serveredictvector(check, origin));
-                               VectorCopy (check->priv.server->moved_fromangles, PRVM_serveredictvector(check, angles));
-                               if(!SV_PushEntity (&trace2, check, move2, true, true))
+                               // hack to invoke all necessary movement triggers
+                               VectorClear(move2);
+                               if(!SV_PushEntity(&trace2, check, move2, true, true))
                                {
                                        // entity "check" got teleported
                                        continue;
                                }
-                               PRVM_serveredictfloat(pusher, solid) = savesolid;
-                               Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, PRVM_serveredictvector(pusher, mins), PRVM_serveredictvector(pusher, maxs), SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), checkcontents);
-                               if (trace.startsolid)
-                               {
-                                       // 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_serverglobaledict(self) = PRVM_EDICT_TO_PROG(pusher);
-                                               PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(check);
-                                               PRVM_ExecuteProgram (PRVM_serveredictfunction(pusher, blocked), "QC function self.blocked is missing");
-                                       }
-                                       break;
-                               }
+                               // 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));
@@ -1859,8 +1974,9 @@ SV_Physics_Pusher
 
 ================
 */
-void SV_Physics_Pusher (prvm_edict_t *ent)
+static void SV_Physics_Pusher (prvm_edict_t *ent)
 {
+       prvm_prog_t *prog = SVVM_prog;
        float thinktime, oldltime, movetime;
 
        oldltime = PRVM_serveredictfloat(ent, ltime);
@@ -1885,7 +2001,7 @@ void SV_Physics_Pusher (prvm_edict_t *ent)
                PRVM_serverglobalfloat(time) = sv.time;
                PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
                PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
-               PRVM_ExecuteProgram (PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
+               prog->ExecuteProgram(prog, PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
        }
 }
 
@@ -1923,8 +2039,9 @@ typedef enum unstickresult_e
 }
 unstickresult_t;
 
-unstickresult_t SV_UnstickEntityReturnOffset (prvm_edict_t *ent, vec3_t offset)
+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
@@ -1969,17 +2086,18 @@ unstickresult_t SV_UnstickEntityReturnOffset (prvm_edict_t *ent, vec3_t offset)
 
 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(PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
+                       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(PRVM_serveredictstring(ent, classname)));
+                               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");
@@ -1995,8 +2113,9 @@ This is a big hack to try and fix the rare case of getting stuck in the world
 clipping hull.
 =============
 */
-void SV_CheckStuck (prvm_edict_t *ent)
+static void SV_CheckStuck (prvm_edict_t *ent)
 {
+       prvm_prog_t *prog = SVVM_prog;
        vec3_t offset;
 
        switch(SV_UnstickEntityReturnOffset(ent, offset))
@@ -2005,18 +2124,18 @@ void SV_CheckStuck (prvm_edict_t *ent)
                        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(PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
+                       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(PRVM_serveredictstring(ent, classname)));
+                               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(PRVM_serveredictstring(ent, classname)));
+                               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");
@@ -2029,8 +2148,9 @@ void SV_CheckStuck (prvm_edict_t *ent)
 SV_CheckWater
 =============
 */
-qboolean SV_CheckWater (prvm_edict_t *ent)
+static qboolean SV_CheckWater (prvm_edict_t *ent)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int cont;
        int nNativeContents;
        vec3_t point;
@@ -2080,8 +2200,9 @@ SV_WallFriction
 
 ============
 */
-void SV_WallFriction (prvm_edict_t *ent, float *stepnormal)
+static void SV_WallFriction (prvm_edict_t *ent, float *stepnormal)
 {
+       prvm_prog_t *prog = SVVM_prog;
        float d, i;
        vec3_t forward, into, side;
 
@@ -2166,8 +2287,9 @@ SV_WalkMove
 Only used by players
 ======================
 */
-void SV_WalkMove (prvm_edict_t *ent)
+static void SV_WalkMove (prvm_edict_t *ent)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int clip;
        int oldonground;
        //int originalmove_clip;
@@ -2184,7 +2306,8 @@ void SV_WalkMove (prvm_edict_t *ent)
        if (sv.frametime <= 0)
                return;
 
-       SV_CheckStuck (ent);
+       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);
 
@@ -2210,6 +2333,8 @@ void SV_WalkMove (prvm_edict_t *ent)
                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
@@ -2368,8 +2493,9 @@ SV_Physics_Follow
 Entities that are "stuck" to another entity
 =============
 */
-void SV_Physics_Follow (prvm_edict_t *ent)
+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;
 
@@ -2420,27 +2546,31 @@ SV_CheckWaterTransition
 
 =============
 */
-void SV_CheckWaterTransition (prvm_edict_t *ent)
+static void SV_CheckWaterTransition (prvm_edict_t *ent)
 {
+       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;
        cont = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_serveredictvector(ent, origin)));
        if (!PRVM_serveredictfloat(ent, watertype))
        {
                // just spawned here
-               PRVM_serveredictfloat(ent, watertype) = cont;
-               PRVM_serveredictfloat(ent, waterlevel) = 1;
-               return;
+               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.
-       if( !SV_CheckContentsTransition(ent, cont) )
+       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);
+                       SV_StartSound (ent, 0, sv_sound_watersplash.string, 255, 1, false, 1.0f);
        }
 
        if (cont <= CONTENTS_WATER)
@@ -2451,7 +2581,7 @@ void SV_CheckWaterTransition (prvm_edict_t *ent)
        else
        {
                PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY;
-               PRVM_serveredictfloat(ent, waterlevel) = 0;
+               PRVM_serveredictfloat(ent, waterlevel) = sv_gameplayfix_fixedcheckwatertransition.integer ? 0 : cont;
        }
 }
 
@@ -2462,13 +2592,18 @@ 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)
@@ -2514,16 +2649,17 @@ void SV_Physics_Toss (prvm_edict_t *ent)
        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, true))
+               VectorScale(PRVM_serveredictvector(ent, velocity), movetime, move);
+               if(!SV_PushEntity(&trace, ent, move, true, true))
                        return; // teleported
                if (ent->priv.server->free)
                        return;
                if (trace.bmodelstartsolid)
                {
                        // try to unstick the entity
-                       SV_UnstickEntity(ent);
-                       if(!SV_PushEntity (&trace, ent, move, false, true))
+                       if (sv_gameplayfix_unstickentities.integer)
+                               SV_UnstickEntity(ent);
+                       if(!SV_PushEntity(&trace, ent, move, false, true))
                                return; // teleported
                        if (ent->priv.server->free)
                                return;
@@ -2531,22 +2667,19 @@ void SV_Physics_Toss (prvm_edict_t *ent)
                if (trace.fraction == 1)
                        break;
                movetime *= 1 - min(1, trace.fraction);
-               if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCEMISSILE)
+               switch((int)PRVM_serveredictfloat(ent, movetype))
                {
-                       float bouncefactor;
+               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);
+                       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;
-               }
-               else if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCE)
-               {
-                       float d, ent_gravity;
-                       float bouncefactor;
-                       float bouncestop;
-
+                       if (!sv_gameplayfix_slidemoveprojectiles.integer)
+                               movetime = 0;
+                       break;
+               case MOVETYPE_BOUNCE:
                        bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
                        if (!bouncefactor)
                                bouncefactor = 0.5f;
@@ -2555,39 +2688,31 @@ void SV_Physics_Toss (prvm_edict_t *ent)
                        if (!bouncestop)
                                bouncestop = 60.0f / 800.0f;
 
-                       ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
+                       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)
                        {
-                               d = DotProduct(trace.plane.normal, PRVM_serveredictvector(ent, velocity));
-                               if (trace.plane.normal[2] > 0.7 && fabs(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));
-                               }
-                               else
-                                       PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
+                               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
                        {
-                               if (trace.plane.normal[2] > 0.7 && PRVM_serveredictvector(ent, velocity)[2] < 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));
-                               }
-                               else
-                                       PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
+                               PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
+                               if (!sv_gameplayfix_slidemoveprojectiles.integer)
+                                       movetime = 0;
                        }
-               }
-               else
-               {
+                       break;
+               default:
                        ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1.0);
                        if (trace.plane.normal[2] > 0.7)
                        {
@@ -2600,9 +2725,9 @@ void SV_Physics_Toss (prvm_edict_t *ent)
                        }
                        else
                                PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
-               }
-               if (!sv_gameplayfix_slidemoveprojectiles.integer || (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_BOUNCE && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCEMISSILE) || ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
+                       movetime = 0;
                        break;
+               }
        }
 
 // check for in water
@@ -2628,8 +2753,9 @@ 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.
 =============
 */
-void SV_Physics_Step (prvm_edict_t *ent)
+static void SV_Physics_Step (prvm_edict_t *ent)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int flags = (int)PRVM_serveredictfloat(ent, flags);
 
        // DRESK
@@ -2671,19 +2797,21 @@ void SV_Physics_Step (prvm_edict_t *ent)
                                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);
+                                       // 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
-                                       PRVM_ExecuteProgram(PRVM_serveredictfunction(ent, movetypesteplandevent), "movetypesteplandevent: NULL 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);
+                                       SV_StartSound(ent, 0, sv_sound_land.string, 255, 1, false, 1.0f);
                        }
                        ent->priv.server->waterposition_forceupdate = true;
                }
@@ -2705,6 +2833,7 @@ void SV_Physics_Step (prvm_edict_t *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
@@ -2750,6 +2879,7 @@ static void SV_Physics_Entity (prvm_edict_t *ent)
        case MOVETYPE_BOUNCEMISSILE:
        case MOVETYPE_FLYMISSILE:
        case MOVETYPE_FLY:
+       case MOVETYPE_FLY_WORLDONLY:
                // regular thinking
                if (SV_RunThink (ent))
                        SV_Physics_Toss (ent);
@@ -2769,6 +2899,7 @@ static void SV_Physics_Entity (prvm_edict_t *ent)
 
 void SV_Physics_ClientMove(void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        prvm_edict_t *ent;
        ent = host_client->edict;
 
@@ -2780,7 +2911,7 @@ void SV_Physics_ClientMove(void)
        PRVM_serverglobalfloat(time) = sv.time;
        PRVM_serverglobalfloat(frametime) = 0;
        PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
-       PRVM_ExecuteProgram (PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
+       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)
@@ -2793,7 +2924,7 @@ void SV_Physics_ClientMove(void)
        PRVM_serverglobalfloat(time) = sv.time;
        PRVM_serverglobalfloat(frametime) = 0;
        PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
-       PRVM_ExecuteProgram (PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
+       prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
        PRVM_serverglobalfloat(frametime) = sv.frametime;
 
        if(PRVM_serveredictfloat(ent, fixangle))
@@ -2810,6 +2941,7 @@ void SV_Physics_ClientMove(void)
 
 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->spawned)
                return;
@@ -2830,7 +2962,7 @@ static void SV_Physics_ClientEntity_PreThink(prvm_edict_t *ent)
        // call standard client pre-think
        PRVM_serverglobalfloat(time) = sv.time;
        PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
-       PRVM_ExecuteProgram(PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
+       prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
 
        // make sure the velocity is still sane (not a NaN)
        SV_CheckVelocity(ent);
@@ -2838,6 +2970,7 @@ static void SV_Physics_ClientEntity_PreThink(prvm_edict_t *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->spawned)
                return;
@@ -2848,7 +2981,7 @@ static void SV_Physics_ClientEntity_PostThink(prvm_edict_t *ent)
        // call standard player post-think
        PRVM_serverglobalfloat(time) = sv.time;
        PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
-       PRVM_ExecuteProgram(PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
+       prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
 
        // make sure the velocity is still sane (not a NaN)
        SV_CheckVelocity(ent);
@@ -2874,6 +3007,7 @@ static void SV_Physics_ClientEntity_PostThink(prvm_edict_t *ent)
 
 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->spawned)
        {
@@ -2922,6 +3056,7 @@ static void SV_Physics_ClientEntity(prvm_edict_t *ent)
                SV_Physics_Toss (ent);
                break;
        case MOVETYPE_FLY:
+       case MOVETYPE_FLY_WORLDONLY:
                SV_RunThink (ent);
                SV_WalkMove (ent);
                break;
@@ -2949,6 +3084,7 @@ SV_Physics
 */
 void SV_Physics (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int i;
        prvm_edict_t *ent;
 
@@ -2957,7 +3093,7 @@ void SV_Physics (void)
        PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
        PRVM_serverglobalfloat(time) = sv.time;
        PRVM_serverglobalfloat(frametime) = sv.frametime;
-       PRVM_ExecuteProgram (PRVM_serverfunction(StartFrame), "QC function StartFrame is missing");
+       prog->ExecuteProgram(prog, PRVM_serverfunction(StartFrame), "QC function StartFrame is missing");
 
        // run physics engine
        World_Physics_Frame(&sv.world, sv.frametime, sv_gravity.value);
@@ -3024,11 +3160,11 @@ void SV_Physics (void)
                PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts);
                PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
                PRVM_serverglobalfloat(time) = sv.time;
-               PRVM_ExecuteProgram (PRVM_serverfunction(EndFrame), "QC function EndFrame is missing");
+               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(PRVM_EDICT_NUM(prog->num_edicts - 1));prog->num_edicts--);
+       for (;PRVM_ED_CanAlloc(prog, PRVM_EDICT_NUM(prog->num_edicts - 1));prog->num_edicts--);
 
        if (!sv_freezenonclients.integer)
                sv.time += sv.frametime;
index 7b59de998cae788d0c60b2b9b9536c710ff650d6..ce0b8e07d1b81c7d4c6045689ba7ce16088a8978 100644 (file)
@@ -34,6 +34,7 @@ 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;
@@ -108,8 +109,9 @@ SV_UserFriction
 
 ==================
 */
-void SV_UserFriction (void)
+static void SV_UserFriction (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        float speed, newspeed, control, friction;
        vec3_t start, stop;
        trace_t trace;
@@ -148,8 +150,9 @@ void SV_UserFriction (void)
 SV_Accelerate
 ==============
 */
-void SV_Accelerate (void)
+static void SV_Accelerate (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int i;
        float addspeed, accelspeed, currentspeed;
 
@@ -166,8 +169,9 @@ void SV_Accelerate (void)
 }
 
 extern cvar_t sv_gameplayfix_q2airaccelerate;
-void SV_AirAccelerate (vec3_t wishveloc)
+static void SV_AirAccelerate (vec3_t wishveloc)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int i;
        float addspeed, wishspd, accelspeed, currentspeed;
 
@@ -187,8 +191,9 @@ void SV_AirAccelerate (vec3_t wishveloc)
 }
 
 
-void DropPunchAngle (void)
+static void DropPunchAngle (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        float len;
        vec3_t v;
 
@@ -211,36 +216,15 @@ void DropPunchAngle (void)
        VectorCopy(v, PRVM_serveredictvector(host_client->edict, punchvector));
 }
 
-/*
-===================
-SV_FreeMove
-===================
-*/
-void SV_FreeMove (void)
-{
-       int i;
-       float wishspeed;
-
-       AngleVectors (PRVM_serveredictvector(host_client->edict, v_angle), forward, right, up);
-
-       for (i = 0; i < 3; i++)
-               PRVM_serveredictvector(host_client->edict, velocity)[i] = forward[i] * cmd.forwardmove + right[i] * cmd.sidemove;
-
-       PRVM_serveredictvector(host_client->edict, velocity)[2] += cmd.upmove;
-
-       wishspeed = VectorLength(PRVM_serveredictvector(host_client->edict, velocity));
-       if (wishspeed > sv_maxspeed.value)
-               VectorScale(PRVM_serveredictvector(host_client->edict, velocity), sv_maxspeed.value / wishspeed, PRVM_serveredictvector(host_client->edict, velocity));
-}
-
 /*
 ===================
 SV_WaterMove
 
 ===================
 */
-void SV_WaterMove (void)
+static void SV_WaterMove (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int i;
        vec3_t wishvel;
        float speed, newspeed, wishspeed, addspeed, accelspeed, temp;
@@ -295,8 +279,9 @@ void SV_WaterMove (void)
                PRVM_serveredictvector(host_client->edict, velocity)[i] += accelspeed * wishvel[i];
 }
 
-void SV_WaterJump (void)
+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;
@@ -313,8 +298,9 @@ SV_AirMove
 
 ===================
 */
-void SV_AirMove (void)
+static void SV_AirMove (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int i;
        vec3_t wishvel;
        float fmove, smove, temp;
@@ -373,6 +359,7 @@ the angle fields specify an exact angular motion in degrees
 */
 void SV_ClientThink (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        vec3_t v_angle;
 
        //Con_Printf("clientthink for %ims\n", (int) (sv.frametime * 1000));
@@ -386,7 +373,7 @@ void SV_ClientThink (void)
        {
                PRVM_serverglobalfloat(time) = sv.time;
                PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
-               PRVM_ExecuteProgram (PRVM_serverfunction(SV_PlayerPhysics), "QC function SV_PlayerPhysics is missing");
+               prog->ExecuteProgram(prog, PRVM_serverfunction(SV_PlayerPhysics), "QC function SV_PlayerPhysics is missing");
                SV_CheckVelocity(host_client->edict);
                return;
        }
@@ -450,21 +437,22 @@ SV_ReadClientMove
 */
 int sv_numreadmoves = 0;
 usercmd_t sv_readmoves[CL_MAX_USERCMDS];
-void SV_ReadClientMove (void)
+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 (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+       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 ();
-       move->time = move->clienttime = MSG_ReadFloat ();
-       if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+               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
@@ -478,48 +466,48 @@ void SV_ReadClientMove (void)
        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();
+                       move->viewangles[i] = MSG_ReadAngle8i(&sv_message);
                else if (sv.protocol == PROTOCOL_DARKPLACES1)
-                       move->viewangles[i] = MSG_ReadAngle16i();
+                       move->viewangles[i] = MSG_ReadAngle16i(&sv_message);
                else if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
-                       move->viewangles[i] = MSG_ReadAngle32f();
+                       move->viewangles[i] = MSG_ReadAngle32f(&sv_message);
                else
-                       move->viewangles[i] = MSG_ReadAngle16i();
+                       move->viewangles[i] = MSG_ReadAngle16i(&sv_message);
        }
-       if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+       if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
 
        // read movement
-       move->forwardmove = MSG_ReadCoord16i ();
-       move->sidemove = MSG_ReadCoord16i ();
-       move->upmove = MSG_ReadCoord16i ();
-       if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+       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 ();
+               move->buttons = MSG_ReadByte(&sv_message);
        else
-               move->buttons = MSG_ReadLong ();
-       if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+               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 ();
-       if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+       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() * (1.0f / 32767.0f);
-               move->cursor_screen[1] = MSG_ReadShort() * (1.0f / 32767.0f);
-               move->cursor_start[0] = MSG_ReadFloat();
-               move->cursor_start[1] = MSG_ReadFloat();
-               move->cursor_start[2] = MSG_ReadFloat();
-               move->cursor_impact[0] = MSG_ReadFloat();
-               move->cursor_impact[1] = MSG_ReadFloat();
-               move->cursor_impact[2] = MSG_ReadFloat();
-               move->cursor_entitynumber = (unsigned short)MSG_ReadShort();
+               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");
@@ -529,7 +517,7 @@ void SV_ReadClientMove (void)
                // entity is free at time of receipt
                if (PRVM_EDICT_NUM(move->cursor_entitynumber)->priv.server->free)
                        move->cursor_entitynumber = 0;
-               if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+               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
@@ -576,8 +564,9 @@ void SV_ReadClientMove (void)
        }
 }
 
-void SV_ExecuteClientMoves(void)
+static void SV_ExecuteClientMoves(void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int moveindex;
        float moveframetime;
        double oldframetime;
@@ -705,6 +694,7 @@ void SV_ExecuteClientMoves(void)
 
 void SV_ApplyClientMove (void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        usercmd_t *move = &host_client->cmd;
        int j, movementloss, packetloss;
 
@@ -765,7 +755,7 @@ void SV_ApplyClientMove (void)
        PRVM_serveredictfloat(host_client->edict, ping_movementloss) = movementloss / (float) NETGRAPH_PACKETS;
 }
 
-void SV_FrameLost(int framenum)
+static void SV_FrameLost(int framenum)
 {
        if (host_client->entitydatabase5)
        {
@@ -774,7 +764,7 @@ void SV_FrameLost(int framenum)
        }
 }
 
-void SV_FrameAck(int framenum)
+static void SV_FrameAck(int framenum)
 {
        if (host_client->entitydatabase)
                EntityFrame_AckFrame(host_client->entitydatabase, framenum);
@@ -789,10 +779,9 @@ void SV_FrameAck(int framenum)
 SV_ReadClientMessage
 ===================
 */
-extern void SV_SendServerinfo(client_t *client);
-extern sizebuf_t vm_tempstringsbuf;
 void SV_ReadClientMessage(void)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int cmd, num, start;
        char *s, *p, *q;
 
@@ -811,14 +800,14 @@ void SV_ReadClientMessage(void)
                        return;
                }
 
-               if (msg_badread)
+               if (sv_message.badread)
                {
                        Con_Print("SV_ReadClientMessage: badread\n");
                        SV_DropClient (false);
                        return;
                }
 
-               cmd = MSG_ReadByte ();
+               cmd = MSG_ReadByte(&sv_message);
                if (cmd == -1)
                {
                        // end of message
@@ -830,9 +819,9 @@ void SV_ReadClientMessage(void)
                switch (cmd)
                {
                default:
-                       Con_Printf("SV_ReadClientMessage: unknown command char %i (at offset 0x%x)\n", cmd, msg_readcount);
+                       Con_Printf("SV_ReadClientMessage: unknown command char %i (at offset 0x%x)\n", cmd, sv_message.readcount);
                        if (developer_networking.integer)
-                               Com_HexDumpToConsole(net_message.data, net_message.cursize);
+                               Com_HexDumpToConsole(sv_message.data, sv_message.cursize);
                        SV_DropClient (false);
                        return;
 
@@ -843,7 +832,7 @@ void SV_ReadClientMessage(void)
                        // allow reliable messages now as the client is done with initial loading
                        if (host_client->sendsignon == 2)
                                host_client->sendsignon = 0;
-                       s = MSG_ReadString ();
+                       s = MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring));
                        q = NULL;
                        for(p = s; *p; ++p) switch(*p)
                        {
@@ -862,18 +851,19 @@ void SV_ReadClientMessage(void)
                        if (strncasecmp(s, "spawn", 5) == 0
                         || strncasecmp(s, "begin", 5) == 0
                         || strncasecmp(s, "prespawn", 8) == 0)
-                               Cmd_ExecuteString (s, src_client);
+                               Cmd_ExecuteString (s, src_client, true);
                        else if (PRVM_serverfunction(SV_ParseClientCommand))
                        {
                                int restorevm_tempstringsbuf_cursize;
-                               restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
-                               PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(s);
+                               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);
-                               PRVM_ExecuteProgram (PRVM_serverfunction(SV_ParseClientCommand), "QC function SV_ParseClientCommand is missing");
-                               vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
+                               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);
+                               Cmd_ExecuteString (s, src_client, true);
                        break;
 
 clc_stringcmd_invalid:
@@ -891,8 +881,8 @@ clc_stringcmd_invalid:
                        break;
 
                case clc_ackdownloaddata:
-                       start = MSG_ReadLong();
-                       num = MSG_ReadShort();
+                       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)
@@ -943,9 +933,9 @@ clc_stringcmd_invalid:
                        break;
 
                case clc_ackframe:
-                       if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
-                       num = MSG_ReadLong();
-                       if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+                       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,
index f252ade14b7e64a06718a40b5d324f6ca393a6ff..3bb77ef654990f94c9e224736a778fa5f9b46412 100644 (file)
@@ -21,8 +21,10 @@ const char *vm_sv_extensions =
 "DP_CON_STARTMAP "
 "DP_CRYPTO "
 "DP_CSQC_BINDMAPS "
-"DP_CSQC_ENTITYNOCULL "
+"DP_CSQC_ENTITYWORLDOBJECT "
+"DP_CSQC_ENTITYMODELLIGHT "
 "DP_CSQC_ENTITYTRANSPARENTSORTING_OFFSET "
+"DP_CSQC_MAINVIEW "
 "DP_CSQC_MULTIFRAME_INTERPOLATION "
 "DP_CSQC_BOXPARTICLES "
 "DP_CSQC_SPAWNPARTICLE "
@@ -53,7 +55,6 @@ const char *vm_sv_extensions =
 "DP_ENT_SCALE "
 "DP_ENT_TRAILEFFECTNUM "
 "DP_ENT_VIEWMODEL "
-"DP_GECKO_SUPPORT "
 "DP_GFX_EXTERNALTEXTURES "
 "DP_GFX_EXTERNALTEXTURES_PERMAP "
 "DP_GFX_FOG "
@@ -74,6 +75,7 @@ const char *vm_sv_extensions =
 "DP_LITSUPPORT "
 "DP_MONSTERWALK "
 "DP_MOVETYPEBOUNCEMISSILE "
+"DP_MOVETYPEFLYWORLDONLY "
 "DP_MOVETYPEFOLLOW "
 "DP_NULL_MODEL "
 "DP_QC_ASINACOSATANATAN2TAN "
@@ -86,6 +88,8 @@ const char *vm_sv_extensions =
 "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 "
@@ -106,6 +110,7 @@ const char *vm_sv_extensions =
 "DP_QC_GETTAGINFO_BONEPROPERTIES "
 "DP_QC_GETTIME "
 "DP_QC_GETTIME_CDTRACK "
+"DP_QC_I18N "
 "DP_QC_LOG "
 "DP_QC_MINMAXBOUND "
 "DP_QC_MULTIPLETEMPSTRINGS "
@@ -141,6 +146,7 @@ const char *vm_sv_extensions =
 "DP_SND_DIRECTIONLESSATTNNONE "
 "DP_SND_FAKETRACKS "
 "DP_SND_SOUND7_WIP1 "
+"DP_SND_SOUND7_WIP2 "
 "DP_SND_OGGVORBIS "
 "DP_SND_SETPARAMS "
 "DP_SND_STEREOWAV "
@@ -225,7 +231,7 @@ This is the only valid way to move an object without using the physics of the wo
 setorigin (entity, origin)
 =================
 */
-static void VM_SV_setorigin (void)
+static void VM_SV_setorigin(prvm_prog_t *prog)
 {
        prvm_edict_t    *e;
        float   *org;
@@ -235,27 +241,29 @@ static void VM_SV_setorigin (void)
        e = PRVM_G_EDICT(OFS_PARM0);
        if (e == prog->edicts)
        {
-               VM_Warning("setorigin: can not modify world entity\n");
+               VM_Warning(prog, "setorigin: can not modify world entity\n");
                return;
        }
        if (e->priv.server->free)
        {
-               VM_Warning("setorigin: can not modify free entity\n");
+               VM_Warning(prog, "setorigin: can not modify free entity\n");
                return;
        }
        org = PRVM_G_VECTOR(OFS_PARM1);
        VectorCopy (org, 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_edict_t *e, float *min, float *max, qboolean rotate)
+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])
-                       PRVM_ERROR("SetMinMaxSize: backwards mins/maxs");
+                       prog->error_cmd("SetMinMaxSize: backwards mins/maxs");
 
 // set derived values
        VectorCopy (min, PRVM_serveredictvector(e, mins));
@@ -275,7 +283,7 @@ LordHavoc: no it isn't...
 setsize (entity, minvector, maxvector)
 =================
 */
-static void VM_SV_setsize (void)
+static void VM_SV_setsize(prvm_prog_t *prog)
 {
        prvm_edict_t    *e;
        float   *min, *max;
@@ -285,17 +293,17 @@ static void VM_SV_setsize (void)
        e = PRVM_G_EDICT(OFS_PARM0);
        if (e == prog->edicts)
        {
-               VM_Warning("setsize: can not modify world entity\n");
+               VM_Warning(prog, "setsize: can not modify world entity\n");
                return;
        }
        if (e->priv.server->free)
        {
-               VM_Warning("setsize: can not modify free entity\n");
+               VM_Warning(prog, "setsize: can not modify free entity\n");
                return;
        }
        min = PRVM_G_VECTOR(OFS_PARM1);
        max = PRVM_G_VECTOR(OFS_PARM2);
-       SetMinMaxSize (e, min, max, false);
+       SetMinMaxSize(prog, e, min, max, false);
 }
 
 
@@ -307,7 +315,7 @@ setmodel(entity, model)
 =================
 */
 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
-static void VM_SV_setmodel (void)
+static void VM_SV_setmodel(prvm_prog_t *prog)
 {
        prvm_edict_t    *e;
        dp_model_t      *mod;
@@ -318,16 +326,16 @@ static void VM_SV_setmodel (void)
        e = PRVM_G_EDICT(OFS_PARM0);
        if (e == prog->edicts)
        {
-               VM_Warning("setmodel: can not modify world entity\n");
+               VM_Warning(prog, "setmodel: can not modify world entity\n");
                return;
        }
        if (e->priv.server->free)
        {
-               VM_Warning("setmodel: can not modify free entity\n");
+               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(sv.model_precache[i]);
+       PRVM_serveredictstring(e, model) = PRVM_SetEngineString(prog, sv.model_precache[i]);
        PRVM_serveredictfloat(e, modelindex) = i;
 
        mod = SV_GetModelByIndex(i);
@@ -335,12 +343,12 @@ static void VM_SV_setmodel (void)
        if (mod)
        {
                if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
-                       SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
+                       SetMinMaxSize(prog, e, mod->normalmins, mod->normalmaxs, true);
                else
-                       SetMinMaxSize (e, quakemins, quakemaxs, true);
+                       SetMinMaxSize(prog, e, quakemins, quakemaxs, true);
        }
        else
-               SetMinMaxSize (e, vec3_origin, vec3_origin, true);
+               SetMinMaxSize(prog, e, vec3_origin, vec3_origin, true);
 }
 
 /*
@@ -352,16 +360,16 @@ single print to a specific client
 sprint(clientent, value)
 =================
 */
-static void VM_SV_sprint (void)
+static void VM_SV_sprint(prvm_prog_t *prog)
 {
        client_t        *client;
        int                     entnum;
        char string[VM_STRINGTEMP_LENGTH];
 
-       VM_VarString(1, string, sizeof(string));
-
        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)
@@ -372,7 +380,7 @@ static void VM_SV_sprint (void)
 
        if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
        {
-               VM_Warning("tried to centerprint to a non-client\n");
+               VM_Warning(prog, "tried to centerprint to a non-client\n");
                return;
        }
 
@@ -394,7 +402,7 @@ single print to a specific client
 centerprint(clientent, value)
 =================
 */
-static void VM_SV_centerprint (void)
+static void VM_SV_centerprint(prvm_prog_t *prog)
 {
        client_t        *client;
        int                     entnum;
@@ -406,7 +414,7 @@ static void VM_SV_centerprint (void)
 
        if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
        {
-               VM_Warning("tried to centerprint to a non-client\n");
+               VM_Warning(prog, "tried to centerprint to a non-client\n");
                return;
        }
 
@@ -414,7 +422,7 @@ static void VM_SV_centerprint (void)
        if (!client->netconnection)
                return;
 
-       VM_VarString(1, string, sizeof(string));
+       VM_VarString(prog, 1, string, sizeof(string));
        MSG_WriteChar(&client->netconnection->message,svc_centerprint);
        MSG_WriteString(&client->netconnection->message, string);
 }
@@ -426,7 +434,7 @@ VM_SV_particle
 particle(origin, color, count)
 =================
 */
-static void VM_SV_particle (void)
+static void VM_SV_particle(prvm_prog_t *prog)
 {
        float           *org, *dir;
        float           color;
@@ -448,7 +456,7 @@ VM_SV_ambientsound
 
 =================
 */
-static void VM_SV_ambientsound (void)
+static void VM_SV_ambientsound(prvm_prog_t *prog)
 {
        const char      *samp;
        float           *pos;
@@ -505,7 +513,7 @@ Larger attenuations will drop off.
 
 =================
 */
-static void VM_SV_sound (void)
+static void VM_SV_sound(prvm_prog_t *prog)
 {
        const char      *sample;
        int                     channel;
@@ -531,7 +539,7 @@ static void VM_SV_sound (void)
        if (prog->argc < 6)
                pitchchange = 0;
        else
-               pitchchange = PRVM_G_FLOAT(OFS_PARM5);
+               pitchchange = PRVM_G_FLOAT(OFS_PARM5) * 0.01f;
 
        if (prog->argc < 7)
        {
@@ -547,13 +555,13 @@ static void VM_SV_sound (void)
 
        if (volume < 0 || volume > 255)
        {
-               VM_Warning("SV_StartSound: volume must be in range 0-1\n");
+               VM_Warning(prog, "SV_StartSound: volume must be in range 0-1\n");
                return;
        }
 
        if (attenuation < 0 || attenuation > 4)
        {
-               VM_Warning("SV_StartSound: attenuation must be in range 0-4\n");
+               VM_Warning(prog, "SV_StartSound: attenuation must be in range 0-4\n");
                return;
        }
 
@@ -561,11 +569,11 @@ static void VM_SV_sound (void)
 
        if (!IS_CHAN(channel))
        {
-               VM_Warning("SV_StartSound: channel must be in range 0-127\n");
+               VM_Warning(prog, "SV_StartSound: channel must be in range 0-127\n");
                return;
        }
 
-       SV_StartSound (entity, channel, sample, volume, attenuation, flags & CHANFLAG_RELIABLE);
+       SV_StartSound (entity, channel, sample, volume, attenuation, flags & CHANFLAG_RELIABLE, pitchchange);
 }
 
 /*
@@ -578,33 +586,35 @@ is omitted (since no entity is being tracked).
 
 =================
 */
-static void VM_SV_pointsound(void)
+static void VM_SV_pointsound(prvm_prog_t *prog)
 {
        const char      *sample;
        int             volume;
        float           attenuation;
+       float           pitchchange;
        vec3_t          org;
 
-       VM_SAFEPARMCOUNT(4, VM_SV_pointsound);
+       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("SV_StartPointSound: volume must be in range 0-1\n");
+               VM_Warning(prog, "SV_StartPointSound: volume must be in range 0-1\n");
                return;
        }
 
        if (attenuation < 0 || attenuation > 4)
        {
-               VM_Warning("SV_StartPointSound: attenuation must be in range 0-4\n");
+               VM_Warning(prog, "SV_StartPointSound: attenuation must be in range 0-4\n");
                return;
        }
 
-       SV_StartPointSound (org, sample, volume, attenuation);
+       SV_StartPointSound (org, sample, volume, attenuation, pitchchange);
 }
 
 /*
@@ -618,7 +628,7 @@ if the tryents flag is set.
 traceline (vector1, vector2, movetype, ignore)
 =================
 */
-static void VM_SV_traceline (void)
+static void VM_SV_traceline(prvm_prog_t *prog)
 {
        float   *v1, *v2;
        trace_t trace;
@@ -635,11 +645,11 @@ static void VM_SV_traceline (void)
        ent = PRVM_G_EDICT(OFS_PARM3);
 
        if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v2[1]) || IS_NAN(v2[2]))
-               PRVM_ERROR("%s: NAN errors detected in traceline('%f %f %f', '%f %f %f', %i, entity %i)\n", PRVM_NAME, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
+               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(&trace);
+       VM_SetTraceGlobals(prog, &trace);
 }
 
 
@@ -655,7 +665,7 @@ 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 (void)
+static void VM_SV_tracebox(prvm_prog_t *prog)
 {
        float   *v1, *v2, *m1, *m2;
        trace_t trace;
@@ -674,14 +684,14 @@ static void VM_SV_tracebox (void)
        ent = PRVM_G_EDICT(OFS_PARM5);
 
        if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v2[1]) || IS_NAN(v2[2]))
-               PRVM_ERROR("%s: NAN errors detected in tracebox('%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', %i, entity %i)\n", PRVM_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));
+               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(&trace);
+       VM_SetTraceGlobals(prog, &trace);
 }
 
-static trace_t SV_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
+static trace_t SV_Trace_Toss(prvm_prog_t *prog, prvm_edict_t *tossent, prvm_edict_t *ignore)
 {
        int i;
        float gravity;
@@ -725,7 +735,7 @@ static trace_t SV_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
        return trace;
 }
 
-static void VM_SV_tracetoss (void)
+static void VM_SV_tracetoss(prvm_prog_t *prog)
 {
        trace_t trace;
        prvm_edict_t    *ent;
@@ -738,14 +748,14 @@ static void VM_SV_tracetoss (void)
        ent = PRVM_G_EDICT(OFS_PARM0);
        if (ent == prog->edicts)
        {
-               VM_Warning("tracetoss: can not use world entity\n");
+               VM_Warning(prog, "tracetoss: can not use world entity\n");
                return;
        }
        ignore = PRVM_G_EDICT(OFS_PARM1);
 
-       trace = SV_Trace_Toss (ent, ignore);
+       trace = SV_Trace_Toss(prog, ent, ignore);
 
-       VM_SetTraceGlobals(&trace);
+       VM_SetTraceGlobals(prog, &trace);
 }
 
 //============================================================================
@@ -753,7 +763,7 @@ static void VM_SV_tracetoss (void)
 static int checkpvsbytes;
 static unsigned char checkpvs[MAX_MAP_LEAFS/8];
 
-static int VM_SV_newcheckclient (int check)
+static int VM_SV_newcheckclient(prvm_prog_t *prog, int check)
 {
        int             i;
        prvm_edict_t    *ent;
@@ -808,7 +818,7 @@ name checkclient ()
 =================
 */
 int c_invis, c_notvis;
-static void VM_SV_checkclient (void)
+static void VM_SV_checkclient(prvm_prog_t *prog)
 {
        prvm_edict_t    *ent, *self;
        vec3_t  view;
@@ -818,7 +828,7 @@ static void VM_SV_checkclient (void)
        // find a new check if on a new frame
        if (sv.time - sv.lastchecktime >= 0.1)
        {
-               sv.lastcheck = VM_SV_newcheckclient (sv.lastcheck);
+               sv.lastcheck = VM_SV_newcheckclient(prog, sv.lastcheck);
                sv.lastchecktime = sv.time;
        }
 
@@ -857,7 +867,7 @@ Should be fast but can be inexact.
 float checkpvs(vector viewpos, entity viewee) = #240;
 =================
 */
-static void VM_SV_checkpvs (void)
+static void VM_SV_checkpvs(prvm_prog_t *prog)
 {
        vec3_t viewpos;
        prvm_edict_t *viewee;
@@ -874,7 +884,7 @@ static void VM_SV_checkpvs (void)
 
        if(viewee->priv.server->free)
        {
-               VM_Warning("checkpvs: can not check free entity\n");
+               VM_Warning(prog, "checkpvs: can not check free entity\n");
                PRVM_G_FLOAT(OFS_RETURN) = 4;
                return;
        }
@@ -923,7 +933,7 @@ Sends text over to the client's execution buffer
 stuffcmd (clientent, value, ...)
 =================
 */
-static void VM_SV_stuffcmd (void)
+static void VM_SV_stuffcmd(prvm_prog_t *prog)
 {
        int             entnum;
        client_t        *old;
@@ -934,11 +944,11 @@ static void VM_SV_stuffcmd (void)
        entnum = PRVM_G_EDICTNUM(OFS_PARM0);
        if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
        {
-               VM_Warning("Can't stuffcmd to a non-client\n");
+               VM_Warning(prog, "Can't stuffcmd to a non-client\n");
                return;
        }
 
-       VM_VarString(1, string, sizeof(string));
+       VM_VarString(prog, 1, string, sizeof(string));
 
        old = host_client;
        host_client = svs.clients + entnum-1;
@@ -955,7 +965,7 @@ Returns a chain of entities that have origins within a spherical area
 findradius (origin, radius)
 =================
 */
-static void VM_SV_findradius (void)
+static void VM_SV_findradius(prvm_prog_t *prog)
 {
        prvm_edict_t *ent, *chain;
        vec_t radius, radius2;
@@ -972,7 +982,7 @@ static void VM_SV_findradius (void)
        else
                chainfield = prog->fieldoffsets.chain;
        if (chainfield < 0)
-               PRVM_ERROR("VM_findchain: %s doesnt have the specified chain field !", PRVM_NAME);
+               prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
 
        chain = (prvm_edict_t *)prog->edicts;
 
@@ -986,7 +996,7 @@ static void VM_SV_findradius (void)
        maxs[0] = org[0] + (radius + 1);
        maxs[1] = org[1] + (radius + 1);
        maxs[2] = org[2] + (radius + 1);
-       numtouchedicts = World_EntitiesInBox(&sv.world, mins, maxs, MAX_EDICTS, touchedicts);
+       numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
        if (numtouchedicts > MAX_EDICTS)
        {
                // this never happens
@@ -1023,13 +1033,13 @@ static void VM_SV_findradius (void)
        VM_RETURN_EDICT(chain);
 }
 
-static void VM_SV_precache_sound (void)
+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 (void)
+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);
@@ -1043,7 +1053,7 @@ VM_SV_walkmove
 float(float yaw, float dist[, settrace]) walkmove
 ===============
 */
-static void VM_SV_walkmove (void)
+static void VM_SV_walkmove(prvm_prog_t *prog)
 {
        prvm_edict_t    *ent;
        float   yaw, dist;
@@ -1060,12 +1070,12 @@ static void VM_SV_walkmove (void)
        ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
        if (ent == prog->edicts)
        {
-               VM_Warning("walkmove: can not modify world entity\n");
+               VM_Warning(prog, "walkmove: can not modify world entity\n");
                return;
        }
        if (ent->priv.server->free)
        {
-               VM_Warning("walkmove: can not modify free entity\n");
+               VM_Warning(prog, "walkmove: can not modify free entity\n");
                return;
        }
        yaw = PRVM_G_FLOAT(OFS_PARM0);
@@ -1100,7 +1110,8 @@ VM_SV_droptofloor
 void() droptofloor
 ===============
 */
-static void VM_SV_droptofloor (void)
+
+static void VM_SV_droptofloor(prvm_prog_t *prog)
 {
        prvm_edict_t            *ent;
        vec3_t          end;
@@ -1114,12 +1125,12 @@ static void VM_SV_droptofloor (void)
        ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
        if (ent == prog->edicts)
        {
-               VM_Warning("droptofloor: can not modify world entity\n");
+               VM_Warning(prog, "droptofloor: can not modify world entity\n");
                return;
        }
        if (ent->priv.server->free)
        {
-               VM_Warning("droptofloor: can not modify free entity\n");
+               VM_Warning(prog, "droptofloor: can not modify free entity\n");
                return;
        }
 
@@ -1127,7 +1138,8 @@ static void VM_SV_droptofloor (void)
        end[2] -= 256;
 
        if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
-               SV_UnstickEntity(ent);
+               if (sv_gameplayfix_unstickentities.integer)
+                       SV_UnstickEntity(ent);
 
        trace = SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
        if (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer)
@@ -1140,7 +1152,8 @@ static void VM_SV_droptofloor (void)
                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_UnstickEntity(ent);
+                       if (sv_gameplayfix_unstickentities.integer)
+                               SV_UnstickEntity(ent);
                        SV_LinkEdict(ent);
                        PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
                        PRVM_serveredictedict(ent, groundentity) = 0;
@@ -1150,7 +1163,8 @@ static void VM_SV_droptofloor (void)
                {
                        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));
-                       SV_UnstickEntity(ent);
+                       if (sv_gameplayfix_unstickentities.integer)
+                               SV_UnstickEntity(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);
@@ -1182,7 +1196,7 @@ VM_SV_lightstyle
 void(float style, string value) lightstyle
 ===============
 */
-static void VM_SV_lightstyle (void)
+static void VM_SV_lightstyle(prvm_prog_t *prog)
 {
        int             style;
        const char      *val;
@@ -1195,7 +1209,7 @@ static void VM_SV_lightstyle (void)
        val = PRVM_G_STRING(OFS_PARM1);
 
        if( (unsigned) style >= MAX_LIGHTSTYLES ) {
-               PRVM_ERROR( "PF_lightstyle: style: %i >= 64", style );
+               prog->error_cmd( "PF_lightstyle: style: %i >= 64", style );
        }
 
 // change the string in sv
@@ -1221,7 +1235,7 @@ static void VM_SV_lightstyle (void)
 VM_SV_checkbottom
 =============
 */
-static void VM_SV_checkbottom (void)
+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));
@@ -1232,7 +1246,7 @@ static void VM_SV_checkbottom (void)
 VM_SV_pointcontents
 =============
 */
-static void VM_SV_pointcontents (void)
+static void VM_SV_pointcontents(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_pointcontents);
        PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
@@ -1246,7 +1260,7 @@ Pick a vector for the player to shoot along
 vector aim(entity, missilespeed)
 =============
 */
-static void VM_SV_aim (void)
+static void VM_SV_aim(prvm_prog_t *prog)
 {
        prvm_edict_t    *ent, *check, *bestent;
        vec3_t  start, dir, end, bestdir;
@@ -1266,12 +1280,12 @@ static void VM_SV_aim (void)
        ent = PRVM_G_EDICT(OFS_PARM0);
        if (ent == prog->edicts)
        {
-               VM_Warning("aim: can not use world entity\n");
+               VM_Warning(prog, "aim: can not use world entity\n");
                return;
        }
        if (ent->priv.server->free)
        {
-               VM_Warning("aim: can not use free entity\n");
+               VM_Warning(prog, "aim: can not use free entity\n");
                return;
        }
        //speed = PRVM_G_FLOAT(OFS_PARM1);
@@ -1351,7 +1365,7 @@ MESSAGE WRITING
 #define        MSG_INIT                3               // write to the init string
 #define        MSG_ENTITY              5
 
-sizebuf_t *WriteDest (void)
+static sizebuf_t *WriteDest(prvm_prog_t *prog)
 {
        int             entnum;
        int             dest;
@@ -1368,14 +1382,14 @@ sizebuf_t *WriteDest (void)
                entnum = PRVM_NUM_FOR_EDICT(ent);
                if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection)
                {
-                       VM_Warning ("WriteDest: tried to write to non-client\n");
+                       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 ("WriteDest: bad destination\n");
+               VM_Warning(prog, "WriteDest: bad destination\n");
        case MSG_ALL:
                return &sv.reliable_datagram;
 
@@ -1389,59 +1403,59 @@ sizebuf_t *WriteDest (void)
        //return NULL;
 }
 
-static void VM_SV_WriteByte (void)
+static void VM_SV_WriteByte(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteByte);
-       MSG_WriteByte (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
+       MSG_WriteByte (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
 }
 
-static void VM_SV_WriteChar (void)
+static void VM_SV_WriteChar(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteChar);
-       MSG_WriteChar (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
+       MSG_WriteChar (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
 }
 
-static void VM_SV_WriteShort (void)
+static void VM_SV_WriteShort(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteShort);
-       MSG_WriteShort (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
+       MSG_WriteShort (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
 }
 
-static void VM_SV_WriteLong (void)
+static void VM_SV_WriteLong(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteLong);
-       MSG_WriteLong (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
+       MSG_WriteLong (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
 }
 
-static void VM_SV_WriteAngle (void)
+static void VM_SV_WriteAngle(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteAngle);
-       MSG_WriteAngle (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
+       MSG_WriteAngle (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
 }
 
-static void VM_SV_WriteCoord (void)
+static void VM_SV_WriteCoord(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteCoord);
-       MSG_WriteCoord (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
+       MSG_WriteCoord (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
 }
 
-static void VM_SV_WriteString (void)
+static void VM_SV_WriteString(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteString);
-       MSG_WriteString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
+       MSG_WriteString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1));
 }
 
-static void VM_SV_WriteUnterminatedString (void)
+static void VM_SV_WriteUnterminatedString(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteUnterminatedString);
-       MSG_WriteUnterminatedString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
+       MSG_WriteUnterminatedString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1));
 }
 
 
-static void VM_SV_WriteEntity (void)
+static void VM_SV_WriteEntity(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteEntity);
-       MSG_WriteShort (WriteDest(), PRVM_G_EDICTNUM(OFS_PARM1));
+       MSG_WriteShort (WriteDest(prog), PRVM_G_EDICTNUM(OFS_PARM1));
 }
 
 // writes a picture as at most size bytes of data
@@ -1450,7 +1464,7 @@ static void VM_SV_WriteEntity (void)
 // 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 (void)
+static void VM_SV_WritePicture(prvm_prog_t *prog)
 {
        const char *imgname;
        void *buf;
@@ -1463,23 +1477,23 @@ static void VM_SV_WritePicture (void)
        if(size > 65535)
                size = 65535;
 
-       MSG_WriteString(WriteDest(), imgname);
+       MSG_WriteString(WriteDest(prog), imgname);
        if(Image_Compress(imgname, size, &buf, &size))
        {
                // actual picture
-               MSG_WriteShort(WriteDest(), size);
-               SZ_Write(WriteDest(), (unsigned char *) buf, size);
+               MSG_WriteShort(WriteDest(prog), size);
+               SZ_Write(WriteDest(prog), (unsigned char *) buf, size);
        }
        else
        {
                // placeholder
-               MSG_WriteShort(WriteDest(), 0);
+               MSG_WriteShort(WriteDest(prog), 0);
        }
 }
 
 //////////////////////////////////////////////////////////
 
-static void VM_SV_makestatic (void)
+static void VM_SV_makestatic(prvm_prog_t *prog)
 {
        prvm_edict_t *ent;
        int i, large;
@@ -1494,12 +1508,12 @@ static void VM_SV_makestatic (void)
                ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
        if (ent == prog->edicts)
        {
-               VM_Warning("makestatic: can not modify world entity\n");
+               VM_Warning(prog, "makestatic: can not modify world entity\n");
                return;
        }
        if (ent->priv.server->free)
        {
-               VM_Warning("makestatic: can not modify free entity\n");
+               VM_Warning(prog, "makestatic: can not modify free entity\n");
                return;
        }
 
@@ -1535,7 +1549,7 @@ static void VM_SV_makestatic (void)
        }
 
 // throw the entity away now
-       PRVM_ED_Free (ent);
+       PRVM_ED_Free(prog, ent);
 }
 
 //=============================================================================
@@ -1545,7 +1559,7 @@ static void VM_SV_makestatic (void)
 VM_SV_setspawnparms
 ==============
 */
-static void VM_SV_setspawnparms (void)
+static void VM_SV_setspawnparms(prvm_prog_t *prog)
 {
        prvm_edict_t    *ent;
        int             i;
@@ -1579,7 +1593,7 @@ Returns a color vector indicating the lighting at the requested point.
 getlight(vector)
 =================
 */
-static void VM_SV_getlight (void)
+static void VM_SV_getlight(prvm_prog_t *prog)
 {
        vec3_t ambientcolor, diffusecolor, diffusenormal;
        vec_t *p;
@@ -1614,6 +1628,7 @@ void VM_CustomStats_Clear (void)
 
 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];
 
@@ -1656,7 +1671,7 @@ void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *ms
 //          1: string (4 stats carrying a total of 16 charactures)
 //          2: float (one stat, float converted to an integer for transportation)
 //          8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
-static void VM_SV_AddStat (void)
+static void VM_SV_AddStat(prvm_prog_t *prog)
 {
        int             off, i;
        unsigned char   type;
@@ -1668,7 +1683,7 @@ static void VM_SV_AddStat (void)
                vm_customstats = (customstat_t *)Z_Malloc((MAX_CL_STATS-32) * sizeof(customstat_t));
                if(!vm_customstats)
                {
-                       VM_Warning("PF_SV_AddStat: not enough memory\n");
+                       VM_Warning(prog, "PF_SV_AddStat: not enough memory\n");
                        return;
                }
        }
@@ -1679,17 +1694,17 @@ static void VM_SV_AddStat (void)
 
        if(i < 0)
        {
-               VM_Warning("PF_SV_AddStat: index may not be less than 32\n");
+               VM_Warning(prog, "PF_SV_AddStat: index may not be less than 32\n");
                return;
        }
        if(i >= (MAX_CL_STATS-32))
        {
-               VM_Warning("PF_SV_AddStat: index >= MAX_CL_STATS\n");
+               VM_Warning(prog, "PF_SV_AddStat: index >= MAX_CL_STATS\n");
                return;
        }
        if(i > (MAX_CL_STATS-32-4) && type == 1)
        {
-               VM_Warning("PF_SV_AddStat: index > (MAX_CL_STATS-4) with string\n");
+               VM_Warning(prog, "PF_SV_AddStat: index > (MAX_CL_STATS-4) with string\n");
                return;
        }
        vm_customstats[i].type          = type;
@@ -1707,30 +1722,30 @@ copies data from one entity to another
 copyentity(src, dst)
 =================
 */
-static void VM_SV_copyentity (void)
+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("copyentity: can not read world entity\n");
+               VM_Warning(prog, "copyentity: can not read world entity\n");
                return;
        }
        if (in->priv.server->free)
        {
-               VM_Warning("copyentity: can not read free entity\n");
+               VM_Warning(prog, "copyentity: can not read free entity\n");
                return;
        }
        out = PRVM_G_EDICT(OFS_PARM1);
        if (out == prog->edicts)
        {
-               VM_Warning("copyentity: can not modify world entity\n");
+               VM_Warning(prog, "copyentity: can not modify world entity\n");
                return;
        }
        if (out->priv.server->free)
        {
-               VM_Warning("copyentity: can not modify free entity\n");
+               VM_Warning(prog, "copyentity: can not modify free entity\n");
                return;
        }
        memcpy(out->fields.vp, in->fields.vp, prog->entityfields * 4);
@@ -1747,7 +1762,7 @@ sets the color of a client and broadcasts the update to all connected clients
 setcolor(clientent, value)
 =================
 */
-static void VM_SV_setcolor (void)
+static void VM_SV_setcolor(prvm_prog_t *prog)
 {
        client_t *client;
        int entnum, i;
@@ -1786,7 +1801,7 @@ VM_SV_effect
 effect(origin, modelname, startframe, framecount, framerate)
 =================
 */
-static void VM_SV_effect (void)
+static void VM_SV_effect(prvm_prog_t *prog)
 {
        int i;
        const char *s;
@@ -1794,33 +1809,33 @@ static void VM_SV_effect (void)
        s = PRVM_G_STRING(OFS_PARM1);
        if (!s[0])
        {
-               VM_Warning("effect: no model specified\n");
+               VM_Warning(prog, "effect: no model specified\n");
                return;
        }
 
        i = SV_ModelIndex(s, 1);
        if (!i)
        {
-               VM_Warning("effect: model not precached\n");
+               VM_Warning(prog, "effect: model not precached\n");
                return;
        }
 
        if (PRVM_G_FLOAT(OFS_PARM3) < 1)
        {
-               VM_Warning("effect: framecount < 1\n");
+               VM_Warning(prog, "effect: framecount < 1\n");
                return;
        }
 
        if (PRVM_G_FLOAT(OFS_PARM4) < 1)
        {
-               VM_Warning("effect: framerate < 1\n");
+               VM_Warning(prog, "effect: framerate < 1\n");
                return;
        }
 
        SV_StartEffect(PRVM_G_VECTOR(OFS_PARM0), 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 (void)
+static void VM_SV_te_blood(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_SV_te_blood);
        if (PRVM_G_FLOAT(OFS_PARM2) < 1)
@@ -1840,7 +1855,7 @@ static void VM_SV_te_blood (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_bloodshower (void)
+static void VM_SV_te_bloodshower(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(4, VM_SV_te_bloodshower);
        if (PRVM_G_FLOAT(OFS_PARM3) < 1)
@@ -1862,7 +1877,7 @@ static void VM_SV_te_bloodshower (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_explosionrgb (void)
+static void VM_SV_te_explosionrgb(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_te_explosionrgb);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -1878,7 +1893,7 @@ static void VM_SV_te_explosionrgb (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_particlecube (void)
+static void VM_SV_te_particlecube(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(7, VM_SV_te_particlecube);
        if (PRVM_G_FLOAT(OFS_PARM3) < 1)
@@ -1908,7 +1923,7 @@ static void VM_SV_te_particlecube (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_particlerain (void)
+static void VM_SV_te_particlerain(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(5, VM_SV_te_particlerain);
        if (PRVM_G_FLOAT(OFS_PARM3) < 1)
@@ -1934,7 +1949,7 @@ static void VM_SV_te_particlerain (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_particlesnow (void)
+static void VM_SV_te_particlesnow(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(5, VM_SV_te_particlesnow);
        if (PRVM_G_FLOAT(OFS_PARM3) < 1)
@@ -1960,7 +1975,7 @@ static void VM_SV_te_particlesnow (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_spark (void)
+static void VM_SV_te_spark(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_SV_te_spark);
        if (PRVM_G_FLOAT(OFS_PARM2) < 1)
@@ -1980,7 +1995,7 @@ static void VM_SV_te_spark (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_gunshotquad (void)
+static void VM_SV_te_gunshotquad(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_gunshotquad);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -1992,7 +2007,7 @@ static void VM_SV_te_gunshotquad (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_spikequad (void)
+static void VM_SV_te_spikequad(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_spikequad);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2004,7 +2019,7 @@ static void VM_SV_te_spikequad (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_superspikequad (void)
+static void VM_SV_te_superspikequad(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_superspikequad);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2016,7 +2031,7 @@ static void VM_SV_te_superspikequad (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_explosionquad (void)
+static void VM_SV_te_explosionquad(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_explosionquad);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2028,7 +2043,7 @@ static void VM_SV_te_explosionquad (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_smallflash (void)
+static void VM_SV_te_smallflash(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_smallflash);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2040,7 +2055,7 @@ static void VM_SV_te_smallflash (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_customflash (void)
+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))
@@ -2062,7 +2077,7 @@ static void VM_SV_te_customflash (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_gunshot (void)
+static void VM_SV_te_gunshot(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_gunshot);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2074,7 +2089,7 @@ static void VM_SV_te_gunshot (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_spike (void)
+static void VM_SV_te_spike(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_spike);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2086,7 +2101,7 @@ static void VM_SV_te_spike (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_superspike (void)
+static void VM_SV_te_superspike(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_superspike);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2098,7 +2113,7 @@ static void VM_SV_te_superspike (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_explosion (void)
+static void VM_SV_te_explosion(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_explosion);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2110,7 +2125,7 @@ static void VM_SV_te_explosion (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_tarexplosion (void)
+static void VM_SV_te_tarexplosion(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_tarexplosion);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2122,7 +2137,7 @@ static void VM_SV_te_tarexplosion (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_wizspike (void)
+static void VM_SV_te_wizspike(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_wizspike);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2134,7 +2149,7 @@ static void VM_SV_te_wizspike (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_knightspike (void)
+static void VM_SV_te_knightspike(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_knightspike);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2146,7 +2161,7 @@ static void VM_SV_te_knightspike (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_lavasplash (void)
+static void VM_SV_te_lavasplash(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_lavasplash);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2158,7 +2173,7 @@ static void VM_SV_te_lavasplash (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_teleport (void)
+static void VM_SV_te_teleport(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_teleport);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2170,7 +2185,7 @@ static void VM_SV_te_teleport (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_explosion2 (void)
+static void VM_SV_te_explosion2(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_SV_te_explosion2);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2185,7 +2200,7 @@ static void VM_SV_te_explosion2 (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_lightning1 (void)
+static void VM_SV_te_lightning1(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_SV_te_lightning1);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2203,7 +2218,7 @@ static void VM_SV_te_lightning1 (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_lightning2 (void)
+static void VM_SV_te_lightning2(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_SV_te_lightning2);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2221,7 +2236,7 @@ static void VM_SV_te_lightning2 (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_lightning3 (void)
+static void VM_SV_te_lightning3(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_SV_te_lightning3);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2239,7 +2254,7 @@ static void VM_SV_te_lightning3 (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_beam (void)
+static void VM_SV_te_beam(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_SV_te_beam);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2257,7 +2272,7 @@ static void VM_SV_te_beam (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_plasmaburn (void)
+static void VM_SV_te_plasmaburn(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2268,7 +2283,7 @@ static void VM_SV_te_plasmaburn (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_flamejet (void)
+static void VM_SV_te_flamejet(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_SV_te_flamejet);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2288,7 +2303,7 @@ static void VM_SV_te_flamejet (void)
 
 //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 (void)
+static void VM_SV_clientcommand(prvm_prog_t *prog)
 {
        client_t *temp_client;
        int i;
@@ -2304,12 +2319,12 @@ static void VM_SV_clientcommand (void)
 
        temp_client = host_client;
        host_client = svs.clients + i;
-       Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
+       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 (void)
+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);
@@ -2320,12 +2335,12 @@ static void VM_SV_setattachment (void)
 
        if (e == prog->edicts)
        {
-               VM_Warning("setattachment: can not modify world entity\n");
+               VM_Warning(prog, "setattachment: can not modify world entity\n");
                return;
        }
        if (e->priv.server->free)
        {
-               VM_Warning("setattachment: can not modify free entity\n");
+               VM_Warning(prog, "setattachment: can not modify free entity\n");
                return;
        }
 
@@ -2354,7 +2369,7 @@ static void VM_SV_setattachment (void)
 /////////////////////////////////////////
 // DP_MD3_TAGINFO extension coded by VorteX
 
-int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
+static int SV_GetTagIndex (prvm_prog_t *prog, prvm_edict_t *e, const char *tagname)
 {
        int i;
 
@@ -2365,7 +2380,7 @@ int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
        return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)PRVM_serveredictfloat(e, skin), tagname);
 }
 
-int SV_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
+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;
@@ -2387,7 +2402,7 @@ int SV_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, cons
        return 1;
 }
 
-void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
+void SV_GetEntityMatrix (prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
 {
        float scale;
        float pitchsign = 1;
@@ -2400,19 +2415,19 @@ void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatri
                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(ent);
+               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);
        }
 }
 
-int SV_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
+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(ent->priv.server->framegroupblend, ent);
+               VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
                VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
-               VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
+               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;
@@ -2429,7 +2444,7 @@ int SV_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out
 extern cvar_t cl_bob;
 extern cvar_t cl_bobcycle;
 extern cvar_t cl_bobup;
-int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
+static int SV_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
 {
        int ret;
        int modelindex, attachloop;
@@ -2449,9 +2464,9 @@ int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
 
        model = SV_GetModelByIndex(modelindex);
 
-       VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
+       VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
        VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
-       VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
+       VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
 
        tagmatrix = identitymatrix;
        // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
@@ -2462,10 +2477,10 @@ int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
                        return 5;
                // apply transformation by child's tagindex on parent entity and then
                // by parent entity itself
-               ret = SV_GetEntityLocalTagMatrix(ent, tagindex - 1, &attachmatrix);
+               ret = SV_GetEntityLocalTagMatrix(prog, ent, tagindex - 1, &attachmatrix);
                if (ret && attachloop == 0)
                        return ret;
-               SV_GetEntityMatrix(ent, &entitymatrix, false);
+               SV_GetEntityMatrix(prog, ent, &entitymatrix, false);
                Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
                Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
                // next iteration we process the parent entity
@@ -2485,7 +2500,7 @@ int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
                Matrix4x4_Copy(&tagmatrix, out);
                ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, viewmodelforclient));
 
-               SV_GetEntityMatrix(ent, &entitymatrix, true);
+               SV_GetEntityMatrix(prog, ent, &entitymatrix, true);
                Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
 
                /*
@@ -2516,7 +2531,7 @@ int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
 
 //float(entity ent, string tagname) gettagindex;
 
-static void VM_SV_gettagindex (void)
+static void VM_SV_gettagindex(prvm_prog_t *prog)
 {
        prvm_edict_t *ent;
        const char *tag_name;
@@ -2529,12 +2544,12 @@ static void VM_SV_gettagindex (void)
 
        if (ent == prog->edicts)
        {
-               VM_Warning("VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
+               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("VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
+               VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
                return;
        }
 
@@ -2543,7 +2558,7 @@ static void VM_SV_gettagindex (void)
                Con_DPrintf("VM_SV_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
        else
        {
-               tag_index = SV_GetTagIndex(ent, tag_name);
+               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);
@@ -2552,7 +2567,7 @@ static void VM_SV_gettagindex (void)
 }
 
 //vector(entity ent, float tagindex) gettaginfo;
-static void VM_SV_gettaginfo (void)
+static void VM_SV_gettaginfo(prvm_prog_t *prog)
 {
        prvm_edict_t *e;
        int tagindex;
@@ -2569,18 +2584,18 @@ static void VM_SV_gettaginfo (void)
        e = PRVM_G_EDICT(OFS_PARM0);
        tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
 
-       returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
+       returncode = SV_GetTagMatrix(prog, &tag_matrix, e, tagindex);
        Matrix4x4_ToVectors(&tag_matrix, PRVM_serverglobalvector(v_forward), le, PRVM_serverglobalvector(v_up), PRVM_G_VECTOR(OFS_RETURN));
        VectorScale(le, -1, PRVM_serverglobalvector(v_right));
        model = SV_GetModelFromEdict(e);
-       VM_GenerateFrameGroupBlend(e->priv.server->framegroupblend, e);
+       VM_GenerateFrameGroupBlend(prog, e->priv.server->framegroupblend, e);
        VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model);
-       VM_UpdateEdictSkeleton(e, model, e->priv.server->frameblend);
-       SV_GetExtendedTagInfo(e, tagindex, &parentindex, &tagname, &tag_localmatrix);
+       VM_UpdateEdictSkeleton(prog, e, model, e->priv.server->frameblend);
+       SV_GetExtendedTagInfo(prog, e, tagindex, &parentindex, &tagname, &tag_localmatrix);
        Matrix4x4_ToVectors(&tag_localmatrix, fo, le, up, trans);
 
        PRVM_serverglobalfloat(gettaginfo_parent) = parentindex;
-       PRVM_serverglobalstring(gettaginfo_name) = tagname ? PRVM_SetTempString(tagname) : 0;
+       PRVM_serverglobalstring(gettaginfo_name) = tagname ? PRVM_SetTempString(prog, tagname) : 0;
        VectorCopy(trans, PRVM_serverglobalvector(gettaginfo_offset));
        VectorCopy(fo, PRVM_serverglobalvector(gettaginfo_forward));
        VectorScale(le, -1, PRVM_serverglobalvector(gettaginfo_right));
@@ -2589,10 +2604,10 @@ static void VM_SV_gettaginfo (void)
        switch(returncode)
        {
                case 1:
-                       VM_Warning("gettagindex: can't affect world entity\n");
+                       VM_Warning(prog, "gettagindex: can't affect world entity\n");
                        break;
                case 2:
-                       VM_Warning("gettagindex: can't affect free entity\n");
+                       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));
@@ -2607,7 +2622,7 @@ static void VM_SV_gettaginfo (void)
 }
 
 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
-static void VM_SV_dropclient (void)
+static void VM_SV_dropclient(prvm_prog_t *prog)
 {
        int clientnum;
        client_t *oldhostclient;
@@ -2615,12 +2630,12 @@ static void VM_SV_dropclient (void)
        clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
        if (clientnum < 0 || clientnum >= svs.maxclients)
        {
-               VM_Warning("dropclient: not a client\n");
+               VM_Warning(prog, "dropclient: not a client\n");
                return;
        }
        if (!svs.clients[clientnum].active)
        {
-               VM_Warning("dropclient: that client slot is not connected\n");
+               VM_Warning(prog, "dropclient: that client slot is not connected\n");
                return;
        }
        oldhostclient = host_client;
@@ -2630,7 +2645,7 @@ static void VM_SV_dropclient (void)
 }
 
 //entity() spawnclient (DP_SV_BOTCLIENT)
-static void VM_SV_spawnclient (void)
+static void VM_SV_spawnclient(prvm_prog_t *prog)
 {
        int i;
        prvm_edict_t    *ed;
@@ -2654,7 +2669,7 @@ static void VM_SV_spawnclient (void)
 }
 
 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
-static void VM_SV_clienttype (void)
+static void VM_SV_clienttype(prvm_prog_t *prog)
 {
        int clientnum;
        VM_SAFEPARMCOUNT(1, VM_SV_clienttype);
@@ -2676,16 +2691,16 @@ VM_SV_serverkey
 string(string key) serverkey
 ===============
 */
-void VM_SV_serverkey(void)
+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(string);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
 }
 
 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
-static void VM_SV_setmodelindex (void)
+static void VM_SV_setmodelindex(prvm_prog_t *prog)
 {
        prvm_edict_t    *e;
        dp_model_t      *mod;
@@ -2695,27 +2710,27 @@ static void VM_SV_setmodelindex (void)
        e = PRVM_G_EDICT(OFS_PARM0);
        if (e == prog->edicts)
        {
-               VM_Warning("setmodelindex: can not modify world entity\n");
+               VM_Warning(prog, "setmodelindex: can not modify world entity\n");
                return;
        }
        if (e->priv.server->free)
        {
-               VM_Warning("setmodelindex: can not modify free entity\n");
+               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("setmodelindex: invalid modelindex\n");
+               VM_Warning(prog, "setmodelindex: invalid modelindex\n");
                return;
        }
        if (!sv.model_precache[i][0])
        {
-               VM_Warning("setmodelindex: model not precached\n");
+               VM_Warning(prog, "setmodelindex: model not precached\n");
                return;
        }
 
-       PRVM_serveredictstring(e, model) = PRVM_SetEngineString(sv.model_precache[i]);
+       PRVM_serveredictstring(e, model) = PRVM_SetEngineString(prog, sv.model_precache[i]);
        PRVM_serveredictfloat(e, modelindex) = i;
 
        mod = SV_GetModelByIndex(i);
@@ -2723,16 +2738,16 @@ static void VM_SV_setmodelindex (void)
        if (mod)
        {
                if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
-                       SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
+                       SetMinMaxSize(prog, e, mod->normalmins, mod->normalmaxs, true);
                else
-                       SetMinMaxSize (e, quakemins, quakemaxs, true);
+                       SetMinMaxSize(prog, e, quakemins, quakemaxs, true);
        }
        else
-               SetMinMaxSize (e, vec3_origin, vec3_origin, true);
+               SetMinMaxSize(prog, e, vec3_origin, vec3_origin, true);
 }
 
 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
-static void VM_SV_modelnameforindex (void)
+static void VM_SV_modelnameforindex(prvm_prog_t *prog)
 {
        int i;
        VM_SAFEPARMCOUNT(1, VM_SV_modelnameforindex);
@@ -2742,20 +2757,20 @@ static void VM_SV_modelnameforindex (void)
        i = (int)PRVM_G_FLOAT(OFS_PARM0);
        if (i <= 0 || i >= MAX_MODELS)
        {
-               VM_Warning("modelnameforindex: invalid modelindex\n");
+               VM_Warning(prog, "modelnameforindex: invalid modelindex\n");
                return;
        }
        if (!sv.model_precache[i][0])
        {
-               VM_Warning("modelnameforindex: model not precached\n");
+               VM_Warning(prog, "modelnameforindex: model not precached\n");
                return;
        }
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(sv.model_precache[i]);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(prog, sv.model_precache[i]);
 }
 
 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
-static void VM_SV_particleeffectnum (void)
+static void VM_SV_particleeffectnum(prvm_prog_t *prog)
 {
        int                     i;
        VM_SAFEPARMCOUNT(1, VM_SV_particleeffectnum);
@@ -2766,7 +2781,7 @@ static void VM_SV_particleeffectnum (void)
 }
 
 // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
-static void VM_SV_trailparticles (void)
+static void VM_SV_trailparticles(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(4, VM_SV_trailparticles);
 
@@ -2782,7 +2797,7 @@ static void VM_SV_trailparticles (void)
 }
 
 //#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
-static void VM_SV_pointparticles (void)
+static void VM_SV_pointparticles(prvm_prog_t *prog)
 {
        int effectnum, count;
        vec3_t org, vel;
@@ -2816,12 +2831,12 @@ static void VM_SV_pointparticles (void)
 }
 
 //PF_setpause,    // void(float pause) setpause        = #531;
-static void VM_SV_setpause(void) {
+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 = Sys_DoubleTime();
+               sv.pausedstart = realtime;
        } else { //disable pause, in case it was enabled
                if (sv.paused != 0) {
                        sv.paused = 0;
@@ -2834,7 +2849,7 @@ static void VM_SV_setpause(void) {
 }
 
 // #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(void)
+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);
@@ -2858,7 +2873,7 @@ static void VM_SV_skel_create(void)
 }
 
 // #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(void)
+static void VM_SV_skel_build(prvm_prog_t *prog)
 {
        int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
        skeleton_t *skeleton;
@@ -2882,7 +2897,7 @@ static void VM_SV_skel_build(void)
        firstbone = max(0, firstbone);
        lastbone = min(lastbone, model->num_bones - 1);
        lastbone = min(lastbone, skeleton->model->num_bones - 1);
-       VM_GenerateFrameGroupBlend(framegroupblend, ed);
+       VM_GenerateFrameGroupBlend(prog, framegroupblend, ed);
        VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model);
        blendfrac = 1.0f - retainfrac;
        for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
@@ -2902,7 +2917,7 @@ static void VM_SV_skel_build(void)
 }
 
 // #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(void)
+static void VM_SV_skel_get_numbones(prvm_prog_t *prog)
 {
        int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
        skeleton_t *skeleton;
@@ -2913,7 +2928,7 @@ static void VM_SV_skel_get_numbones(void)
 }
 
 // #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(void)
+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;
@@ -2923,11 +2938,11 @@ static void VM_SV_skel_get_bonename(void)
                return;
        if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
                return;
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(skeleton->model->data_bones[bonenum].name);
+       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(void)
+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;
@@ -2941,7 +2956,7 @@ static void VM_SV_skel_get_boneparent(void)
 }
 
 // #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(void)
+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);
@@ -2953,7 +2968,7 @@ static void VM_SV_skel_find_bone(void)
 }
 
 // #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(void)
+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;
@@ -2977,7 +2992,7 @@ static void VM_SV_skel_get_bonerel(void)
 }
 
 // #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(void)
+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;
@@ -3008,7 +3023,7 @@ static void VM_SV_skel_get_boneabs(void)
 }
 
 // #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(void)
+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;
@@ -3028,7 +3043,7 @@ static void VM_SV_skel_set_bone(void)
 }
 
 // #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(void)
+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;
@@ -3050,7 +3065,7 @@ static void VM_SV_skel_mul_bone(void)
 }
 
 // #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(void)
+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;
@@ -3077,7 +3092,7 @@ static void VM_SV_skel_mul_bones(void)
 }
 
 // #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(void)
+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;
@@ -3098,7 +3113,7 @@ static void VM_SV_skel_copybones(void)
 }
 
 // #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(void)
+static void VM_SV_skel_delete(prvm_prog_t *prog)
 {
        int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
        skeleton_t *skeleton;
@@ -3109,7 +3124,7 @@ static void VM_SV_skel_delete(void)
 }
 
 // #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(void)
+static void VM_SV_frameforname(prvm_prog_t *prog)
 {
        int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
        dp_model_t *model = SV_GetModelByIndex(modelindex);
@@ -3129,7 +3144,7 @@ static void VM_SV_frameforname(void)
 }
 
 // #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(void)
+static void VM_SV_frameduration(prvm_prog_t *prog)
 {
        int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
        dp_model_t *model = SV_GetModelByIndex(modelindex);
@@ -3210,7 +3225,7 @@ VM_changepitch,                                   // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) (QUA
 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)
-SV_MoveToGoal,                                 // #67 void(float step) movetogoal (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)
@@ -3778,25 +3793,35 @@ 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 VM_SV_Cmd_Init(void)
+void SVVM_init_cmd(prvm_prog_t *prog)
 {
-       VM_Cmd_Init();
+       VM_Cmd_Init(prog);
 }
 
-void VM_SV_Cmd_Reset(void)
+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
-               PRVM_ExecuteProgram(s,"SV_Shutdown() required");
+               prog->ExecuteProgram(prog, s,"SV_Shutdown() required");
        }
 
-       VM_Cmd_Reset();
+       VM_Cmd_Reset(prog);
 }
-
index 37fcc8044fb87051d91eb7cfbd3e3715f7bfe2c1..628c5d613ebff22f7ceff4ea74ac945dbca66f53 100644 (file)
@@ -72,6 +72,7 @@ void Sys_Error (const char *error, ...) DP_FUNC_PRINTF(1);
 
 /// (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);
@@ -84,7 +85,14 @@ void Sys_Quit (int returnvalue);
  */
 void Sys_AllowProfiling (qboolean enable);
 
-double Sys_DoubleTime (void);
+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);
 
@@ -102,5 +110,10 @@ 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
 
index 6175b4f5e31f8bdc7d893fc343339c74664a0fdc..13be11eae2f7a1d25f9afea2059d44d2a9d88f3c 100644 (file)
@@ -83,7 +83,7 @@ void Sys_PrintToTerminal(const char *text)
 
 char *Sys_ConsoleInput(void)
 {
-       if (cls.state == ca_dedicated)
+//     if (cls.state == ca_dedicated)
        {
                static char text[MAX_INPUTLINE];
                int len = 0;
index 298de87d385349cb93c0432d159c78952b0aced1..d033323a9d0f161be28698dea7bf3ef0d0bac411 100644 (file)
@@ -263,7 +263,7 @@ static cvar_t sys_usequeryperformancecounter = {CVAR_SAVE, "sys_usequeryperforma
 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 unsigned long benchmark_time;
+static double benchmark_time; // actually always contains an integer amount of milliseconds, will eventually "overflow"
 
 void Sys_Init_Commands (void)
 {
@@ -284,21 +284,21 @@ void Sys_Init_Commands (void)
 #endif
 }
 
-double Sys_DoubleTime(void)
+double Sys_DirtyTime(void)
 {
-       static int first = true;
-       static double oldtime = 0.0, curtime = 0.0;
-       double newtime;
+       // first all the OPTIONAL timers
+
+       // benchmark timer (fake clock)
        if(sys_usenoclockbutbenchmark.integer)
        {
+               double old_benchmark_time = benchmark_time;
                benchmark_time += 1;
-               return ((double) benchmark_time) / 1e6;
+               if(benchmark_time == old_benchmark_time)
+                       Sys_Error("sys_usenoclockbutbenchmark cannot run any longer, sorry");
+               return benchmark_time * 0.000001;
        }
-
-       // first all the OPTIONAL timers
-
 #if HAVE_QUERYPERFORMANCECOUNTER
-       else if (sys_usequeryperformancecounter.integer)
+       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
@@ -313,27 +313,29 @@ double Sys_DoubleTime(void)
                LARGE_INTEGER PerformanceFreq;
                LARGE_INTEGER PerformanceCount;
 
-               if (!QueryPerformanceFrequency (&PerformanceFreq))
+               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 timeGetTime
+                       Con_Printf("No hardware timer available\n");
+                       // fall back to other clock sources
                        Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
-                       return Sys_DoubleTime();
                }
-               QueryPerformanceCounter (&PerformanceCount);
-
-               #ifdef __BORLANDC__
-               timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
-               newtime = ((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);
-               newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
-               #endif
        }
 #endif
 
 #if HAVE_CLOCKGETTIME
-       else if (sys_useclockgettime.integer)
+       if (sys_useclockgettime.integer)
        {
                struct timespec ts;
 #  ifdef CLOCK_MONOTONIC
@@ -343,24 +345,20 @@ double Sys_DoubleTime(void)
                // sunos
                clock_gettime(CLOCK_HIGHRES, &ts);
 #  endif
-               newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
+               return (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
        }
 #endif
 
        // now all the FALLBACK timers
-       else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
-       {
-               newtime = (double) Sys_SDL_GetTicks() / 1000.0;
-       }
+       if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
+               return (double) Sys_SDL_GetTicks() / 1000.0;
 #if HAVE_GETTIMEOFDAY
-       else
        {
                struct timeval tp;
                gettimeofday(&tp, NULL);
-               newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
+               return (double) tp.tv_sec + tp.tv_usec / 1000000.0;
        }
 #elif HAVE_TIMEGETTIME
-       else
        {
                static int firsttimegettime = true;
                // timeGetTime
@@ -374,42 +372,17 @@ double Sys_DoubleTime(void)
                // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
                if (firsttimegettime)
                {
-                       timeBeginPeriod (1);
+                       timeBeginPeriod(1);
                        firsttimegettime = false;
                }
 
-               newtime = (double) timeGetTime () / 1000.0;
+               return (double) timeGetTime() / 1000.0;
        }
 #else
        // fallback for using the SDL timer if no other timer is available
-       else
-       {
-               newtime = (double) Sys_SDL_GetTicks() / 1000.0;
-               // this calls Sys_Error() if not linking against SDL
-       }
+       // this calls Sys_Error() if not linking against SDL
+       return (double) Sys_SDL_GetTicks() / 1000.0;
 #endif
-
-       if (first)
-       {
-               first = false;
-               oldtime = newtime;
-       }
-
-       if (newtime < oldtime)
-       {
-               // warn if it's significant
-               if (newtime - oldtime < -0.01)
-                       Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
-       }
-       else if (newtime > oldtime + 1800)
-       {
-               Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
-       }
-       else
-               curtime += newtime - oldtime;
-       oldtime = newtime;
-
-       return curtime;
 }
 
 void Sys_Sleep(int microseconds)
@@ -417,12 +390,18 @@ void Sys_Sleep(int microseconds)
        double t = 0;
        if(sys_usenoclockbutbenchmark.integer)
        {
-               benchmark_time += microseconds;
+               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_DoubleTime();
+               t = Sys_DirtyTime();
        }
        if(sys_supportsdlgetticks && sys_usesdldelay.integer)
        {
@@ -454,12 +433,25 @@ void Sys_Sleep(int microseconds)
 #endif
        if(sys_debugsleep.integer)
        {
-               t = Sys_DoubleTime() - t;
-               printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
+               t = Sys_DirtyTime() - t;
+               Sys_PrintfToTerminal("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
        }
 }
 
-const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
+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;
@@ -481,8 +473,9 @@ const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, cha
        }
        return name;
 }
+#endif
 
-const char *Sys_FindExecutableName(void)
+static const char *Sys_FindExecutableName(void)
 {
 #if defined(WIN32)
        return com_argv[0];
@@ -570,3 +563,70 @@ qboolean Sys_HaveSSE2(void)
        return false;
 }
 #endif
+
+/// called to set process priority for dedicated servers
+#if defined(__linux__)
+#include <sys/resource.h>
+#include <errno.h>
+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
index 590da9771ff4a52f508554000ed49828ff928dfc..5ba9be8ffa166f49a190f676edabaf3fb02164e5 100644 (file)
@@ -1,19 +1,36 @@
 #ifndef THREAD_H
 
+// enable Sys_PrintfToTerminal calls on nearly every threading call
+//#define THREADDEBUG
+// 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__))
+
 int Thread_Init(void);
 void Thread_Shutdown(void);
 qboolean Thread_HasThreads(void);
-void *Thread_CreateMutex(void);
-void Thread_DestroyMutex(void *mutex);
-int Thread_LockMutex(void *mutex);
-int Thread_UnlockMutex(void *mutex);
-void *Thread_CreateCond(void);
-void Thread_DestroyCond(void *cond);
-int Thread_CondSignal(void *cond);
-int Thread_CondBroadcast(void *cond);
-int Thread_CondWait(void *cond, void *mutex);
-void *Thread_CreateThread(int (*fn)(void *), void *data);
-int Thread_WaitThread(void *thread, int retval);
+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);
 
 #endif
 
index 5d788a49ba99ada73e63a23a7ca1279a9f16ba69..c7d439c90cf2538b5f533e13a6ab68eeb992dd69 100644 (file)
@@ -15,56 +15,55 @@ qboolean Thread_HasThreads(void)
        return false;
 }
 
-void *Thread_CreateMutex(void)
+void *_Thread_CreateMutex(const char *filename, int fileline)
 {
        return NULL;
 }
 
-void Thread_DestroyMutex(void *mutex)
+void _Thread_DestroyMutex(void *mutex, const char *filename, int fileline)
 {
 }
 
-int Thread_LockMutex(void *mutex)
+int _Thread_LockMutex(void *mutex, const char *filename, int fileline)
 {
        return -1;
 }
 
-int Thread_UnlockMutex(void *mutex)
+int _Thread_UnlockMutex(void *mutex, const char *filename, int fileline)
 {
        return -1;
 }
 
-void *Thread_CreateCond(void)
+void *_Thread_CreateCond(const char *filename, int fileline)
 {
        return NULL;
 }
 
-void Thread_DestroyCond(void *cond)
+void _Thread_DestroyCond(void *cond, const char *filename, int fileline)
 {
 }
 
-int Thread_CondSignal(void *cond)
+int _Thread_CondSignal(void *cond, const char *filename, int fileline)
 {
        return -1;
 }
 
-int Thread_CondBroadcast(void *cond)
+int _Thread_CondBroadcast(void *cond, const char *filename, int fileline)
 {
        return -1;
 }
 
-int Thread_CondWait(void *cond, void *mutex)
+int _Thread_CondWait(void *cond, void *mutex, const char *filename, int fileline)
 {
        return -1;
 }
 
-void *Thread_CreateThread(int (*fn)(void *), void *data)
+void *_Thread_CreateThread(int (*fn)(void *), void *data, const char *filename, int fileline)
 {
        return NULL;
 }
 
-int Thread_WaitThread(void *thread, int retval)
+int _Thread_WaitThread(void *thread, int retval, const char *filename, int fileline)
 {
        return retval;
 }
-       
index d394b6db08ac5f6da886016cdee3d4fb6c862050..9340403ebb91cbc39a992401004a9de8bb1e7fe6 100644 (file)
@@ -1,8 +1,12 @@
 #include "quakedef.h"
 #include "thread.h"
+#ifdef THREADRECURSIVE
+#define __USE_UNIX98
 #include <pthread.h>
+#endif
 #include <stdint.h>
 
+
 int Thread_Init(void)
 {
        return 0;
@@ -17,68 +21,106 @@ qboolean Thread_HasThreads(void)
        return true;
 }
 
-void *Thread_CreateMutex(void)
+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_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+       pthread_mutex_init(mutexp, &attr);
+#else
        pthread_mutex_init(mutexp, NULL);
+#endif
        return mutexp;
 }
 
-void Thread_DestroyMutex(void *mutex)
+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)
+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)
+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(void)
+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)
+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)
+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)
+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)
+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)
+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)
        {
@@ -88,10 +130,13 @@ void *Thread_CreateThread(int (*fn)(void *), void *data)
        return threadp;
 }
 
-int Thread_WaitThread(void *thread, int retval)
+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;
index 5272221e946206fe6955725a2a447dae51d9f274..64006dbfb6242fbc1cb05a6c90fce7ac3461552e 100644 (file)
@@ -17,59 +17,95 @@ qboolean Thread_HasThreads(void)
        return true;
 }
 
-void *Thread_CreateMutex(void)
+void *_Thread_CreateMutex(const char *filename, int fileline)
 {
-       return SDL_CreateMutex();
+       void *mutex = SDL_CreateMutex();
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p mutex create %s:%i\n" , mutex, filename, fileline);
+#endif
+       return mutex;
 }
 
-void Thread_DestroyMutex(void *mutex)
+void _Thread_DestroyMutex(void *mutex, const char *filename, int fileline)
 {
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p mutex destroy %s:%i\n", mutex, filename, fileline);
+#endif
        SDL_DestroyMutex((SDL_mutex *)mutex);
 }
 
-int Thread_LockMutex(void *mutex)
+int _Thread_LockMutex(void *mutex, const char *filename, int fileline)
 {
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p mutex lock %s:%i\n"   , mutex, filename, fileline);
+#endif
        return SDL_LockMutex((SDL_mutex *)mutex);
 }
 
-int Thread_UnlockMutex(void *mutex)
+int _Thread_UnlockMutex(void *mutex, const char *filename, int fileline)
 {
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p mutex unlock %s:%i\n" , mutex, filename, fileline);
+#endif
        return SDL_UnlockMutex((SDL_mutex *)mutex);
 }
 
-void *Thread_CreateCond(void)
+void *_Thread_CreateCond(const char *filename, int fileline)
 {
-       return SDL_CreateCond();
+       void *cond = (void *)SDL_CreateCond();
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p cond create %s:%i\n"   , cond, filename, fileline);
+#endif
+       return cond;
 }
 
-void Thread_DestroyCond(void *cond)
+void _Thread_DestroyCond(void *cond, const char *filename, int fileline)
 {
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p cond destroy %s:%i\n"   , cond, filename, fileline);
+#endif
        SDL_DestroyCond((SDL_cond *)cond);
 }
 
-int Thread_CondSignal(void *cond)
+int _Thread_CondSignal(void *cond, const char *filename, int fileline)
 {
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p cond signal %s:%i\n"   , cond, filename, fileline);
+#endif
        return SDL_CondSignal((SDL_cond *)cond);
 }
 
-int Thread_CondBroadcast(void *cond)
+int _Thread_CondBroadcast(void *cond, const char *filename, int fileline)
 {
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p cond broadcast %s:%i\n"   , cond, filename, fileline);
+#endif
        return SDL_CondBroadcast((SDL_cond *)cond);
 }
 
-int Thread_CondWait(void *cond, void *mutex)
+int _Thread_CondWait(void *cond, void *mutex, const char *filename, int fileline)
 {
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p cond wait %s:%i\n"   , cond, filename, fileline);
+#endif
        return SDL_CondWait((SDL_cond *)cond, (SDL_mutex *)mutex);
 }
 
-void *Thread_CreateThread(int (*fn)(void *), void *data)
+void *_Thread_CreateThread(int (*fn)(void *), void *data, const char *filename, int fileline)
 {
-       return SDL_CreateThread(fn, data);
+       void *thread = (void *)SDL_CreateThread(fn, data);
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p thread create %s:%i\n"   , thread, filename, fileline);
+#endif
+       return thread;
 }
 
-int Thread_WaitThread(void *thread, int retval)
+int _Thread_WaitThread(void *thread, int retval, const char *filename, int fileline)
 {
        int status = retval;
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p thread wait %s:%i\n"   , thread, filename, fileline);
+#endif
        SDL_WaitThread((SDL_Thread *)thread, &status);
        return status;
 }
index a55e6b4cdac01e7acba1ec29933e971f842b5add..893e8306048ede60d060f24efbe3e5c9b8669a23 100644 (file)
@@ -16,23 +16,36 @@ qboolean Thread_HasThreads(void)
        return true;
 }
 
-void *Thread_CreateMutex(void)
+void *_Thread_CreateMutex(const char *filename, int fileline)
 {
-       return (void *)CreateMutex(NULL, FALSE, NULL);
+       void *mutex = (void *)CreateMutex(NULL, FALSE, NULL);
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p mutex create %s:%i\n" , mutex, filename, fileline);
+#endif
+       return mutex;
 }
 
-void Thread_DestroyMutex(void *mutex)
+void _Thread_DestroyMutex(void *mutex, const char *filename, int fileline)
 {
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p mutex destroy %s:%i\n", mutex, filename, fileline);
+#endif
        CloseHandle(mutex);
 }
 
-int Thread_LockMutex(void *mutex)
+int _Thread_LockMutex(void *mutex, const char *filename, int fileline)
 {
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p mutex lock %s:%i\n"   , mutex, filename, fileline);
+#endif
        return (WaitForSingleObject(mutex, INFINITE) == WAIT_FAILED) ? -1 : 0;
 }
 
-int Thread_UnlockMutex(void *mutex)
+int _Thread_UnlockMutex(void *mutex, const char *filename, int fileline)
 {
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p mutex unlock %s:%i\n" , mutex, filename, fileline);
+#endif
        return (ReleaseMutex(mutex) == FALSE) ? -1 : 0;
 }
 
@@ -89,7 +102,7 @@ typedef struct thread_cond_s
 }
 thread_cond_t;
 
-void *Thread_CreateCond(void)
+void *_Thread_CreateCond(const char *filename, int fileline)
 {
        thread_cond_t *c = (thread_cond_t *)calloc(sizeof(*c), 1);
        c->mutex = CreateMutex(NULL, FALSE, NULL);
@@ -97,21 +110,30 @@ void *Thread_CreateCond(void)
        c->done = Thread_CreateSemaphore(0);
        c->waiting = 0;
        c->signals = 0;
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p cond create %s:%i\n"   , c, filename, fileline);
+#endif
        return c;
 }
 
-void Thread_DestroyCond(void *cond)
+void _Thread_DestroyCond(void *cond, const char *filename, int fileline)
 {
        thread_cond_t *c = (thread_cond_t *)cond;
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p cond destroy %s:%i\n"   , cond, filename, fileline);
+#endif
        Thread_DestroySemaphore(c->sem);
        Thread_DestroySemaphore(c->done);
        CloseHandle(c->mutex);
 }
 
-int Thread_CondSignal(void *cond)
+int _Thread_CondSignal(void *cond, const char *filename, int fileline)
 {
        thread_cond_t *c = (thread_cond_t *)cond;
        int n;
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p cond signal %s:%i\n"   , cond, filename, fileline);
+#endif
        WaitForSingleObject(c->mutex, INFINITE);
        n = c->waiting - c->signals;
        if (n > 0)
@@ -125,11 +147,14 @@ int Thread_CondSignal(void *cond)
        return 0;
 }
 
-int Thread_CondBroadcast(void *cond)
+int _Thread_CondBroadcast(void *cond, const char *filename, int fileline)
 {
        thread_cond_t *c = (thread_cond_t *)cond;
        int i = 0;
        int n = 0;
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p cond broadcast %s:%i\n"   , cond, filename, fileline);
+#endif
        WaitForSingleObject(c->mutex, INFINITE);
        n = c->waiting - c->signals;
        if (n > 0)
@@ -144,10 +169,13 @@ int Thread_CondBroadcast(void *cond)
        return 0;
 }
 
-int Thread_CondWait(void *cond, void *mutex)
+int _Thread_CondWait(void *cond, void *mutex, const char *filename, int fileline)
 {
        thread_cond_t *c = (thread_cond_t *)cond;
        int waitresult;
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p cond wait %s:%i\n"   , cond, filename, fileline);
+#endif
 
        WaitForSingleObject(c->mutex, INFINITE);
        c->waiting++;
@@ -189,9 +217,12 @@ unsigned int __stdcall Thread_WrapperFunc(void *d)
        return w->result;
 }
 
-void *Thread_CreateThread(int (*fn)(void *), void *data)
+void *_Thread_CreateThread(int (*fn)(void *), void *data, const char *filename, int fileline)
 {
        threadwrapper_t *w = (threadwrapper_t *)calloc(sizeof(*w), 1);
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p thread create %s:%i\n"   , w, filename, fileline);
+#endif
        w->fn = fn;
        w->data = data;
        w->threadid = 0;
@@ -200,9 +231,12 @@ void *Thread_CreateThread(int (*fn)(void *), void *data)
        return (void *)w;
 }
 
-int Thread_WaitThread(void *d, int retval)
+int _Thread_WaitThread(void *d, int retval, const char *filename, int fileline)
 {
        threadwrapper_t *w = (threadwrapper_t *)d;
+#ifdef THREADDEBUG
+       Sys_PrintfToTerminal("%p thread wait %s:%i\n"   , w, filename, fileline);
+#endif
        WaitForSingleObject(w->handle, INFINITE);
        CloseHandle(w->handle);
        retval = w->result;
index 310f4e8f1164c7437598350206636b1a6c635e5f..33da8584e95f2817b84fcdfb08e53181d8d42f9c 100644 (file)
@@ -25,15 +25,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #if defined(DO_TIMING)
 
-#define TIMING_BEGIN   double _timing_end_, _timing_start_ = Sys_DoubleTime();
+#define TIMING_BEGIN   double _timing_end_, _timing_start_ = Sys_DirtyTime();
 #define TIMING_END_STR(S)              \
-  _timing_end_ = Sys_DoubleTime();     \
+  _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_DoubleTime();                             \
+    double currentTime = Sys_DirtyTime();                              \
     Con_Printf ("%s: %.3g s\n", S, currentTime - _timing_start_);      \
   }
   
index b726e220d9768ca01d82b973aba0d5d464fecdd2..8994bd7a00a697e124779b86318919aea0d5aaf9 100644 (file)
@@ -596,15 +596,14 @@ int u8_fromchar(Uchar w, char *to, size_t maxlen)
  * @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 *u8_encodech(Uchar ch, size_t *l, char *buf16)
 {
-       static char buf[16];
        size_t len;
-       len = u8_fromchar(ch, buf, sizeof(buf));
+       len = u8_fromchar(ch, buf16, 16);
        if (len > 0)
        {
                if (l) *l = len;
-               return buf;
+               return buf16;
        }
        return NULL;
 }
index 9124c4e7905ea72ed0123aca9c20daf7a02e9f7e..36c16fe1444d967a255cbe11d87f2904929f6d8b 100644 (file)
@@ -38,11 +38,12 @@ 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  *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);
 
index 4840ae4a53451c476e45edaaa08e934e48df812d..21b8266e8dfed1f08f5881c0a6ac10cb6db5e096 100644 (file)
@@ -49,6 +49,7 @@ typedef struct viddef_support_s
        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;
@@ -63,6 +64,7 @@ typedef struct viddef_support_s
        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;
@@ -191,6 +193,8 @@ 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;
 
@@ -225,10 +229,6 @@ extern const char *gl_platformextensions;
 // name of driver library (opengl32.dll, libGL.so.1, or whatever)
 extern char gl_driver[256];
 
-// compatibility hacks
-extern qboolean isG200;
-extern qboolean isRagePro;
-
 void *GL_GetProcAddress(const char *name);
 qboolean GL_CheckExtension(const char *minglver_or_ext, const dllfunction_t *funcs, const char *disableparm, int silent);
 
@@ -274,6 +274,7 @@ 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
@@ -288,5 +289,6 @@ 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
 
index d21ffc063193ab1078fc0f3c9624fae4bf358e4f..87559d36f19a980d4cf2b7f1336af3f9959087e5 100644 (file)
@@ -312,7 +312,7 @@ int VID_GetGamma(unsigned short *ramps, int rampsize)
 
 void signal_handler(int sig)
 {
-       printf("Received signal %d, exiting...\n", sig);
+       Sys_PrintfToTerminal("Received signal %d, exiting...\n", sig);
        VID_RestoreSystemGamma();
        Sys_Quit(1);
 }
index 9f142bb9a0caf34be92da7fe97f6611d3a111146..9ac4e02fab1e54c66e3c3d22daa71d25df10fa28 100644 (file)
@@ -17,6 +17,10 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 
+#if !defined(__APPLE__) && !defined(__MACH__) && !defined(SUNOS)
+//#define USEDGA
+#endif
+
 #include <signal.h>
 
 #include <dlfcn.h>
@@ -35,7 +39,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include <X11/xpm.h>
 
 #include <X11/extensions/XShm.h>
-#if !defined(__APPLE__) && !defined(__MACH__) && !defined(SUNOS)
+#ifdef USEDGA
 #include <X11/extensions/xf86dga.h>
 #endif
 #include <X11/extensions/xf86vmode.h>
@@ -116,10 +120,12 @@ static qboolean vid_usinghidecursor = false;
 static qboolean vid_usingvsync = false;
 static qboolean vid_usevsync = false;
 static qboolean vid_x11_hardwaregammasupported = false;
+#ifdef USEDGA
 static qboolean vid_x11_dgasupported = false;
+#endif
 static int vid_x11_gammarampsize = 0;
 
-#if !defined(__APPLE__) && !defined(SUNOS)
+#ifdef USEDGA
 cvar_t vid_dgamouse = {CVAR_SAVE, "vid_dgamouse", "0", "make use of DGA mouse input"};
 static qboolean vid_usingdgamouse = false;
 #endif
@@ -141,8 +147,8 @@ static Colormap vidx11_colormap;
 /*-----------------------------------------------------------------------*/
 //
 
-long keysym2ucs(KeySym keysym);
-void DP_Xutf8LookupString(XKeyEvent * ev,
+extern long keysym2ucs(KeySym keysym); // LordHavoc: suppress warning just in this case, it's not worth having a header file for this...
+static void DP_Xutf8LookupString(XKeyEvent * ev,
                         Uchar *uch,
                         KeySym * keysym_return,
                         Status * status_return)
@@ -325,7 +331,7 @@ void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecurso
        static int originalmouseparms_threshold;
        static qboolean restore_spi;
 
-#if !defined(__APPLE__) && !defined(SUNOS)
+#ifdef USEDGA
        qboolean usedgamouse;
 #endif
 
@@ -338,7 +344,7 @@ void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecurso
        if (!mouse_avail)
                fullscreengrab = relative = hidecursor = false;
 
-#if !defined(__APPLE__) && !defined(SUNOS)
+#ifdef USEDGA
        usedgamouse = relative && vid_dgamouse.integer;
        if (!vid_x11_dgasupported)
                usedgamouse = false;
@@ -374,7 +380,7 @@ void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecurso
                        attribs_2.event_mask = attribs_1.your_event_mask | KEY_MASK | MOUSE_MASK;
                        XChangeWindowAttributes(vidx11_display, win, CWEventMask, &attribs_2);
 
-#if !defined(__APPLE__) && !defined(SUNOS)
+#ifdef USEDGA
                        vid_usingdgamouse = usedgamouse;
                        if (usedgamouse)
                        {
@@ -386,7 +392,7 @@ void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecurso
                                XWarpPointer(vidx11_display, None, win, 0, 0, 0, 0, vid.width / 2, vid.height / 2);
 
 // COMMANDLINEOPTION: X11 Input: -noforcemparms disables setting of mouse parameters (not used with DGA, windows only)
-#if !defined(__APPLE__) && !defined(SUNOS)
+#ifdef USEDGA
                        if (!COM_CheckParm ("-noforcemparms") && !usedgamouse)
 #else
                        if (!COM_CheckParm ("-noforcemparms"))
@@ -407,7 +413,7 @@ void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecurso
        {
                if (vid_usingmouse)
                {
-#if !defined(__APPLE__) && !defined(SUNOS)
+#ifdef USEDGA
                        if (vid_usingdgamouse)
                                XF86DGADirectVideo(vidx11_display, DefaultScreen(vidx11_display), 0);
                        vid_usingdgamouse = false;
@@ -599,7 +605,7 @@ static void HandleEvents(void)
                        // mouse moved
                        if (vid_usingmouse)
                        {
-#if !defined(__APPLE__) && !defined(SUNOS)
+#ifdef USEDGA
                                if (vid_usingdgamouse)
                                {
                                        in_mouse_x += event.xmotion.x_root;
@@ -871,14 +877,14 @@ void VID_Shutdown(void)
        Key_ClearStates ();
 }
 
-void signal_handler(int sig)
+static void signal_handler(int sig)
 {
        Con_Printf("Received signal %d, exiting...\n", sig);
        VID_RestoreSystemGamma();
        Sys_Quit(1);
 }
 
-void InitSig(void)
+static void InitSig(void)
 {
        signal(SIGHUP, signal_handler);
        signal(SIGINT, signal_handler);
@@ -965,7 +971,7 @@ int VID_GetGamma(unsigned short *ramps, int rampsize)
 
 void VID_Init(void)
 {
-#if !defined(__APPLE__) && !defined(SUNOS)
+#ifdef USEDGA
        Cvar_RegisterVariable (&vid_dgamouse);
 #endif
        Cvar_RegisterVariable (&vid_netwmfullscreen);
@@ -977,7 +983,7 @@ void VID_Init(void)
        vidx11_shminfo[1].shmid = -1;
 }
 
-void VID_BuildGLXAttrib(int *attrib, qboolean stencil, qboolean stereobuffer, int samples)
+static void VID_BuildGLXAttrib(int *attrib, qboolean stencil, qboolean stereobuffer, int samples)
 {
        *attrib++ = GLX_RGBA;
        *attrib++ = GLX_RED_SIZE;*attrib++ = stencil ? 8 : 5;
@@ -1003,7 +1009,7 @@ void VID_BuildGLXAttrib(int *attrib, qboolean stencil, qboolean stereobuffer, in
        *attrib++ = None;
 }
 
-qboolean VID_InitModeSoft(viddef_mode_t *mode)
+static qboolean VID_InitModeSoft(viddef_mode_t *mode)
 {
        int i, j;
        XSetWindowAttributes attr;
@@ -1017,6 +1023,7 @@ qboolean VID_InitModeSoft(viddef_mode_t *mode)
        unsigned char *data;
        XGCValues gcval;
        const char *dpyname;
+       char vabuf[1024];
 
        vid_isfullscreen = false;
        vid_isnetwmfullscreen = false;
@@ -1190,7 +1197,7 @@ qboolean VID_InitModeSoft(viddef_mode_t *mode)
                        }
                        ++i;
                        Mem_Free(data);
-                       data = loadimagepixelsbgra(va("darkplaces-icon%d", i), false, false, false, NULL);
+                       data = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "darkplaces-icon%d", i), false, false, false, NULL);
                }
                XChangeProperty(vidx11_display, win, net_wm_icon, cardinal, 32, PropModeReplace, (const unsigned char *) netwm_icon, pos);
        }
@@ -1290,7 +1297,7 @@ qboolean VID_InitModeSoft(viddef_mode_t *mode)
        vid_hidden = false;
        vid_activewindow = true;
        vid_x11_hardwaregammasupported = XF86VidModeGetGammaRampSize(vidx11_display, vidx11_screen, &vid_x11_gammarampsize) != 0;
-#if !defined(__APPLE__) && !defined(SUNOS)
+#ifdef USEDGA
        vid_x11_dgasupported = XF86DGAQueryVersion(vidx11_display, &MajorVersion, &MinorVersion);
        if (!vid_x11_dgasupported)
                Con_Print( "Failed to detect XF86DGA Mouse extension\n" );
@@ -1300,7 +1307,8 @@ qboolean VID_InitModeSoft(viddef_mode_t *mode)
 
        return true;
 }
-qboolean VID_InitModeGL(viddef_mode_t *mode)
+
+static qboolean VID_InitModeGL(viddef_mode_t *mode)
 {
        int i, j;
        int attrib[32];
@@ -1315,6 +1323,7 @@ qboolean VID_InitModeGL(viddef_mode_t *mode)
        char *xpm;
        char **idata;
        unsigned char *data;
+       char vabuf[1024];
 
        vid_isfullscreen = false;
        vid_isnetwmfullscreen = false;
@@ -1523,7 +1532,7 @@ qboolean VID_InitModeGL(viddef_mode_t *mode)
                        }
                        ++i;
                        Mem_Free(data);
-                       data = loadimagepixelsbgra(va("darkplaces-icon%d", i), false, false, false, NULL);
+                       data = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "darkplaces-icon%d", i), false, false, false, NULL);
                }
                XChangeProperty(vidx11_display, win, net_wm_icon, cardinal, 32, PropModeReplace, (const unsigned char *) netwm_icon, pos);
        }
@@ -1628,7 +1637,7 @@ qboolean VID_InitModeGL(viddef_mode_t *mode)
        vid_hidden = false;
        vid_activewindow = true;
        vid_x11_hardwaregammasupported = XF86VidModeGetGammaRampSize(vidx11_display, vidx11_screen, &vid_x11_gammarampsize) != 0;
-#if !defined(__APPLE__) && !defined(SUNOS)
+#ifdef USEDGA
        vid_x11_dgasupported = XF86DGAQueryVersion(vidx11_display, &MajorVersion, &MinorVersion);
        if (!vid_x11_dgasupported)
                Con_Print( "Failed to detect XF86DGA Mouse extension\n" );
index 4ac7ab11a9c336c573c14f8818c5ca5ae3eb1f70..166315892c591ac60ccbe5424eb5e0cd4c6da7a5 100644 (file)
@@ -29,13 +29,13 @@ void VID_Shutdown(void)
 {
 }
 
-void signal_handler(int sig)
+static void signal_handler(int sig)
 {
        Con_Printf("Received signal %d, exiting...\n", sig);
        Sys_Quit(1);
 }
 
-void InitSig(void)
+static void InitSig(void)
 {
 #ifndef WIN32
        signal(SIGHUP, signal_handler);
index d356150d6dc2e4d8cb4aafb31e327358ceeafe6d..97433653fdeb9bfc8409aa6a2f4d1e951ed3c443 100644 (file)
@@ -66,18 +66,18 @@ int cl_available = true;
 
 qboolean vid_supportrefreshrate = false;
 
-#ifdef USE_GLES2
-# define SETVIDEOMODE 0
+#if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION == 2
+# define SETVIDEOMODE 1
 #else
-# if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION == 2
-#  define SETVIDEOMODE 1
+# ifdef USE_GLES2
+#  define SETVIDEOMODE 0
 # else
 // LordHavoc: SDL 1.3's SDL_CreateWindow API is not finished enough to use yet, but you can set this to 0 if you want to try it...
-#  ifndef SETVIDEOMODE
-#   define SETVIDEOMODE 1
+#   ifndef SETVIDEOMODE
+#    define SETVIDEOMODE 1
+#   endif
 #  endif
 # endif
-#endif
 
 static qboolean vid_usingmouse = false;
 static qboolean vid_usinghidecursor = false;
@@ -380,7 +380,7 @@ SDL_bool SDL_iPhoneKeyboardIsShown(SDL_Window * window);  // returns whether or
 int SDL_iPhoneKeyboardToggle(SDL_Window * window); // toggles the visibility of the onscreen keyboard.  Returns 0 on success and -1 on error.
 #endif
 
-void VID_ShowKeyboard(qboolean show)
+static void VID_ShowKeyboard(qboolean show)
 {
 #ifdef __IPHONEOS__
        if (show)
@@ -486,7 +486,7 @@ void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecurso
 #define MAXFINGERS 11
 int multitouch[MAXFINGERS][3];
 
-qboolean VID_TouchscreenArea(int corner, float px, float py, float pwidth, float pheight, const char *icon, float *resultmove, qboolean *resultbutton, keynum_t key)
+static qboolean VID_TouchscreenArea(int corner, float px, float py, float pwidth, float pheight, const char *icon, float *resultmove, qboolean *resultbutton, keynum_t key)
 {
        int finger;
        float fx, fy, fwidth, fheight;
@@ -1073,234 +1073,245 @@ void Sys_SendKeyEvents( void )
 ////
 
 #ifdef USE_GLES2
+#ifndef qglClear
 #ifdef __IPHONEOS__
 #include <OpenGLES/ES2/gl.h>
 #else
 #include <SDL_opengles.h>
 #endif
 
-GLboolean wrapglIsBuffer(GLuint buffer) {return glIsBuffer(buffer);}
-GLboolean wrapglIsEnabled(GLenum cap) {return glIsEnabled(cap);}
-GLboolean wrapglIsFramebuffer(GLuint framebuffer) {return glIsFramebuffer(framebuffer);}
-//GLboolean wrapglIsQuery(GLuint qid) {return glIsQuery(qid);}
-GLboolean wrapglIsRenderbuffer(GLuint renderbuffer) {return glIsRenderbuffer(renderbuffer);}
-//GLboolean wrapglUnmapBuffer(GLenum target) {return glUnmapBuffer(target);}
-GLenum wrapglCheckFramebufferStatus(GLenum target) {return glCheckFramebufferStatus(target);}
-GLenum wrapglGetError(void) {return glGetError();}
-GLuint wrapglCreateProgram(void) {return glCreateProgram();}
-GLuint wrapglCreateShader(GLenum shaderType) {return glCreateShader(shaderType);}
-//GLuint wrapglGetHandle(GLenum pname) {return glGetHandle(pname);}
-GLint wrapglGetAttribLocation(GLuint programObj, const GLchar *name) {return glGetAttribLocation(programObj, name);}
-GLint wrapglGetUniformLocation(GLuint programObj, const GLchar *name) {return glGetUniformLocation(programObj, name);}
-//GLvoid* wrapglMapBuffer(GLenum target, GLenum access) {return glMapBuffer(target, access);}
-const GLubyte* wrapglGetString(GLenum name) {return glGetString(name);}
-void wrapglActiveStencilFace(GLenum e) {Con_Printf("glActiveStencilFace(e)\n");}
-void wrapglActiveTexture(GLenum e) {glActiveTexture(e);}
-void wrapglAlphaFunc(GLenum func, GLclampf ref) {Con_Printf("glAlphaFunc(func, ref)\n");}
-void wrapglArrayElement(GLint i) {Con_Printf("glArrayElement(i)\n");}
-void wrapglAttachShader(GLuint containerObj, GLuint obj) {glAttachShader(containerObj, obj);}
-//void wrapglBegin(GLenum mode) {Con_Printf("glBegin(mode)\n");}
-//void wrapglBeginQuery(GLenum target, GLuint qid) {glBeginQuery(target, qid);}
-void wrapglBindAttribLocation(GLuint programObj, GLuint index, const GLchar *name) {glBindAttribLocation(programObj, index, name);}
-void wrapglBindFragDataLocation(GLuint programObj, GLuint index, const GLchar *name) {glBindFragDataLocation(programObj, index, name);}
-void wrapglBindBuffer(GLenum target, GLuint buffer) {glBindBuffer(target, buffer);}
-void wrapglBindFramebuffer(GLenum target, GLuint framebuffer) {glBindFramebuffer(target, framebuffer);}
-void wrapglBindRenderbuffer(GLenum target, GLuint renderbuffer) {glBindRenderbuffer(target, renderbuffer);}
-void wrapglBindTexture(GLenum target, GLuint texture) {glBindTexture(target, texture);}
-void wrapglBlendEquation(GLenum e) {glBlendEquation(e);}
-void wrapglBlendFunc(GLenum sfactor, GLenum dfactor) {glBlendFunc(sfactor, dfactor);}
-void wrapglBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) {glBufferData(target, size, data, usage);}
-void wrapglBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data) {glBufferSubData(target, offset, size, data);}
-void wrapglClear(GLbitfield mask) {glClear(mask);}
-void wrapglClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {glClearColor(red, green, blue, alpha);}
-void wrapglClearDepth(GLclampd depth) {glClearDepthf((float)depth);}
-void wrapglClearStencil(GLint s) {glClearStencil(s);}
-void wrapglClientActiveTexture(GLenum target) {Con_Printf("glClientActiveTexture(target)\n");}
-void wrapglColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {Con_Printf("glColor4f(red, green, blue, alpha)\n");}
-void wrapglColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) {Con_Printf("glColor4ub(red, green, blue, alpha)\n");}
-void wrapglColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {glColorMask(red, green, blue, alpha);}
-void wrapglColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr) {Con_Printf("glColorPointer(size, type, stride, ptr)\n");}
-void wrapglCompileShader(GLuint shaderObj) {glCompileShader(shaderObj);}
-void wrapglCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border,  GLsizei imageSize, const void *data) {glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);}
-void wrapglCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data) {Con_Printf("glCompressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, data)\n");}
-void wrapglCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) {glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);}
-void wrapglCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data) {Con_Printf("glCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data)\n");}
-void wrapglCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);}
-void wrapglCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);}
-void wrapglCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) {Con_Printf("glCopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height)\n");}
-void wrapglCullFace(GLenum mode) {glCullFace(mode);}
-void wrapglDeleteBuffers(GLsizei n, const GLuint *buffers) {glDeleteBuffers(n, buffers);}
-void wrapglDeleteFramebuffers(GLsizei n, const GLuint *framebuffers) {glDeleteFramebuffers(n, framebuffers);}
-void wrapglDeleteShader(GLuint obj) {glDeleteShader(obj);}
-void wrapglDeleteProgram(GLuint obj) {glDeleteProgram(obj);}
-//void wrapglDeleteQueries(GLsizei n, const GLuint *ids) {glDeleteQueries(n, ids);}
-void wrapglDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) {glDeleteRenderbuffers(n, renderbuffers);}
-void wrapglDeleteTextures(GLsizei n, const GLuint *textures) {glDeleteTextures(n, textures);}
-void wrapglDepthFunc(GLenum func) {glDepthFunc(func);}
-void wrapglDepthMask(GLboolean flag) {glDepthMask(flag);}
-void wrapglDepthRange(GLclampd near_val, GLclampd far_val) {glDepthRangef((float)near_val, (float)far_val);}
-void wrapglDetachShader(GLuint containerObj, GLuint attachedObj) {glDetachShader(containerObj, attachedObj);}
-void wrapglDisable(GLenum cap) {glDisable(cap);}
-void wrapglDisableClientState(GLenum cap) {Con_Printf("glDisableClientState(cap)\n");}
-void wrapglDisableVertexAttribArray(GLuint index) {glDisableVertexAttribArray(index);}
-void wrapglDrawArrays(GLenum mode, GLint first, GLsizei count) {glDrawArrays(mode, first, count);}
-void wrapglDrawBuffer(GLenum mode) {Con_Printf("glDrawBuffer(mode)\n");}
-void wrapglDrawBuffers(GLsizei n, const GLenum *bufs) {Con_Printf("glDrawBuffers(n, bufs)\n");}
-void wrapglDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) {glDrawElements(mode, count, type, indices);}
-//void wrapglDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices) {glDrawRangeElements(mode, start, end, count, type, indices);}
-//void wrapglDrawRangeElementsEXT(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices) {glDrawRangeElements(mode, start, end, count, type, indices);}
-void wrapglEnable(GLenum cap) {glEnable(cap);}
-void wrapglEnableClientState(GLenum cap) {Con_Printf("glEnableClientState(cap)\n");}
-void wrapglEnableVertexAttribArray(GLuint index) {glEnableVertexAttribArray(index);}
-//void wrapglEnd(void) {Con_Printf("glEnd()\n");}
-//void wrapglEndQuery(GLenum target) {glEndQuery(target);}
-void wrapglFinish(void) {glFinish();}
-void wrapglFlush(void) {glFlush();}
-void wrapglFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);}
-void wrapglFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {glFramebufferTexture2D(target, attachment, textarget, texture, level);}
-void wrapglFramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) {Con_Printf("glFramebufferTexture3D()\n");}
-void wrapglGenBuffers(GLsizei n, GLuint *buffers) {glGenBuffers(n, buffers);}
-void wrapglGenFramebuffers(GLsizei n, GLuint *framebuffers) {glGenFramebuffers(n, framebuffers);}
-//void wrapglGenQueries(GLsizei n, GLuint *ids) {glGenQueries(n, ids);}
-void wrapglGenRenderbuffers(GLsizei n, GLuint *renderbuffers) {glGenRenderbuffers(n, renderbuffers);}
-void wrapglGenTextures(GLsizei n, GLuint *textures) {glGenTextures(n, textures);}
-void wrapglGenerateMipmap(GLenum target) {glGenerateMipmap(target);}
-void wrapglGetActiveAttrib(GLuint programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLchar *name) {glGetActiveAttrib(programObj, index, maxLength, length, size, type, name);}
-void wrapglGetActiveUniform(GLuint programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLchar *name) {glGetActiveUniform(programObj, index, maxLength, length, size, type, name);}
-void wrapglGetAttachedShaders(GLuint containerObj, GLsizei maxCount, GLsizei *count, GLuint *obj) {glGetAttachedShaders(containerObj, maxCount, count, obj);}
-void wrapglGetBooleanv(GLenum pname, GLboolean *params) {glGetBooleanv(pname, params);}
-void wrapglGetCompressedTexImage(GLenum target, GLint lod, void *img) {Con_Printf("glGetCompressedTexImage(target, lod, img)\n");}
-void wrapglGetDoublev(GLenum pname, GLdouble *params) {Con_Printf("glGetDoublev(pname, params)\n");}
-void wrapglGetFloatv(GLenum pname, GLfloat *params) {glGetFloatv(pname, params);}
-void wrapglGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint *params) {glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);}
-void wrapglGetShaderInfoLog(GLuint obj, GLsizei maxLength, GLsizei *length, GLchar *infoLog) {glGetShaderInfoLog(obj, maxLength, length, infoLog);}
-void wrapglGetProgramInfoLog(GLuint obj, GLsizei maxLength, GLsizei *length, GLchar *infoLog) {glGetProgramInfoLog(obj, maxLength, length, infoLog);}
-void wrapglGetIntegerv(GLenum pname, GLint *params) {glGetIntegerv(pname, params);}
-void wrapglGetShaderiv(GLuint obj, GLenum pname, GLint *params) {glGetShaderiv(obj, pname, params);}
-void wrapglGetProgramiv(GLuint obj, GLenum pname, GLint *params) {glGetProgramiv(obj, pname, params);}
-//void wrapglGetQueryObjectiv(GLuint qid, GLenum pname, GLint *params) {glGetQueryObjectiv(qid, pname, params);}
-//void wrapglGetQueryObjectuiv(GLuint qid, GLenum pname, GLuint *params) {glGetQueryObjectuiv(qid, pname, params);}
-//void wrapglGetQueryiv(GLenum target, GLenum pname, GLint *params) {glGetQueryiv(target, pname, params);}
-void wrapglGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params) {glGetRenderbufferParameteriv(target, pname, params);}
-void wrapglGetShaderSource(GLuint obj, GLsizei maxLength, GLsizei *length, GLchar *source) {glGetShaderSource(obj, maxLength, length, source);}
-void wrapglGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels) {Con_Printf("glGetTexImage(target, level, format, type, pixels)\n");}
-void wrapglGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params) {Con_Printf("glGetTexLevelParameterfv(target, level, pname, params)\n");}
-void wrapglGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params) {Con_Printf("glGetTexLevelParameteriv(target, level, pname, params)\n");}
-void wrapglGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params) {glGetTexParameterfv(target, pname, params);}
-void wrapglGetTexParameteriv(GLenum target, GLenum pname, GLint *params) {glGetTexParameteriv(target, pname, params);}
-void wrapglGetUniformfv(GLuint programObj, GLint location, GLfloat *params) {glGetUniformfv(programObj, location, params);}
-void wrapglGetUniformiv(GLuint programObj, GLint location, GLint *params) {glGetUniformiv(programObj, location, params);}
-void wrapglHint(GLenum target, GLenum mode) {glHint(target, mode);}
-void wrapglLineWidth(GLfloat width) {glLineWidth(width);}
-void wrapglLinkProgram(GLuint programObj) {glLinkProgram(programObj);}
-void wrapglLoadIdentity(void) {Con_Printf("glLoadIdentity()\n");}
-void wrapglLoadMatrixf(const GLfloat *m) {Con_Printf("glLoadMatrixf(m)\n");}
-void wrapglMatrixMode(GLenum mode) {Con_Printf("glMatrixMode(mode)\n");}
-void wrapglMultiTexCoord1f(GLenum target, GLfloat s) {Con_Printf("glMultiTexCoord1f(target, s)\n");}
-void wrapglMultiTexCoord2f(GLenum target, GLfloat s, GLfloat t) {Con_Printf("glMultiTexCoord2f(target, s, t)\n");}
-void wrapglMultiTexCoord3f(GLenum target, GLfloat s, GLfloat t, GLfloat r) {Con_Printf("glMultiTexCoord3f(target, s, t, r)\n");}
-void wrapglMultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) {Con_Printf("glMultiTexCoord4f(target, s, t, r, q)\n");}
-void wrapglNormalPointer(GLenum type, GLsizei stride, const GLvoid *ptr) {Con_Printf("glNormalPointer(type, stride, ptr)\n");}
-void wrapglPixelStorei(GLenum pname, GLint param) {glPixelStorei(pname, param);}
-void wrapglPointSize(GLfloat size) {Con_Printf("glPointSize(size)\n");}
-//void wrapglPolygonMode(GLenum face, GLenum mode) {Con_Printf("glPolygonMode(face, mode)\n");}
-void wrapglPolygonOffset(GLfloat factor, GLfloat units) {glPolygonOffset(factor, units);}
-void wrapglPolygonStipple(const GLubyte *mask) {Con_Printf("glPolygonStipple(mask)\n");}
-void wrapglReadBuffer(GLenum mode) {Con_Printf("glReadBuffer(mode)\n");}
-void wrapglReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) {glReadPixels(x, y, width, height, format, type, pixels);}
-void wrapglRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {glRenderbufferStorage(target, internalformat, width, height);}
-void wrapglScissor(GLint x, GLint y, GLsizei width, GLsizei height) {glScissor(x, y, width, height);}
-void wrapglShaderSource(GLuint shaderObj, GLsizei count, const GLchar **string, const GLint *length) {glShaderSource(shaderObj, count, string, length);}
-void wrapglStencilFunc(GLenum func, GLint ref, GLuint mask) {glStencilFunc(func, ref, mask);}
-void wrapglStencilFuncSeparate(GLenum func1, GLenum func2, GLint ref, GLuint mask) {Con_Printf("glStencilFuncSeparate(func1, func2, ref, mask)\n");}
-void wrapglStencilMask(GLuint mask) {glStencilMask(mask);}
-void wrapglStencilOp(GLenum fail, GLenum zfail, GLenum zpass) {glStencilOp(fail, zfail, zpass);}
-void wrapglStencilOpSeparate(GLenum e1, GLenum e2, GLenum e3, GLenum e4) {Con_Printf("glStencilOpSeparate(e1, e2, e3, e4)\n");}
-void wrapglTexCoord1f(GLfloat s) {Con_Printf("glTexCoord1f(s)\n");}
-void wrapglTexCoord2f(GLfloat s, GLfloat t) {Con_Printf("glTexCoord2f(s, t)\n");}
-void wrapglTexCoord3f(GLfloat s, GLfloat t, GLfloat r) {Con_Printf("glTexCoord3f(s, t, r)\n");}
-void wrapglTexCoord4f(GLfloat s, GLfloat t, GLfloat r, GLfloat q) {Con_Printf("glTexCoord4f(s, t, r, q)\n");}
-void wrapglTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr) {Con_Printf("glTexCoordPointer(size, type, stride, ptr)\n");}
-void wrapglTexEnvf(GLenum target, GLenum pname, GLfloat param) {Con_Printf("glTexEnvf(target, pname, param)\n");}
-void wrapglTexEnvfv(GLenum target, GLenum pname, const GLfloat *params) {Con_Printf("glTexEnvfv(target, pname, params)\n");}
-void wrapglTexEnvi(GLenum target, GLenum pname, GLint param) {Con_Printf("glTexEnvi(target, pname, param)\n");}
-void wrapglTexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) {glTexImage2D(target, level, internalFormat, width, height, border, format, type, pixels);}
-void wrapglTexImage3D(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) {Con_Printf("glTexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels)\n");}
-void wrapglTexParameterf(GLenum target, GLenum pname, GLfloat param) {glTexParameterf(target, pname, param);}
-void wrapglTexParameterfv(GLenum target, GLenum pname, GLfloat *params) {glTexParameterfv(target, pname, params);}
-void wrapglTexParameteri(GLenum target, GLenum pname, GLint param) {glTexParameteri(target, pname, param);}
-void wrapglTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) {glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);}
-void wrapglTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels) {Con_Printf("glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels)\n");}
-void wrapglUniform1f(GLint location, GLfloat v0) {glUniform1f(location, v0);}
-void wrapglUniform1fv(GLint location, GLsizei count, const GLfloat *value) {glUniform1fv(location, count, value);}
-void wrapglUniform1i(GLint location, GLint v0) {glUniform1i(location, v0);}
-void wrapglUniform1iv(GLint location, GLsizei count, const GLint *value) {glUniform1iv(location, count, value);}
-void wrapglUniform2f(GLint location, GLfloat v0, GLfloat v1) {glUniform2f(location, v0, v1);}
-void wrapglUniform2fv(GLint location, GLsizei count, const GLfloat *value) {glUniform2fv(location, count, value);}
-void wrapglUniform2i(GLint location, GLint v0, GLint v1) {glUniform2i(location, v0, v1);}
-void wrapglUniform2iv(GLint location, GLsizei count, const GLint *value) {glUniform2iv(location, count, value);}
-void wrapglUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) {glUniform3f(location, v0, v1, v2);}
-void wrapglUniform3fv(GLint location, GLsizei count, const GLfloat *value) {glUniform3fv(location, count, value);}
-void wrapglUniform3i(GLint location, GLint v0, GLint v1, GLint v2) {glUniform3i(location, v0, v1, v2);}
-void wrapglUniform3iv(GLint location, GLsizei count, const GLint *value) {glUniform3iv(location, count, value);}
-void wrapglUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {glUniform4f(location, v0, v1, v2, v3);}
-void wrapglUniform4fv(GLint location, GLsizei count, const GLfloat *value) {glUniform4fv(location, count, value);}
-void wrapglUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) {glUniform4i(location, v0, v1, v2, v3);}
-void wrapglUniform4iv(GLint location, GLsizei count, const GLint *value) {glUniform4iv(location, count, value);}
-void wrapglUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {glUniformMatrix2fv(location, count, transpose, value);}
-void wrapglUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {glUniformMatrix3fv(location, count, transpose, value);}
-void wrapglUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {glUniformMatrix4fv(location, count, transpose, value);}
-void wrapglUseProgram(GLuint programObj) {glUseProgram(programObj);}
-void wrapglValidateProgram(GLuint programObj) {glValidateProgram(programObj);}
-void wrapglVertex2f(GLfloat x, GLfloat y) {Con_Printf("glVertex2f(x, y)\n");}
-void wrapglVertex3f(GLfloat x, GLfloat y, GLfloat z) {Con_Printf("glVertex3f(x, y, z)\n");}
-void wrapglVertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w) {Con_Printf("glVertex4f(x, y, z, w)\n");}
-void wrapglVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) {glVertexAttribPointer(index, size, type, normalized, stride, pointer);}
-void wrapglVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr) {Con_Printf("glVertexPointer(size, type, stride, ptr)\n");}
-void wrapglViewport(GLint x, GLint y, GLsizei width, GLsizei height) {glViewport(x, y, width, height);}
-void wrapglVertexAttrib1f(GLuint index, GLfloat v0) {glVertexAttrib1f(index, v0);}
-//void wrapglVertexAttrib1s(GLuint index, GLshort v0) {glVertexAttrib1s(index, v0);}
-//void wrapglVertexAttrib1d(GLuint index, GLdouble v0) {glVertexAttrib1d(index, v0);}
-void wrapglVertexAttrib2f(GLuint index, GLfloat v0, GLfloat v1) {glVertexAttrib2f(index, v0, v1);}
-//void wrapglVertexAttrib2s(GLuint index, GLshort v0, GLshort v1) {glVertexAttrib2s(index, v0, v1);}
-//void wrapglVertexAttrib2d(GLuint index, GLdouble v0, GLdouble v1) {glVertexAttrib2d(index, v0, v1);}
-void wrapglVertexAttrib3f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2) {glVertexAttrib3f(index, v0, v1, v2);}
-//void wrapglVertexAttrib3s(GLuint index, GLshort v0, GLshort v1, GLshort v2) {glVertexAttrib3s(index, v0, v1, v2);}
-//void wrapglVertexAttrib3d(GLuint index, GLdouble v0, GLdouble v1, GLdouble v2) {glVertexAttrib3d(index, v0, v1, v2);}
-void wrapglVertexAttrib4f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {glVertexAttrib4f(index, v0, v1, v2, v3);}
-//void wrapglVertexAttrib4s(GLuint index, GLshort v0, GLshort v1, GLshort v2, GLshort v3) {glVertexAttrib4s(index, v0, v1, v2, v3);}
-//void wrapglVertexAttrib4d(GLuint index, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3) {glVertexAttrib4d(index, v0, v1, v2, v3);}
-//void wrapglVertexAttrib4Nub(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w) {glVertexAttrib4Nub(index, x, y, z, w);}
-void wrapglVertexAttrib1fv(GLuint index, const GLfloat *v) {glVertexAttrib1fv(index, v);}
-//void wrapglVertexAttrib1sv(GLuint index, const GLshort *v) {glVertexAttrib1sv(index, v);}
-//void wrapglVertexAttrib1dv(GLuint index, const GLdouble *v) {glVertexAttrib1dv(index, v);}
-void wrapglVertexAttrib2fv(GLuint index, const GLfloat *v) {glVertexAttrib2fv(index, v);}
-//void wrapglVertexAttrib2sv(GLuint index, const GLshort *v) {glVertexAttrib2sv(index, v);}
-//void wrapglVertexAttrib2dv(GLuint index, const GLdouble *v) {glVertexAttrib2dv(index, v);}
-void wrapglVertexAttrib3fv(GLuint index, const GLfloat *v) {glVertexAttrib3fv(index, v);}
-//void wrapglVertexAttrib3sv(GLuint index, const GLshort *v) {glVertexAttrib3sv(index, v);}
-//void wrapglVertexAttrib3dv(GLuint index, const GLdouble *v) {glVertexAttrib3dv(index, v);}
-void wrapglVertexAttrib4fv(GLuint index, const GLfloat *v) {glVertexAttrib4fv(index, v);}
-//void wrapglVertexAttrib4sv(GLuint index, const GLshort *v) {glVertexAttrib4sv(index, v);}
-//void wrapglVertexAttrib4dv(GLuint index, const GLdouble *v) {glVertexAttrib4dv(index, v);}
-//void wrapglVertexAttrib4iv(GLuint index, const GLint *v) {glVertexAttrib4iv(index, v);}
-//void wrapglVertexAttrib4bv(GLuint index, const GLbyte *v) {glVertexAttrib4bv(index, v);}
-//void wrapglVertexAttrib4ubv(GLuint index, const GLubyte *v) {glVertexAttrib4ubv(index, v);}
-//void wrapglVertexAttrib4usv(GLuint index, const GLushort *v) {glVertexAttrib4usv(index, GLushort v);}
-//void wrapglVertexAttrib4uiv(GLuint index, const GLuint *v) {glVertexAttrib4uiv(index, v);}
-//void wrapglVertexAttrib4Nbv(GLuint index, const GLbyte *v) {glVertexAttrib4Nbv(index, v);}
-//void wrapglVertexAttrib4Nsv(GLuint index, const GLshort *v) {glVertexAttrib4Nsv(index, v);}
-//void wrapglVertexAttrib4Niv(GLuint index, const GLint *v) {glVertexAttrib4Niv(index, v);}
-//void wrapglVertexAttrib4Nubv(GLuint index, const GLubyte *v) {glVertexAttrib4Nubv(index, v);}
-//void wrapglVertexAttrib4Nusv(GLuint index, const GLushort *v) {glVertexAttrib4Nusv(index, GLushort v);}
-//void wrapglVertexAttrib4Nuiv(GLuint index, const GLuint *v) {glVertexAttrib4Nuiv(index, v);}
-//void wrapglGetVertexAttribdv(GLuint index, GLenum pname, GLdouble *params) {glGetVertexAttribdv(index, pname, params);}
-void wrapglGetVertexAttribfv(GLuint index, GLenum pname, GLfloat *params) {glGetVertexAttribfv(index, pname, params);}
-void wrapglGetVertexAttribiv(GLuint index, GLenum pname, GLint *params) {glGetVertexAttribiv(index, pname, params);}
-void wrapglGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid **pointer) {glGetVertexAttribPointerv(index, pname, pointer);}
+//#define PRECALL //Con_Printf("GLCALL %s:%i\n", __FILE__, __LINE__)
+#define PRECALL
+#define POSTCALL
+GLboolean wrapglIsBuffer(GLuint buffer) {PRECALL;return glIsBuffer(buffer);POSTCALL;}
+GLboolean wrapglIsEnabled(GLenum cap) {PRECALL;return glIsEnabled(cap);POSTCALL;}
+GLboolean wrapglIsFramebuffer(GLuint framebuffer) {PRECALL;return glIsFramebuffer(framebuffer);POSTCALL;}
+//GLboolean wrapglIsQuery(GLuint qid) {PRECALL;return glIsQuery(qid);POSTCALL;}
+GLboolean wrapglIsRenderbuffer(GLuint renderbuffer) {PRECALL;return glIsRenderbuffer(renderbuffer);POSTCALL;}
+//GLboolean wrapglUnmapBuffer(GLenum target) {PRECALL;return glUnmapBuffer(target);POSTCALL;}
+GLenum wrapglCheckFramebufferStatus(GLenum target) {PRECALL;return glCheckFramebufferStatus(target);POSTCALL;}
+GLenum wrapglGetError(void) {PRECALL;return glGetError();POSTCALL;}
+GLuint wrapglCreateProgram(void) {PRECALL;return glCreateProgram();POSTCALL;}
+GLuint wrapglCreateShader(GLenum shaderType) {PRECALL;return glCreateShader(shaderType);POSTCALL;}
+//GLuint wrapglGetHandle(GLenum pname) {PRECALL;return glGetHandle(pname);POSTCALL;}
+GLint wrapglGetAttribLocation(GLuint programObj, const GLchar *name) {PRECALL;return glGetAttribLocation(programObj, name);POSTCALL;}
+GLint wrapglGetUniformLocation(GLuint programObj, const GLchar *name) {PRECALL;return glGetUniformLocation(programObj, name);POSTCALL;}
+//GLvoid* wrapglMapBuffer(GLenum target, GLenum access) {PRECALL;return glMapBuffer(target, access);POSTCALL;}
+const GLubyte* wrapglGetString(GLenum name) {PRECALL;return (const GLubyte*)glGetString(name);POSTCALL;}
+void wrapglActiveStencilFace(GLenum e) {PRECALL;Con_Printf("glActiveStencilFace(e)\n");POSTCALL;}
+void wrapglActiveTexture(GLenum e) {PRECALL;glActiveTexture(e);POSTCALL;}
+void wrapglAlphaFunc(GLenum func, GLclampf ref) {PRECALL;Con_Printf("glAlphaFunc(func, ref)\n");POSTCALL;}
+void wrapglArrayElement(GLint i) {PRECALL;Con_Printf("glArrayElement(i)\n");POSTCALL;}
+void wrapglAttachShader(GLuint containerObj, GLuint obj) {PRECALL;glAttachShader(containerObj, obj);POSTCALL;}
+//void wrapglBegin(GLenum mode) {PRECALL;Con_Printf("glBegin(mode)\n");POSTCALL;}
+//void wrapglBeginQuery(GLenum target, GLuint qid) {PRECALL;glBeginQuery(target, qid);POSTCALL;}
+void wrapglBindAttribLocation(GLuint programObj, GLuint index, const GLchar *name) {PRECALL;glBindAttribLocation(programObj, index, name);POSTCALL;}
+//void wrapglBindFragDataLocation(GLuint programObj, GLuint index, const GLchar *name) {PRECALL;glBindFragDataLocation(programObj, index, name);POSTCALL;}
+void wrapglBindBuffer(GLenum target, GLuint buffer) {PRECALL;glBindBuffer(target, buffer);POSTCALL;}
+void wrapglBindFramebuffer(GLenum target, GLuint framebuffer) {PRECALL;glBindFramebuffer(target, framebuffer);POSTCALL;}
+void wrapglBindRenderbuffer(GLenum target, GLuint renderbuffer) {PRECALL;glBindRenderbuffer(target, renderbuffer);POSTCALL;}
+void wrapglBindTexture(GLenum target, GLuint texture) {PRECALL;glBindTexture(target, texture);POSTCALL;}
+void wrapglBlendEquation(GLenum e) {PRECALL;glBlendEquation(e);POSTCALL;}
+void wrapglBlendFunc(GLenum sfactor, GLenum dfactor) {PRECALL;glBlendFunc(sfactor, dfactor);POSTCALL;}
+void wrapglBufferData(GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage) {PRECALL;glBufferData(target, size, data, usage);POSTCALL;}
+void wrapglBufferSubData(GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data) {PRECALL;glBufferSubData(target, offset, size, data);POSTCALL;}
+void wrapglClear(GLbitfield mask) {PRECALL;glClear(mask);POSTCALL;}
+void wrapglClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {PRECALL;glClearColor(red, green, blue, alpha);POSTCALL;}
+void wrapglClearDepth(GLclampd depth) {PRECALL;/*Con_Printf("glClearDepth(%f)\n", depth);glClearDepthf((float)depth);*/POSTCALL;}
+void wrapglClearStencil(GLint s) {PRECALL;glClearStencil(s);POSTCALL;}
+void wrapglClientActiveTexture(GLenum target) {PRECALL;Con_Printf("glClientActiveTexture(target)\n");POSTCALL;}
+void wrapglColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {PRECALL;Con_Printf("glColor4f(red, green, blue, alpha)\n");POSTCALL;}
+void wrapglColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) {PRECALL;Con_Printf("glColor4ub(red, green, blue, alpha)\n");POSTCALL;}
+void wrapglColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {PRECALL;glColorMask(red, green, blue, alpha);POSTCALL;}
+void wrapglColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr) {PRECALL;Con_Printf("glColorPointer(size, type, stride, ptr)\n");POSTCALL;}
+void wrapglCompileShader(GLuint shaderObj) {PRECALL;glCompileShader(shaderObj);POSTCALL;}
+void wrapglCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border,  GLsizei imageSize, const void *data) {PRECALL;glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);POSTCALL;}
+void wrapglCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data) {PRECALL;Con_Printf("glCompressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, data)\n");POSTCALL;}
+void wrapglCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) {PRECALL;glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);POSTCALL;}
+void wrapglCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data) {PRECALL;Con_Printf("glCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data)\n");POSTCALL;}
+void wrapglCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {PRECALL;glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);POSTCALL;}
+void wrapglCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {PRECALL;glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);POSTCALL;}
+void wrapglCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) {PRECALL;Con_Printf("glCopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height)\n");POSTCALL;}
+void wrapglCullFace(GLenum mode) {PRECALL;glCullFace(mode);POSTCALL;}
+void wrapglDeleteBuffers(GLsizei n, const GLuint *buffers) {PRECALL;glDeleteBuffers(n, buffers);POSTCALL;}
+void wrapglDeleteFramebuffers(GLsizei n, const GLuint *framebuffers) {PRECALL;glDeleteFramebuffers(n, framebuffers);POSTCALL;}
+void wrapglDeleteShader(GLuint obj) {PRECALL;glDeleteShader(obj);POSTCALL;}
+void wrapglDeleteProgram(GLuint obj) {PRECALL;glDeleteProgram(obj);POSTCALL;}
+//void wrapglDeleteQueries(GLsizei n, const GLuint *ids) {PRECALL;glDeleteQueries(n, ids);POSTCALL;}
+void wrapglDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) {PRECALL;glDeleteRenderbuffers(n, renderbuffers);POSTCALL;}
+void wrapglDeleteTextures(GLsizei n, const GLuint *textures) {PRECALL;glDeleteTextures(n, textures);POSTCALL;}
+void wrapglDepthFunc(GLenum func) {PRECALL;glDepthFunc(func);POSTCALL;}
+void wrapglDepthMask(GLboolean flag) {PRECALL;glDepthMask(flag);POSTCALL;}
+//void wrapglDepthRange(GLclampd near_val, GLclampd far_val) {PRECALL;glDepthRangef((float)near_val, (float)far_val);POSTCALL;}
+void wrapglDepthRangef(GLclampf near_val, GLclampf far_val) {PRECALL;glDepthRangef(near_val, far_val);POSTCALL;}
+void wrapglDetachShader(GLuint containerObj, GLuint attachedObj) {PRECALL;glDetachShader(containerObj, attachedObj);POSTCALL;}
+void wrapglDisable(GLenum cap) {PRECALL;glDisable(cap);POSTCALL;}
+void wrapglDisableClientState(GLenum cap) {PRECALL;Con_Printf("glDisableClientState(cap)\n");POSTCALL;}
+void wrapglDisableVertexAttribArray(GLuint index) {PRECALL;glDisableVertexAttribArray(index);POSTCALL;}
+void wrapglDrawArrays(GLenum mode, GLint first, GLsizei count) {PRECALL;glDrawArrays(mode, first, count);POSTCALL;}
+void wrapglDrawBuffer(GLenum mode) {PRECALL;Con_Printf("glDrawBuffer(mode)\n");POSTCALL;}
+void wrapglDrawBuffers(GLsizei n, const GLenum *bufs) {PRECALL;Con_Printf("glDrawBuffers(n, bufs)\n");POSTCALL;}
+void wrapglDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) {PRECALL;glDrawElements(mode, count, type, indices);POSTCALL;}
+//void wrapglDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices) {PRECALL;glDrawRangeElements(mode, start, end, count, type, indices);POSTCALL;}
+//void wrapglDrawRangeElementsEXT(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices) {PRECALL;glDrawRangeElements(mode, start, end, count, type, indices);POSTCALL;}
+void wrapglEnable(GLenum cap) {PRECALL;glEnable(cap);POSTCALL;}
+void wrapglEnableClientState(GLenum cap) {PRECALL;Con_Printf("glEnableClientState(cap)\n");POSTCALL;}
+void wrapglEnableVertexAttribArray(GLuint index) {PRECALL;glEnableVertexAttribArray(index);POSTCALL;}
+//void wrapglEnd(void) {PRECALL;Con_Printf("glEnd()\n");POSTCALL;}
+//void wrapglEndQuery(GLenum target) {PRECALL;glEndQuery(target);POSTCALL;}
+void wrapglFinish(void) {PRECALL;glFinish();POSTCALL;}
+void wrapglFlush(void) {PRECALL;glFlush();POSTCALL;}
+void wrapglFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {PRECALL;glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);POSTCALL;}
+void wrapglFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {PRECALL;glFramebufferTexture2D(target, attachment, textarget, texture, level);POSTCALL;}
+void wrapglFramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) {PRECALL;Con_Printf("glFramebufferTexture3D()\n");POSTCALL;}
+void wrapglGenBuffers(GLsizei n, GLuint *buffers) {PRECALL;glGenBuffers(n, buffers);POSTCALL;}
+void wrapglGenFramebuffers(GLsizei n, GLuint *framebuffers) {PRECALL;glGenFramebuffers(n, framebuffers);POSTCALL;}
+//void wrapglGenQueries(GLsizei n, GLuint *ids) {PRECALL;glGenQueries(n, ids);POSTCALL;}
+void wrapglGenRenderbuffers(GLsizei n, GLuint *renderbuffers) {PRECALL;glGenRenderbuffers(n, renderbuffers);POSTCALL;}
+void wrapglGenTextures(GLsizei n, GLuint *textures) {PRECALL;glGenTextures(n, textures);POSTCALL;}
+void wrapglGenerateMipmap(GLenum target) {PRECALL;glGenerateMipmap(target);POSTCALL;}
+void wrapglGetActiveAttrib(GLuint programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLchar *name) {PRECALL;glGetActiveAttrib(programObj, index, maxLength, length, size, type, name);POSTCALL;}
+void wrapglGetActiveUniform(GLuint programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLchar *name) {PRECALL;glGetActiveUniform(programObj, index, maxLength, length, size, type, name);POSTCALL;}
+void wrapglGetAttachedShaders(GLuint containerObj, GLsizei maxCount, GLsizei *count, GLuint *obj) {PRECALL;glGetAttachedShaders(containerObj, maxCount, count, obj);POSTCALL;}
+void wrapglGetBooleanv(GLenum pname, GLboolean *params) {PRECALL;glGetBooleanv(pname, params);POSTCALL;}
+void wrapglGetCompressedTexImage(GLenum target, GLint lod, void *img) {PRECALL;Con_Printf("glGetCompressedTexImage(target, lod, img)\n");POSTCALL;}
+void wrapglGetDoublev(GLenum pname, GLdouble *params) {PRECALL;Con_Printf("glGetDoublev(pname, params)\n");POSTCALL;}
+void wrapglGetFloatv(GLenum pname, GLfloat *params) {PRECALL;glGetFloatv(pname, params);POSTCALL;}
+void wrapglGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint *params) {PRECALL;glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);POSTCALL;}
+void wrapglGetShaderInfoLog(GLuint obj, GLsizei maxLength, GLsizei *length, GLchar *infoLog) {PRECALL;glGetShaderInfoLog(obj, maxLength, length, infoLog);POSTCALL;}
+void wrapglGetProgramInfoLog(GLuint obj, GLsizei maxLength, GLsizei *length, GLchar *infoLog) {PRECALL;glGetProgramInfoLog(obj, maxLength, length, infoLog);POSTCALL;}
+void wrapglGetIntegerv(GLenum pname, GLint *params) {PRECALL;glGetIntegerv(pname, params);POSTCALL;}
+void wrapglGetShaderiv(GLuint obj, GLenum pname, GLint *params) {PRECALL;glGetShaderiv(obj, pname, params);POSTCALL;}
+void wrapglGetProgramiv(GLuint obj, GLenum pname, GLint *params) {PRECALL;glGetProgramiv(obj, pname, params);POSTCALL;}
+//void wrapglGetQueryObjectiv(GLuint qid, GLenum pname, GLint *params) {PRECALL;glGetQueryObjectiv(qid, pname, params);POSTCALL;}
+//void wrapglGetQueryObjectuiv(GLuint qid, GLenum pname, GLuint *params) {PRECALL;glGetQueryObjectuiv(qid, pname, params);POSTCALL;}
+//void wrapglGetQueryiv(GLenum target, GLenum pname, GLint *params) {PRECALL;glGetQueryiv(target, pname, params);POSTCALL;}
+void wrapglGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params) {PRECALL;glGetRenderbufferParameteriv(target, pname, params);POSTCALL;}
+void wrapglGetShaderSource(GLuint obj, GLsizei maxLength, GLsizei *length, GLchar *source) {PRECALL;glGetShaderSource(obj, maxLength, length, source);POSTCALL;}
+void wrapglGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels) {PRECALL;Con_Printf("glGetTexImage(target, level, format, type, pixels)\n");POSTCALL;}
+void wrapglGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params) {PRECALL;Con_Printf("glGetTexLevelParameterfv(target, level, pname, params)\n");POSTCALL;}
+void wrapglGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params) {PRECALL;Con_Printf("glGetTexLevelParameteriv(target, level, pname, params)\n");POSTCALL;}
+void wrapglGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params) {PRECALL;glGetTexParameterfv(target, pname, params);POSTCALL;}
+void wrapglGetTexParameteriv(GLenum target, GLenum pname, GLint *params) {PRECALL;glGetTexParameteriv(target, pname, params);POSTCALL;}
+void wrapglGetUniformfv(GLuint programObj, GLint location, GLfloat *params) {PRECALL;glGetUniformfv(programObj, location, params);POSTCALL;}
+void wrapglGetUniformiv(GLuint programObj, GLint location, GLint *params) {PRECALL;glGetUniformiv(programObj, location, params);POSTCALL;}
+void wrapglHint(GLenum target, GLenum mode) {PRECALL;glHint(target, mode);POSTCALL;}
+void wrapglLineWidth(GLfloat width) {PRECALL;glLineWidth(width);POSTCALL;}
+void wrapglLinkProgram(GLuint programObj) {PRECALL;glLinkProgram(programObj);POSTCALL;}
+void wrapglLoadIdentity(void) {PRECALL;Con_Printf("glLoadIdentity()\n");POSTCALL;}
+void wrapglLoadMatrixf(const GLfloat *m) {PRECALL;Con_Printf("glLoadMatrixf(m)\n");POSTCALL;}
+void wrapglMatrixMode(GLenum mode) {PRECALL;Con_Printf("glMatrixMode(mode)\n");POSTCALL;}
+void wrapglMultiTexCoord1f(GLenum target, GLfloat s) {PRECALL;Con_Printf("glMultiTexCoord1f(target, s)\n");POSTCALL;}
+void wrapglMultiTexCoord2f(GLenum target, GLfloat s, GLfloat t) {PRECALL;Con_Printf("glMultiTexCoord2f(target, s, t)\n");POSTCALL;}
+void wrapglMultiTexCoord3f(GLenum target, GLfloat s, GLfloat t, GLfloat r) {PRECALL;Con_Printf("glMultiTexCoord3f(target, s, t, r)\n");POSTCALL;}
+void wrapglMultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) {PRECALL;Con_Printf("glMultiTexCoord4f(target, s, t, r, q)\n");POSTCALL;}
+void wrapglNormalPointer(GLenum type, GLsizei stride, const GLvoid *ptr) {PRECALL;Con_Printf("glNormalPointer(type, stride, ptr)\n");POSTCALL;}
+void wrapglPixelStorei(GLenum pname, GLint param) {PRECALL;glPixelStorei(pname, param);POSTCALL;}
+void wrapglPointSize(GLfloat size) {PRECALL;Con_Printf("glPointSize(size)\n");POSTCALL;}
+//void wrapglPolygonMode(GLenum face, GLenum mode) {PRECALL;Con_Printf("glPolygonMode(face, mode)\n");POSTCALL;}
+void wrapglPolygonOffset(GLfloat factor, GLfloat units) {PRECALL;glPolygonOffset(factor, units);POSTCALL;}
+void wrapglPolygonStipple(const GLubyte *mask) {PRECALL;Con_Printf("glPolygonStipple(mask)\n");POSTCALL;}
+void wrapglReadBuffer(GLenum mode) {PRECALL;Con_Printf("glReadBuffer(mode)\n");POSTCALL;}
+void wrapglReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) {PRECALL;glReadPixels(x, y, width, height, format, type, pixels);POSTCALL;}
+void wrapglRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {PRECALL;glRenderbufferStorage(target, internalformat, width, height);POSTCALL;}
+void wrapglScissor(GLint x, GLint y, GLsizei width, GLsizei height) {PRECALL;glScissor(x, y, width, height);POSTCALL;}
+void wrapglShaderSource(GLuint shaderObj, GLsizei count, const GLchar **string, const GLint *length) {PRECALL;glShaderSource(shaderObj, count, string, length);POSTCALL;}
+void wrapglStencilFunc(GLenum func, GLint ref, GLuint mask) {PRECALL;glStencilFunc(func, ref, mask);POSTCALL;}
+void wrapglStencilFuncSeparate(GLenum func1, GLenum func2, GLint ref, GLuint mask) {PRECALL;Con_Printf("glStencilFuncSeparate(func1, func2, ref, mask)\n");POSTCALL;}
+void wrapglStencilMask(GLuint mask) {PRECALL;glStencilMask(mask);POSTCALL;}
+void wrapglStencilOp(GLenum fail, GLenum zfail, GLenum zpass) {PRECALL;glStencilOp(fail, zfail, zpass);POSTCALL;}
+void wrapglStencilOpSeparate(GLenum e1, GLenum e2, GLenum e3, GLenum e4) {PRECALL;Con_Printf("glStencilOpSeparate(e1, e2, e3, e4)\n");POSTCALL;}
+void wrapglTexCoord1f(GLfloat s) {PRECALL;Con_Printf("glTexCoord1f(s)\n");POSTCALL;}
+void wrapglTexCoord2f(GLfloat s, GLfloat t) {PRECALL;Con_Printf("glTexCoord2f(s, t)\n");POSTCALL;}
+void wrapglTexCoord3f(GLfloat s, GLfloat t, GLfloat r) {PRECALL;Con_Printf("glTexCoord3f(s, t, r)\n");POSTCALL;}
+void wrapglTexCoord4f(GLfloat s, GLfloat t, GLfloat r, GLfloat q) {PRECALL;Con_Printf("glTexCoord4f(s, t, r, q)\n");POSTCALL;}
+void wrapglTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr) {PRECALL;Con_Printf("glTexCoordPointer(size, type, stride, ptr)\n");POSTCALL;}
+void wrapglTexEnvf(GLenum target, GLenum pname, GLfloat param) {PRECALL;Con_Printf("glTexEnvf(target, pname, param)\n");POSTCALL;}
+void wrapglTexEnvfv(GLenum target, GLenum pname, const GLfloat *params) {PRECALL;Con_Printf("glTexEnvfv(target, pname, params)\n");POSTCALL;}
+void wrapglTexEnvi(GLenum target, GLenum pname, GLint param) {PRECALL;Con_Printf("glTexEnvi(target, pname, param)\n");POSTCALL;}
+void wrapglTexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) {PRECALL;glTexImage2D(target, level, internalFormat, width, height, border, format, type, pixels);POSTCALL;}
+void wrapglTexImage3D(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) {PRECALL;Con_Printf("glTexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels)\n");POSTCALL;}
+void wrapglTexParameterf(GLenum target, GLenum pname, GLfloat param) {PRECALL;glTexParameterf(target, pname, param);POSTCALL;}
+void wrapglTexParameterfv(GLenum target, GLenum pname, GLfloat *params) {PRECALL;glTexParameterfv(target, pname, params);POSTCALL;}
+void wrapglTexParameteri(GLenum target, GLenum pname, GLint param) {PRECALL;glTexParameteri(target, pname, param);POSTCALL;}
+void wrapglTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) {PRECALL;glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);POSTCALL;}
+void wrapglTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels) {PRECALL;Con_Printf("glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels)\n");POSTCALL;}
+void wrapglUniform1f(GLint location, GLfloat v0) {PRECALL;glUniform1f(location, v0);POSTCALL;}
+void wrapglUniform1fv(GLint location, GLsizei count, const GLfloat *value) {PRECALL;glUniform1fv(location, count, value);POSTCALL;}
+void wrapglUniform1i(GLint location, GLint v0) {PRECALL;glUniform1i(location, v0);POSTCALL;}
+void wrapglUniform1iv(GLint location, GLsizei count, const GLint *value) {PRECALL;glUniform1iv(location, count, value);POSTCALL;}
+void wrapglUniform2f(GLint location, GLfloat v0, GLfloat v1) {PRECALL;glUniform2f(location, v0, v1);POSTCALL;}
+void wrapglUniform2fv(GLint location, GLsizei count, const GLfloat *value) {PRECALL;glUniform2fv(location, count, value);POSTCALL;}
+void wrapglUniform2i(GLint location, GLint v0, GLint v1) {PRECALL;glUniform2i(location, v0, v1);POSTCALL;}
+void wrapglUniform2iv(GLint location, GLsizei count, const GLint *value) {PRECALL;glUniform2iv(location, count, value);POSTCALL;}
+void wrapglUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) {PRECALL;glUniform3f(location, v0, v1, v2);POSTCALL;}
+void wrapglUniform3fv(GLint location, GLsizei count, const GLfloat *value) {PRECALL;glUniform3fv(location, count, value);POSTCALL;}
+void wrapglUniform3i(GLint location, GLint v0, GLint v1, GLint v2) {PRECALL;glUniform3i(location, v0, v1, v2);POSTCALL;}
+void wrapglUniform3iv(GLint location, GLsizei count, const GLint *value) {PRECALL;glUniform3iv(location, count, value);POSTCALL;}
+void wrapglUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {PRECALL;glUniform4f(location, v0, v1, v2, v3);POSTCALL;}
+void wrapglUniform4fv(GLint location, GLsizei count, const GLfloat *value) {PRECALL;glUniform4fv(location, count, value);POSTCALL;}
+void wrapglUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) {PRECALL;glUniform4i(location, v0, v1, v2, v3);POSTCALL;}
+void wrapglUniform4iv(GLint location, GLsizei count, const GLint *value) {PRECALL;glUniform4iv(location, count, value);POSTCALL;}
+void wrapglUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {PRECALL;glUniformMatrix2fv(location, count, transpose, value);POSTCALL;}
+void wrapglUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {PRECALL;glUniformMatrix3fv(location, count, transpose, value);POSTCALL;}
+void wrapglUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {PRECALL;glUniformMatrix4fv(location, count, transpose, value);POSTCALL;}
+void wrapglUseProgram(GLuint programObj) {PRECALL;glUseProgram(programObj);POSTCALL;}
+void wrapglValidateProgram(GLuint programObj) {PRECALL;glValidateProgram(programObj);POSTCALL;}
+void wrapglVertex2f(GLfloat x, GLfloat y) {PRECALL;Con_Printf("glVertex2f(x, y)\n");POSTCALL;}
+void wrapglVertex3f(GLfloat x, GLfloat y, GLfloat z) {PRECALL;Con_Printf("glVertex3f(x, y, z)\n");POSTCALL;}
+void wrapglVertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w) {PRECALL;Con_Printf("glVertex4f(x, y, z, w)\n");POSTCALL;}
+void wrapglVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) {PRECALL;glVertexAttribPointer(index, size, type, normalized, stride, pointer);POSTCALL;}
+void wrapglVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr) {PRECALL;Con_Printf("glVertexPointer(size, type, stride, ptr)\n");POSTCALL;}
+void wrapglViewport(GLint x, GLint y, GLsizei width, GLsizei height) {PRECALL;glViewport(x, y, width, height);POSTCALL;}
+void wrapglVertexAttrib1f(GLuint index, GLfloat v0) {PRECALL;glVertexAttrib1f(index, v0);POSTCALL;}
+//void wrapglVertexAttrib1s(GLuint index, GLshort v0) {PRECALL;glVertexAttrib1s(index, v0);POSTCALL;}
+//void wrapglVertexAttrib1d(GLuint index, GLdouble v0) {PRECALL;glVertexAttrib1d(index, v0);POSTCALL;}
+void wrapglVertexAttrib2f(GLuint index, GLfloat v0, GLfloat v1) {PRECALL;glVertexAttrib2f(index, v0, v1);POSTCALL;}
+//void wrapglVertexAttrib2s(GLuint index, GLshort v0, GLshort v1) {PRECALL;glVertexAttrib2s(index, v0, v1);POSTCALL;}
+//void wrapglVertexAttrib2d(GLuint index, GLdouble v0, GLdouble v1) {PRECALL;glVertexAttrib2d(index, v0, v1);POSTCALL;}
+void wrapglVertexAttrib3f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2) {PRECALL;glVertexAttrib3f(index, v0, v1, v2);POSTCALL;}
+//void wrapglVertexAttrib3s(GLuint index, GLshort v0, GLshort v1, GLshort v2) {PRECALL;glVertexAttrib3s(index, v0, v1, v2);POSTCALL;}
+//void wrapglVertexAttrib3d(GLuint index, GLdouble v0, GLdouble v1, GLdouble v2) {PRECALL;glVertexAttrib3d(index, v0, v1, v2);POSTCALL;}
+void wrapglVertexAttrib4f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {PRECALL;glVertexAttrib4f(index, v0, v1, v2, v3);POSTCALL;}
+//void wrapglVertexAttrib4s(GLuint index, GLshort v0, GLshort v1, GLshort v2, GLshort v3) {PRECALL;glVertexAttrib4s(index, v0, v1, v2, v3);POSTCALL;}
+//void wrapglVertexAttrib4d(GLuint index, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3) {PRECALL;glVertexAttrib4d(index, v0, v1, v2, v3);POSTCALL;}
+//void wrapglVertexAttrib4Nub(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w) {PRECALL;glVertexAttrib4Nub(index, x, y, z, w);POSTCALL;}
+void wrapglVertexAttrib1fv(GLuint index, const GLfloat *v) {PRECALL;glVertexAttrib1fv(index, v);POSTCALL;}
+//void wrapglVertexAttrib1sv(GLuint index, const GLshort *v) {PRECALL;glVertexAttrib1sv(index, v);POSTCALL;}
+//void wrapglVertexAttrib1dv(GLuint index, const GLdouble *v) {PRECALL;glVertexAttrib1dv(index, v);POSTCALL;}
+void wrapglVertexAttrib2fv(GLuint index, const GLfloat *v) {PRECALL;glVertexAttrib2fv(index, v);POSTCALL;}
+//void wrapglVertexAttrib2sv(GLuint index, const GLshort *v) {PRECALL;glVertexAttrib2sv(index, v);POSTCALL;}
+//void wrapglVertexAttrib2dv(GLuint index, const GLdouble *v) {PRECALL;glVertexAttrib2dv(index, v);POSTCALL;}
+void wrapglVertexAttrib3fv(GLuint index, const GLfloat *v) {PRECALL;glVertexAttrib3fv(index, v);POSTCALL;}
+//void wrapglVertexAttrib3sv(GLuint index, const GLshort *v) {PRECALL;glVertexAttrib3sv(index, v);POSTCALL;}
+//void wrapglVertexAttrib3dv(GLuint index, const GLdouble *v) {PRECALL;glVertexAttrib3dv(index, v);POSTCALL;}
+void wrapglVertexAttrib4fv(GLuint index, const GLfloat *v) {PRECALL;glVertexAttrib4fv(index, v);POSTCALL;}
+//void wrapglVertexAttrib4sv(GLuint index, const GLshort *v) {PRECALL;glVertexAttrib4sv(index, v);POSTCALL;}
+//void wrapglVertexAttrib4dv(GLuint index, const GLdouble *v) {PRECALL;glVertexAttrib4dv(index, v);POSTCALL;}
+//void wrapglVertexAttrib4iv(GLuint index, const GLint *v) {PRECALL;glVertexAttrib4iv(index, v);POSTCALL;}
+//void wrapglVertexAttrib4bv(GLuint index, const GLbyte *v) {PRECALL;glVertexAttrib4bv(index, v);POSTCALL;}
+//void wrapglVertexAttrib4ubv(GLuint index, const GLubyte *v) {PRECALL;glVertexAttrib4ubv(index, v);POSTCALL;}
+//void wrapglVertexAttrib4usv(GLuint index, const GLushort *v) {PRECALL;glVertexAttrib4usv(index, GLushort v);POSTCALL;}
+//void wrapglVertexAttrib4uiv(GLuint index, const GLuint *v) {PRECALL;glVertexAttrib4uiv(index, v);POSTCALL;}
+//void wrapglVertexAttrib4Nbv(GLuint index, const GLbyte *v) {PRECALL;glVertexAttrib4Nbv(index, v);POSTCALL;}
+//void wrapglVertexAttrib4Nsv(GLuint index, const GLshort *v) {PRECALL;glVertexAttrib4Nsv(index, v);POSTCALL;}
+//void wrapglVertexAttrib4Niv(GLuint index, const GLint *v) {PRECALL;glVertexAttrib4Niv(index, v);POSTCALL;}
+//void wrapglVertexAttrib4Nubv(GLuint index, const GLubyte *v) {PRECALL;glVertexAttrib4Nubv(index, v);POSTCALL;}
+//void wrapglVertexAttrib4Nusv(GLuint index, const GLushort *v) {PRECALL;glVertexAttrib4Nusv(index, GLushort v);POSTCALL;}
+//void wrapglVertexAttrib4Nuiv(GLuint index, const GLuint *v) {PRECALL;glVertexAttrib4Nuiv(index, v);POSTCALL;}
+//void wrapglGetVertexAttribdv(GLuint index, GLenum pname, GLdouble *params) {PRECALL;glGetVertexAttribdv(index, pname, params);POSTCALL;}
+void wrapglGetVertexAttribfv(GLuint index, GLenum pname, GLfloat *params) {PRECALL;glGetVertexAttribfv(index, pname, params);POSTCALL;}
+void wrapglGetVertexAttribiv(GLuint index, GLenum pname, GLint *params) {PRECALL;glGetVertexAttribiv(index, pname, params);POSTCALL;}
+void wrapglGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid **pointer) {PRECALL;glGetVertexAttribPointerv(index, pname, pointer);POSTCALL;}
+#endif
+
+#if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION == 2
+#define SDL_GL_ExtensionSupported(x) (strstr(gl_extensions, x) || strstr(gl_platformextensions, x))
+#endif
 
 void GLES_Init(void)
 {
+#ifndef qglClear
        qglIsBufferARB = wrapglIsBuffer;
        qglIsEnabled = wrapglIsEnabled;
        qglIsFramebufferEXT = wrapglIsFramebuffer;
@@ -1324,7 +1335,7 @@ void GLES_Init(void)
 //     qglBegin = wrapglBegin;
 //     qglBeginQueryARB = wrapglBeginQuery;
        qglBindAttribLocation = wrapglBindAttribLocation;
-       qglBindFragDataLocation = wrapglBindFragDataLocation;
+//     qglBindFragDataLocation = wrapglBindFragDataLocation;
        qglBindBufferARB = wrapglBindBuffer;
        qglBindFramebufferEXT = wrapglBindFramebuffer;
        qglBindRenderbufferEXT = wrapglBindRenderbuffer;
@@ -1360,7 +1371,7 @@ void GLES_Init(void)
        qglDeleteTextures = wrapglDeleteTextures;
        qglDepthFunc = wrapglDepthFunc;
        qglDepthMask = wrapglDepthMask;
-       qglDepthRange = wrapglDepthRange;
+       qglDepthRangef = wrapglDepthRangef;
        qglDetachShader = wrapglDetachShader;
        qglDisable = wrapglDisable;
        qglDisableClientState = wrapglDisableClientState;
@@ -1519,6 +1530,7 @@ void GLES_Init(void)
        qglGetVertexAttribfv = wrapglGetVertexAttribfv;
        qglGetVertexAttribiv = wrapglGetVertexAttribiv;
        qglGetVertexAttribPointerv = wrapglGetVertexAttribPointerv;
+#endif
 
        gl_renderer = (const char *)qglGetString(GL_RENDERER);
        gl_vendor = (const char *)qglGetString(GL_VENDOR);
@@ -1560,9 +1572,10 @@ void GLES_Init(void)
        vid.support.ext_blend_subtract = true;
        vid.support.ext_draw_range_elements = true;
        vid.support.ext_framebuffer_object = false;//true;
+       vid.support.ext_packed_depth_stencil = false;
        vid.support.ext_stencil_two_side = false;
-       vid.support.ext_texture_3d = false;//SDL_GL_ExtensionSupported("GL_OES_texture_3D"); // iPhoneOS does not support 3D textures, odd...
-       vid.support.ext_texture_compression_s3tc = 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;
@@ -1571,11 +1584,29 @@ void GLES_Init(void)
        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_ARB, (GLint*)&vid.maxtexturesize_cubemap);
+               qglGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, (GLint*)&vid.maxtexturesize_cubemap);
+#ifdef GL_MAX_3D_TEXTURE_SIZE
        if (vid.support.ext_texture_3d)
                qglGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, (GLint*)&vid.maxtexturesize_3d);
+#endif
        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);
+               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)
@@ -1780,7 +1811,7 @@ static SDL_Surface *VID_WrapSDL_SetVideoMode(int screenwidth, int screenheight,
 
                        // reallocate with malloc, as this is in tempmempool (do not want)
                        xpm = data;
-                       data = malloc(width * height * 4);
+                       data = (char *) malloc(width * height * 4);
                        memcpy(data, xpm, width * height * 4);
                        Mem_Free(xpm);
                        xpm = NULL;
@@ -1934,6 +1965,7 @@ static SDL_Surface *VID_WrapSDL_SetVideoMode(int screenwidth, int screenheight,
                                static long netwm_icon[MAX_NETWM_ICON];
                                int pos = 0;
                                int i = 1;
+                               char vabuf[1024];
 
                                while(data)
                                {
@@ -1951,7 +1983,7 @@ static SDL_Surface *VID_WrapSDL_SetVideoMode(int screenwidth, int screenheight,
                                        }
                                        ++i;
                                        Mem_Free(data);
-                                       data = (char *) loadimagepixelsbgra(va("darkplaces-icon%d", i), false, false, false, NULL);
+                                       data = (char *) loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "darkplaces-icon%d", i), false, false, false, NULL);
                                }
 
                                info.info.x11.lock_func();
@@ -1981,7 +2013,7 @@ static void VID_OutputVersion(void)
                                        version->major, version->minor, version->patch );
 }
 
-qboolean VID_InitModeGL(viddef_mode_t *mode)
+static qboolean VID_InitModeGL(viddef_mode_t *mode)
 {
        int i;
 #if SETVIDEOMODE
@@ -2015,6 +2047,7 @@ qboolean VID_InitModeGL(viddef_mode_t *mode)
        notfirstvideomode = true;
 #endif
 
+#ifndef USE_GLES2
        // SDL usually knows best
        drivername = NULL;
 
@@ -2027,6 +2060,7 @@ qboolean VID_InitModeGL(viddef_mode_t *mode)
                Con_Printf("Unable to load GL driver \"%s\": %s\n", drivername, SDL_GetError());
                return false;
        }
+#endif
 
 #ifdef __IPHONEOS__
        // mobile platforms are always fullscreen, we'll get the resolution after opening the window
@@ -2166,7 +2200,7 @@ extern cvar_t gl_info_version;
 extern cvar_t gl_info_platform;
 extern cvar_t gl_info_driver;
 
-qboolean VID_InitModeSoft(viddef_mode_t *mode)
+static qboolean VID_InitModeSoft(viddef_mode_t *mode)
 {
 #if SETVIDEOMODE
        int flags = SDL_HWSURFACE;
@@ -2399,7 +2433,7 @@ size_t VID_ListModes(vid_mode_t *modes, size_t maxcount)
        int bpp = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
 
        k = 0;
-       for(vidmodes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE); vidmodes && *vidmodes; ++vidmodes)
+       for(vidmodes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE); vidmodes && vidmodes != (SDL_Rect**)(-1) && *vidmodes; ++vidmodes)
        {
                if(k >= maxcount)
                        break;
index c34f1c82e795f81da570e04bcf3546495bafb061..9f24869d4cea01848a8ca44551fea8bdd8cdd921 100644 (file)
@@ -1,6 +1,7 @@
 
 #include "quakedef.h"
 #include "cdaudio.h"
+#include "image.h"
 
 #ifdef SUPPORTD3D
 #include <d3d9.h>
@@ -71,10 +72,6 @@ int vid_xinputindex = -1;
 // global video state
 viddef_t vid;
 
-// LordHavoc: these are only set in wgl
-qboolean isG200 = false; // LordHavoc: the Matrox G200 can't do per pixel alpha, and it uses a D3D driver for GL... ugh...
-qboolean isRagePro = false; // LordHavoc: the ATI Rage Pro has limitations with per pixel alpha (the color scaler does not apply to per pixel alpha images...), although not as bad as a G200.
-
 // AK FIXME -> input_dest
 qboolean in_client_mouse = true;
 
@@ -138,7 +135,7 @@ cvar_t joy_x360_sensitivityroll = {0, "joy_x360_sensitivityroll", "1", "movement
 
 // 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", "2", "the number of threads the DarkPlaces Software Rasterizer should use"}; 
+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!
@@ -177,6 +174,7 @@ cvar_t vid_gl13 = {0, "vid_gl13", "1", "enables faster rendering using OpenGL 1.
 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" };
@@ -198,6 +196,7 @@ cvar_t v_color_white_g = {CVAR_SAVE, "v_color_white_g", "1", "desired color of w
 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
@@ -216,6 +215,7 @@ 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);
@@ -257,6 +257,7 @@ 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);
@@ -464,24 +465,27 @@ 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_EXT_framebuffer_object
-GLboolean (GLAPIENTRY *qglIsRenderbufferEXT)(GLuint renderbuffer);
-void (GLAPIENTRY *qglBindRenderbufferEXT)(GLenum target, GLuint renderbuffer);
-void (GLAPIENTRY *qglDeleteRenderbuffersEXT)(GLsizei n, const GLuint *renderbuffers);
-void (GLAPIENTRY *qglGenRenderbuffersEXT)(GLsizei n, GLuint *renderbuffers);
-void (GLAPIENTRY *qglRenderbufferStorageEXT)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
-void (GLAPIENTRY *qglGetRenderbufferParameterivEXT)(GLenum target, GLenum pname, GLint *params);
-GLboolean (GLAPIENTRY *qglIsFramebufferEXT)(GLuint framebuffer);
-void (GLAPIENTRY *qglBindFramebufferEXT)(GLenum target, GLuint framebuffer);
-void (GLAPIENTRY *qglDeleteFramebuffersEXT)(GLsizei n, const GLuint *framebuffers);
-void (GLAPIENTRY *qglGenFramebuffersEXT)(GLsizei n, GLuint *framebuffers);
-GLenum (GLAPIENTRY *qglCheckFramebufferStatusEXT)(GLenum target);
-//void (GLAPIENTRY *qglFramebufferTexture1DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
-void (GLAPIENTRY *qglFramebufferTexture2DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
-void (GLAPIENTRY *qglFramebufferTexture3DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
-void (GLAPIENTRY *qglFramebufferRenderbufferEXT)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
-void (GLAPIENTRY *qglGetFramebufferAttachmentParameterivEXT)(GLenum target, GLenum attachment, GLenum pname, GLint *params);
-void (GLAPIENTRY *qglGenerateMipmapEXT)(GLenum target);
+//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);
 
@@ -503,6 +507,7 @@ void (GLAPIENTRY *qglGetQueryObjectivARB)(GLuint qid, GLenum pname, GLint *param
 void (GLAPIENTRY *qglGetQueryObjectuivARB)(GLuint qid, GLenum pname, GLuint *params);
 
 void (GLAPIENTRY *qglSampleCoverageARB)(GLclampf value, GLboolean invert);
+#endif
 
 #if _MSC_VER >= 1400
 #define sscanf sscanf_s
@@ -583,6 +588,7 @@ qboolean GL_CheckExtension(const char *minglver_or_ext, const dllfunction_t *fun
        return true;
 }
 
+#ifndef USE_GLES2
 static dllfunction_t opengl110funcs[] =
 {
        {"glClearColor", (void **) &qglClearColor},
@@ -859,25 +865,50 @@ static dllfunction_t vbofuncs[] =
        {NULL, NULL}
 };
 
-static dllfunction_t fbofuncs[] =
+static dllfunction_t arbfbofuncs[] =
 {
-       {"glIsRenderbufferEXT"                      , (void **) &qglIsRenderbufferEXT},
-       {"glBindRenderbufferEXT"                    , (void **) &qglBindRenderbufferEXT},
-       {"glDeleteRenderbuffersEXT"                 , (void **) &qglDeleteRenderbuffersEXT},
-       {"glGenRenderbuffersEXT"                    , (void **) &qglGenRenderbuffersEXT},
-       {"glRenderbufferStorageEXT"                 , (void **) &qglRenderbufferStorageEXT},
-       {"glGetRenderbufferParameterivEXT"          , (void **) &qglGetRenderbufferParameterivEXT},
-       {"glIsFramebufferEXT"                       , (void **) &qglIsFramebufferEXT},
-       {"glBindFramebufferEXT"                     , (void **) &qglBindFramebufferEXT},
-       {"glDeleteFramebuffersEXT"                  , (void **) &qglDeleteFramebuffersEXT},
-       {"glGenFramebuffersEXT"                     , (void **) &qglGenFramebuffersEXT},
-       {"glCheckFramebufferStatusEXT"              , (void **) &qglCheckFramebufferStatusEXT},
-//     {"glFramebufferTexture1DEXT"                , (void **) &qglFramebufferTexture1DEXT},
-       {"glFramebufferTexture2DEXT"                , (void **) &qglFramebufferTexture2DEXT},
-       {"glFramebufferTexture3DEXT"                , (void **) &qglFramebufferTexture3DEXT},
-       {"glFramebufferRenderbufferEXT"             , (void **) &qglFramebufferRenderbufferEXT},
-       {"glGetFramebufferAttachmentParameterivEXT" , (void **) &qglGetFramebufferAttachmentParameterivEXT},
-       {"glGenerateMipmapEXT"                      , (void **) &qglGenerateMipmapEXT},
+       {"glIsRenderbufferARB"                      , (void **) &qglIsRenderbuffer},
+       {"glBindRenderbufferARB"                    , (void **) &qglBindRenderbuffer},
+       {"glDeleteRenderbuffersARB"                 , (void **) &qglDeleteRenderbuffers},
+       {"glGenRenderbuffersARB"                    , (void **) &qglGenRenderbuffers},
+       {"glRenderbufferStorageARB"                 , (void **) &qglRenderbufferStorage},
+       {"glRenderbufferStorageMultisampleARB"      , (void **) &qglRenderbufferStorageMultisample}, // not in GL_EXT_framebuffer_object
+       {"glGetRenderbufferParameterivARB"          , (void **) &qglGetRenderbufferParameteriv},
+       {"glIsFramebufferARB"                       , (void **) &qglIsFramebuffer},
+       {"glBindFramebufferARB"                     , (void **) &qglBindFramebuffer},
+       {"glDeleteFramebuffersARB"                  , (void **) &qglDeleteFramebuffers},
+       {"glGenFramebuffersARB"                     , (void **) &qglGenFramebuffers},
+       {"glCheckFramebufferStatusARB"              , (void **) &qglCheckFramebufferStatus},
+       {"glFramebufferTexture1DARB"                , (void **) &qglFramebufferTexture1D},
+       {"glFramebufferTexture2DARB"                , (void **) &qglFramebufferTexture2D},
+       {"glFramebufferTexture3DARB"                , (void **) &qglFramebufferTexture3D},
+       {"glFramebufferTextureLayerARB"             , (void **) &qglFramebufferTextureLayer}, // not in GL_EXT_framebuffer_object
+       {"glFramebufferRenderbufferARB"             , (void **) &qglFramebufferRenderbuffer},
+       {"glGetFramebufferAttachmentParameterivARB" , (void **) &qglGetFramebufferAttachmentParameteriv},
+       {"glBlitFramebufferARB"                     , (void **) &qglBlitFramebuffer}, // not in GL_EXT_framebuffer_object
+       {"glGenerateMipmapARB"                      , (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}
 };
 
@@ -917,6 +948,7 @@ static dllfunction_t multisamplefuncs[] =
        {"glSampleCoverageARB",          (void **) &qglSampleCoverageARB},
        {NULL, NULL}
 };
+#endif
 
 void VID_ClearExtensions(void)
 {
@@ -939,6 +971,7 @@ void VID_ClearExtensions(void)
        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;
@@ -946,10 +979,12 @@ void VID_ClearExtensions(void)
        qglFlush = NULL;
        qglActiveTexture = NULL;
        qglGetCompressedTexImageARB = NULL;
-       qglFramebufferTexture2DEXT = NULL;
+       qglFramebufferTexture2D = NULL;
        qglDrawBuffersARB = NULL;
+#endif
 }
 
+#ifndef USE_GLES2
 void VID_CheckExtensions(void)
 {
        if (!GL_CheckExtension("glbase", opengl110funcs, NULL, false))
@@ -998,7 +1033,12 @@ void VID_CheckExtensions(void)
        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.ext_framebuffer_object = GL_CheckExtension("GL_EXT_framebuffer_object", fbofuncs, "-nofbo", 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);
@@ -1055,7 +1095,7 @@ void VID_CheckExtensions(void)
        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_ARB, (GLint*)&vid.maxtexturesize_cubemap);
+               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);
 
@@ -1068,10 +1108,10 @@ void VID_CheckExtensions(void)
 
        vid.texunits = vid.teximageunits = vid.texarrayunits = 1;
        if (vid.support.arb_multitexture)
-               qglGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, (GLint*)&vid.texunits);
+               qglGetIntegerv(GL_MAX_TEXTURE_UNITS, (GLint*)&vid.texunits);
        if (vid_gl20.integer && vid.support.gl20shaders)
        {
-               qglGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, (GLint*)&vid.texunits);
+               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);
@@ -1083,13 +1123,12 @@ void VID_CheckExtensions(void)
                vid.sRGBcapable3D = true;
                vid.useinterleavedarrays = false;
                Con_Printf("vid.support.arb_multisample %i\n", vid.support.arb_multisample);
-               Con_Printf("vid.mode.samples %i\n", vid.mode.samples);
                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_ARB, (GLint*)&vid.texunits);
+               qglGetIntegerv(GL_MAX_TEXTURE_UNITS, (GLint*)&vid.texunits);
                vid.texunits = bound(1, vid.texunits, MAX_TEXTUREUNITS);
                vid.teximageunits = vid.texunits;
                vid.texarrayunits = vid.texunits;
@@ -1116,13 +1155,17 @@ void VID_CheckExtensions(void)
        {
                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);
@@ -1131,6 +1174,7 @@ void VID_CheckExtensions(void)
        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)
 {
@@ -1224,7 +1268,7 @@ void VID_Shared_BuildJoyState_Finish(vid_joystate_t *joystate)
        joystate->button[35] = r < 0.0f;
 }
 
-void VID_KeyEventForButton(qboolean oldbutton, qboolean newbutton, int key, double *timer)
+static void VID_KeyEventForButton(qboolean oldbutton, qboolean newbutton, int key, double *timer)
 {
        if (oldbutton)
        {
@@ -1369,7 +1413,7 @@ int VID_Shared_SetJoystick(int index)
 }
 
 
-void Force_CenterView_f (void)
+static void Force_CenterView_f (void)
 {
        cl.viewangles[PITCH] = 0;
 }
@@ -1382,18 +1426,24 @@ unsigned int vid_gammatables_serial = 0; // so other subsystems can poll if gamm
 qboolean vid_gammatables_trivial = true;
 void VID_BuildGammaTables(unsigned short *ramps, int rampsize)
 {
-       float srgbmul = (vid.sRGB2D || vid.sRGB3D) ? 2.2f : 1.0f;
        if (cachecolorenable)
        {
-               BuildGammaTable16(1.0f, invpow(0.5, 1 - cachegrey[0]) * srgbmul, cachewhite[0], cacheblack[0], cachecontrastboost, ramps, rampsize);
-               BuildGammaTable16(1.0f, invpow(0.5, 1 - cachegrey[1]) * srgbmul, cachewhite[1], cacheblack[1], cachecontrastboost, ramps + rampsize, rampsize);
-               BuildGammaTable16(1.0f, invpow(0.5, 1 - cachegrey[2]) * srgbmul, cachewhite[2], cacheblack[2], cachecontrastboost, ramps + rampsize*2, rampsize);
+               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 * srgbmul, cachecontrast, cachebrightness, cachecontrastboost, ramps, rampsize);
-               BuildGammaTable16(1.0f, cachegamma * srgbmul, cachecontrast, cachebrightness, cachecontrastboost, ramps + rampsize, rampsize);
-               BuildGammaTable16(1.0f, cachegamma * srgbmul, cachecontrast, cachebrightness, cachecontrastboost, ramps + rampsize*2, rampsize);
+               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
@@ -1649,6 +1699,7 @@ void VID_Shared_Init(void)
 
        Cvar_RegisterVariable(&v_hwgamma);
        Cvar_RegisterVariable(&v_glslgamma);
+       Cvar_RegisterVariable(&v_glslgamma_2d);
 
        Cvar_RegisterVariable(&v_psycho);
 
@@ -1672,6 +1723,7 @@ void VID_Shared_Init(void)
        Cvar_RegisterVariable(&vid_gl20);
        Cvar_RegisterVariable(&gl_finish);
        Cvar_RegisterVariable(&vid_sRGB);
+       Cvar_RegisterVariable(&vid_sRGB_fallback);
 
        Cvar_RegisterVariable(&joy_active);
 #ifdef WIN32
@@ -1727,9 +1779,10 @@ void VID_Shared_Init(void)
        Cmd_AddCommand("vid_restart", VID_Restart_f, "restarts video system (closes and reopens the window, restarts renderer)");
 }
 
-int VID_Mode(int fullscreen, int width, int height, int bpp, float refreshrate, int stereobuffer, int samples)
+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;
@@ -1742,6 +1795,8 @@ int VID_Mode(int fullscreen, int width, int height, int bpp, float refreshrate,
        mode.samples = samples;
        cl_ignoremousemoves = 2;
        VID_ClearExtensions();
+
+       vid.samples = vid.mode.samples;
        if (VID_InitMode(&mode))
        {
                // accept the (possibly modified) mode
@@ -1753,12 +1808,22 @@ int VID_Mode(int fullscreen, int width, int height, int bpp, float refreshrate,
                vid.refreshrate    = vid.mode.refreshrate;
                vid.userefreshrate = vid.mode.userefreshrate;
                vid.stereobuffer   = vid.mode.stereobuffer;
-               vid.samples        = vid.mode.samples;
                vid.stencil        = vid.mode.bitsperpixel > 16;
                vid.sRGB2D         = vid_sRGB.integer >= 1 && vid.sRGBcapable2D;
                vid.sRGB3D         = vid_sRGB.integer >= 1 && vid.sRGBcapable3D;
 
-               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(" (%ix AA)", mode.samples) : "");
+               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.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);
@@ -1792,6 +1857,8 @@ 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;
@@ -1803,8 +1870,8 @@ void VID_Restart_f(void)
        }
 
        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("x%.2fhz", vid.mode.refreshrate) : "", vid.mode.samples > 1 ? va(" (%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("x%.2fhz", vid_refreshrate.value) : "", vid_samples.integer > 1 ? va(" (%ix AA)", vid_samples.integer) : "");
+               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))
@@ -1883,7 +1950,7 @@ void VID_Stop(void)
        VID_Shutdown();
 }
 
-int VID_SortModes_Compare(const void *a_, const void *b_)
+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_;
index d30c6a759f368321862876df7e02dfc8873ede85..3f7d177dcd1aac21a30ed04e519bd986c5f01a63 100644 (file)
@@ -1900,8 +1900,8 @@ void VID_Shutdown (void)
                if (vid_begunscene)
                        IDirect3DDevice9_EndScene(vid_d3d9dev);
                vid_begunscene = false;
-//             Cmd_ExecuteString("r_texturestats", src_command);
-//             Cmd_ExecuteString("memlist", src_command);
+//             Cmd_ExecuteString("r_texturestats", src_command, true);
+//             Cmd_ExecuteString("memlist", src_command, true);
                IDirect3DDevice9_Release(vid_d3d9dev);
        }
        vid_d3d9dev = NULL;
index 3e0ccc57ebbf17154f9e4e8dd536fdc818222de5..e5bdad5999b59d828bc91164052f1efc2b43ba1f 100644 (file)
@@ -23,8 +23,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "cl_collision.h"
 #include "image.h"
 
-void CL_VM_UpdateDmgGlobals (int dmg_take, int dmg_save, vec3_t dmg_origin);
-
 /*
 
 The view is allowed to move slightly from it's true position for bobbing,
@@ -260,9 +258,9 @@ void V_ParseDamage (void)
        //float side;
        float count;
 
-       armor = MSG_ReadByte ();
-       blood = MSG_ReadByte ();
-       MSG_ReadVector(from, cls.protocol);
+       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);
@@ -430,9 +428,8 @@ static void highpass3_limited(vec3_t value, vec_t fracx, vec_t limitx, vec_t fra
        out[2] = highpass_limited(value[2], fracz, limitz, &store[2]);
 }
 
-void V_CalcRefdef (void)
+void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewangles, qboolean teleported, qboolean clonground, qboolean clcmdjump)
 {
-       entity_t *ent;
        float vieworg[3], viewangles[3], smoothtime;
        float gunorg[3], gunangles[3];
        matrix4x4_t tmpmatrix;
@@ -446,377 +443,405 @@ void V_CalcRefdef (void)
 // 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;
+
        VectorClear(gunorg);
        viewmodelmatrix_nobob = identitymatrix;
        viewmodelmatrix_withbob = identitymatrix;
        r_refdef.view.matrix = identitymatrix;
-       if (cls.state == ca_connected && cls.signon == SIGNONS)
-       {
-               // ent is the view entity (visible when out of body)
-               ent = &cl.entities[cl.viewentity];
-               // player can look around, so take the origin from the entity,
-               // and the angles from the input system
-               Matrix4x4_OriginFromMatrix(&ent->render.matrix, vieworg);
-               VectorCopy(cl.viewangles, 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;
+       // 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);
+       // fade damage flash
+       if (v_dmg_time > 0)
+               v_dmg_time -= bound(0, smoothtime, 0.1);
 
-               if (cl.intermission)
+       if (cl.intermission)
+       {
+               // 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
                {
-                       // 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 = ent->render.matrix;
-                               Matrix4x4_AdjustOrigin(&r_refdef.view.matrix, 0, 0, cl.stats[STAT_VIEWHEIGHT]);
-                       }
-                       Matrix4x4_Copy(&viewmodelmatrix_nobob, &r_refdef.view.matrix);
-                       Matrix4x4_ConcatScale(&viewmodelmatrix_nobob, cl_viewmodel_scale.value);
-                       Matrix4x4_Copy(&viewmodelmatrix_withbob, &viewmodelmatrix_nobob);
+                       r_refdef.view.matrix = *entrendermatrix;
+                       Matrix4x4_AdjustOrigin(&r_refdef.view.matrix, 0, 0, cl.stats[STAT_VIEWHEIGHT]);
                }
+               Matrix4x4_Copy(&viewmodelmatrix_nobob, &r_refdef.view.matrix);
+               Matrix4x4_ConcatScale(&viewmodelmatrix_nobob, cl_viewmodel_scale.value);
+               Matrix4x4_Copy(&viewmodelmatrix_withbob, &viewmodelmatrix_nobob);
+       }
+       else
+       {
+               // smooth stair stepping, but only if clonground and enabled
+               if (!clonground || cl_stairsmoothspeed.value <= 0 || teleported)
+                       cl.stairsmoothz = vieworg[2];
                else
                {
-                       // smooth stair stepping, but only if onground and enabled
-                       if (!cl.onground || cl_stairsmoothspeed.value <= 0 || !ent->persistent.trail_allowed) // FIXME use a better way to detect teleport/warp
-                               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);
-                       }
+                       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 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.oldtime) / max(0.0001, cl_smoothviewheight.value), 1);
-                       viewheightavg = viewheightavg * (1 - viewheight) + cl.stats[STAT_VIEWHEIGHT] * viewheight;
-                       vieworg[2] += viewheightavg;
+               // 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.oldtime) / max(0.0001, cl_smoothviewheight.value), 1);
+               viewheightavg = viewheightavg * (1 - viewheight) + cl.stats[STAT_VIEWHEIGHT] * 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];
+               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;
+                       camback = chase_back.value;
+                       camup = chase_up.value;
+                       campitch = chase_pitchangle.value;
 
-                               AngleVectors(viewangles, forward, NULL, NULL);
+                       AngleVectors(viewangles, forward, NULL, NULL);
 
-                               if (chase_overhead.integer)
-                               {
+                       if (chase_overhead.integer)
+                       {
 #if 1
-                                       vec3_t offset;
-                                       vec3_t bestvieworg;
+                               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;
+                               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);
+                               //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);
+                               //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;
+                               VectorCopy(trace.endpos, vieworg);
+                               vieworg[2] -= 8;
 #else
-                                       // trace from first person view location to our chosen third person view location
+                               // 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);
+                               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);
+                               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)
+                               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)
                                        {
-                                               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];
+                                               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);
+                                               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);
+                                               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];
-                                               }
+                                               if (bestvieworg[2] > trace.endpos[2])
+                                                       bestvieworg[2] = trace.endpos[2];
                                        }
-                                       bestvieworg[2] -= 8;
-                                       VectorCopy(bestvieworg, vieworg);
-#endif
-                                       viewangles[PITCH] = campitch;
                                }
-                               else
+                               bestvieworg[2] -= 8;
+                               VectorCopy(bestvieworg, vieworg);
+#endif
+                               viewangles[PITCH] = campitch;
+                       }
+                       else
+                       {
+                               if (gamemode == GAME_GOODVSBAD2 && chase_stevie.integer)
                                {
-                                       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);
+                                       // 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
+               }
+               else
+               {
+                       // first person view from entity
+                       // angles
+                       if (cl.stats[STAT_HEALTH] <= 0 && v_deathtilt.integer)
+                               viewangles[ROLL] = v_deathtiltangle.value;
+                       VectorAdd(viewangles, cl.punchangle, viewangles);
+                       viewangles[ROLL] += V_CalcRoll(cl.viewangles, cl.velocity);
+                       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 (cl.stats[STAT_HEALTH] > 0)
                        {
-                               // first person view from entity
-                               // angles
-                               if (cl.stats[STAT_HEALTH] <= 0 && v_deathtilt.integer)
-                                       viewangles[ROLL] = v_deathtiltangle.value;
-                               VectorAdd(viewangles, cl.punchangle, viewangles);
-                               viewangles[ROLL] += V_CalcRoll(cl.viewangles, cl.velocity);
-                               if (v_dmg_time > 0)
+                               double xyspeed, bob, bobfall;
+                               float cycle;
+                               vec_t frametime;
+
+                               //frametime = cl.realframetime * cl.movevars_timescale;
+                               frametime = (cl.time - cl.oldtime) * cl.movevars_timescale;
+
+                               // 1. if we teleported, clear the frametime... the lowpass will recover the previous value then
+                               if(teleported)
                                {
-                                       viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll;
-                                       viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch;
+                                       // 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);
                                }
-                               // origin
-                               VectorAdd(vieworg, cl.punchvector, vieworg);
-                               if (cl.stats[STAT_HEALTH] > 0)
+
+                               // 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(cl.velocity[0]*cl.velocity[0] + cl.velocity[1]*cl.velocity[1]), 400);
+
+                               // vertical view bobbing code
+                               if (cl_bob.value && cl_bobcycle.value)
                                {
-                                       double xyspeed, bob, bobfall;
-                                       float cycle;
-                                       vec_t frametime;
-
-                                       //frametime = cl.realframetime * cl.movevars_timescale;
-                                       frametime = (cl.time - cl.oldtime) * cl.movevars_timescale;
-                                       
-                                       // 1. if we teleported, clear the frametime... the lowpass will recover the previous value then
-                                       if(!ent->persistent.trail_allowed) // FIXME improve this check
-                                       {
-                                               // 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);
-                                       }
+                                       // 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;
+                               }
 
-                                       // 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(cl.velocity[0]*cl.velocity[0] + cl.velocity[1]*cl.velocity[1]), 400);
-
-                                       // vertical view bobbing code
-                                       if (cl_bob.value && cl_bobcycle.value)
+                               // 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
                                        {
-                                               // 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);
+                                               if(cl.bob2_smooth > 0)
+                                                       cl.bob2_smooth -= bound(0, cl_bob2smooth.value, 1);
                                                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;
+                                                       cl.bob2_smooth = 0;
                                        }
 
-                                       // 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;
+                                       // 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 (cl.velocity, right) * cl.bob2_smooth, 400);
+                                       front = bound(-400, DotProduct (cl.velocity, 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];
+                               }
 
-                                               // 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 (cl.onground && !cl.cmd.jump) // also block the effect while the jump button is pressed, to avoid twitches when bunny-hopping
-                                                       cl.bob2_smooth = 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, cl.velocity[2], 0) * bound(0, cl_bobfall.value, 0.1);
+                                               if (cl.velocity[2] < -cl_bobfallminspeed.value)
+                                                       cl.bobfall_swing = 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 (cl.velocity, right) * cl.bob2_smooth, 400);
-                                               front = bound(-400, DotProduct (cl.velocity, 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];
+                                                       cl.bobfall_swing = 0; // TODO really?
                                        }
-
-                                       // fall bobbing code
-                                       // causes the view to swing down and back up when touching the ground
-                                       if (cl_bobfall.value && cl_bobfallcycle.value)
+                                       else
                                        {
-                                               if (!cl.onground)
-                                               {
-                                                       cl.bobfall_speed = bound(-400, cl.velocity[2], 0) * bound(0, cl_bobfall.value, 0.1);
-                                                       if (cl.velocity[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);
+                                               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;
-                                               }
+                                               bobfall = sin(M_PI * cl.bobfall_swing) * cl.bobfall_speed;
+                                               vieworg[2] += bobfall;
+                                               gunorg[2] += bobfall;
                                        }
+                               }
 
-                                       // gun model bobbing code
-                                       if (cl_bobmodel.value)
+                               // 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)
                                        {
-                                               // 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 (cl.onground)
-                                               {
-                                                       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
+                                               if (cl.time - cl.hitgroundtime < 0.2)
                                                {
-                                                       // 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);
+                                                       // 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;
                                                }
-
-                                               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);
+                                               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 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);
+               // 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_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);
-               }
+               Matrix4x4_Invert_Simple(&tmpmatrix, &r_refdef.view.matrix);
+               Matrix4x4_Concat(&cl.csqc_viewmodelmatrixfromengine, &tmpmatrix, &viewmodelmatrix_withbob);
+       }
+}
+
+void V_CalcRefdef (void)
+{
+       entity_t *ent;
+
+       if (cls.state == ca_connected && cls.signon == SIGNONS && !cl.csqc_server2csqcentitynumber[cl.playerentity])
+       {
+               // ent is the view entity (visible when out of body)
+               ent = &cl.entities[cl.viewentity];
+
+               V_CalcRefdefUsing(&ent->render.matrix, cl.viewangles, !ent->persistent.trail_allowed, cl.onground, cl.cmd.jump); // 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);
        }
 }
 
index 4830996ca77b50073ca69005e277fa51bee82b37..1225090c626d57c03f04e42ecbfbf65f22495ccd 100644 (file)
@@ -102,13 +102,14 @@ World_SetSize
 
 ===============
 */
-void World_SetSize(world_t *world, const char *filename, const vec3_t mins, const vec3_t maxs)
+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)
@@ -144,6 +145,7 @@ 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
@@ -173,24 +175,29 @@ void World_UnlinkEdict(prvm_edict_t *ent)
        }
 }
 
-int World_EntitiesInBox(world_t *world, const vec3_t mins, const vec3_t maxs, int maxlist, prvm_edict_t **list)
+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];
 
+       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);
+
        // 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((mins[0] + world->areagrid_bias[0]) * world->areagrid_scale[0]);
-       igridmins[1] = (int) floor((mins[1] + world->areagrid_bias[1]) * world->areagrid_scale[1]);
-       //igridmins[2] = (int) ((mins[2] + world->areagrid_bias[2]) * world->areagrid_scale[2]);
-       igridmaxs[0] = (int) floor((maxs[0] + world->areagrid_bias[0]) * world->areagrid_scale[0]) + 1;
-       igridmaxs[1] = (int) floor((maxs[1] + world->areagrid_bias[1]) * world->areagrid_scale[1]) + 1;
-       //igridmaxs[2] = (int) ((maxs[2] + world->areagrid_bias[2]) * world->areagrid_scale[2]) + 1;
+       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]);
@@ -198,10 +205,13 @@ int World_EntitiesInBox(world_t *world, const vec3_t mins, const vec3_t maxs, in
        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 != &world->areagrid_outside)
+       if (world->areagrid_outside.next)
        {
                grid = &world->areagrid_outside;
                for (l = grid->next;l != grid;l = l->next)
@@ -210,7 +220,7 @@ int World_EntitiesInBox(world_t *world, const vec3_t mins, const vec3_t maxs, in
                        if (ent->priv.server->areagridmarknumber != world->areagrid_marknumber)
                        {
                                ent->priv.server->areagridmarknumber = world->areagrid_marknumber;
-                               if (!ent->priv.server->free && BoxesOverlap(mins, maxs, ent->priv.server->areamins, ent->priv.server->areamaxs))
+                               if (!ent->priv.server->free && BoxesOverlap(paddedmins, paddedmaxs, ent->priv.server->areamins, ent->priv.server->areamaxs))
                                {
                                        if (numlist < maxlist)
                                                list[numlist] = ent;
@@ -226,7 +236,7 @@ int World_EntitiesInBox(world_t *world, const vec3_t mins, const vec3_t maxs, in
                grid = world->areagrid + igrid[1] * AREA_GRID + igridmins[0];
                for (igrid[0] = igridmins[0];igrid[0] < igridmaxs[0];igrid[0]++, grid++)
                {
-                       if (grid->next != grid)
+                       if (grid->next)
                        {
                                for (l = grid->next;l != grid;l = l->next)
                                {
@@ -234,7 +244,7 @@ int World_EntitiesInBox(world_t *world, const vec3_t mins, const vec3_t maxs, in
                                        if (ent->priv.server->areagridmarknumber != world->areagrid_marknumber)
                                        {
                                                ent->priv.server->areagridmarknumber = world->areagrid_marknumber;
-                                               if (!ent->priv.server->free && BoxesOverlap(mins, maxs, ent->priv.server->areamins, ent->priv.server->areamaxs))
+                                               if (!ent->priv.server->free && BoxesOverlap(paddedmins, paddedmaxs, ent->priv.server->areamins, ent->priv.server->areamaxs))
                                                {
                                                        if (numlist < maxlist)
                                                                list[numlist] = ent;
@@ -250,8 +260,9 @@ int World_EntitiesInBox(world_t *world, const vec3_t mins, const vec3_t maxs, in
        return numlist;
 }
 
-void World_LinkEdict_AreaGrid(world_t *world, prvm_edict_t *ent)
+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);
 
@@ -291,6 +302,7 @@ 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);
@@ -323,14 +335,10 @@ void World_LinkEdict(world_t *world, prvm_edict_t *ent, const vec3_t mins, const
 #define USEODE 1
 #endif
 
-// recent ODE trunk has dWorldStepFast1 removed
-//#define ODE_USE_STEPFAST
-
 #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_contactsurfacelayer = {0, "physics_ode_contactsurfacelayer","1", "allows objects to overlap this many units to reduce jitter"};
-cvar_t physics_ode_worldstep = {0, "physics_ode_worldstep","2", "step function to use, 0 - dWorldStep, 1 - dWorldStepFast1, 2 - dWorldQuickStep"};
-cvar_t physics_ode_worldstep_iterations = {0, "physics_ode_worldstep_iterations", "20", "parameter to dWorldQuickStep and dWorldStepFast1"};
+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)"};
@@ -341,8 +349,9 @@ cvar_t physics_ode_world_damping_linear = {0, "physics_ode_world_damping_linear"
 cvar_t physics_ode_world_damping_linear_threshold = {0, "physics_ode_world_damping_linear_threshold", "0.01", "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.005", "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.01", "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", "1", "use constant step (sys_ticrate value) instead of variable step which tends to increase stability"};
+cvar_t physics_ode_constantstep = {0, "physics_ode_constantstep", "1", "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"};
@@ -558,7 +567,7 @@ void            (ODE_API *dMassSetSphereTotal)(dMass *, dReal total_mass, dReal
 //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 *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);
@@ -576,7 +585,7 @@ 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 *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);
@@ -587,9 +596,7 @@ void            (ODE_API *dWorldSetQuickStepNumIterations)(dWorldID, int num);
 //dReal           (ODE_API *dWorldGetContactMaxCorrectingVel)(dWorldID);
 void            (ODE_API *dWorldSetContactSurfaceLayer)(dWorldID, dReal depth);
 //dReal           (ODE_API *dWorldGetContactSurfaceLayer)(dWorldID);
-#ifdef ODE_USE_STEPFAST
-void            (ODE_API *dWorldStepFast1)(dWorldID, dReal stepsize, int maxiterations);
-#endif
+//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);
@@ -949,7 +956,7 @@ dGeomID         (ODE_API *dCreateCapsule)(dSpaceID space, dReal radius, dReal le
 //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);
+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);
 //
@@ -1025,7 +1032,7 @@ static dllfunction_t odefuncs[] =
 //     {"dMassSetCapsule",                                                             (void **) &dMassSetCapsule},
        {"dMassSetCapsuleTotal",                                                (void **) &dMassSetCapsuleTotal},
 //     {"dMassSetCylinder",                                                    (void **) &dMassSetCylinder},
-//     {"dMassSetCylinderTotal",                                               (void **) &dMassSetCylinderTotal},
+       {"dMassSetCylinderTotal",                                               (void **) &dMassSetCylinderTotal},
 //     {"dMassSetBox",                                                                 (void **) &dMassSetBox},
        {"dMassSetBoxTotal",                                                    (void **) &dMassSetBoxTotal},
 //     {"dMassSetTrimesh",                                                             (void **) &dMassSetTrimesh},
@@ -1043,7 +1050,7 @@ static dllfunction_t odefuncs[] =
 //     {"dWorldGetERP",                                                                (void **) &dWorldGetERP},
        {"dWorldSetCFM",                                                                (void **) &dWorldSetCFM},
 //     {"dWorldGetCFM",                                                                (void **) &dWorldGetCFM},
-       {"dWorldStep",                                                                  (void **) &dWorldStep},
+//     {"dWorldStep",                                                                  (void **) &dWorldStep},
 //     {"dWorldImpulseToForce",                                                (void **) &dWorldImpulseToForce},
        {"dWorldQuickStep",                                                             (void **) &dWorldQuickStep},
        {"dWorldSetQuickStepNumIterations",                             (void **) &dWorldSetQuickStepNumIterations},
@@ -1054,9 +1061,7 @@ static dllfunction_t odefuncs[] =
 //     {"dWorldGetContactMaxCorrectingVel",                    (void **) &dWorldGetContactMaxCorrectingVel},
        {"dWorldSetContactSurfaceLayer",                                (void **) &dWorldSetContactSurfaceLayer},
 //     {"dWorldGetContactSurfaceLayer",                                (void **) &dWorldGetContactSurfaceLayer},
-#ifdef ODE_USE_STEPFAST
-       {"dWorldStepFast1",                                                             (void **) &dWorldStepFast1},
-#endif
+//     {"dWorldStepFast1",                                                             (void **) &dWorldStepFast1},
 //     {"dWorldSetAutoEnableDepthSF1",                                 (void **) &dWorldSetAutoEnableDepthSF1},
 //     {"dWorldGetAutoEnableDepthSF1",                                 (void **) &dWorldGetAutoEnableDepthSF1},
 //     {"dWorldGetAutoDisableLinearThreshold",                 (void **) &dWorldGetAutoDisableLinearThreshold},
@@ -1407,7 +1412,7 @@ static dllfunction_t odefuncs[] =
 //     {"dGeomCapsuleSetParams",                                               (void **) &dGeomCapsuleSetParams},
 //     {"dGeomCapsuleGetParams",                                               (void **) &dGeomCapsuleGetParams},
 //     {"dGeomCapsulePointDepth",                                              (void **) &dGeomCapsulePointDepth},
-//     {"dCreateCylinder",                                                             (void **) &dCreateCylinder},
+       {"dCreateCylinder",                                                             (void **) &dCreateCylinder},
 //     {"dGeomCylinderSetParams",                                              (void **) &dGeomCylinderSetParams},
 //     {"dGeomCylinderGetParams",                                              (void **) &dGeomCylinderGetParams},
 //     {"dCreateRay",                                                                  (void **) &dCreateRay},
@@ -1483,7 +1488,6 @@ static void World_Physics_Init(void)
 
        Cvar_RegisterVariable(&physics_ode_quadtree_depth);
        Cvar_RegisterVariable(&physics_ode_contactsurfacelayer);
-       Cvar_RegisterVariable(&physics_ode_worldstep);
        Cvar_RegisterVariable(&physics_ode_worldstep_iterations);
        Cvar_RegisterVariable(&physics_ode_contact_mu);
        Cvar_RegisterVariable(&physics_ode_contact_erp);
@@ -1495,6 +1499,7 @@ static void World_Physics_Init(void)
        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);
@@ -1738,6 +1743,7 @@ void World_Physics_ApplyCmd(prvm_edict_t *ed, edict_odefunc_t *f)
 #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
@@ -1803,13 +1809,13 @@ static void World_Physics_Frame_BodyToEntity(world_t *world, prvm_edict_t *ed)
 
        {
                float pitchsign = 1;
-               if(!strcmp(prog->name, "server")) // FIXME some better way?
+               if(prog == SVVM_prog) // FIXME some better way?
                {
-                       pitchsign = SV_GetPitchSign(ed);
+                       pitchsign = SV_GetPitchSign(prog, ed);
                }
-               else if(!strcmp(prog->name, "client"))
+               else if(prog == CLVM_prog)
                {
-                       pitchsign = CL_GetPitchSign(ed);
+                       pitchsign = CL_GetPitchSign(prog, ed);
                }
                angles[PITCH] *= pitchsign;
                avelocity[PITCH] *= pitchsign;
@@ -1831,7 +1837,7 @@ static void World_Physics_Frame_BodyToEntity(world_t *world, prvm_edict_t *ed)
        VectorCopy(avelocity, ed->priv.server->ode_avelocity);
        ed->priv.server->ode_gravity = dBodyGetGravityMode(body) != 0;
 
-       if(!strcmp(prog->name, "server")) // FIXME some better way?
+       if(prog == SVVM_prog) // FIXME some better way?
        {
                SV_LinkEdict(ed);
                SV_LinkEdict_TouchAreaGrid(ed);
@@ -1840,6 +1846,7 @@ static void World_Physics_Frame_BodyToEntity(world_t *world, prvm_edict_t *ed)
 
 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;
@@ -2021,6 +2028,7 @@ static void World_Physics_Frame_JointFromEntity(world_t *world, prvm_edict_t *ed
 
 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 = (dBodyID)ed->priv.server->ode_body;
@@ -2074,16 +2082,12 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed)
        movetype = (int)PRVM_gameedictfloat(ed, movetype);
        scale = PRVM_gameedictfloat(ed, scale);if (!scale) scale = 1.0f;
        modelindex = 0;
-       if (world == &sv.world)
-               mempool = sv_mempool;
-       else if (world == &cl.world)
-               mempool = cls.levelmempool;
-       else
-               mempool = NULL;
+       mempool = prog->progs_mempool;
        model = NULL;
        switch(solid)
        {
        case SOLID_BSP:
+       case SOLID_PHYSICS_TRIMESH:
                modelindex = (int)PRVM_gameedictfloat(ed, modelindex);
                if (world == &sv.world)
                        model = SV_GetModelByIndex(modelindex);
@@ -2131,6 +2135,12 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed)
        if (movetype != MOVETYPE_PHYSICS)
                massval = 1.0f;
 
+       // get friction from entity
+       if (PRVM_gameedictfloat(ed, friction))
+               ed->priv.server->ode_friction = PRVM_gameedictfloat(ed, friction);
+       else
+               ed->priv.server->ode_friction = 1.0;
+               
        // check if we need to create or replace the geom
        if (!ed->priv.server->ode_physics
         || !VectorCompare(ed->priv.server->ode_mins, entmins)
@@ -2146,12 +2156,15 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed)
                ed->priv.server->ode_mass = massval;
                ed->priv.server->ode_modelindex = modelindex;
                VectorMAM(0.5f, entmins, 0.5f, entmaxs, geomcenter);
+               if (PRVM_gameedictvector(ed, massofs))
+                       VectorCopy(geomcenter, PRVM_gameedictvector(ed, massofs));
+               else
+                       VectorMAM(0.5f, entmins, 0.5f, entmaxs, geomcenter);
                ed->priv.server->ode_movelimit = min(geomsize[0], min(geomsize[1], geomsize[2]));
-
                if (massval * 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(PRVM_gameedictstring(ed, classname)));
+                               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)));
                        massval = 1.0f;
                        VectorSet(geomsize, 1.0f, 1.0f, 1.0f);
                }
@@ -2159,10 +2172,11 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed)
                switch(solid)
                {
                case SOLID_BSP:
+               case SOLID_PHYSICS_TRIMESH:
                        ed->priv.server->ode_offsetmatrix = identitymatrix;
                        if (!model)
                        {
-                               Con_Printf("entity %i (classname %s) has no model\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(PRVM_gameedictstring(ed, classname)));
+                               Con_Printf("entity %i (classname %s) has no model\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(prog, PRVM_gameedictstring(ed, classname)));
                                goto treatasbox;
                        }
                        // add an optimized mesh to the model containing only the SUPERCONTENTS_SOLID surfaces
@@ -2170,7 +2184,7 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed)
                                Mod_CreateCollisionMesh(model);
                        if (!model->brush.collisionmesh || !model->brush.collisionmesh->numtriangles)
                        {
-                               Con_Printf("entity %i (classname %s) has no geometry\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(PRVM_gameedictstring(ed, classname)));
+                               Con_Printf("entity %i (classname %s) has no geometry\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(prog, PRVM_gameedictstring(ed, classname)));
                                goto treatasbox;
                        }
                        // ODE requires persistent mesh storage, so we need to copy out
@@ -2217,6 +2231,7 @@ treatasbox:
                        dMassSetSphereTotal(&mass, massval, geomsize[0] * 0.5f);
                        break;
                case SOLID_PHYSICS_CAPSULE:
+               case SOLID_PHYSICS_CYLINDER:
                        axisindex = 0;
                        if (geomsize[axisindex] < geomsize[1])
                                axisindex = 1;
@@ -2238,8 +2253,16 @@ treatasbox:
                        // 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);
+                       if (solid == SOLID_PHYSICS_CAPSULE)
+                       {
+                               ed->priv.server->ode_geom = (void *)dCreateCapsule((dSpaceID)world->physics.ode_space, radius, length);
+                               dMassSetCapsuleTotal(&mass, massval, axisindex+1, radius, length);
+                       }
+                       else
+                       {
+                               ed->priv.server->ode_geom = (void *)dCreateCylinder((dSpaceID)world->physics.ode_space, radius, length);
+                               dMassSetCylinderTotal(&mass, massval, axisindex+1, radius, length);
+                       }
                        break;
                default:
                        Sys_Error("World_Physics_BodyFromEntity: unrecognized solid value %i was accepted by filter\n", solid);
@@ -2253,7 +2276,7 @@ treatasbox:
                memcpy(ed->priv.server->ode_massbuf, &mass, sizeof(dMass));
        }
 
-       if(ed->priv.server->ode_geom)
+       if (ed->priv.server->ode_geom)
                dGeomSetData((dGeomID)ed->priv.server->ode_geom, (void*)ed);
        if (movetype == MOVETYPE_PHYSICS && ed->priv.server->ode_geom)
        {
@@ -2308,13 +2331,13 @@ treatasbox:
                VectorCopy(angles, qangles);
                VectorCopy(avelocity, qavelocity);
 
-               if(!strcmp(prog->name, "server")) // FIXME some better way?
+               if(prog == SVVM_prog) // FIXME some better way?
                {
-                       pitchsign = SV_GetPitchSign(ed);
+                       pitchsign = SV_GetPitchSign(prog, ed);
                }
-               else if(!strcmp(prog->name, "client"))
+               else if(prog == CLVM_prog)
                {
-                       pitchsign = CL_GetPitchSign(ed);
+                       pitchsign = CL_GetPitchSign(prog, ed);
                }
                qangles[PITCH] *= pitchsign;
                qavelocity[PITCH] *= pitchsign;
@@ -2348,7 +2371,7 @@ treatasbox:
                        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(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]);
+                               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 (IS_NAN(test))
                                VectorClear(origin);
@@ -2401,7 +2424,6 @@ treatasbox:
                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);
@@ -2494,6 +2516,7 @@ treatasbox:
 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
        dBodyID b1;
        dBodyID b2;
@@ -2551,7 +2574,7 @@ static void nearCallback (void *data, dGeomID o1, dGeomID o2)
                        bouncestop2 = 60.0f / 800.0f;
        }
 
-       if(!strcmp(prog->name, "server"))
+       if(prog == SVVM_prog)
        {
                if(ed1 && PRVM_serveredictfunction(ed1, touch))
                {
@@ -2589,7 +2612,7 @@ static void nearCallback (void *data, dGeomID o1, dGeomID o2)
        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;
+               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;
                contact[i].surface.soft_cfm = physics_ode_contact_cfm.value;
                contact[i].surface.bounce = bouncefactor1;
@@ -2602,9 +2625,10 @@ static void nearCallback (void *data, dGeomID o1, dGeomID o2)
 
 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_DoubleTime();
+       tdelta = Sys_DirtyTime();
 #ifdef USEODE
        if (world->physics.ode && physics_ode.integer)
        {
@@ -2612,8 +2636,10 @@ void World_Physics_Frame(world_t *world, double frametime, double gravity)
                prvm_edict_t *ed;
 
                world->physics.ode_iterations = bound(1, physics_ode_iterationsperframe.integer, 1000);
-               if (physics_ode_constantstep.integer)
-                       world->physics.ode_step = sys_ticrate.value / world->physics.ode_iterations;
+               if (physics_ode_constantstep.integer > 0 && physics_ode_constantstep.integer < 1)
+                       world->physics.ode_step = physics_ode_constantstep.integer / world->physics.ode_iterations;
+               else if (physics_ode_constantstep.integer)
+                       world->physics.ode_step = sys_ticrate.integer / world->physics.ode_iterations;
                else
                        world->physics.ode_step = frametime / world->physics.ode_iterations;
                world->physics.ode_movelimit = physics_ode_movelimit.value / world->physics.ode_step;
@@ -2631,37 +2657,30 @@ void World_Physics_Frame(world_t *world, double frametime, double gravity)
                                        World_Physics_Frame_JointFromEntity(world, ed);
                }
 
-               tdelta2 = Sys_DoubleTime();
+               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);
+                       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_DoubleTime();
+                       tdelta3 = Sys_DirtyTime();
                        dSpaceCollide((dSpaceID)world->physics.ode_space, (void *)world, nearCallback);
-                       collisiontime += (Sys_DoubleTime() - tdelta3)*10000;
+                       collisiontime += (Sys_DirtyTime() - tdelta3)*10000;
 
                        // run physics (move objects, calculate new velocities)
-                       if (physics_ode_worldstep.integer == 2)
-                       {
-                               dWorldSetQuickStepNumIterations((dWorldID)world->physics.ode_world, bound(1, physics_ode_worldstep_iterations.integer, 200));
+                       // 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);
-                       }
-#ifdef ODE_USE_STEPFAST
-                       else if (physics_ode_worldstep.integer == 1)
-                               dWorldStepFast1((dWorldID)world->physics.ode_world, world->physics.ode_step, bound(1, physics_ode_worldstep_iterations.integer, 200));
-#endif
-                       else
-                               dWorldStep((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_DoubleTime() - tdelta2)*10000;
+               simulationtime = (Sys_DirtyTime() - tdelta2)*10000;
 
                // copy physics properties from physics engine to entities and do some stats
                if (prog)
@@ -2688,7 +2707,7 @@ void World_Physics_Frame(world_t *world, double frametime, double gravity)
                                        if (dBodyIsEnabled(body))
                                                world->physics.ode_activeovjects++;
                                }
-                               Con_Printf("ODE Stats(%s): %3.01f (%3.01f collision) %3.01f total : %i objects %i active %i disabled\n", prog->name, simulationtime, collisiontime, (Sys_DoubleTime() - tdelta)*10000, world->physics.ode_numobjects, world->physics.ode_activeovjects, (world->physics.ode_numobjects - world->physics.ode_activeovjects));
+                               Con_Printf("ODE Stats(%s): %3.01f (%3.01f collision) %3.01f total : %i objects %i active %i disabled\n", prog->name, simulationtime, collisiontime, (Sys_DirtyTime() - tdelta)*10000, world->physics.ode_numobjects, world->physics.ode_activeovjects, (world->physics.ode_numobjects - world->physics.ode_activeovjects));
                        }
                }
        }
index 334420fbff9599d29012044e417b139dadf4be51..122b9c708a635d959f66780fd8bf6857ad31c612 100644 (file)
@@ -46,7 +46,7 @@ typedef struct world_physics_s
        void *ode_world;
        void *ode_space;
        void *ode_contactgroup;
-       // number of constraint solver iterations to use (for dWorldStepFast)
+       // number of constraint solver iterations to use (for dWorldQuickStep)
        int ode_iterations;
        // actual step (server frametime / ode_iterations)
        vec_t ode_step;
@@ -59,12 +59,15 @@ typedef struct world_physics_s
 }
 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;
@@ -95,7 +98,7 @@ 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);
+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);
 
@@ -121,7 +124,7 @@ 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(prvm_edict_s *ed, edict_odefunc_s *f);
+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
index 585c10396d03db32e726ccaef168d1eb32b52043..02920535287b75970eaf7f258849f75cd2204748 100644 (file)
@@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // Z_zone.c
 
 #include "quakedef.h"
+#include "thread.h"
 
 #ifdef WIN32
 #include <windows.h>
@@ -37,6 +38,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 unsigned int sentinel_seed;
 
 qboolean mem_bigendian = false;
+void *mem_mutex = NULL;
 
 // LordHavoc: enables our own low-level allocator (instead of malloc)
 #define MEMCLUMPING 0
@@ -330,6 +332,8 @@ void *_Mem_Alloc(mempool_t *pool, void *olddata, size_t size, size_t alignment,
        }
        if (pool == NULL)
                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)
@@ -367,6 +371,9 @@ void *_Mem_Alloc(mempool_t *pool, void *olddata, size_t size, size_t alignment,
        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;
@@ -405,6 +412,8 @@ static void _Mem_FreeBlock(memheader_t *mem, const char *filename, int fileline)
        // 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
@@ -417,6 +426,8 @@ static void _Mem_FreeBlock(memheader_t *mem, const char *filename, int fileline)
        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)
@@ -634,7 +645,7 @@ void Mem_ExpandableArray_FreeArray(memexpandablearray_t *l)
 void *Mem_ExpandableArray_AllocRecordAtIndex(memexpandablearray_t *l, size_t index)
 {
        size_t j;
-       if (index == l->numarrays)
+       if (index >= l->numarrays)
        {
                if (l->numarrays == l->maxarrays)
                {
@@ -813,7 +824,7 @@ void Mem_PrintList(size_t minallocationsize)
        }
 }
 
-void MemList_f(void)
+static void MemList_f(void)
 {
        switch(Cmd_Argc())
        {
@@ -831,8 +842,7 @@ void MemList_f(void)
        }
 }
 
-extern void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal);
-void MemStats_f(void)
+static void MemStats_f(void)
 {
        Mem_CheckSentinelsGlobal();
        R_TextureStats_Print(false, false, true);
@@ -868,12 +878,19 @@ void Memory_Init (void)
        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)