]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
Merge remote branch 'origin/master' into akari/irc akari/irc
authorSamual <samual@xonotic.org>
Sat, 20 Aug 2011 10:20:39 +0000 (06:20 -0400)
committerSamual <samual@xonotic.org>
Sat, 20 Aug 2011 10:20:39 +0000 (06:20 -0400)
Conflicts:
makefile.inc

112 files changed:
BSDmakefile
SDLMain.m
cap_avi.c
cap_ogg.c
cd_shared.c
cl_collision.c
cl_gecko.c
cl_input.c
cl_main.c
cl_parse.c
cl_particles.c
cl_screen.c
cl_video.c
cl_video_jamdecode.c
client.h
clprogdefs.h
clvm_cmds.c
cmd.c
common.c
common.h
console.c
crypto.c
csprogs.c
cvar.c
cvar.h
dpdefs/csprogsdefs.qc
dpdefs/dpextensions.qc
dpdefs/menudefs.qc
dpdefs/source_compare.pl [new file with mode: 0755]
dpdefs/source_compare.txt [new file with mode: 0644]
dpsoftrast.c
dpsoftrast.h
dpvsimpledecode.c
draw.h
filematch.c
fs.c
ft2.c
ft2_fontdefs.h
gl_backend.c
gl_backend.h
gl_draw.c
gl_rmain.c
gl_rsurf.c
gl_textures.c
glquake.h
host.c
host_cmd.c
image.c
image.h
keys.c
keys.h
makefile
makefile.inc
mathlib.c
mathlib.h
menu.c
meshqueue.c
meshqueue.h
model_alias.c
model_brush.c
model_brush.h
model_iqm.h
model_shared.c
model_shared.h
model_sprite.c
mprogdefs.h
mvm_cmds.c
netconn.c
pr_comp.h
progsvm.h
protocol.c
protocol.h
prvm_cmds.c
prvm_edict.c
prvm_exec.c
prvm_execprogram.h
prvm_offsets.h [new file with mode: 0644]
quakedef.h
r_explosion.c
r_shadow.c
r_sky.c
r_textures.h
render.h
sbar.c
server.h
shader_glsl.h
shader_hlsl.h
snd_main.c
snd_main.h
snd_mix.c
snd_null.c
sound.h
sv_demo.c
sv_main.c
sv_move.c
sv_phys.c
sv_user.c
svvm_cmds.c
sys_shared.c
todo
utf8lib.c
utf8lib.h
vid.h
vid_agl.c
vid_glx.c
vid_null.c
vid_sdl.c
vid_shared.c
vid_wgl.c
view.c
world.c
zone.c

index 28106df6c7cff170c0cdc214c122e366a01ffdee..ac9793a06a0f6db3a0c065836add4438f2922ff4 100644 (file)
@@ -10,6 +10,14 @@ DP_ARCH != uname
 # Command used to delete files
 CMD_RM=$(CMD_UNIXRM)
 
+# default targets
+TARGETS_DEBUG=sv-debug cl-debug sdl-debug
+TARGETS_PROFILE=sv-profile cl-profile sdl-profile
+TARGETS_RELEASE=sv-release cl-release sdl-release
+TARGETS_RELEASE_PROFILE=sv-release-profile cl-release-profile sdl-release-profile
+TARGETS_NEXUIZ=sv-nexuiz cl-nexuiz sdl-nexuiz
+
+# X11 libs
 UNIX_X11LIBPATH=/usr/X11R6/lib
 
 # BSD configuration
index 2eaa1c11ef70105dd764a19468ca5e871819c94f..2434f81aa9b7389770550961a8c61d9f6018dc86 100644 (file)
--- a/SDLMain.m
+++ b/SDLMain.m
@@ -5,10 +5,10 @@
     Feel free to customize this file to suit your needs
 */
 
-#import "SDL.h"
-#import "SDLMain.h"
-#import <sys/param.h> /* for MAXPATHLEN */
-#import <unistd.h>
+#include "SDL.h"
+#include "SDLMain.h"
+#include <sys/param.h> /* for MAXPATHLEN */
+#include <unistd.h>
 
 /* For some reaon, Apple removed setAppleMenu from the headers in 10.4,
  but the method still is there and works. To avoid warnings, we declare
@@ -43,11 +43,11 @@ static BOOL   gCalledAppMainline = FALSE;
 
 static NSString *getApplicationName(void)
 {
-    NSDictionary *dict;
+    const NSDictionary *dict;
     NSString *appName = 0;
 
     /* Determine the application name */
-    dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
+    dict = (const NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
     if (dict)
         appName = [dict objectForKey: @"CFBundleName"];
     
@@ -64,10 +64,10 @@ static NSString *getApplicationName(void)
 @end
 #endif
 
-@interface SDLApplication : NSApplication
+@interface NSApplication (SDLApplication)
 @end
 
-@implementation SDLApplication
+@implementation NSApplication (SDLApplication)
 /* Invoked from the Quit menu item */
 - (void)terminate:(id)sender
 {
@@ -87,15 +87,14 @@ static NSString *getApplicationName(void)
     if (shouldChdir)
     {
         char parentdir[MAXPATHLEN];
-               CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
-               CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
-               if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) {
-               assert ( chdir (parentdir) == 0 );   /* chdir to the binary app's parent */
-               }
-               CFRelease(url);
-               CFRelease(url2);
-       }
-
+        CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
+        CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
+        if (CFURLGetFileSystemRepresentation(url2, 1, (UInt8 *)parentdir, MAXPATHLEN)) {
+            chdir(parentdir);   /* chdir to the binary app's parent */
+        }
+        CFRelease(url);
+        CFRelease(url2);
+    }
 }
 
 #if SDL_USE_NIB_FILE
@@ -120,7 +119,6 @@ static NSString *getApplicationName(void)
         if ([menuItem hasSubmenu])
             [self fixMenu:[menuItem submenu] withAppName:appName];
     }
-    [ aMenu sizeToFit ];
 }
 
 #else
@@ -203,7 +201,7 @@ static void CustomApplicationMain (int argc, char **argv)
     SDLMain                            *sdlMain;
 
     /* Ensure the application object is initialised */
-    [SDLApplication sharedApplication];
+    [NSApplication sharedApplication];
     
 #ifdef SDL_USE_CPS
     {
@@ -212,7 +210,7 @@ static void CustomApplicationMain (int argc, char **argv)
         if (!CPSGetCurrentProcess(&PSN))
             if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
                 if (!CPSSetFrontProcess(&PSN))
-                    [SDLApplication sharedApplication];
+                    [NSApplication sharedApplication];
     }
 #endif /* SDL_USE_CPS */
 
@@ -319,7 +317,7 @@ static void CustomApplicationMain (int argc, char **argv)
     NSString *result;
 
     bufferSize = selfLen + aStringLen - aRange.length;
-    buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar));
+    buffer = (unichar *)NSAllocateMemoryPages(bufferSize*sizeof(unichar));
     
     /* Get first part into buffer */
     localRange.location = 0;
@@ -374,7 +372,6 @@ int main (int argc, char **argv)
     }
 
 #if SDL_USE_NIB_FILE
-    [SDLApplication poseAsClass:[NSApplication class]];
     NSApplicationMain (argc, argv);
 #else
     CustomApplicationMain (argc, argv);
index e7cf88d675f9cf363a5876d7c0b4f2fec8fcf8b5..e1c0e9396c4f4c82e8763173cf0376117c34d189 100644 (file)
--- a/cap_avi.c
+++ b/cap_avi.c
@@ -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;
index 3318c356c4119bb34e0465ed7307d3c4de7aa568..609947ca3d02a32fc6f23b7eff8daec98c18ef62 100644 (file)
--- a/cap_ogg.c
+++ b/cap_ogg.c
@@ -8,8 +8,9 @@
 #include "cap_ogg.h"
 
 // video capture cvars
-static cvar_t cl_capturevideo_ogg_theora_quality = {CVAR_SAVE, "cl_capturevideo_ogg_theora_quality", "32", "video quality factor (0 to 63), or -1 to use bitrate only; higher is better"};
-static cvar_t cl_capturevideo_ogg_theora_bitrate = {CVAR_SAVE, "cl_capturevideo_ogg_theora_bitrate", "-1", "video bitrate (45 to 2000 kbps), or -1 to use quality only; higher is better"};
+static cvar_t cl_capturevideo_ogg_theora_vp3compat = {CVAR_SAVE, "cl_capturevideo_ogg_theora_vp3compat", "1", "make VP3 compatible theora streams"};
+static cvar_t cl_capturevideo_ogg_theora_quality = {CVAR_SAVE, "cl_capturevideo_ogg_theora_quality", "48", "video quality factor (0 to 63), or -1 to use bitrate only; higher is better; setting both to -1 achieves unlimited quality"};
+static cvar_t cl_capturevideo_ogg_theora_bitrate = {CVAR_SAVE, "cl_capturevideo_ogg_theora_bitrate", "-1", "video bitrate (45 to 2000 kbps), or -1 to use quality only; higher is better; setting both to -1 achieves unlimited quality"};
 static cvar_t cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier = {CVAR_SAVE, "cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier", "1.5", "how much more bit rate to use for keyframes, specified as a factor of at least 1"};
 static cvar_t cl_capturevideo_ogg_theora_keyframe_maxinterval = {CVAR_SAVE, "cl_capturevideo_ogg_theora_keyframe_maxinterval", "64", "maximum keyframe interval (1 to 1000)"};
 static cvar_t cl_capturevideo_ogg_theora_keyframe_mininterval = {CVAR_SAVE, "cl_capturevideo_ogg_theora_keyframe_mininterval", "8", "minimum keyframe interval (1 to 1000)"};
@@ -310,6 +311,9 @@ static int (*qvorbis_encode_init_vbr) (vorbis_info *vi,
 // end of vorbisenc.h stuff
 
 // theora.h stuff
+
+#define TH_ENCCTL_SET_VP3_COMPATIBLE (10)
+
 typedef struct {
     int   y_width;      /**< Width of the Y' luminance plane */
     int   y_height;     /**< Height of the luminance plane */
@@ -457,6 +461,7 @@ static void (*qtheora_clear) (theora_state *t);
 static void (*qtheora_comment_init) (theora_comment *tc);
 static void  (*qtheora_comment_clear) (theora_comment *tc);
 static double (*qtheora_granule_time) (theora_state *th,ogg_int64_t granulepos);
+static int (*qtheora_control) (theora_state *th,int req,void *buf,size_t buf_sz);
 // end of theora.h stuff
 
 static dllfunction_t oggfuncs[] =
@@ -512,6 +517,7 @@ static dllfunction_t theorafuncs[] =
        {"theora_encode_tables", (void **) &qtheora_encode_tables},
        {"theora_clear", (void **) &qtheora_clear},
        {"theora_granule_time", (void **) &qtheora_granule_time},
+       {"theora_control", (void **) &qtheora_control},
        {NULL, NULL}
 };
 
@@ -590,6 +596,7 @@ void SCR_CaptureVideo_Ogg_Init(void)
 {
        SCR_CaptureVideo_Ogg_OpenLibrary();
 
+       Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_vp3compat);
        Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_quality);
        Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_bitrate);
        Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier);
@@ -840,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)
                        {
@@ -945,6 +952,7 @@ void SCR_CaptureVideo_Ogg_BeginVideo(void)
                theora_comment tc;
                vorbis_comment vc;
                theora_info ti;
+               int vp3compat;
 
                format->serial1 = rand();
                qogg_stream_init(&format->to, format->serial1);
@@ -1002,32 +1010,24 @@ void SCR_CaptureVideo_Ogg_BeginVideo(void)
 
                if(ti.target_bitrate <= 0)
                {
-                       if(ti.quality < 0)
-                       {
-                               ti.target_bitrate = -1;
-                               ti.keyframe_data_target_bitrate = (unsigned int)-1;
-                               ti.quality = 63;
-                       }
-                       else
-                       {
-                               ti.target_bitrate = -1;
-                               ti.keyframe_data_target_bitrate = (unsigned int)-1;
-                               ti.quality = bound(0, ti.quality, 63);
-                       }
+                       ti.target_bitrate = -1;
+                       ti.keyframe_data_target_bitrate = (unsigned int)-1;
                }
                else
                {
-                       if(ti.quality < 0)
-                       {
-                               ti.target_bitrate = bound(45000, ti.target_bitrate, 2000000);
-                               ti.keyframe_data_target_bitrate = (int) (ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value));
-                               ti.quality = -1;
-                       }
-                       else
+                       ti.keyframe_data_target_bitrate = (int) (ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value));
+
+                       if(ti.target_bitrate < 45000 || ti.target_bitrate > 2000000)
+                               Con_DPrintf("WARNING: requesting an odd bitrate for theora (sensible values range from 45 to 2000 kbps)\n");
+               }
+
+               if(ti.quality < 0 || ti.quality > 63)
+               {
+                       ti.quality = 63;
+                       if(ti.target_bitrate <= 0)
                        {
-                               ti.target_bitrate = bound(45000, ti.target_bitrate, 2000000);
-                               ti.keyframe_data_target_bitrate = (int) (ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value));
-                               ti.quality = -1;
+                               ti.target_bitrate = 0x7FFFFFFF;
+                               ti.keyframe_data_target_bitrate = 0x7FFFFFFF;
                        }
                }
 
@@ -1044,6 +1044,14 @@ void SCR_CaptureVideo_Ogg_BeginVideo(void)
                qtheora_encode_init(&format->ts, &ti);
                qtheora_info_clear(&ti);
 
+               if(cl_capturevideo_ogg_theora_vp3compat.integer)
+               {
+                       vp3compat = 1;
+                       qtheora_control(&format->ts, TH_ENCCTL_SET_VP3_COMPATIBLE, &vp3compat, sizeof(vp3compat));
+                       if(!vp3compat)
+                               Con_DPrintf("Warning: theora stream is not fully VP3 compatible\n");
+               }
+
                // vorbis?
                if(cls.capturevideo.soundrate)
                {
index 7ca41ed60079493485e6ad7db7323fdf94f30e32..453aba622b1b565afc8b83ac7efd2f99ee3c1745 100644 (file)
@@ -322,15 +322,11 @@ void CDAudio_Play_byName (const char *trackname, qboolean looping, qboolean tryr
                if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "music/%s.ogg", trackname); // added by motorsep
                if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "music/cdtracks/%s.ogg", trackname); // added by motorsep
        }
-       if (FS_FileExists(filename) && (sfx = S_PrecacheSound (filename, false, true)))
+       if (FS_FileExists(filename) && (sfx = S_PrecacheSound (filename, false, false)))
        {
-               faketrack = S_StartSound_StartPosition (-1, 0, sfx, vec3_origin, cdvolume, 0, startposition);
+               faketrack = S_StartSound_StartPosition_Flags (-1, 0, sfx, vec3_origin, cdvolume, 0, startposition, (looping ? CHANNELFLAG_FORCELOOP : 0) | CHANNELFLAG_FULLVOLUME | CHANNELFLAG_LOCALSOUND);
                if (faketrack != -1)
                {
-                       if (looping)
-                               S_SetChannelFlag (faketrack, CHANNELFLAG_FORCELOOP, true);
-                       S_SetChannelFlag (faketrack, CHANNELFLAG_FULLVOLUME, true);
-                       S_SetChannelFlag (faketrack, CHANNELFLAG_LOCALSOUND, true); // not pausable
                        if(track >= 1)
                        {
                                if(cdaudio.integer != 0) // we don't need these messages if only fake tracks can be played anyway
@@ -393,7 +389,7 @@ void CDAudio_Stop (void)
 
        if (faketrack != -1)
        {
-               S_StopChannel (faketrack, true);
+               S_StopChannel (faketrack, true, true);
                faketrack = -1;
        }
        else if (cdPlaying && (CDAudio_SysStop() == -1))
index 93ba65989efbfd0e00f314c26fb4bc8006bd7123..8c9540669c9ba6518bcb472962286efa79b71446 100644 (file)
@@ -130,7 +130,7 @@ dp_model_t *CL_GetModelFromEdict(prvm_edict_t *ed)
 {
        if (!ed || ed->priv.server->free)
                return NULL;
-       return CL_GetModelByIndex((int)ed->fields.client->modelindex);
+       return CL_GetModelByIndex((int)PRVM_clientedictfloat(ed, modelindex));
 }
 
 void CL_LinkEdict(prvm_edict_t *ent)
@@ -145,9 +145,9 @@ void CL_LinkEdict(prvm_edict_t *ent)
 
        // set the abs box
 
-       if (ent->fields.client->solid == SOLID_BSP)
+       if (PRVM_clientedictfloat(ent, solid) == SOLID_BSP)
        {
-               dp_model_t *model = CL_GetModelByIndex( (int)ent->fields.client->modelindex );
+               dp_model_t *model = CL_GetModelByIndex( (int)PRVM_clientedictfloat(ent, modelindex) );
                if (model == NULL)
                {
                        Con_Printf("edict %i: SOLID_BSP with invalid modelindex!\n", PRVM_NUM_FOR_EDICT(ent));
@@ -160,59 +160,58 @@ void CL_LinkEdict(prvm_edict_t *ent)
                        if (!model->TraceBox)
                                Con_DPrintf("edict %i: SOLID_BSP with non-collidable model\n", PRVM_NUM_FOR_EDICT(ent));
 
-                       if (ent->fields.client->angles[0] || ent->fields.client->angles[2] || ent->fields.client->avelocity[0] || ent->fields.client->avelocity[2])
+                       if (PRVM_clientedictvector(ent, angles)[0] || PRVM_clientedictvector(ent, angles)[2] || PRVM_clientedictvector(ent, avelocity)[0] || PRVM_clientedictvector(ent, avelocity)[2])
                        {
-                               VectorAdd(ent->fields.client->origin, model->rotatedmins, mins);
-                               VectorAdd(ent->fields.client->origin, model->rotatedmaxs, maxs);
+                               VectorAdd(PRVM_clientedictvector(ent, origin), model->rotatedmins, mins);
+                               VectorAdd(PRVM_clientedictvector(ent, origin), model->rotatedmaxs, maxs);
                        }
-                       else if (ent->fields.client->angles[1] || ent->fields.client->avelocity[1])
+                       else if (PRVM_clientedictvector(ent, angles)[1] || PRVM_clientedictvector(ent, avelocity)[1])
                        {
-                               VectorAdd(ent->fields.client->origin, model->yawmins, mins);
-                               VectorAdd(ent->fields.client->origin, model->yawmaxs, maxs);
+                               VectorAdd(PRVM_clientedictvector(ent, origin), model->yawmins, mins);
+                               VectorAdd(PRVM_clientedictvector(ent, origin), model->yawmaxs, maxs);
                        }
                        else
                        {
-                               VectorAdd(ent->fields.client->origin, model->normalmins, mins);
-                               VectorAdd(ent->fields.client->origin, model->normalmaxs, maxs);
+                               VectorAdd(PRVM_clientedictvector(ent, origin), model->normalmins, mins);
+                               VectorAdd(PRVM_clientedictvector(ent, origin), model->normalmaxs, maxs);
                        }
                }
                else
                {
                        // SOLID_BSP with no model is valid, mainly because some QC setup code does so temporarily
-                       VectorAdd(ent->fields.client->origin, ent->fields.client->mins, mins);
-                       VectorAdd(ent->fields.client->origin, ent->fields.client->maxs, maxs);
+                       VectorAdd(PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, mins), mins);
+                       VectorAdd(PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, maxs), maxs);
                }
        }
        else
        {
-               VectorAdd(ent->fields.client->origin, ent->fields.client->mins, mins);
-               VectorAdd(ent->fields.client->origin, ent->fields.client->maxs, maxs);
+               VectorAdd(PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, mins), mins);
+               VectorAdd(PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, maxs), maxs);
        }
 
-       VectorCopy(mins, ent->fields.client->absmin);
-       VectorCopy(maxs, ent->fields.client->absmax);
+       VectorCopy(mins, PRVM_clientedictvector(ent, absmin));
+       VectorCopy(maxs, PRVM_clientedictvector(ent, absmax));
 
-       World_LinkEdict(&cl.world, ent, ent->fields.client->absmin, ent->fields.client->absmax);
+       World_LinkEdict(&cl.world, ent, PRVM_clientedictvector(ent, absmin), PRVM_clientedictvector(ent, absmax));
 }
 
 int CL_GenericHitSuperContentsMask(const prvm_edict_t *passedict)
 {
-       prvm_eval_t *val;
        if (passedict)
        {
-               val = PRVM_EDICTFIELDVALUE(passedict, prog->fieldoffsets.dphitcontentsmask);
-               if (val && val->_float)
-                       return (int)val->_float;
-               else if (passedict->fields.client->solid == SOLID_SLIDEBOX)
+               int dphitcontentsmask = (int)PRVM_clientedictfloat(passedict, dphitcontentsmask);
+               if (dphitcontentsmask)
+                       return dphitcontentsmask;
+               else if (PRVM_clientedictfloat(passedict, solid) == SOLID_SLIDEBOX)
                {
-                       if ((int)passedict->fields.client->flags & FL_MONSTER)
+                       if ((int)PRVM_clientedictfloat(passedict, flags) & FL_MONSTER)
                                return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_MONSTERCLIP;
                        else
                                return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP;
                }
-               else if (passedict->fields.client->solid == SOLID_CORPSE)
+               else if (PRVM_clientedictfloat(passedict, solid) == SOLID_CORPSE)
                        return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;
-               else if (passedict->fields.client->solid == SOLID_TRIGGER)
+               else if (PRVM_clientedictfloat(passedict, solid) == SOLID_TRIGGER)
                        return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;
                else
                        return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE;
@@ -298,7 +297,7 @@ trace_t CL_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int
        // precalculate prog value for passedict for comparisons
        passedictprog = prog != NULL ? PRVM_EDICT_TO_PROG(passedict) : 0;
        // precalculate passedict's owner edict pointer for comparisons
-       traceowner = passedict ? PRVM_PROG_TO_EDICT(passedict->fields.client->owner) : NULL;
+       traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_clientedictedict(passedict, owner)) : NULL;
 
        // collide against network entities
        if (hitnetworkbrushmodels)
@@ -383,9 +382,9 @@ skipnetworkplayers:
        {
                touch = touchedicts[i];
 
-               if (touch->fields.client->solid < SOLID_BBOX)
+               if (PRVM_clientedictfloat(touch, solid) < SOLID_BBOX)
                        continue;
-               if (type == MOVE_NOMONSTERS && touch->fields.client->solid != SOLID_BSP)
+               if (type == MOVE_NOMONSTERS && PRVM_clientedictfloat(touch, solid) != SOLID_BSP)
                        continue;
 
                if (passedict)
@@ -397,32 +396,32 @@ skipnetworkplayers:
                        if (traceowner == touch)
                                continue;
                        // don't clip owner against owned entities
-                       if (passedictprog == touch->fields.client->owner)
+                       if (passedictprog == PRVM_clientedictedict(touch, owner))
                                continue;
                        // don't clip points against points (they can't collide)
-                       if (VectorCompare(touch->fields.client->mins, touch->fields.client->maxs) && (type != MOVE_MISSILE || !((int)touch->fields.client->flags & FL_MONSTER)))
+                       if (VectorCompare(PRVM_clientedictvector(touch, mins), PRVM_clientedictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_clientedictfloat(touch, flags) & FL_MONSTER)))
                                continue;
                }
 
-               bodysupercontents = touch->fields.client->solid == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
+               bodysupercontents = PRVM_clientedictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
 
                // might interact, so do an exact clip
                model = NULL;
-               if ((int) touch->fields.client->solid == SOLID_BSP || type == MOVE_HITMODEL)
+               if ((int) PRVM_clientedictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
                        model = CL_GetModelFromEdict(touch);
                if (model)
-                       Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.client->origin[0], touch->fields.client->origin[1], touch->fields.client->origin[2], touch->fields.client->angles[0], touch->fields.client->angles[1], touch->fields.client->angles[2], 1);
+                       Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_clientedictvector(touch, origin)[0], PRVM_clientedictvector(touch, origin)[1], PRVM_clientedictvector(touch, origin)[2], PRVM_clientedictvector(touch, angles)[0], PRVM_clientedictvector(touch, angles)[1], PRVM_clientedictvector(touch, angles)[2], 1);
                else
-                       Matrix4x4_CreateTranslate(&matrix, touch->fields.client->origin[0], touch->fields.client->origin[1], touch->fields.client->origin[2]);
+                       Matrix4x4_CreateTranslate(&matrix, PRVM_clientedictvector(touch, origin)[0], PRVM_clientedictvector(touch, origin)[1], PRVM_clientedictvector(touch, origin)[2]);
                Matrix4x4_Invert_Simple(&imatrix, &matrix);
-               if ((int)touch->fields.client->flags & FL_MONSTER)
-                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touch->fields.client->mins, touch->fields.client->maxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipstart, hitsupercontentsmask);
+               if ((int)PRVM_clientedictfloat(touch, flags) & FL_MONSTER)
+                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_clientedictvector(touch, mins), PRVM_clientedictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipstart, hitsupercontentsmask);
                else
-                       Collision_ClipPointToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touch->fields.client->mins, touch->fields.client->maxs, bodysupercontents, &matrix, &imatrix, clipstart, hitsupercontentsmask);
+                       Collision_ClipPointToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_clientedictvector(touch, mins), PRVM_clientedictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, hitsupercontentsmask);
 
                if (cliptrace.realfraction > trace.realfraction && hitnetworkentity)
                        *hitnetworkentity = 0;
-               Collision_CombineTraces(&cliptrace, &trace, (void *)touch, touch->fields.client->solid == SOLID_BSP);
+               Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_clientedictfloat(touch, solid) == SOLID_BSP);
        }
 
 finished:
@@ -531,7 +530,7 @@ trace_t CL_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
        // precalculate prog value for passedict for comparisons
        passedictprog = prog != NULL ? PRVM_EDICT_TO_PROG(passedict) : 0;
        // precalculate passedict's owner edict pointer for comparisons
-       traceowner = passedict ? PRVM_PROG_TO_EDICT(passedict->fields.client->owner) : NULL;
+       traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_clientedictedict(passedict, owner)) : NULL;
 
        // collide against network entities
        if (hitnetworkbrushmodels)
@@ -616,9 +615,9 @@ skipnetworkplayers:
        {
                touch = touchedicts[i];
 
-               if (touch->fields.client->solid < SOLID_BBOX)
+               if (PRVM_clientedictfloat(touch, solid) < SOLID_BBOX)
                        continue;
-               if (type == MOVE_NOMONSTERS && touch->fields.client->solid != SOLID_BSP)
+               if (type == MOVE_NOMONSTERS && PRVM_clientedictfloat(touch, solid) != SOLID_BSP)
                        continue;
 
                if (passedict)
@@ -630,32 +629,32 @@ skipnetworkplayers:
                        if (traceowner == touch)
                                continue;
                        // don't clip owner against owned entities
-                       if (passedictprog == touch->fields.client->owner)
+                       if (passedictprog == PRVM_clientedictedict(touch, owner))
                                continue;
                        // don't clip points against points (they can't collide)
-                       if (VectorCompare(touch->fields.client->mins, touch->fields.client->maxs) && (type != MOVE_MISSILE || !((int)touch->fields.client->flags & FL_MONSTER)))
+                       if (VectorCompare(PRVM_clientedictvector(touch, mins), PRVM_clientedictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_clientedictfloat(touch, flags) & FL_MONSTER)))
                                continue;
                }
 
-               bodysupercontents = touch->fields.client->solid == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
+               bodysupercontents = PRVM_clientedictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
 
                // might interact, so do an exact clip
                model = NULL;
-               if ((int) touch->fields.client->solid == SOLID_BSP || type == MOVE_HITMODEL)
+               if ((int) PRVM_clientedictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
                        model = CL_GetModelFromEdict(touch);
                if (model)
-                       Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.client->origin[0], touch->fields.client->origin[1], touch->fields.client->origin[2], touch->fields.client->angles[0], touch->fields.client->angles[1], touch->fields.client->angles[2], 1);
+                       Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_clientedictvector(touch, origin)[0], PRVM_clientedictvector(touch, origin)[1], PRVM_clientedictvector(touch, origin)[2], PRVM_clientedictvector(touch, angles)[0], PRVM_clientedictvector(touch, angles)[1], PRVM_clientedictvector(touch, angles)[2], 1);
                else
-                       Matrix4x4_CreateTranslate(&matrix, touch->fields.client->origin[0], touch->fields.client->origin[1], touch->fields.client->origin[2]);
+                       Matrix4x4_CreateTranslate(&matrix, PRVM_clientedictvector(touch, origin)[0], PRVM_clientedictvector(touch, origin)[1], PRVM_clientedictvector(touch, origin)[2]);
                Matrix4x4_Invert_Simple(&imatrix, &matrix);
-               if (type == MOVE_MISSILE && (int)touch->fields.client->flags & FL_MONSTER)
-                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touch->fields.client->mins, touch->fields.client->maxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
+               if (type == MOVE_MISSILE && (int)PRVM_clientedictfloat(touch, flags) & FL_MONSTER)
+                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_clientedictvector(touch, mins), PRVM_clientedictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
                else
-                       Collision_ClipLineToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touch->fields.client->mins, touch->fields.client->maxs, bodysupercontents, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, hitsurfaces);
+                       Collision_ClipLineToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_clientedictvector(touch, mins), PRVM_clientedictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, hitsurfaces);
 
                if (cliptrace.realfraction > trace.realfraction && hitnetworkentity)
                        *hitnetworkentity = 0;
-               Collision_CombineTraces(&cliptrace, &trace, (void *)touch, touch->fields.client->solid == SOLID_BSP);
+               Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_clientedictfloat(touch, solid) == SOLID_BSP);
        }
 
 finished:
@@ -805,7 +804,7 @@ trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
        // figure out whether this is a point trace for comparisons
        pointtrace = VectorCompare(clipmins, clipmaxs);
        // precalculate passedict's owner edict pointer for comparisons
-       traceowner = passedict ? PRVM_PROG_TO_EDICT(passedict->fields.client->owner) : NULL;
+       traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_clientedictedict(passedict, owner)) : NULL;
 
        // collide against network entities
        if (hitnetworkbrushmodels)
@@ -890,9 +889,9 @@ skipnetworkplayers:
        {
                touch = touchedicts[i];
 
-               if (touch->fields.client->solid < SOLID_BBOX)
+               if (PRVM_clientedictfloat(touch, solid) < SOLID_BBOX)
                        continue;
-               if (type == MOVE_NOMONSTERS && touch->fields.client->solid != SOLID_BSP)
+               if (type == MOVE_NOMONSTERS && PRVM_clientedictfloat(touch, solid) != SOLID_BSP)
                        continue;
 
                if (passedict)
@@ -904,32 +903,32 @@ skipnetworkplayers:
                        if (traceowner == touch)
                                continue;
                        // don't clip owner against owned entities
-                       if (passedictprog == touch->fields.client->owner)
+                       if (passedictprog == PRVM_clientedictedict(touch, owner))
                                continue;
                        // don't clip points against points (they can't collide)
-                       if (pointtrace && VectorCompare(touch->fields.client->mins, touch->fields.client->maxs) && (type != MOVE_MISSILE || !((int)touch->fields.client->flags & FL_MONSTER)))
+                       if (pointtrace && VectorCompare(PRVM_clientedictvector(touch, mins), PRVM_clientedictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_clientedictfloat(touch, flags) & FL_MONSTER)))
                                continue;
                }
 
-               bodysupercontents = touch->fields.client->solid == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
+               bodysupercontents = PRVM_clientedictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
 
                // might interact, so do an exact clip
                model = NULL;
-               if ((int) touch->fields.client->solid == SOLID_BSP || type == MOVE_HITMODEL)
+               if ((int) PRVM_clientedictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
                        model = CL_GetModelFromEdict(touch);
                if (model)
-                       Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.client->origin[0], touch->fields.client->origin[1], touch->fields.client->origin[2], touch->fields.client->angles[0], touch->fields.client->angles[1], touch->fields.client->angles[2], 1);
+                       Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_clientedictvector(touch, origin)[0], PRVM_clientedictvector(touch, origin)[1], PRVM_clientedictvector(touch, origin)[2], PRVM_clientedictvector(touch, angles)[0], PRVM_clientedictvector(touch, angles)[1], PRVM_clientedictvector(touch, angles)[2], 1);
                else
-                       Matrix4x4_CreateTranslate(&matrix, touch->fields.client->origin[0], touch->fields.client->origin[1], touch->fields.client->origin[2]);
+                       Matrix4x4_CreateTranslate(&matrix, PRVM_clientedictvector(touch, origin)[0], PRVM_clientedictvector(touch, origin)[1], PRVM_clientedictvector(touch, origin)[2]);
                Matrix4x4_Invert_Simple(&imatrix, &matrix);
-               if ((int)touch->fields.client->flags & FL_MONSTER)
-                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touch->fields.client->mins, touch->fields.client->maxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
+               if ((int)PRVM_clientedictfloat(touch, flags) & FL_MONSTER)
+                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_clientedictvector(touch, mins), PRVM_clientedictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
                else
-                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touch->fields.client->mins, touch->fields.client->maxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
+                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_clientedictvector(touch, mins), PRVM_clientedictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
 
                if (cliptrace.realfraction > trace.realfraction && hitnetworkentity)
                        *hitnetworkentity = 0;
-               Collision_CombineTraces(&cliptrace, &trace, (void *)touch, touch->fields.client->solid == SOLID_BSP);
+               Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_clientedictfloat(touch, solid) == SOLID_BSP);
        }
 
 finished:
index d92ed0a4fed6de3f221d5f20a7983d2ab2e40629..e66482d68730e060e31d3ca90098c4f062ca1c0f 100644 (file)
@@ -525,14 +525,14 @@ static OSGK_ScriptResult dpGlobal_query (void* objTag, void* methTag,
   saveProg = prog;
   PRVM_SetProg(instance->ownerProg);
 
-  if (prog->funcoffsets.Gecko_Query)
+  if (PRVM_clientfunction(Gecko_Query))
   {
     OSGK_String* paramStr, *resultStr;
 
     if (!osgk_variant_get_string (strVal, &paramStr)) return srFailed;
         PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString (instance->name);
         PRVM_G_INT(OFS_PARM1) = PRVM_SetTempString (osgk_string_get (paramStr));
-    PRVM_ExecuteProgram(prog->funcoffsets.Gecko_Query,"Gecko_Query() required");
+    PRVM_ExecuteProgram(PRVM_clientfunction(Gecko_Query),"Gecko_Query() required");
     resultStr = osgk_string_create (PRVM_G_STRING (OFS_RETURN));
     *returnVal = osgk_variant_create_string (cl_geckoembedding, resultStr);
     osgk_release (resultStr);
index 577df50572811787e858b511261fa5cfa345acf9..d449bdf6d062a27eed7a281ed9bf5d339f8ab77c 100644 (file)
@@ -457,6 +457,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;
 
 /*
@@ -516,6 +518,7 @@ CL_Input
 Send the intended movement message to the server
 ================
 */
+extern qboolean CL_VM_InputEvent (int eventtype, int x, int y);
 void CL_Input (void)
 {
        float mx, my;
@@ -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)
        {
@@ -588,14 +612,7 @@ void CL_Input (void)
                }
                else
                {
-                       /*
-                       f = log(averagespeed);
-                       mi = log(mi);
-                       ma = log(ma);
-                       */
                        f = averagespeed;
-                       mi = mi;
-                       ma = ma;
                        f = (f - mi) / (ma - mi) * (m_accelerate.value - 1) + 1;
                }
 
@@ -1161,7 +1178,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 sidefric, vec_t speedlimit)
+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;
@@ -1170,10 +1187,16 @@ void CL_ClientMovement_Physics_PM_Accelerate(cl_clientmovement_state_t *s, vec3_
        vec3_t vel_xy;
        vec_t vel_xy_current;
        vec_t vel_xy_backward, vel_xy_forward;
-       qboolean speedclamp;
+       vec_t speedclamp;
 
-       speedclamp = (accelqw < 0);
-       if(speedclamp)
+       if(stretchfactor > 0)
+               speedclamp = stretchfactor;
+       else if(accelqw < 0)
+               speedclamp = 1;
+       else
+               speedclamp = -1; // no clamping
+
+       if(accelqw < 0)
                accelqw = -accelqw;
 
        if(cl.moveflags & MOVEFLAG_Q2AIRACCELERATE)
@@ -1220,13 +1243,15 @@ void CL_ClientMovement_Physics_PM_Accelerate(cl_clientmovement_state_t *s, vec3_
 
        VectorMA(vel_perpend, vel_straight, wishdir, s->velocity);
 
-       if(speedclamp)
+       if(speedclamp >= 0)
        {
-               vel_xy_current = min(VectorLength(s->velocity), vel_xy_forward);
-               if(vel_xy_current > 0) // prevent division by zero
+               vec_t vel_xy_preclamp;
+               vel_xy_preclamp = VectorLength(s->velocity);
+               if(vel_xy_preclamp > 0) // prevent division by zero
                {
-                       VectorNormalize(s->velocity);
-                       VectorScale(s->velocity, vel_xy_current, s->velocity);
+                       vel_xy_current += (vel_xy_forward - vel_xy_current) * speedclamp;
+                       if(vel_xy_current < vel_xy_preclamp)
+                               VectorScale(s->velocity, (vel_xy_current / vel_xy_preclamp), s->velocity);
                }
        }
 
@@ -1422,7 +1447,7 @@ void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s)
                        if(cl.movevars_warsowbunny_turnaccel && accelerating && s->cmd.sidemove == 0 && s->cmd.forwardmove != 0)
                                CL_ClientMovement_Physics_PM_AirAccelerate(s, wishdir, wishspeed2);
                        else
-                               CL_ClientMovement_Physics_PM_Accelerate(s, wishdir, wishspeed, wishspeed0, accel, accelqw, cl.movevars_airaccel_sideways_friction / cl.movevars_maxairspeed, cl.movevars_airspeedlimit_nonqw);
+                               CL_ClientMovement_Physics_PM_Accelerate(s, wishdir, wishspeed, wishspeed0, accel, accelqw, cl.movevars_airaccel_qw_stretchfactor, cl.movevars_airaccel_sideways_friction / cl.movevars_maxairspeed, cl.movevars_airspeedlimit_nonqw);
 
                        if(cl.movevars_aircontrol)
                                CL_ClientMovement_Physics_CPM_PM_Aircontrol(s, wishdir, wishspeed2);
@@ -1476,6 +1501,7 @@ void CL_UpdateMoveVars(void)
                cl.movevars_maxairspeed = cl.statsf[STAT_MOVEVARS_MAXAIRSPEED];
                cl.movevars_stepheight = cl.statsf[STAT_MOVEVARS_STEPHEIGHT];
                cl.movevars_airaccel_qw = cl.statsf[STAT_MOVEVARS_AIRACCEL_QW];
+               cl.movevars_airaccel_qw_stretchfactor = cl.statsf[STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR];
                cl.movevars_airaccel_sideways_friction = cl.statsf[STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION];
                cl.movevars_friction = cl.statsf[STAT_MOVEVARS_FRICTION];
                cl.movevars_wallfriction = cl.statsf[STAT_MOVEVARS_WALLFRICTION];
@@ -1515,6 +1541,7 @@ void CL_UpdateMoveVars(void)
                cl.movevars_maxairspeed = cl_movement_maxairspeed.value;
                cl.movevars_stepheight = cl_movement_stepheight.value;
                cl.movevars_airaccel_qw = cl_movement_airaccel_qw.value;
+               cl.movevars_airaccel_qw_stretchfactor = 0;
                cl.movevars_airaccel_sideways_friction = cl_movement_airaccel_sideways_friction.value;
                cl.movevars_airstopaccelerate = 0;
                cl.movevars_airstrafeaccelerate = 0;
@@ -2231,5 +2258,7 @@ void CL_InitInput (void)
        Cvar_RegisterVariable(&cl_netimmediatebuttons);
 
        Cvar_RegisterVariable(&cl_nodelta);
+
+       Cvar_RegisterVariable(&cl_csqc_generatemousemoveevents);
 }
 
index b64a6983ad4e65ba35e1324b094ac5c1adcd30e5..f9226401d9ff5fd5dda505e3c38fd73520141360 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -39,6 +39,7 @@ cvar_t csqc_progsize = {CVAR_READONLY, "csqc_progsize","-1","file size of csprog
 
 cvar_t cl_shownet = {0, "cl_shownet","0","1 = print packet size, 2 = print packet message list"};
 cvar_t cl_nolerp = {0, "cl_nolerp", "0","network update smoothing"};
+cvar_t cl_lerpexcess = {0, "cl_lerpexcess", "0","maximum allowed lerp excess (hides, not fixes, some packet loss)"};
 cvar_t cl_lerpanim_maxdelta_server = {0, "cl_lerpanim_maxdelta_server", "0.1","maximum frame delta for smoothing between server-controlled animation frames (when 0, one network frame)"};
 cvar_t cl_lerpanim_maxdelta_framegroups = {0, "cl_lerpanim_maxdelta_framegroups", "0.1","maximum frame delta for smoothing between framegroups (when 0, one network frame)"};
 
@@ -629,7 +630,7 @@ static float CL_LerpPoint(void)
        }
 
        f = (cl.time - cl.mtime[1]) / (cl.mtime[0] - cl.mtime[1]);
-       return bound(0, f, 1);
+       return bound(0, f, 1 + cl_lerpexcess.value);
 }
 
 void CL_ClearTempEntities (void)
@@ -908,7 +909,8 @@ void CL_AddQWCTFFlagModel(entity_t *player, int skin)
        CL_UpdateRenderEntity(flagrender);
 }
 
-matrix4x4_t viewmodelmatrix;
+matrix4x4_t viewmodelmatrix_withbob;
+matrix4x4_t viewmodelmatrix_nobob;
 
 static const vec3_t muzzleflashorigin = {18, 0, 0};
 
@@ -1011,9 +1013,9 @@ void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit, qboolean interpolat
        {
                // view-relative entity (guns and such)
                if (e->render.effects & EF_NOGUNBOB)
-                       matrix = &r_refdef.view.matrix; // really attached to view
+                       matrix = &viewmodelmatrix_nobob; // really attached to view
                else
-                       matrix = &viewmodelmatrix; // attached to gun bob matrix
+                       matrix = &viewmodelmatrix_withbob; // attached to gun bob matrix
        }
        else
        {
@@ -1034,7 +1036,7 @@ void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit, qboolean interpolat
                VectorCopy(cl.movement_origin, origin);
                VectorSet(angles, 0, cl.viewangles[1], 0);
        }
-       else if (interpolate && e->persistent.lerpdeltatime > 0 && (lerp = (cl.time - e->persistent.lerpstarttime) / e->persistent.lerpdeltatime) < 1)
+       else if (interpolate && e->persistent.lerpdeltatime > 0 && (lerp = (cl.time - e->persistent.lerpstarttime) / e->persistent.lerpdeltatime) < 1 + cl_lerpexcess.value)
        {
                // interpolate the origin and angles
                lerp = max(0, lerp);
@@ -1099,7 +1101,17 @@ void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit, qboolean interpolat
        }
 
        // animation lerp
-       if (e->render.framegroupblend[0].frame == frame)
+       e->render.skeleton = NULL;
+       if (e->render.flags & RENDER_COMPLEXANIMATION)
+       {
+               e->render.framegroupblend[0] = e->state_current.framegroupblend[0];
+               e->render.framegroupblend[1] = e->state_current.framegroupblend[1];
+               e->render.framegroupblend[2] = e->state_current.framegroupblend[2];
+               e->render.framegroupblend[3] = e->state_current.framegroupblend[3];
+               if (e->state_current.skeletonobject.model && e->state_current.skeletonobject.relativetransforms)
+                       e->render.skeleton = &e->state_current.skeletonobject;
+       }
+       else if (e->render.framegroupblend[0].frame == frame)
        {
                // update frame lerp fraction
                e->render.framegroupblend[0].lerp = 1;
@@ -1250,6 +1262,8 @@ void CL_UpdateNetworkEntityTrail(entity_t *e)
        // do trails
        if (e->render.flags & RENDER_GLOWTRAIL)
                trailtype = EFFECT_TR_GLOWTRAIL;
+       if (e->state_current.traileffectnum)
+               trailtype = (effectnameindex_t)e->state_current.traileffectnum;
        // check if a trail is allowed (it is not after a teleport for example)
        if (trailtype && e->persistent.trail_allowed)
        {
@@ -1547,6 +1561,8 @@ void CL_LinkNetworkEntity(entity_t *e)
        // do trail light
        if (e->render.flags & RENDER_GLOWTRAIL)
                trailtype = EFFECT_TR_GLOWTRAIL;
+       if (e->state_current.traileffectnum)
+               trailtype = (effectnameindex_t)e->state_current.traileffectnum;
        if (trailtype)
                CL_ParticleTrail(trailtype, 1, origin, origin, vec3_origin, vec3_origin, NULL, e->state_current.glowcolor, true, false, NULL, NULL);
 
@@ -2405,6 +2421,7 @@ void CL_Init (void)
        Cvar_RegisterVariable (&cl_anglespeedkey);
        Cvar_RegisterVariable (&cl_shownet);
        Cvar_RegisterVariable (&cl_nolerp);
+       Cvar_RegisterVariable (&cl_lerpexcess);
        Cvar_RegisterVariable (&cl_lerpanim_maxdelta_server);
        Cvar_RegisterVariable (&cl_lerpanim_maxdelta_framegroups);
        Cvar_RegisterVariable (&cl_deathfade);
index 1f229fd6a51177b0af6a6083c4cba0f5373cb3b5..3d56d11199524f718b880249a9707b05a3952524 100644 (file)
@@ -247,7 +247,7 @@ void CL_ParseStartSoundPacket(int largesoundindex)
                if (field_mask & SND_LARGEENTITY)
                {
                        ent = (unsigned short) MSG_ReadShort ();
-                       channel = MSG_ReadByte ();
+                       channel = MSG_ReadChar ();
                }
                else
                {
@@ -262,6 +262,8 @@ void CL_ParseStartSoundPacket(int largesoundindex)
                        sound_num = MSG_ReadByte ();
        }
 
+       channel = CHAN_NET2ENGINE(channel);
+
        MSG_ReadVector(pos, cls.protocol);
 
        if (sound_num >= MAX_SOUNDS)
@@ -3202,6 +3204,7 @@ 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)
 {
@@ -3285,6 +3288,20 @@ static void CL_NetworkTimeReceived(double newtime)
 
        if (cl.mtime[0] > cl.mtime[1])
                World_Physics_Frame(&cl.world, cl.mtime[0] - cl.mtime[1], cl.movevars_gravity);
+
+       // only lerp entities that also get an update in this frame, when lerp excess is used
+       if(cl_lerpexcess.value > 0)
+       {
+               int i;
+               for (i = 1;i < cl.num_entities;i++)
+               {
+                       if (cl.entities_active[i])
+                       {
+                               entity_t *ent = cl.entities + i;
+                               ent->persistent.lerpdeltatime = 0;
+                       }
+               }
+       }
 }
 
 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf("%3i:%s(%i)\n", msg_readcount-1, x, cmd);
index 392b46b765451f91520150a47ae6d293f8017381..25e8b8b15740e05b45195ee7969dc976bbdb328f 100644 (file)
@@ -192,6 +192,81 @@ static const int tex_bubble = 62;
 static const int tex_raindrop = 61;
 static const int tex_beam = 60;
 
+particleeffectinfo_t baselineparticleeffectinfo =
+{
+       0, //int effectnameindex; // which effect this belongs to
+       // PARTICLEEFFECT_* bits
+       0, //int flags;
+       // blood effects may spawn very few particles, so proper fraction-overflow
+       // handling is very important, this variable keeps track of the fraction
+       0.0, //double particleaccumulator;
+       // the math is: countabsolute + requestedcount * countmultiplier * quality
+       // absolute number of particles to spawn, often used for decals
+       // (unaffected by quality and requestedcount)
+       0.0f, //float countabsolute;
+       // multiplier for the number of particles CL_ParticleEffect was told to
+       // spawn, most effects do not really have a count and hence use 1, so
+       // this is often the actual count to spawn, not merely a multiplier
+       0.0f, //float countmultiplier;
+       // if > 0 this causes the particle to spawn in an evenly spaced line from
+       // originmins to originmaxs (causing them to describe a trail, not a box)
+       0.0f, //float trailspacing;
+       // type of particle to spawn (defines some aspects of behavior)
+       pt_alphastatic, //ptype_t particletype;
+       // blending mode used on this particle type
+       PBLEND_ALPHA, //pblend_t blendmode;
+       // orientation of this particle type (BILLBOARD, SPARK, BEAM, etc)
+       PARTICLE_BILLBOARD, //porientation_t orientation;
+       // range of colors to choose from in hex RRGGBB (like HTML color tags),
+       // randomly interpolated at spawn
+       {0xFFFFFF, 0xFFFFFF}, //unsigned int color[2];
+       // a random texture is chosen in this range (note the second value is one
+       // past the last choosable, so for example 8,16 chooses any from 8 up and
+       // including 15)
+       // if start and end of the range are the same, no randomization is done
+       {63, 63 /* tex_particle */}, //int tex[2];
+       // range of size values randomly chosen when spawning, plus size increase over time
+       {1, 1, 0.0f}, //float size[3];
+       // range of alpha values randomly chosen when spawning, plus alpha fade
+       {0.0f, 256.0f, 256.0f}, //float alpha[3];
+       // how long the particle should live (note it is also removed if alpha drops to 0)
+       {16777216.0f, 16777216.0f}, //float time[2];
+       // how much gravity affects this particle (negative makes it fly up!)
+       0.0f, //float gravity;
+       // how much bounce the particle has when it hits a surface
+       // if negative the particle is removed on impact
+       0.0f, //float bounce;
+       // if in air this friction is applied
+       // if negative the particle accelerates
+       0.0f, //float airfriction;
+       // if in liquid (water/slime/lava) this friction is applied
+       // if negative the particle accelerates
+       0.0f, //float liquidfriction;
+       // these offsets are added to the values given to particleeffect(), and
+       // then an ellipsoid-shaped jitter is added as defined by these
+       // (they are the 3 radii)
+       1.0f, //float stretchfactor;
+       // stretch velocity factor (used for sparks)
+       {0.0f, 0.0f, 0.0f}, //float originoffset[3];
+       {0.0f, 0.0f, 0.0f}, //float velocityoffset[3];
+       {0.0f, 0.0f, 0.0f}, //float originjitter[3];
+       {0.0f, 0.0f, 0.0f}, //float velocityjitter[3];
+       0.0f, //float velocitymultiplier;
+       // an effect can also spawn a dlight
+       0.0f, //float lightradiusstart;
+       0.0f, //float lightradiusfade;
+       16777216.0f, //float lighttime;
+       {1.0f, 1.0f, 1.0f}, //float lightcolor[3];
+       true, //qboolean lightshadow;
+       0, //int lightcubemapnum;
+       {(unsigned int)-1, (unsigned int)-1}, //unsigned int staincolor[2]; // note: 0x808080 = neutral (particle's own color), these are modding factors for the particle's original color!
+       {-1, -1}, //int staintex[2];
+       {1.0f, 1.0f}, //float stainalpha[2];
+       {2.0f, 2.0f}, //float stainsize[2];
+       // other parameters
+       {0.0f, 360.0f, 0.0f, 0.0f}, //float rotate[4]; // min/max base angle, min/max rotation over time
+};
+
 cvar_t cl_particles = {CVAR_SAVE, "cl_particles", "1", "enables particle effects"};
 cvar_t cl_particles_quality = {CVAR_SAVE, "cl_particles_quality", "1", "multiplies number of particles"};
 cvar_t cl_particles_alpha = {CVAR_SAVE, "cl_particles_alpha", "1", "multiplies opacity of particles"};
@@ -289,37 +364,9 @@ void CL_Particles_ParseEffectInfo(const char *textstart, const char *textend, co
                                break;
                        }
                        info = particleeffectinfo + numparticleeffectinfo++;
+                       // copy entire info from baseline, then fix up the nameindex
+                       *info = baselineparticleeffectinfo;
                        info->effectnameindex = effectnameindex;
-                       info->particletype = pt_alphastatic;
-                       info->blendmode = particletype[info->particletype].blendmode;
-                       info->orientation = particletype[info->particletype].orientation;
-                       info->tex[0] = tex_particle;
-                       info->tex[1] = tex_particle;
-                       info->color[0] = 0xFFFFFF;
-                       info->color[1] = 0xFFFFFF;
-                       info->size[0] = 1;
-                       info->size[1] = 1;
-                       info->alpha[0] = 0;
-                       info->alpha[1] = 256;
-                       info->alpha[2] = 256;
-                       info->time[0] = 9999;
-                       info->time[1] = 9999;
-                       VectorSet(info->lightcolor, 1, 1, 1);
-                       info->lightshadow = true;
-                       info->lighttime = 9999;
-                       info->stretchfactor = 1;
-                       info->staincolor[0] = (unsigned int)-1;
-                       info->staincolor[1] = (unsigned int)-1;
-                       info->staintex[0] = -1;
-                       info->staintex[1] = -1;
-                       info->stainalpha[0] = 1;
-                       info->stainalpha[1] = 1;
-                       info->stainsize[0] = 2;
-                       info->stainsize[1] = 2;
-                       info->rotate[0] = 0;
-                       info->rotate[1] = 360;
-                       info->rotate[2] = 0;
-                       info->rotate[3] = 0;
                }
                else if (info == NULL)
                {
@@ -602,6 +649,12 @@ particle_t *CL_NewParticle(const vec3_t sortorigin, unsigned short ptypeindex, i
        part->color[0] = ((((pcolor1 >> 16) & 0xFF) * l1 + ((pcolor2 >> 16) & 0xFF) * l2) >> 8) & 0xFF;
        part->color[1] = ((((pcolor1 >>  8) & 0xFF) * l1 + ((pcolor2 >>  8) & 0xFF) * l2) >> 8) & 0xFF;
        part->color[2] = ((((pcolor1 >>  0) & 0xFF) * l1 + ((pcolor2 >>  0) & 0xFF) * l2) >> 8) & 0xFF;
+       if (vid.sRGB3D)
+       {
+               part->color[0] = (unsigned char)(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->alpha = palpha;
        part->alphafade = palphafade;
        part->staintexnum = staintex;
@@ -758,7 +811,10 @@ void CL_SpawnDecalParticleForSurface(int hitent, const vec3_t org, const vec3_t
 
        if (cl_decals_newsystem.integer)
        {
-               R_DecalSystem_SplatEntities(org, normal, color[0]*(1.0f/255.0f), color[1]*(1.0f/255.0f), color[2]*(1.0f/255.0f), alpha*(1.0f/255.0f), particletexture[texnum].s1, particletexture[texnum].t1, particletexture[texnum].s2, particletexture[texnum].t2, size);
+               if (vid.sRGB3D)
+                       R_DecalSystem_SplatEntities(org, normal, Image_LinearFloatFromsRGB(color[0]), Image_LinearFloatFromsRGB(color[1]), Image_LinearFloatFromsRGB(color[2]), alpha*(1.0f/255.0f), particletexture[texnum].s1, particletexture[texnum].t1, particletexture[texnum].s2, particletexture[texnum].t2, size);
+               else
+                       R_DecalSystem_SplatEntities(org, normal, color[0]*(1.0f/255.0f), color[1]*(1.0f/255.0f), color[2]*(1.0f/255.0f), alpha*(1.0f/255.0f), particletexture[texnum].s1, particletexture[texnum].t1, particletexture[texnum].s2, particletexture[texnum].t2, size);
                return;
        }
 
@@ -780,6 +836,12 @@ void CL_SpawnDecalParticleForSurface(int hitent, const vec3_t org, const vec3_t
        decal->color[0] = color[0];
        decal->color[1] = color[1];
        decal->color[2] = color[2];
+       if (vid.sRGB3D)
+       {
+               decal->color[0] = (unsigned char)(Image_LinearFloatFromsRGB(decal->color[0]) * 256.0f);
+               decal->color[1] = (unsigned char)(Image_LinearFloatFromsRGB(decal->color[1]) * 256.0f);
+               decal->color[2] = (unsigned char)(Image_LinearFloatFromsRGB(decal->color[2]) * 256.0f);
+       }
        decal->owner = hitent;
        decal->clusterindex = -1000; // no vis culling unless we're sure
        if (hitent)
@@ -1824,11 +1886,11 @@ void CL_ParticleRain (const vec3_t mins, const vec3_t maxs, const vec3_t dir, in
        }
 }
 
-static cvar_t r_drawparticles = {0, "r_drawparticles", "1", "enables drawing of particles"};
+cvar_t r_drawparticles = {0, "r_drawparticles", "1", "enables drawing of particles"};
 static cvar_t r_drawparticles_drawdistance = {CVAR_SAVE, "r_drawparticles_drawdistance", "2000", "particles further than drawdistance*size will not be drawn"};
 static cvar_t r_drawparticles_nearclip_min = {CVAR_SAVE, "r_drawparticles_nearclip_min", "4", "particles closer than drawnearclip_min will not be drawn"};
 static cvar_t r_drawparticles_nearclip_max = {CVAR_SAVE, "r_drawparticles_nearclip_max", "4", "particles closer than drawnearclip_min will be faded"};
-static cvar_t r_drawdecals = {0, "r_drawdecals", "1", "enables drawing of decals"};
+cvar_t r_drawdecals = {0, "r_drawdecals", "1", "enables drawing of decals"};
 static cvar_t r_drawdecals_drawdistance = {CVAR_SAVE, "r_drawdecals_drawdistance", "500", "decals further than drawdistance*size will not be drawn"};
 
 #define PARTICLETEXTURESIZE 64
@@ -2159,7 +2221,7 @@ static void R_InitParticleTexture (void)
        }
 
 #ifndef DUMPPARTICLEFONT
-       particletexture[tex_beam].texture = loadtextureimage(particletexturepool, "particles/nexbeam.tga", false, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, true, r_texture_sRGB_skin_diffuse.integer != 0);
+       particletexture[tex_beam].texture = loadtextureimage(particletexturepool, "particles/nexbeam.tga", false, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, true, vid.sRGB3D);
        if (!particletexture[tex_beam].texture)
 #endif
        {
@@ -2281,14 +2343,13 @@ static void r_part_newmap(void)
        CL_Particles_LoadEffectInfo();
 }
 
-#define BATCHSIZE 256
-unsigned short particle_elements[BATCHSIZE*6];
-float particle_vertex3f[BATCHSIZE*12], particle_texcoord2f[BATCHSIZE*8], particle_color4f[BATCHSIZE*16];
+unsigned short particle_elements[MESHQUEUE_TRANSPARENT_BATCHSIZE*6];
+float particle_vertex3f[MESHQUEUE_TRANSPARENT_BATCHSIZE*12], particle_texcoord2f[MESHQUEUE_TRANSPARENT_BATCHSIZE*8], particle_color4f[MESHQUEUE_TRANSPARENT_BATCHSIZE*16];
 
 void R_Particles_Init (void)
 {
        int i;
-       for (i = 0;i < BATCHSIZE;i++)
+       for (i = 0;i < MESHQUEUE_TRANSPARENT_BATCHSIZE;i++)
        {
                particle_elements[i*6+0] = i*4+0;
                particle_elements[i*6+1] = i*4+1;
@@ -2375,7 +2436,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);
+       R_SetupShader_Generic(particletexture[63].texture, NULL, GL_MODULATE, 1, false, false);
        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);
 }
@@ -2685,7 +2746,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);
+                       R_SetupShader_Generic(texture, NULL, GL_MODULATE, 1, false, false);
                }
 
                if (p->blendmode == PBLEND_INVMOD)
index 60cae502929ddbb7353cb813df57067f7e0e9617..d5ca01e61e40651d7d15c3b17e446756cba8c5d7 100644 (file)
@@ -766,7 +766,7 @@ void R_TimeReport_BeginFrame(void)
        r_timereport_active = false;
        memset(&r_refdef.stats, 0, sizeof(r_refdef.stats));
 
-       if (r_speeds.integer >= 2 && cls.signon == SIGNONS && cls.state == ca_connected)
+       if (r_speeds.integer >= 2)
        {
                r_timereport_active = true;
                r_timereport_start = r_timereport_current = Sys_DoubleTime();
@@ -791,16 +791,16 @@ void R_TimeReport_EndFrame(void)
        mleaf_t *viewleaf;
 
        string[0] = 0;
-       if (r_speeds.integer && cls.signon == SIGNONS && cls.state == ca_connected)
+       if (r_speeds.integer)
        {
                // put the location name in the r_speeds display as it greatly helps
                // when creating loc files
                loc = CL_Locs_FindNearest(cl.movement_origin);
                viewleaf = (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.PointInLeaf) ? r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, r_refdef.view.origin) : NULL;
                dpsnprintf(string, sizeof(string),
-"%6.0fus rendertime %3.0f%% viewscale %s%s\n"
+"%6.0fus rendertime %3.0f%% viewscale %s%s %.3f cl.time\n"
 "%3i renders org:'%+8.2f %+8.2f %+8.2f' dir:'%+2.3f %+2.3f %+2.3f'\n"
-"%5i viewleaf%5i cluster%2i area%4i brushes%4i surfaces(%7i triangles)\n"
+"%5i viewleaf%5i cluster%3i area%4i brushes%4i surfaces(%7i triangles)\n"
 "%7i surfaces%7i triangles %5i entities (%7i surfaces%7i triangles)\n"
 "%5i leafs%5i portals%6i/%6i particles%6i/%6i decals %3i%% quality\n"
 "%7i lightmap updates (%7i pixels)%8iKB/%8iKB framedata\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 : ""
+, r_refdef.lastdrawscreentime * 1000000.0, r_viewscale.value * sqrt(viewscalefpsadjusted) * 100.0f, loc ? "Location: " : "", loc ? loc->name : "", cl.time
 , 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
@@ -1791,7 +1791,6 @@ void SCR_DrawScreen (void)
                SCR_DrawPause ();
                if (!r_letterbox.value)
                        Sbar_Draw();
-               Sbar_ShowFPS();
                SHOWLMP_drawall();
                SCR_CheckDrawCenterString();
        }
@@ -1811,11 +1810,9 @@ void SCR_DrawScreen (void)
        if (r_timereport_active)
                R_TimeReport("2d");
 
-       if (cls.signon == SIGNONS)
-       {
-               R_TimeReport_EndFrame();
-               R_TimeReport_BeginFrame();
-       }
+       R_TimeReport_EndFrame();
+       R_TimeReport_BeginFrame();
+       Sbar_ShowFPS();
 
        DrawQ_Finish();
 
@@ -2009,7 +2006,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);
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, true, true);
                R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
 
                // make sure everything is cleared, including the progress indicator
@@ -2042,7 +2039,7 @@ static void SCR_DrawLoadingScreen_SharedSetup (qboolean clear)
        R_Mesh_Start();
        R_EntityMatrix(&identitymatrix);
        // draw the loading plaque
-       loadingscreenpic = Draw_CachePic (loadingscreenpic_number ? va("gfx/loading%d", loadingscreenpic_number+1) : "gfx/loading");
+       loadingscreenpic = Draw_CachePic_Flags (loadingscreenpic_number ? va("gfx/loading%d", loadingscreenpic_number+1) : "gfx/loading", loadingscreenpic_number ? CACHEPICFLAG_NOTPERSISTENT : 0);
 
        w = loadingscreenpic->width;
        h = loadingscreenpic->height;
@@ -2108,11 +2105,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);
+               R_SetupShader_Generic(loadingscreentexture, NULL, GL_MODULATE, 1, 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(loadingscreenpic->tex, NULL, GL_MODULATE, 1);
+       R_SetupShader_Generic(Draw_GetPicTexture(loadingscreenpic), NULL, GL_MODULATE, 1, true, true);
        R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
        SCR_DrawLoadingStack();
 }
@@ -2154,6 +2151,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);
@@ -2170,6 +2171,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
@@ -2280,6 +2282,7 @@ void CL_UpdateScreen(void)
 
        SCR_SetUpToDrawConsole();
 
+#ifndef USE_GLES2
        if (qglDrawBuffer)
        {
                CHECKGLERROR
@@ -2294,6 +2297,7 @@ 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();
@@ -2308,6 +2312,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)
@@ -2334,10 +2339,12 @@ void CL_UpdateScreen(void)
                        qglDisable(GL_POLYGON_STIPPLE);CHECKGLERROR
                }
        }
+#endif
 
        if (r_viewscale_fpsscaling.integer)
                GL_Finish();
        drawscreenstart = Sys_DoubleTime();
+#ifndef USE_GLES2
        if (R_Stereo_Active())
        {
                r_stereo_side = 0;
@@ -2369,6 +2376,7 @@ void CL_UpdateScreen(void)
                SCR_DrawScreen();
        }
        else
+#endif
                SCR_DrawScreen();
        if (r_viewscale_fpsscaling.integer)
                GL_Finish();
index 3e75822706987bc7868e0a59bff62c2018a26bba..095db75e32df2e3f236fedad451003ed10322c74 100644 (file)
@@ -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)
index 55a4983708aa7f5740433bacb1dd268ce23efc20..a652dbc221734955ef5480e630fb9ecd1f5da783 100644 (file)
@@ -143,7 +143,7 @@ void jam_close(void *stream)
        Z_Free(s->prevframedata);
        Z_Free(s->videopixels);
        if (s->sndchan != -1)
-               S_StopChannel(s->sndchan, true);
+               S_StopChannel(s->sndchan, true, true);
        if (s->file)
                FS_Close(s->file);
        Z_Free(s);
@@ -250,7 +250,7 @@ readframe:
                {
                        compsize = LittleLong(*(frameHead + 8)) - 16;
                        outsize = LittleLong(*(frameHead + 12));
-                       if (compsize < 0 || compsize > s->framesize || outsize < 0 || outsize > s->framesize)
+                       if (compsize > s->framesize || outsize > s->framesize)
                                s->error = JAMDECODEERROR_BAD_FRAME_HEADER;
                        else if (FS_Read(s->file, s->compressed, compsize))
                        {
@@ -352,4 +352,4 @@ readframe:
        else
                s->error = DPVSIMPLEDECODEERROR_EOF;
        return s->error;
-}
\ No newline at end of file
+}
index 11f9aa17e2222e2edffe2f86781d7576b7732e50..57d50dd1bcfa3dce58ccd243943370dcd9f9a494 100644 (file)
--- a/client.h
+++ b/client.h
@@ -215,6 +215,10 @@ typedef struct rtlight_s
        int particlecache_maxparticles;
        int particlecache_updateparticle;
        rtlight_particle_t *particlecache_particles;
+
+       /// bouncegrid light info
+       float photoncolor[3];
+       float photons;
 }
 rtlight_t;
 
@@ -291,18 +295,6 @@ typedef struct dlight_s
 }
 dlight_t;
 
-#define MAX_FRAMEGROUPBLENDS 4
-typedef struct framegroupblend_s
-{
-       // animation number and blend factor
-       // (for most models this is the frame number)
-       int frame;
-       float lerp;
-       // time frame began playing (for framegroup animations)
-       double start;
-}
-framegroupblend_t;
-
 // this is derived from processing of the framegroupblend array
 // note: technically each framegroupblend can produce two of these, but that
 // never happens in practice because no one blends between more than 2
@@ -1216,6 +1208,7 @@ typedef struct client_state_s
        float movevars_maxairspeed;
        float movevars_stepheight;
        float movevars_airaccel_qw;
+       float movevars_airaccel_qw_stretchfactor;
        float movevars_airaccel_sideways_friction;
        float movevars_airstopaccelerate;
        float movevars_airstrafeaccelerate;
@@ -1255,8 +1248,11 @@ typedef struct client_state_s
        // server entity number corresponding to a clientside entity
        unsigned short csqc_server2csqcentitynumber[MAX_EDICTS];
        qboolean csqc_loaded;
-       vec3_t csqc_origin;
-       vec3_t csqc_angles;
+       vec3_t csqc_vieworigin;
+       vec3_t csqc_viewangles;
+       vec3_t csqc_vieworiginfromengine;
+       vec3_t csqc_viewanglesfromengine;
+       matrix4x4_t csqc_viewmodelmatrixfromengine;
        qboolean csqc_usecsqclistener;
        matrix4x4_t csqc_listenermatrix;
        char csqc_printtextbuf[MAX_INPUTLINE];
@@ -1274,6 +1270,9 @@ typedef struct client_state_s
        // freed on each level change
        size_t buildlightmapmemorysize;
        unsigned char *buildlightmapmemory;
+
+       // used by EntityState5_ReadUpdate
+       skeleton_t *engineskeletonobjects;
 }
 client_state_t;
 
index b9354fbb599895ee3c2058345b5efdd6fbc1d58b..bee62abdcdd0a4e84d2319315d13928f3ba644ba 100644 (file)
@@ -4,6 +4,7 @@
 #ifndef CLPROGDEFS_H
 #define CLPROGDEFS_H
 
+/*
 typedef struct cl_globalvars_s
 {
        int                     pad[28];
@@ -92,5 +93,6 @@ typedef struct cl_entvars_s
 } cl_entvars_t;
 
 #define CL_PROGHEADER_CRC 52195
+*/
 
 #endif
index ffcff83f7d70760e8fd8b922fc7849fdea8e39b7..d9b8c77d23ceed63a817370961183273df5f4da6 100644 (file)
@@ -34,7 +34,7 @@ void CSQC_RelinkCSQCEntities (void);
 static void VM_CL_makevectors (void)
 {
        VM_SAFEPARMCOUNT(1, VM_CL_makevectors);
-       AngleVectors (PRVM_G_VECTOR(OFS_PARM0), prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up);
+       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
@@ -56,7 +56,7 @@ void VM_CL_setorigin (void)
                return;
        }
        org = PRVM_G_VECTOR(OFS_PARM1);
-       VectorCopy (org, e->fields.client->origin);
+       VectorCopy (org, PRVM_clientedictvector(e, origin));
        CL_LinkEdict(e);
 }
 
@@ -69,9 +69,9 @@ static void SetMinMaxSize (prvm_edict_t *e, float *min, float *max)
                        PRVM_ERROR("SetMinMaxSize: backwards mins/maxs");
 
        // set derived values
-       VectorCopy (min, e->fields.client->mins);
-       VectorCopy (max, e->fields.client->maxs);
-       VectorSubtract (max, min, e->fields.client->size);
+       VectorCopy (min, PRVM_clientedictvector(e, mins));
+       VectorCopy (max, PRVM_clientedictvector(e, maxs));
+       VectorSubtract (max, min, PRVM_clientedictvector(e, size));
 
        CL_LinkEdict (e);
 }
@@ -87,8 +87,8 @@ void VM_CL_setmodel (void)
        VM_SAFEPARMCOUNT(2, VM_CL_setmodel);
 
        e = PRVM_G_EDICT(OFS_PARM0);
-       e->fields.client->modelindex = 0;
-       e->fields.client->model = 0;
+       PRVM_clientedictfloat(e, modelindex) = 0;
+       PRVM_clientedictstring(e, model) = 0;
 
        m = PRVM_G_STRING(OFS_PARM1);
        mod = NULL;
@@ -97,8 +97,8 @@ void VM_CL_setmodel (void)
                if (!strcmp(cl.csqc_model_precache[i]->name, m))
                {
                        mod = cl.csqc_model_precache[i];
-                       e->fields.client->model = PRVM_SetEngineString(mod->name);
-                       e->fields.client->modelindex = -(i+1);
+                       PRVM_clientedictstring(e, model) = PRVM_SetEngineString(mod->name);
+                       PRVM_clientedictfloat(e, modelindex) = -(i+1);
                        break;
                }
        }
@@ -109,8 +109,8 @@ void VM_CL_setmodel (void)
                        mod = cl.model_precache[i];
                        if (mod && !strcmp(mod->name, m))
                        {
-                               e->fields.client->model = PRVM_SetEngineString(mod->name);
-                               e->fields.client->modelindex = i;
+                               PRVM_clientedictstring(e, model) = PRVM_SetEngineString(mod->name);
+                               PRVM_clientedictfloat(e, modelindex) = i;
                                break;
                        }
                }
@@ -161,9 +161,11 @@ static void VM_CL_sound (void)
        prvm_edict_t            *entity;
        float                           volume;
        float                           attenuation;
+       float pitchchange;
+       int flags;
        vec3_t                          org;
 
-       VM_SAFEPARMCOUNT(5, VM_CL_sound);
+       VM_SAFEPARMCOUNTRANGE(5, 7, VM_CL_sound);
 
        entity = PRVM_G_EDICT(OFS_PARM0);
        channel = (int)PRVM_G_FLOAT(OFS_PARM1);
@@ -183,9 +185,22 @@ static void VM_CL_sound (void)
                return;
        }
 
-       if (channel < 0 || channel > 7)
+       if (prog->argc < 6)
+               pitchchange = 0;
+       else
+               pitchchange = PRVM_G_FLOAT(OFS_PARM5);
+       // ignoring prog->argc < 7 for now (no flags supported yet)
+
+       if (prog->argc < 7)
+               flags = 0;
+       else
+               flags = PRVM_G_FLOAT(OFS_PARM6);
+
+       channel = CHAN_USER2ENGINE(channel);
+
+       if (!IS_CHAN(channel))
        {
-               VM_Warning("VM_CL_sound: channel must be in range 0-7\n");
+               VM_Warning("VM_CL_sound: channel must be in range 0-127\n");
                return;
        }
 
@@ -234,10 +249,8 @@ static void VM_CL_spawn (void)
 
 void CL_VM_SetTraceGlobals(const trace_t *trace, int svent)
 {
-       prvm_eval_t *val;
        VM_SetTraceGlobals(trace);
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_networkentity)))
-               val->_float = svent;
+       PRVM_clientglobalfloat(trace_networkentity) = svent;
 }
 
 #define CL_HitNetworkBrushModels(move) !((move) == MOVE_WORLDONLY)
@@ -320,38 +333,35 @@ trace_t CL_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore, int *svent)
        vec3_t original_velocity;
        vec3_t original_angles;
        vec3_t original_avelocity;
-       prvm_eval_t *val;
        trace_t trace;
 
-       VectorCopy(tossent->fields.client->origin   , original_origin   );
-       VectorCopy(tossent->fields.client->velocity , original_velocity );
-       VectorCopy(tossent->fields.client->angles   , original_angles   );
-       VectorCopy(tossent->fields.client->avelocity, original_avelocity);
+       VectorCopy(PRVM_clientedictvector(tossent, origin)   , original_origin   );
+       VectorCopy(PRVM_clientedictvector(tossent, velocity) , original_velocity );
+       VectorCopy(PRVM_clientedictvector(tossent, angles)   , original_angles   );
+       VectorCopy(PRVM_clientedictvector(tossent, avelocity), original_avelocity);
 
-       val = PRVM_EDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity);
-       if (val != NULL && val->_float != 0)
-               gravity = val->_float;
-       else
-               gravity = 1.0;
+       gravity = PRVM_clientedictfloat(tossent, gravity);
+       if (!gravity)
+               gravity = 1.0f;
        gravity *= cl.movevars_gravity * 0.05;
 
        for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
        {
-               tossent->fields.client->velocity[2] -= gravity;
-               VectorMA (tossent->fields.client->angles, 0.05, tossent->fields.client->avelocity, tossent->fields.client->angles);
-               VectorScale (tossent->fields.client->velocity, 0.05, move);
-               VectorAdd (tossent->fields.client->origin, move, end);
-               trace = CL_TraceBox(tossent->fields.client->origin, tossent->fields.client->mins, tossent->fields.client->maxs, end, MOVE_NORMAL, tossent, CL_GenericHitSuperContentsMask(tossent), true, true, NULL, true);
-               VectorCopy (trace.endpos, tossent->fields.client->origin);
+               PRVM_clientedictvector(tossent, velocity)[2] -= gravity;
+               VectorMA (PRVM_clientedictvector(tossent, angles), 0.05, PRVM_clientedictvector(tossent, avelocity), PRVM_clientedictvector(tossent, angles));
+               VectorScale (PRVM_clientedictvector(tossent, velocity), 0.05, move);
+               VectorAdd (PRVM_clientedictvector(tossent, origin), move, end);
+               trace = CL_TraceBox(PRVM_clientedictvector(tossent, origin), PRVM_clientedictvector(tossent, mins), PRVM_clientedictvector(tossent, maxs), end, MOVE_NORMAL, tossent, CL_GenericHitSuperContentsMask(tossent), true, true, NULL, true);
+               VectorCopy (trace.endpos, PRVM_clientedictvector(tossent, origin));
 
                if (trace.fraction < 1)
                        break;
        }
 
-       VectorCopy(original_origin   , tossent->fields.client->origin   );
-       VectorCopy(original_velocity , tossent->fields.client->velocity );
-       VectorCopy(original_angles   , tossent->fields.client->angles   );
-       VectorCopy(original_avelocity, tossent->fields.client->avelocity);
+       VectorCopy(original_origin   , PRVM_clientedictvector(tossent, origin)   );
+       VectorCopy(original_velocity , PRVM_clientedictvector(tossent, velocity) );
+       VectorCopy(original_angles   , PRVM_clientedictvector(tossent, angles)   );
+       VectorCopy(original_avelocity, PRVM_clientedictvector(tossent, avelocity));
 
        return trace;
 }
@@ -428,7 +438,7 @@ int CSQC_EntitiesInBox (vec3_t mins, vec3_t maxs, int maxlist, prvm_edict_t **li
        {
                if (ent->priv.required->free)
                        continue;
-               if(BoxesOverlap(mins, maxs, ent->fields.client->absmin, ent->fields.client->absmax))
+               if(BoxesOverlap(mins, maxs, PRVM_clientedictvector(ent, absmin), PRVM_clientedictvector(ent, absmax)))
                        list[k++] = ent;
        }
        return k;
@@ -477,23 +487,23 @@ static void VM_CL_findradius (void)
                ent = touchedicts[i];
                // Quake did not return non-solid entities but darkplaces does
                // (note: this is the reason you can't blow up fallen zombies)
-               if (ent->fields.client->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
+               if (PRVM_clientedictfloat(ent, solid) == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
                        continue;
                // LordHavoc: compare against bounding box rather than center so it
                // doesn't miss large objects, and use DotProduct instead of Length
                // for a major speedup
-               VectorSubtract(org, ent->fields.client->origin, eorg);
+               VectorSubtract(org, PRVM_clientedictvector(ent, origin), eorg);
                if (sv_gameplayfix_findradiusdistancetobox.integer)
                {
-                       eorg[0] -= bound(ent->fields.client->mins[0], eorg[0], ent->fields.client->maxs[0]);
-                       eorg[1] -= bound(ent->fields.client->mins[1], eorg[1], ent->fields.client->maxs[1]);
-                       eorg[2] -= bound(ent->fields.client->mins[2], eorg[2], ent->fields.client->maxs[2]);
+                       eorg[0] -= bound(PRVM_clientedictvector(ent, mins)[0], eorg[0], PRVM_clientedictvector(ent, maxs)[0]);
+                       eorg[1] -= bound(PRVM_clientedictvector(ent, mins)[1], eorg[1], PRVM_clientedictvector(ent, maxs)[1]);
+                       eorg[2] -= bound(PRVM_clientedictvector(ent, mins)[2], eorg[2], PRVM_clientedictvector(ent, maxs)[2]);
                }
                else
-                       VectorMAMAM(1, eorg, -0.5f, ent->fields.client->mins, -0.5f, ent->fields.client->maxs, eorg);
+                       VectorMAMAM(1, eorg, -0.5f, PRVM_clientedictvector(ent, mins), -0.5f, PRVM_clientedictvector(ent, maxs), eorg);
                if (DotProduct(eorg, eorg) < radius2)
                {
-                       PRVM_EDICTFIELDVALUE(ent, chainfield)->edict = PRVM_EDICT_TO_PROG(chain);
+                       PRVM_EDICTFIELDEDICT(ent, chainfield) = PRVM_EDICT_TO_PROG(chain);
                        chain = ent;
                }
        }
@@ -505,7 +515,6 @@ static void VM_CL_findradius (void)
 static void VM_CL_droptofloor (void)
 {
        prvm_edict_t            *ent;
-       prvm_eval_t                     *val;
        vec3_t                          end;
        trace_t                         trace;
 
@@ -514,7 +523,7 @@ static void VM_CL_droptofloor (void)
        // assume failure if it returns early
        PRVM_G_FLOAT(OFS_RETURN) = 0;
 
-       ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
+       ent = PRVM_PROG_TO_EDICT(PRVM_clientglobaledict(self));
        if (ent == prog->edicts)
        {
                VM_Warning("droptofloor: can not modify world entity\n");
@@ -526,17 +535,16 @@ static void VM_CL_droptofloor (void)
                return;
        }
 
-       VectorCopy (ent->fields.client->origin, end);
+       VectorCopy (PRVM_clientedictvector(ent, origin), end);
        end[2] -= 256;
 
-       trace = CL_TraceBox(ent->fields.client->origin, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+       trace = CL_TraceBox(PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, mins), PRVM_clientedictvector(ent, maxs), end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
 
        if (trace.fraction != 1)
        {
-               VectorCopy (trace.endpos, ent->fields.client->origin);
-               ent->fields.client->flags = (int)ent->fields.client->flags | FL_ONGROUND;
-               if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
-                       val->edict = PRVM_EDICT_TO_PROG(trace.ent);
+               VectorCopy (trace.endpos, PRVM_clientedictvector(ent, origin));
+               PRVM_clientedictfloat(ent, flags) = (int)PRVM_clientedictfloat(ent, flags) | FL_ONGROUND;
+               PRVM_clientedictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
                PRVM_G_FLOAT(OFS_RETURN) = 1;
                // if support is destroyed, keep suspended (gross hack for floating items in various maps)
 //             ent->priv.server->suspendedinairflag = true;
@@ -577,8 +585,8 @@ static void VM_CL_checkbottom (void)
        ent = PRVM_G_EDICT(OFS_PARM0);
        PRVM_G_FLOAT(OFS_RETURN) = 0;
 
-       VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
-       VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
+       VectorAdd (PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, mins), mins);
+       VectorAdd (PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, maxs), maxs);
 
 // if all of the points under the corners are solid world, don't bother
 // with the tougher checks
@@ -690,11 +698,14 @@ static void VM_CL_getlight (void)
 //[515]: SCENE MANAGER builtins
 extern qboolean CSQC_AddRenderEdict (prvm_edict_t *ed, int edictnum);//csprogs.c
 
-static void CSQC_R_RecalcView (void)
+void CSQC_R_RecalcView (void)
 {
-       extern matrix4x4_t viewmodelmatrix;
-       Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], 1);
-       Matrix4x4_CreateFromQuakeEntity(&viewmodelmatrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], cl_viewmodel_scale.value);
+       extern matrix4x4_t viewmodelmatrix_nobob;
+       extern matrix4x4_t viewmodelmatrix_withbob;
+       Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, cl.csqc_vieworigin[0], cl.csqc_vieworigin[1], cl.csqc_vieworigin[2], cl.csqc_viewangles[0], cl.csqc_viewangles[1], cl.csqc_viewangles[2], 1);
+       Matrix4x4_Copy(&viewmodelmatrix_nobob, &r_refdef.view.matrix);
+       Matrix4x4_ConcatScale(&viewmodelmatrix_nobob, cl_viewmodel_scale.value);
+       Matrix4x4_Concat(&viewmodelmatrix_withbob, &r_refdef.view.matrix, &cl.csqc_viewmodelmatrixfromengine);
 }
 
 void CL_RelinkLightFlashes(void);
@@ -722,11 +733,12 @@ void VM_CL_R_ClearScene (void)
        r_refdef.view.ortho_y = scr_fov.value * (3.0 / 4.0);
        r_refdef.view.clear = true;
        r_refdef.view.isoverlay = false;
-       // FIXME: restore cl.csqc_origin
-       // FIXME: restore cl.csqc_angles
+       VectorCopy(cl.csqc_vieworiginfromengine, cl.csqc_vieworigin);
+       VectorCopy(cl.csqc_viewanglesfromengine, cl.csqc_viewangles);
        cl.csqc_vidvars.drawworld = r_drawworld.integer != 0;
        cl.csqc_vidvars.drawenginesbar = false;
        cl.csqc_vidvars.drawcrosshair = false;
+       CSQC_R_RecalcView();
 }
 
 //#301 void(float mask) addentities (EXT_CSQC)
@@ -742,7 +754,7 @@ void VM_CL_R_AddEntities (void)
        CSQC_RelinkAllEntities(drawmask);
        CL_RelinkLightFlashes();
 
-       prog->globals.client->time = cl.time;
+       PRVM_clientglobalfloat(time) = cl.time;
        for(i=1;i<prog->num_edicts;i++)
        {
                // so we can easily check if CSQC entity #edictnum is currently drawn
@@ -757,13 +769,13 @@ void VM_CL_R_AddEntities (void)
                CSQC_Predraw(ed);
                if(ed->priv.required->free)
                        continue;
-               if(!((int)ed->fields.client->drawmask & drawmask))
+               if(!((int)PRVM_clientedictfloat(ed, drawmask) & drawmask))
                        continue;
                CSQC_AddRenderEdict(ed, i);
        }
 
        // callprofile fixing hack: do not include this time in what is counted for CSQC_UpdateView
-       prog->functions[prog->funcoffsets.CSQC_UpdateView].totaltime -= Sys_DoubleTime() - t;
+       prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= Sys_DoubleTime() - t;
 }
 
 //#302 void(entity ent) addentity (EXT_CSQC)
@@ -772,12 +784,14 @@ void VM_CL_R_AddEntity (void)
        double t = Sys_DoubleTime();
        VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
        CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0), 0);
-       prog->functions[prog->funcoffsets.CSQC_UpdateView].totaltime -= Sys_DoubleTime() - t;
+       prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= Sys_DoubleTime() - 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)
 {
@@ -825,28 +839,28 @@ void VM_CL_R_SetView (void)
                        PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.ortho_y;
                        break;
                case VF_ORIGIN:
-                       VectorCopy(cl.csqc_origin, PRVM_G_VECTOR(OFS_RETURN));
+                       VectorCopy(cl.csqc_vieworigin, PRVM_G_VECTOR(OFS_RETURN));
                        break;
                case VF_ORIGIN_X:
-                       PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_origin[0];
+                       PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vieworigin[0];
                        break;
                case VF_ORIGIN_Y:
-                       PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_origin[1];
+                       PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vieworigin[1];
                        break;
                case VF_ORIGIN_Z:
-                       PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_origin[2];
+                       PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vieworigin[2];
                        break;
                case VF_ANGLES:
-                       VectorCopy(cl.csqc_angles, PRVM_G_VECTOR(OFS_RETURN));
+                       VectorCopy(cl.csqc_viewangles, PRVM_G_VECTOR(OFS_RETURN));
                        break;
                case VF_ANGLES_X:
-                       PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_angles[0];
+                       PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_viewangles[0];
                        break;
                case VF_ANGLES_Y:
-                       PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_angles[1];
+                       PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_viewangles[1];
                        break;
                case VF_ANGLES_Z:
-                       PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_angles[2];
+                       PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_viewangles[2];
                        break;
                case VF_DRAWWORLD:
                        PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vidvars.drawworld;
@@ -932,35 +946,35 @@ void VM_CL_R_SetView (void)
                r_refdef.view.frustum_y = tan(k * M_PI / 360.0);r_refdef.view.ortho_y = k;
                break;
        case VF_ORIGIN:
-               VectorCopy(f, cl.csqc_origin);
+               VectorCopy(f, cl.csqc_vieworigin);
                CSQC_R_RecalcView();
                break;
        case VF_ORIGIN_X:
-               cl.csqc_origin[0] = k;
+               cl.csqc_vieworigin[0] = k;
                CSQC_R_RecalcView();
                break;
        case VF_ORIGIN_Y:
-               cl.csqc_origin[1] = k;
+               cl.csqc_vieworigin[1] = k;
                CSQC_R_RecalcView();
                break;
        case VF_ORIGIN_Z:
-               cl.csqc_origin[2] = k;
+               cl.csqc_vieworigin[2] = k;
                CSQC_R_RecalcView();
                break;
        case VF_ANGLES:
-               VectorCopy(f, cl.csqc_angles);
+               VectorCopy(f, cl.csqc_viewangles);
                CSQC_R_RecalcView();
                break;
        case VF_ANGLES_X:
-               cl.csqc_angles[0] = k;
+               cl.csqc_viewangles[0] = k;
                CSQC_R_RecalcView();
                break;
        case VF_ANGLES_Y:
-               cl.csqc_angles[1] = k;
+               cl.csqc_viewangles[1] = k;
                CSQC_R_RecalcView();
                break;
        case VF_ANGLES_Z:
-               cl.csqc_angles[2] = k;
+               cl.csqc_viewangles[2] = k;
                CSQC_R_RecalcView();
                break;
        case VF_DRAWWORLD:
@@ -1041,14 +1055,14 @@ void VM_CL_R_AddDynamicLight (void)
        coronaintensity = (pflags & PFLAGS_CORONA) != 0;
        castshadow = (pflags & PFLAGS_NOSHADOW) == 0;
 
-       VectorScale(prog->globals.client->v_forward, radius, forward);
-       VectorScale(prog->globals.client->v_right, -radius, left);
-       VectorScale(prog->globals.client->v_up, radius, up);
+       VectorScale(PRVM_clientglobalvector(v_forward), radius, forward);
+       VectorScale(PRVM_clientglobalvector(v_right), -radius, left);
+       VectorScale(PRVM_clientglobalvector(v_up), radius, up);
        Matrix4x4_FromVectors(&matrix, forward, left, up, org);
 
        R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &matrix, col, style, cubemapname, castshadow, coronaintensity, coronasizescale, ambientscale, diffusescale, specularscale, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
        r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights];r_refdef.scene.numlights++;
-       prog->functions[prog->funcoffsets.CSQC_UpdateView].totaltime -= Sys_DoubleTime() - t;
+       prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= Sys_DoubleTime() - t;
 }
 
 //============================================================================
@@ -1176,8 +1190,8 @@ static void VM_CL_setmodelindex (void)
 
        i = (int)PRVM_G_FLOAT(OFS_PARM1);
 
-       t->fields.client->model = 0;
-       t->fields.client->modelindex = 0;
+       PRVM_clientedictstring(t, model) = 0;
+       PRVM_clientedictfloat(t, modelindex) = 0;
 
        if (!i)
                return;
@@ -1188,8 +1202,8 @@ static void VM_CL_setmodelindex (void)
                VM_Warning("VM_CL_setmodelindex: null model\n");
                return;
        }
-       t->fields.client->model = PRVM_SetEngineString(model->name);
-       t->fields.client->modelindex = i;
+       PRVM_clientedictstring(t, model) = PRVM_SetEngineString(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)
@@ -1238,7 +1252,7 @@ static void VM_CL_trailparticles (void)
 
        if (i < 0)
                return;
-       CL_ParticleEffect(i, 1, start, end, t->fields.client->velocity, t->fields.client->velocity, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
+       CL_ParticleEffect(i, 1, start, end, PRVM_clientedictvector(t, velocity), PRVM_clientedictvector(t, velocity), NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
 }
 
 //#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC)
@@ -1266,7 +1280,6 @@ static void VM_CL_boxparticles (void)
        float count;
        int flags;
        float tintmins[4], tintmaxs[4];
-       prvm_eval_t *val;
        VM_SAFEPARMCOUNTRANGE(7, 8, VM_CL_boxparticles);
 
        effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
@@ -1284,17 +1297,13 @@ static void VM_CL_boxparticles (void)
        Vector4Set(tintmaxs, 1, 1, 1, 1);
        if(flags & 1) // read alpha
        {
-               if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.particles_alphamin)))
-                       tintmins[3] = val->_float;
-               if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.particles_alphamax)))
-                       tintmaxs[3] = val->_float;
+               tintmins[3] = PRVM_clientglobalfloat(particles_alphamin);
+               tintmaxs[3] = PRVM_clientglobalfloat(particles_alphamax);
        }
        if(flags & 2) // read color
        {
-               if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.particles_colormin)))
-                       VectorCopy(val->vector, tintmins);
-               if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.particles_colormax)))
-                       VectorCopy(val->vector, tintmaxs);
+               VectorCopy(PRVM_clientglobalvector(particles_colormin), tintmins);
+               VectorCopy(PRVM_clientglobalvector(particles_colormax), tintmaxs);
        }
        if (effectnum < 0)
                return;
@@ -1311,7 +1320,7 @@ static void VM_CL_setpause(void)
                cl.csqc_paused = false;
 }
 
-//#343 void(float usecursor) setcursormode (EXT_CSQC)
+//#343 void(float usecursor) setcursormode (DP_CSQC)
 static void VM_CL_setcursormode (void)
 {
        VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
@@ -1319,7 +1328,7 @@ static void VM_CL_setcursormode (void)
        cl_ignoremousemoves = 2;
 }
 
-//#344 vector() getmousepos (EXT_CSQC)
+//#344 vector() getmousepos (DP_CSQC)
 static void VM_CL_getmousepos(void)
 {
        VM_SAFEPARMCOUNT(0,VM_CL_getmousepos);
@@ -1343,21 +1352,21 @@ static void VM_CL_getinputstate (void)
        {
                if (cl.movecmd[i].sequence == frame)
                {
-                       VectorCopy(cl.movecmd[i].viewangles, prog->globals.client->input_angles);
-                       prog->globals.client->input_buttons = cl.movecmd[i].buttons; // FIXME: this should not be directly exposed to csqc (translation layer needed?)
-                       prog->globals.client->input_movevalues[0] = cl.movecmd[i].forwardmove;
-                       prog->globals.client->input_movevalues[1] = cl.movecmd[i].sidemove;
-                       prog->globals.client->input_movevalues[2] = cl.movecmd[i].upmove;
-                       prog->globals.client->input_timelength = cl.movecmd[i].frametime;
+                       VectorCopy(cl.movecmd[i].viewangles, PRVM_clientglobalvector(input_angles));
+                       PRVM_clientglobalfloat(input_buttons) = cl.movecmd[i].buttons; // FIXME: this should not be directly exposed to csqc (translation layer needed?)
+                       PRVM_clientglobalvector(input_movevalues)[0] = cl.movecmd[i].forwardmove;
+                       PRVM_clientglobalvector(input_movevalues)[1] = cl.movecmd[i].sidemove;
+                       PRVM_clientglobalvector(input_movevalues)[2] = cl.movecmd[i].upmove;
+                       PRVM_clientglobalfloat(input_timelength) = cl.movecmd[i].frametime;
                        if(cl.movecmd[i].crouch)
                        {
-                               VectorCopy(cl.playercrouchmins, prog->globals.client->pmove_mins);
-                               VectorCopy(cl.playercrouchmaxs, prog->globals.client->pmove_maxs);
+                               VectorCopy(cl.playercrouchmins, PRVM_clientglobalvector(pmove_mins));
+                               VectorCopy(cl.playercrouchmaxs, PRVM_clientglobalvector(pmove_maxs));
                        }
                        else
                        {
-                               VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
-                               VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
+                               VectorCopy(cl.playerstandmins, PRVM_clientglobalvector(pmove_mins));
+                               VectorCopy(cl.playerstandmaxs, PRVM_clientglobalvector(pmove_maxs));
                        }
                        PRVM_G_FLOAT(OFS_RETURN) = true;
                }
@@ -1426,6 +1435,20 @@ static void VM_CL_getplayerkey (void)
        else
                if(!strcasecmp(c, "viewentity"))
                        dpsnprintf(t, sizeof(t), "%i", i+1);
+       else
+               if(gamemode == GAME_XONOTIC && !strcasecmp(c, "TEMPHACK_origin"))
+               {
+                       // PLEASE REMOVE THIS once deltalisten() of EXT_CSQC_1
+                       // is implemented, or Xonotic uses CSQC-networked
+                       // players, whichever comes first
+                       entity_t *e = cl.entities + (i+1);
+                       if(e->state_current.active)
+                       {
+                               vec3_t origin;
+                               Matrix4x4_OriginFromMatrix(&e->render.matrix, origin);
+                               dpsnprintf(t, sizeof(t), "%.9g %.9g %.9g", origin[0], origin[1], origin[2]);
+                       }
+               }
        if(!t[0])
                return;
        PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
@@ -1586,40 +1609,42 @@ static void VM_CL_makestatic (void)
        if (cl.num_static_entities < cl.max_static_entities)
        {
                int renderflags;
-               prvm_eval_t *val;
                entity_t *staticent = &cl.static_entities[cl.num_static_entities++];
 
                // copy it to the current state
                memset(staticent, 0, sizeof(*staticent));
-               staticent->render.model = CL_GetModelByIndex((int)ent->fields.client->modelindex);
-               staticent->render.framegroupblend[0].frame = (int)ent->fields.client->frame;
+               staticent->render.model = CL_GetModelByIndex((int)PRVM_clientedictfloat(ent, modelindex));
+               staticent->render.framegroupblend[0].frame = (int)PRVM_clientedictfloat(ent, frame);
                staticent->render.framegroupblend[0].lerp = 1;
                // make torchs play out of sync
                staticent->render.framegroupblend[0].start = lhrandom(-10, -1);
-               staticent->render.skinnum = (int)ent->fields.client->skin;
-               staticent->render.effects = (int)ent->fields.client->effects;
-               staticent->render.alpha = 1;
-               if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)) && val->_float) staticent->render.alpha = val->_float;
-               staticent->render.scale = 1;
-               if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)) && val->_float) staticent->render.scale = val->_float;
-               if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.colormod);
-               if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glowmod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.glowmod);
+               staticent->render.skinnum = (int)PRVM_clientedictfloat(ent, skin);
+               staticent->render.effects = (int)PRVM_clientedictfloat(ent, effects);
+               staticent->render.alpha = PRVM_clientedictfloat(ent, alpha);
+               staticent->render.scale = PRVM_clientedictfloat(ent, scale);
+               VectorCopy(PRVM_clientedictvector(ent, colormod), staticent->render.colormod);
+               VectorCopy(PRVM_clientedictvector(ent, glowmod), staticent->render.glowmod);
+
+               // sanitize values
+               if (!staticent->render.alpha)
+                       staticent->render.alpha = 1.0f;
+               if (!staticent->render.scale)
+                       staticent->render.scale = 1.0f;
                if (!VectorLength2(staticent->render.colormod))
                        VectorSet(staticent->render.colormod, 1, 1, 1);
                if (!VectorLength2(staticent->render.glowmod))
                        VectorSet(staticent->render.glowmod, 1, 1, 1);
 
-               renderflags = 0;
-               if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && val->_float) renderflags = (int)val->_float;
+               renderflags = (int)PRVM_clientedictfloat(ent, renderflags);
                if (renderflags & RF_USEAXIS)
                {
                        vec3_t left;
-                       VectorNegate(prog->globals.client->v_right, left);
-                       Matrix4x4_FromVectors(&staticent->render.matrix, prog->globals.client->v_forward, left, prog->globals.client->v_up, ent->fields.client->origin);
+                       VectorNegate(PRVM_clientglobalvector(v_right), left);
+                       Matrix4x4_FromVectors(&staticent->render.matrix, PRVM_clientglobalvector(v_forward), left, PRVM_clientglobalvector(v_up), PRVM_clientedictvector(ent, origin));
                        Matrix4x4_Scale(&staticent->render.matrix, staticent->render.scale, 1);
                }
                else
-                       Matrix4x4_CreateFromQuakeEntity(&staticent->render.matrix, ent->fields.client->origin[0], ent->fields.client->origin[1], ent->fields.client->origin[2], ent->fields.client->angles[0], ent->fields.client->angles[1], ent->fields.client->angles[2], staticent->render.scale);
+                       Matrix4x4_CreateFromQuakeEntity(&staticent->render.matrix, PRVM_clientedictvector(ent, origin)[0], PRVM_clientedictvector(ent, origin)[1], PRVM_clientedictvector(ent, origin)[2], PRVM_clientedictvector(ent, angles)[0], PRVM_clientedictvector(ent, angles)[1], PRVM_clientedictvector(ent, angles)[2], staticent->render.scale);
 
                // either fullbright or lit
                if(!r_fullbright.integer)
@@ -1686,7 +1711,7 @@ static void VM_CL_copyentity (void)
                VM_Warning("copyentity: can not modify free entity\n");
                return;
        }
-       memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
+       memcpy(out->fields.vp, in->fields.vp, prog->entityfields * 4);
        CL_LinkEdict(out);
 }
 
@@ -2100,8 +2125,8 @@ void VM_CL_setattachment (void)
        prvm_edict_t *e;
        prvm_edict_t *tagentity;
        const char *tagname;
-       prvm_eval_t *v;
        int modelindex;
+       int tagindex;
        dp_model_t *model;
        VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
 
@@ -2123,26 +2148,23 @@ void VM_CL_setattachment (void)
        if (tagentity == NULL)
                tagentity = prog->edicts;
 
-       v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
-       if (v)
-               v->edict = PRVM_EDICT_TO_PROG(tagentity);
-
-       v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
-       if (v)
-               v->_float = 0;
+       tagindex = 0;
        if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
        {
-               modelindex = (int)tagentity->fields.client->modelindex;
+               modelindex = (int)PRVM_clientedictfloat(tagentity, modelindex);
                model = CL_GetModelByIndex(modelindex);
                if (model)
                {
-                       v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.client->skin, tagname);
-                       if (v->_float == 0)
+                       tagindex = Mod_Alias_GetTagIndexForName(model, (int)PRVM_clientedictfloat(tagentity, skin), tagname);
+                       if (tagindex == 0)
                                Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity), model->name);
                }
                else
                        Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity));
        }
+
+       PRVM_clientedictedict(e, tag_entity) = PRVM_EDICT_TO_PROG(tagentity);
+       PRVM_clientedictfloat(e, tag_index) = tagindex;
 }
 
 /////////////////////////////////////////
@@ -2152,7 +2174,7 @@ int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
 {
        dp_model_t *model = CL_GetModelFromEdict(e);
        if (model)
-               return Mod_Alias_GetTagIndexForName(model, (int)e->fields.client->skin, tagname);
+               return Mod_Alias_GetTagIndexForName(model, (int)PRVM_clientedictfloat(e, skin), tagname);
        else
                return -1;
 }
@@ -2170,7 +2192,7 @@ int CL_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, cons
         && (model = CL_GetModelFromEdict(e))
         && model->animscenes)
        {
-               r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)e->fields.client->skin, e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
+               r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)PRVM_clientedictfloat(e, skin), e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
 
                if(!r) // success?
                        *parentindex += 1;
@@ -2191,22 +2213,31 @@ int CL_GetPitchSign(prvm_edict_t *ent)
 
 void CL_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
 {
-       prvm_eval_t *val;
        float scale;
        float pitchsign = 1;
 
-       scale = 1;
-       val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
-       if (val && val->_float != 0)
-               scale = val->_float;
+       scale = PRVM_clientedictfloat(ent, scale);
+       if (!scale)
+               scale = 1.0f;
 
-       // TODO do we need the same weird angle inverting logic here as in the server side case?
        if(viewmatrix)
-               Matrix4x4_CreateFromQuakeEntity(out, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], scale * cl_viewmodel_scale.value);
+               *out = r_refdef.view.matrix;
+       else if ((int)PRVM_clientedictfloat(ent, renderflags) & RF_USEAXIS)
+       {
+               vec3_t forward;
+               vec3_t left;
+               vec3_t up;
+               vec3_t origin;
+               VectorScale(PRVM_clientglobalvector(v_forward), scale, forward);
+               VectorScale(PRVM_clientglobalvector(v_right), -scale, left);
+               VectorScale(PRVM_clientglobalvector(v_up), scale, up);
+               VectorCopy(PRVM_clientedictvector(ent, origin), origin);
+               Matrix4x4_FromVectors(out, forward, left, up, origin);
+       }
        else
        {
                pitchsign = CL_GetPitchSign(ent);
-               Matrix4x4_CreateFromQuakeEntity(out, ent->fields.client->origin[0], ent->fields.client->origin[1], ent->fields.client->origin[2], pitchsign * ent->fields.client->angles[0], ent->fields.client->angles[1], ent->fields.client->angles[2], scale);
+               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);
        }
 }
 
@@ -2239,7 +2270,6 @@ extern cvar_t cl_bobup;
 int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
 {
        int ret;
-       prvm_eval_t *val;
        int attachloop;
        matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
        dp_model_t *model;
@@ -2270,10 +2300,10 @@ int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
                Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
                Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
                // next iteration we process the parent entity
-               if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
+               if (PRVM_clientedictedict(ent, tag_entity))
                {
-                       tagindex = (int)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
-                       ent = PRVM_EDICT_NUM(val->edict);
+                       tagindex = (int)PRVM_clientedictfloat(ent, tag_index);
+                       ent = PRVM_EDICT_NUM(PRVM_clientedictedict(ent, tag_entity));
                }
                else
                        break;
@@ -2281,7 +2311,7 @@ int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
        }
 
        // RENDER_VIEWMODEL magic
-       if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float))
+       if ((int)PRVM_clientedictfloat(ent, renderflags) & RF_VIEWMODEL)
        {
                Matrix4x4_Copy(&tagmatrix, out);
 
@@ -2290,7 +2320,7 @@ int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
 
                /*
                // Cl_bob, ported from rendering code
-               if (ent->fields.client->health > 0 && cl_bob.value && cl_bobcycle.value)
+               if (PRVM_clientedictfloat(ent, health) > 0 && cl_bob.value && cl_bobcycle.value)
                {
                        double bob, cycle;
                        // LordHavoc: this code is *weird*, but not replacable (I think it
@@ -2305,7 +2335,7 @@ int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
                                cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
                        // bob is proportional to velocity in the xy plane
                        // (don't count Z, or jumping messes it up)
-                       bob = sqrt(ent->fields.client->velocity[0]*ent->fields.client->velocity[0] + ent->fields.client->velocity[1]*ent->fields.client->velocity[1])*cl_bob.value;
+                       bob = sqrt(PRVM_clientedictvector(ent, velocity)[0]*PRVM_clientedictvector(ent, velocity)[0] + PRVM_clientedictvector(ent, velocity)[1]*PRVM_clientedictvector(ent, velocity)[1])*cl_bob.value;
                        bob = bob*0.3 + bob*0.7*cycle;
                        Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
                }
@@ -2358,7 +2388,6 @@ void VM_CL_gettaginfo (void)
        int parentindex;
        const char *tagname;
        int returncode;
-       prvm_eval_t *val;
        vec3_t fo, le, up, trans;
        const dp_model_t *model;
 
@@ -2367,8 +2396,8 @@ 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);
-       Matrix4x4_ToVectors(&tag_matrix, prog->globals.client->v_forward, le, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
-       VectorScale(le, -1, prog->globals.client->v_right);
+       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_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model);
@@ -2376,18 +2405,12 @@ void VM_CL_gettaginfo (void)
        CL_GetExtendedTagInfo(e, tagindex, &parentindex, &tagname, &tag_localmatrix);
        Matrix4x4_ToVectors(&tag_localmatrix, fo, le, up, trans);
 
-       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_parent)))
-               val->_float = parentindex;
-       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_name)))
-               val->string = tagname ? PRVM_SetTempString(tagname) : 0;
-       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_offset)))
-               VectorCopy(trans, val->vector);
-       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_forward)))
-               VectorCopy(fo, val->vector);
-       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_right)))
-               VectorScale(le, -1, val->vector);
-       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_up)))
-               VectorCopy(up, val->vector);
+       PRVM_clientglobalfloat(gettaginfo_parent) = parentindex;
+       PRVM_clientglobalstring(gettaginfo_name) = tagname ? PRVM_SetTempString(tagname) : 0;
+       VectorCopy(trans, PRVM_clientglobalvector(gettaginfo_offset));
+       VectorCopy(fo, PRVM_clientglobalvector(gettaginfo_forward));
+       VectorScale(le, -1, PRVM_clientglobalvector(gettaginfo_right));
+       VectorCopy(up, PRVM_clientglobalvector(gettaginfo_up));
 
        switch(returncode)
        {
@@ -2494,8 +2517,6 @@ vmparticlespawner_t vmpartspawner;
 // TODO: automatic max_themes grow
 static void VM_InitParticleSpawner (int maxthemes)
 {
-       prvm_eval_t *val;
-
        // bound max themes to not be an insane value
        if (maxthemes < 4)
                maxthemes = 4;
@@ -2513,37 +2534,35 @@ static void VM_InitParticleSpawner (int maxthemes)
        vmpartspawner.initialized = true;
        vmpartspawner.verified = true;
        // get field addresses for fast querying (we can do 1000 calls of spawnparticle in a frame)
-       #define getglobal(v,s) val = PRVM_GLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset(s)); if (val) { vmpartspawner.v = &val->_float; } else { VM_Warning("VM_InitParticleSpawner: missing global '%s', spawner cannot work\n", s); vmpartspawner.verified = false; }
-       #define getglobalvector(v,s) val = PRVM_GLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset(s)); if (val) { vmpartspawner.v = (float *)val->vector; } else { VM_Warning("VM_InitParticleSpawner: missing global '%s', spawner cannot work\n", s); vmpartspawner.verified = false; }
-       getglobal(particle_type, "particle_type");
-       getglobal(particle_blendmode, "particle_blendmode");
-       getglobal(particle_orientation, "particle_orientation");
-       getglobalvector(particle_color1, "particle_color1");
-       getglobalvector(particle_color2, "particle_color2");
-       getglobal(particle_tex, "particle_tex");
-       getglobal(particle_size, "particle_size");
-       getglobal(particle_sizeincrease, "particle_sizeincrease");
-       getglobal(particle_alpha, "particle_alpha");
-       getglobal(particle_alphafade, "particle_alphafade");
-       getglobal(particle_time, "particle_time");
-       getglobal(particle_gravity, "particle_gravity");
-       getglobal(particle_bounce, "particle_bounce");
-       getglobal(particle_airfriction, "particle_airfriction");
-       getglobal(particle_liquidfriction, "particle_liquidfriction");
-       getglobal(particle_originjitter, "particle_originjitter");
-       getglobal(particle_velocityjitter, "particle_velocityjitter");
-       getglobal(particle_qualityreduction, "particle_qualityreduction");
-       getglobal(particle_stretch, "particle_stretch");
-       getglobalvector(particle_staincolor1, "particle_staincolor1");
-       getglobalvector(particle_staincolor2, "particle_staincolor2");
-       getglobal(particle_stainalpha, "particle_stainalpha");
-       getglobal(particle_stainsize, "particle_stainsize");
-       getglobal(particle_staintex, "particle_staintex");
-       getglobal(particle_staintex, "particle_staintex");
-       getglobal(particle_delayspawn, "particle_delayspawn");
-       getglobal(particle_delaycollision, "particle_delaycollision");
-       getglobal(particle_angle, "particle_angle");
-       getglobal(particle_spin, "particle_spin");
+       vmpartspawner.particle_type = &PRVM_clientglobalfloat(particle_type);
+       vmpartspawner.particle_blendmode = &PRVM_clientglobalfloat(particle_blendmode);
+       vmpartspawner.particle_orientation = &PRVM_clientglobalfloat(particle_orientation);
+       vmpartspawner.particle_color1 = PRVM_clientglobalvector(particle_color1);
+       vmpartspawner.particle_color2 = PRVM_clientglobalvector(particle_color2);
+       vmpartspawner.particle_tex = &PRVM_clientglobalfloat(particle_tex);
+       vmpartspawner.particle_size = &PRVM_clientglobalfloat(particle_size);
+       vmpartspawner.particle_sizeincrease = &PRVM_clientglobalfloat(particle_sizeincrease);
+       vmpartspawner.particle_alpha = &PRVM_clientglobalfloat(particle_alpha);
+       vmpartspawner.particle_alphafade = &PRVM_clientglobalfloat(particle_alphafade);
+       vmpartspawner.particle_time = &PRVM_clientglobalfloat(particle_time);
+       vmpartspawner.particle_gravity = &PRVM_clientglobalfloat(particle_gravity);
+       vmpartspawner.particle_bounce = &PRVM_clientglobalfloat(particle_bounce);
+       vmpartspawner.particle_airfriction = &PRVM_clientglobalfloat(particle_airfriction);
+       vmpartspawner.particle_liquidfriction = &PRVM_clientglobalfloat(particle_liquidfriction);
+       vmpartspawner.particle_originjitter = &PRVM_clientglobalfloat(particle_originjitter);
+       vmpartspawner.particle_velocityjitter = &PRVM_clientglobalfloat(particle_velocityjitter);
+       vmpartspawner.particle_qualityreduction = &PRVM_clientglobalfloat(particle_qualityreduction);
+       vmpartspawner.particle_stretch = &PRVM_clientglobalfloat(particle_stretch);
+       vmpartspawner.particle_staincolor1 = PRVM_clientglobalvector(particle_staincolor1);
+       vmpartspawner.particle_staincolor2 = PRVM_clientglobalvector(particle_staincolor2);
+       vmpartspawner.particle_stainalpha = &PRVM_clientglobalfloat(particle_stainalpha);
+       vmpartspawner.particle_stainsize = &PRVM_clientglobalfloat(particle_stainsize);
+       vmpartspawner.particle_staintex = &PRVM_clientglobalfloat(particle_staintex);
+       vmpartspawner.particle_staintex = &PRVM_clientglobalfloat(particle_staintex);
+       vmpartspawner.particle_delayspawn = &PRVM_clientglobalfloat(particle_delayspawn);
+       vmpartspawner.particle_delaycollision = &PRVM_clientglobalfloat(particle_delaycollision);
+       vmpartspawner.particle_angle = &PRVM_clientglobalfloat(particle_angle);
+       vmpartspawner.particle_spin = &PRVM_clientglobalfloat(particle_spin);
        #undef getglobal
        #undef getglobalvector
 }
@@ -2917,7 +2936,7 @@ void VM_CL_GetEntity (void)
                        PRVM_G_FLOAT(OFS_RETURN) = Matrix4x4_ScaleFromMatrix(&cl.entities[entnum].render.matrix);
                        break;  
                case 6: // origin + v_forward, v_right, v_up
-                       Matrix4x4_ToVectors(&cl.entities[entnum].render.matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN)); 
+                       Matrix4x4_ToVectors(&cl.entities[entnum].render.matrix, PRVM_clientglobalvector(v_forward), PRVM_clientglobalvector(v_right), PRVM_clientglobalvector(v_up), PRVM_G_VECTOR(OFS_RETURN));        
                        break;  
                case 7: // alpha
                        PRVM_G_FLOAT(OFS_RETURN) = cl.entities[entnum].render.alpha;
@@ -3022,7 +3041,7 @@ void VM_CL_R_RenderScene (void)
        polys->progstarttime = prog->starttime;
 
        // callprofile fixing hack: do not include this time in what is counted for CSQC_UpdateView
-       prog->functions[prog->funcoffsets.CSQC_UpdateView].totaltime -= Sys_DoubleTime() - t;
+       prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= Sys_DoubleTime() - t;
 }
 
 static void VM_ResizePolygons(vmpolygons_t *polys)
@@ -3089,7 +3108,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);
+               R_SetupShader_Generic(tex, NULL, GL_MODULATE, 1, false, false);
                numtriangles = 0;
                for (;surfacelistindex < numsurfaces;surfacelistindex++)
                {
@@ -3366,8 +3385,8 @@ qboolean CL_CheckBottom (prvm_edict_t *ent)
        int             x, y;
        float   mid, bottom;
 
-       VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
-       VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
+       VectorAdd (PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, mins), mins);
+       VectorAdd (PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, maxs), maxs);
 
 // if all of the points under the corners are solid world, don't bother
 // with the tougher checks
@@ -3434,39 +3453,38 @@ qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean
        trace_t         trace;
        int                     i, svent;
        prvm_edict_t            *enemy;
-       prvm_eval_t     *val;
 
 // try the move
-       VectorCopy (ent->fields.client->origin, oldorg);
-       VectorAdd (ent->fields.client->origin, move, neworg);
+       VectorCopy (PRVM_clientedictvector(ent, origin), oldorg);
+       VectorAdd (PRVM_clientedictvector(ent, origin), move, neworg);
 
 // flying monsters don't step up
-       if ( (int)ent->fields.client->flags & (FL_SWIM | FL_FLY) )
+       if ( (int)PRVM_clientedictfloat(ent, flags) & (FL_SWIM | FL_FLY) )
        {
        // try one move with vertical motion, then one without
                for (i=0 ; i<2 ; i++)
                {
-                       VectorAdd (ent->fields.client->origin, move, neworg);
-                       enemy = PRVM_PROG_TO_EDICT(ent->fields.client->enemy);
+                       VectorAdd (PRVM_clientedictvector(ent, origin), move, neworg);
+                       enemy = PRVM_PROG_TO_EDICT(PRVM_clientedictedict(ent, enemy));
                        if (i == 0 && enemy != prog->edicts)
                        {
-                               dz = ent->fields.client->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.client->enemy)->fields.client->origin[2];
+                               dz = PRVM_clientedictvector(ent, origin)[2] - PRVM_clientedictvector(PRVM_PROG_TO_EDICT(PRVM_clientedictedict(ent, enemy)), origin)[2];
                                if (dz > 40)
                                        neworg[2] -= 8;
                                if (dz < 30)
                                        neworg[2] += 8;
                        }
-                       trace = CL_TraceBox(ent->fields.client->origin, ent->fields.client->mins, ent->fields.client->maxs, neworg, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
+                       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);
 
                        if (trace.fraction == 1)
                        {
                                VectorCopy(trace.endpos, traceendpos);
-                               if (((int)ent->fields.client->flags & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
+                               if (((int)PRVM_clientedictfloat(ent, flags) & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
                                        return false;   // swim monster left water
 
-                               VectorCopy (traceendpos, ent->fields.client->origin);
+                               VectorCopy (traceendpos, PRVM_clientedictvector(ent, origin));
                                if (relink)
                                        CL_LinkEdict(ent);
                                return true;
@@ -3484,14 +3502,14 @@ qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean
        VectorCopy (neworg, end);
        end[2] -= sv_stepheight.value*2;
 
-       trace = CL_TraceBox(neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
+       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);
 
        if (trace.startsolid)
        {
                neworg[2] -= sv_stepheight.value;
-               trace = CL_TraceBox(neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
+               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);
                if (trace.startsolid)
@@ -3500,12 +3518,12 @@ qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean
        if (trace.fraction == 1)
        {
        // if monster had the ground pulled out, go ahead and fall
-               if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
+               if ( (int)PRVM_clientedictfloat(ent, flags) & FL_PARTIALGROUND )
                {
-                       VectorAdd (ent->fields.client->origin, move, ent->fields.client->origin);
+                       VectorAdd (PRVM_clientedictvector(ent, origin), move, PRVM_clientedictvector(ent, origin));
                        if (relink)
                                CL_LinkEdict(ent);
-                       ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_ONGROUND;
+                       PRVM_clientedictfloat(ent, flags) = (int)PRVM_clientedictfloat(ent, flags) & ~FL_ONGROUND;
                        return true;
                }
 
@@ -3513,26 +3531,25 @@ qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean
        }
 
 // check point traces down for dangling corners
-       VectorCopy (trace.endpos, ent->fields.client->origin);
+       VectorCopy (trace.endpos, PRVM_clientedictvector(ent, origin));
 
        if (!CL_CheckBottom (ent))
        {
-               if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
+               if ( (int)PRVM_clientedictfloat(ent, flags) & FL_PARTIALGROUND )
                {       // entity had floor mostly pulled out from underneath it
                        // and is trying to correct
                        if (relink)
                                CL_LinkEdict(ent);
                        return true;
                }
-               VectorCopy (oldorg, ent->fields.client->origin);
+               VectorCopy (oldorg, PRVM_clientedictvector(ent, origin));
                return false;
        }
 
-       if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
-               ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND;
+       if ( (int)PRVM_clientedictfloat(ent, flags) & FL_PARTIALGROUND )
+               PRVM_clientedictfloat(ent, flags) = (int)PRVM_clientedictfloat(ent, flags) & ~FL_PARTIALGROUND;
 
-       if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
-               val->edict = PRVM_EDICT_TO_PROG(trace.ent);
+       PRVM_clientedictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
 
 // the move is ok
        if (relink)
@@ -3561,7 +3578,7 @@ static void VM_CL_walkmove (void)
        // assume failure if it returns early
        PRVM_G_FLOAT(OFS_RETURN) = 0;
 
-       ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
+       ent = PRVM_PROG_TO_EDICT(PRVM_clientglobaledict(self));
        if (ent == prog->edicts)
        {
                VM_Warning("walkmove: can not modify world entity\n");
@@ -3576,7 +3593,7 @@ static void VM_CL_walkmove (void)
        dist = PRVM_G_FLOAT(OFS_PARM1);
        settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
 
-       if ( !( (int)ent->fields.client->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
+       if ( !( (int)PRVM_clientedictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
                return;
 
        yaw = yaw*M_PI*2 / 360;
@@ -3587,14 +3604,14 @@ static void VM_CL_walkmove (void)
 
 // save program state, because CL_movestep may call other progs
        oldf = prog->xfunction;
-       oldself = prog->globals.client->self;
+       oldself = PRVM_clientglobaledict(self);
 
        PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
 
 
 // restore program state
        prog->xfunction = oldf;
-       prog->globals.client->self = oldself;
+       PRVM_clientglobaledict(self) = oldself;
 }
 
 /*
@@ -3645,8 +3662,8 @@ static void VM_CL_checkpvs (void)
                return;
        }
 
-       VectorAdd(viewee->fields.server->origin, viewee->fields.server->mins, mi);
-       VectorAdd(viewee->fields.server->origin, viewee->fields.server->maxs, ma);
+       VectorAdd(PRVM_serveredictvector(viewee, origin), PRVM_serveredictvector(viewee, mins), mi);
+       VectorAdd(PRVM_serveredictvector(viewee, origin), PRVM_serveredictvector(viewee, maxs), ma);
 
 #if 1
        if(!sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS)
@@ -3810,18 +3827,18 @@ static void VM_CL_skel_get_bonerel(void)
        matrix4x4_t matrix;
        vec3_t forward, left, up, origin;
        VectorClear(PRVM_G_VECTOR(OFS_RETURN));
-       VectorClear(prog->globals.client->v_forward);
-       VectorClear(prog->globals.client->v_right);
-       VectorClear(prog->globals.client->v_up);
+       VectorClear(PRVM_clientglobalvector(v_forward));
+       VectorClear(PRVM_clientglobalvector(v_right));
+       VectorClear(PRVM_clientglobalvector(v_up));
        if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
                return;
        if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
                return;
        matrix = skeleton->relativetransforms[bonenum];
        Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
-       VectorCopy(forward, prog->globals.client->v_forward);
-       VectorNegate(left, prog->globals.client->v_right);
-       VectorCopy(up, prog->globals.client->v_up);
+       VectorCopy(forward, PRVM_clientglobalvector(v_forward));
+       VectorNegate(left, PRVM_clientglobalvector(v_right));
+       VectorCopy(up, PRVM_clientglobalvector(v_up));
        VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
 }
 
@@ -3835,9 +3852,9 @@ static void VM_CL_skel_get_boneabs(void)
        matrix4x4_t temp;
        vec3_t forward, left, up, origin;
        VectorClear(PRVM_G_VECTOR(OFS_RETURN));
-       VectorClear(prog->globals.client->v_forward);
-       VectorClear(prog->globals.client->v_right);
-       VectorClear(prog->globals.client->v_up);
+       VectorClear(PRVM_clientglobalvector(v_forward));
+       VectorClear(PRVM_clientglobalvector(v_right));
+       VectorClear(PRVM_clientglobalvector(v_up));
        if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
                return;
        if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
@@ -3850,9 +3867,9 @@ static void VM_CL_skel_get_boneabs(void)
                Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
        }
        Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
-       VectorCopy(forward, prog->globals.client->v_forward);
-       VectorNegate(left, prog->globals.client->v_right);
-       VectorCopy(up, prog->globals.client->v_up);
+       VectorCopy(forward, PRVM_clientglobalvector(v_forward));
+       VectorNegate(left, PRVM_clientglobalvector(v_right));
+       VectorCopy(up, PRVM_clientglobalvector(v_up));
        VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
 }
 
@@ -3868,9 +3885,9 @@ static void VM_CL_skel_set_bone(void)
                return;
        if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
                return;
-       VectorCopy(prog->globals.client->v_forward, forward);
-       VectorNegate(prog->globals.client->v_right, left);
-       VectorCopy(prog->globals.client->v_up, up);
+       VectorCopy(PRVM_clientglobalvector(v_forward), forward);
+       VectorNegate(PRVM_clientglobalvector(v_right), left);
+       VectorCopy(PRVM_clientglobalvector(v_up), up);
        VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
        Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
        skeleton->relativetransforms[bonenum] = matrix;
@@ -3890,9 +3907,9 @@ static void VM_CL_skel_mul_bone(void)
        if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
                return;
        VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
-       VectorCopy(prog->globals.client->v_forward, forward);
-       VectorNegate(prog->globals.client->v_right, left);
-       VectorCopy(prog->globals.client->v_up, up);
+       VectorCopy(PRVM_clientglobalvector(v_forward), forward);
+       VectorNegate(PRVM_clientglobalvector(v_right), left);
+       VectorCopy(PRVM_clientglobalvector(v_up), up);
        Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
        temp = skeleton->relativetransforms[bonenum];
        Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
@@ -3912,9 +3929,9 @@ static void VM_CL_skel_mul_bones(void)
        if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
                return;
        VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
-       VectorCopy(prog->globals.client->v_forward, forward);
-       VectorNegate(prog->globals.client->v_right, left);
-       VectorCopy(prog->globals.client->v_up, up);
+       VectorCopy(PRVM_clientglobalvector(v_forward), forward);
+       VectorNegate(PRVM_clientglobalvector(v_right), left);
+       VectorCopy(PRVM_clientglobalvector(v_up), up);
        Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
        firstbone = max(0, firstbone);
        lastbone = min(lastbone, skeleton->model->num_bones - 1);
@@ -4018,7 +4035,7 @@ void VM_CL_RotateMoves(void)
         * has to detect input the client sent before it received the origin
         * update, but after the warp occurred on the server, and has to adjust
         * input appropriately.
-        */
+    */
        matrix4x4_t m;
        vec3_t v = {0, 0, 0};
        vec3_t x, y, z;
@@ -4028,6 +4045,16 @@ void VM_CL_RotateMoves(void)
        CL_RotateMoves(&m);
 }
 
+// #358 void(string cubemapname) loadcubemap
+static void VM_CL_loadcubemap(void)
+{
+       const char *name;
+
+       VM_SAFEPARMCOUNT(1, VM_CL_loadcubemap);
+       name = PRVM_G_STRING(OFS_PARM0);
+       R_GetCubemap(name);
+}
+
 //============================================================================
 
 // To create a almost working builtin file from this replace:
@@ -4350,7 +4377,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
@@ -4362,8 +4389,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
@@ -4384,8 +4411,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)
@@ -4399,7 +4426,7 @@ VM_CL_serverkey,                          // #354 string(string key) serverkey (EXT_CSQC)
 VM_CL_videoplaying,                            // #355
 VM_findfont,                                   // #356 float(string fontname) loadfont (DP_GFX_FONTS)
 VM_loadfont,                                   // #357 float(string fontname, string fontmaps, string sizes, float slot) loadfont (DP_GFX_FONTS)
-NULL,                                                  // #358
+VM_CL_loadcubemap,                             // #358 void(string cubemapname) loadcubemap (DP_GFX_)
 NULL,                                                  // #359
 VM_CL_ReadByte,                                        // #360 float() readbyte (EXT_CSQC)
 VM_CL_ReadChar,                                        // #361 float() readchar (EXT_CSQC)
diff --git a/cmd.c b/cmd.c
index a395eed658b9a65d8c95517ed3fb53e0820de83a..e894a8c2a0da6f5212970af10baaa02d283cf6c3 100644 (file)
--- a/cmd.c
+++ b/cmd.c
@@ -450,24 +450,11 @@ void Cmd_StuffCmds_f (void)
        Cbuf_InsertText (build);
 }
 
-
-/*
-===============
-Cmd_Exec_f
-===============
-*/
-static void Cmd_Exec_f (void)
+static void Cmd_Exec(const char *filename)
 {
        char *f;
-       const char *filename;
+       qboolean isdefaultcfg = strlen(filename) >= 11 && !strcmp(filename + strlen(filename) - 11, "default.cfg");
 
-       if (Cmd_Argc () != 2)
-       {
-               Con_Print("exec <filename> : execute a script file\n");
-               return;
-       }
-
-       filename = Cmd_Argv(1);
        if (!strcmp(filename, "config.cfg"))
        {
                filename = CONFIGFILENAME;
@@ -486,7 +473,7 @@ static void Cmd_Exec_f (void)
        // 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)
@@ -495,23 +482,58 @@ static void Cmd_Exec_f (void)
        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");
+       }
+}
+
+/*
+===============
+Cmd_Exec_f
+===============
+*/
+static void Cmd_Exec_f (void)
+{
+       fssearch_t *s;
+       int i;
+
+       if (Cmd_Argc () != 2)
+       {
+               Con_Print("exec <filename> : execute a script file\n");
+               return;
+       }
+
+       s = FS_Search(Cmd_Argv(1), true, true);
+       if(!s || !s->numfilenames)
+       {
+               Con_Printf("couldn't exec %s\n",Cmd_Argv(1));
+               return;
+       }
+
+       for(i = 0; i < s->numfilenames; ++i)
+               Cmd_Exec(s->filenames[i]);
+
+       FS_FreeSearch(s);
 }
 
 
index 8e9bf40a40f8273e4476faabdc0fd802c4ffa514..d939a0207492aa1ad6ae0baf1e47f3ac0a4214ae 100644 (file)
--- a/common.c
+++ b/common.c
@@ -26,6 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #endif
 
 #include "quakedef.h"
+#include "utf8lib.h"
 
 cvar_t registered = {0, "registered","0", "indicates if this is running registered quake (whether gfx/pop.lmp was found)"};
 cvar_t cmdline = {0, "cmdline","0", "contains commandline the engine was launched with"};
@@ -493,9 +494,12 @@ float MSG_ReadBigFloat (void)
 char *MSG_ReadString (void)
 {
        static char string[MAX_INPUTLINE];
-       int l,c;
-       for (l = 0;l < (int) sizeof(string) - 1 && (c = MSG_ReadByte()) != -1 && c != 0;l++)
-               string[l] = c;
+       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)
+               if (l < maxstring - 1)
+                       string[l++] = c;
        string[l] = 0;
        return string;
 }
@@ -1687,6 +1691,23 @@ void COM_ToLowerString (const char *in, char *out, size_t size_out)
        if (size_out == 0)
                return;
 
+       if(utf8_enable.integer)
+       {
+               *out = 0;
+               while(*in && size_out > 1)
+               {
+                       int n;
+                       Uchar ch = u8_getchar_utf8_enabled(in, &in);
+                       ch = u8_tolower(ch);
+                       n = u8_fromchar(ch, out, size_out);
+                       if(n <= 0)
+                               break;
+                       out += n;
+                       size_out -= n;
+               }
+               return;
+       }
+
        while (*in && size_out > 1)
        {
                if (*in >= 'A' && *in <= 'Z')
@@ -1703,6 +1724,23 @@ void COM_ToUpperString (const char *in, char *out, size_t size_out)
        if (size_out == 0)
                return;
 
+       if(utf8_enable.integer)
+       {
+               *out = 0;
+               while(*in && size_out > 1)
+               {
+                       int n;
+                       Uchar ch = u8_getchar_utf8_enabled(in, &in);
+                       ch = u8_toupper(ch);
+                       n = u8_fromchar(ch, out, size_out);
+                       if(n <= 0)
+                               break;
+                       out += n;
+                       size_out -= n;
+               }
+               return;
+       }
+
        while (*in && size_out > 1)
        {
                if (*in >= 'a' && *in <= 'z')
index ecd8b8569f481420691605d12d04c72007f10a67..bd715ed65eeb2cc9259b33bfabb116c5db959b6a 100644 (file)
--- a/common.h
+++ b/common.h
@@ -251,6 +251,16 @@ extern int dpvsnprintf (char *buffer, size_t buffersize, const char *format, va_
 extern struct cvar_s   registered;
 extern struct cvar_s   cmdline;
 
+typedef enum userdirmode_e
+{
+       USERDIRMODE_NOHOME, // basedir only
+       USERDIRMODE_HOME, // Windows basedir, general POSIX (~/.)
+       USERDIRMODE_MYGAMES, // pre-Vista (My Documents/My Games/), general POSIX (~/.)
+       USERDIRMODE_SAVEDGAMES, // Vista (%USERPROFILE%/Saved Games/), OSX (~/Library/Application Support/), Linux (~/.config)
+       USERDIRMODE_COUNT
+}
+userdirmode_t;
+
 typedef enum gamemode_e
 {
        GAME_NORMAL,
@@ -319,7 +329,7 @@ int matchpattern_with_separator(const char *in, const char *pattern, int caseins
 void stringlistinit(stringlist_t *list);
 void stringlistfreecontents(stringlist_t *list);
 void stringlistappend(stringlist_t *list, const char *text);
-void stringlistsort(stringlist_t *list);
+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);
index 157cd2b95722e4c9ec6640d4064b5f2a40396d45..e89ad5314346361e2eaa7e17db503b3d30167df3 100644 (file)
--- a/console.c
+++ b/console.c
@@ -625,8 +625,11 @@ 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);
+       }
 }
 
 
@@ -639,8 +642,11 @@ 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);
+       }
 }
 
 /*
@@ -2842,7 +2848,7 @@ void Con_CompleteCommandLine (void)
                                        }
                                        else
                                        {
-                                               stringlistsort(&resultbuf); // dirbuf is already sorted
+                                               stringlistsort(&resultbuf, true); // dirbuf is already sorted
                                                Con_Printf("\n%i possible filenames\n", resultbuf.numstrings + dirbuf.numstrings);
                                                for(i = 0; i < dirbuf.numstrings; ++i)
                                                {
index 6a40df4c7233b4c259c9e1c14ed839cc3caa486e..ef281462187b7bb9be90c2071c51f84d20330bfc 100644 (file)
--- a/crypto.c
+++ b/crypto.c
@@ -782,7 +782,7 @@ 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 for key_%d.d0pk (public key fingerprint: %s)\n", i, 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));
                                                }
@@ -1043,7 +1043,7 @@ 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));
                crypto_idstring = crypto_idstring_buf;
@@ -1185,7 +1185,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 (public key fingerprint: %s)\n", i, pubkeys_priv_fp64[i]);
                }
        }
 }
index 33f2987f5b1f72cea8a45ee3d26d2f43affc787e..8ebaa7f22b1e3fbe6aff4c9cdb22b63f70c99fab 100644 (file)
--- a/csprogs.c
+++ b/csprogs.c
@@ -19,13 +19,11 @@ static prvm_prog_t *csqc_tmpprog;
 
 void CL_VM_PreventInformationLeaks(void)
 {
-       prvm_eval_t *val;
        if(!cl.csqc_loaded)
                return;
        CSQC_BEGIN
                VM_ClearTraceGlobals();
-               if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_networkentity)))
-                       val->_float = 0;
+               PRVM_clientglobalfloat(trace_networkentity) = 0;
        CSQC_END
 }
 
@@ -40,6 +38,164 @@ static const char *cl_required_func[] =
 
 static int cl_numrequiredfunc = sizeof(cl_required_func) / sizeof(char*);
 
+#define CL_REQFIELDS (sizeof(cl_reqfields) / sizeof(prvm_required_field_t))
+
+prvm_required_field_t cl_reqfields[] =
+{
+#define PRVM_DECLARE_serverglobalfloat(x)
+#define PRVM_DECLARE_serverglobalvector(x)
+#define PRVM_DECLARE_serverglobalstring(x)
+#define PRVM_DECLARE_serverglobaledict(x)
+#define PRVM_DECLARE_serverglobalfunction(x)
+#define PRVM_DECLARE_clientglobalfloat(x)
+#define PRVM_DECLARE_clientglobalvector(x)
+#define PRVM_DECLARE_clientglobalstring(x)
+#define PRVM_DECLARE_clientglobaledict(x)
+#define PRVM_DECLARE_clientglobalfunction(x)
+#define PRVM_DECLARE_menuglobalfloat(x)
+#define PRVM_DECLARE_menuglobalvector(x)
+#define PRVM_DECLARE_menuglobalstring(x)
+#define PRVM_DECLARE_menuglobaledict(x)
+#define PRVM_DECLARE_menuglobalfunction(x)
+#define PRVM_DECLARE_serverfieldfloat(x)
+#define PRVM_DECLARE_serverfieldvector(x)
+#define PRVM_DECLARE_serverfieldstring(x)
+#define PRVM_DECLARE_serverfieldedict(x)
+#define PRVM_DECLARE_serverfieldfunction(x)
+#define PRVM_DECLARE_clientfieldfloat(x) {ev_float, #x },
+#define PRVM_DECLARE_clientfieldvector(x) {ev_vector, #x },
+#define PRVM_DECLARE_clientfieldstring(x) {ev_string, #x },
+#define PRVM_DECLARE_clientfieldedict(x) {ev_entity, #x },
+#define PRVM_DECLARE_clientfieldfunction(x) {ev_function, #x },
+#define PRVM_DECLARE_menufieldfloat(x)
+#define PRVM_DECLARE_menufieldvector(x)
+#define PRVM_DECLARE_menufieldstring(x)
+#define PRVM_DECLARE_menufieldedict(x)
+#define PRVM_DECLARE_menufieldfunction(x)
+#define PRVM_DECLARE_serverfunction(x)
+#define PRVM_DECLARE_clientfunction(x)
+#define PRVM_DECLARE_menufunction(x)
+#define PRVM_DECLARE_field(x)
+#define PRVM_DECLARE_global(x)
+#define PRVM_DECLARE_function(x)
+#include "prvm_offsets.h"
+#undef PRVM_DECLARE_serverglobalfloat
+#undef PRVM_DECLARE_serverglobalvector
+#undef PRVM_DECLARE_serverglobalstring
+#undef PRVM_DECLARE_serverglobaledict
+#undef PRVM_DECLARE_serverglobalfunction
+#undef PRVM_DECLARE_clientglobalfloat
+#undef PRVM_DECLARE_clientglobalvector
+#undef PRVM_DECLARE_clientglobalstring
+#undef PRVM_DECLARE_clientglobaledict
+#undef PRVM_DECLARE_clientglobalfunction
+#undef PRVM_DECLARE_menuglobalfloat
+#undef PRVM_DECLARE_menuglobalvector
+#undef PRVM_DECLARE_menuglobalstring
+#undef PRVM_DECLARE_menuglobaledict
+#undef PRVM_DECLARE_menuglobalfunction
+#undef PRVM_DECLARE_serverfieldfloat
+#undef PRVM_DECLARE_serverfieldvector
+#undef PRVM_DECLARE_serverfieldstring
+#undef PRVM_DECLARE_serverfieldedict
+#undef PRVM_DECLARE_serverfieldfunction
+#undef PRVM_DECLARE_clientfieldfloat
+#undef PRVM_DECLARE_clientfieldvector
+#undef PRVM_DECLARE_clientfieldstring
+#undef PRVM_DECLARE_clientfieldedict
+#undef PRVM_DECLARE_clientfieldfunction
+#undef PRVM_DECLARE_menufieldfloat
+#undef PRVM_DECLARE_menufieldvector
+#undef PRVM_DECLARE_menufieldstring
+#undef PRVM_DECLARE_menufieldedict
+#undef PRVM_DECLARE_menufieldfunction
+#undef PRVM_DECLARE_serverfunction
+#undef PRVM_DECLARE_clientfunction
+#undef PRVM_DECLARE_menufunction
+#undef PRVM_DECLARE_field
+#undef PRVM_DECLARE_global
+#undef PRVM_DECLARE_function
+};
+
+#define CL_REQGLOBALS (sizeof(cl_reqglobals) / sizeof(prvm_required_field_t))
+
+prvm_required_field_t cl_reqglobals[] =
+{
+#define PRVM_DECLARE_serverglobalfloat(x)
+#define PRVM_DECLARE_serverglobalvector(x)
+#define PRVM_DECLARE_serverglobalstring(x)
+#define PRVM_DECLARE_serverglobaledict(x)
+#define PRVM_DECLARE_serverglobalfunction(x)
+#define PRVM_DECLARE_clientglobalfloat(x) {ev_float, #x},
+#define PRVM_DECLARE_clientglobalvector(x) {ev_vector, #x},
+#define PRVM_DECLARE_clientglobalstring(x) {ev_string, #x},
+#define PRVM_DECLARE_clientglobaledict(x) {ev_entity, #x},
+#define PRVM_DECLARE_clientglobalfunction(x) {ev_function, #x},
+#define PRVM_DECLARE_menuglobalfloat(x)
+#define PRVM_DECLARE_menuglobalvector(x)
+#define PRVM_DECLARE_menuglobalstring(x)
+#define PRVM_DECLARE_menuglobaledict(x)
+#define PRVM_DECLARE_menuglobalfunction(x)
+#define PRVM_DECLARE_serverfieldfloat(x)
+#define PRVM_DECLARE_serverfieldvector(x)
+#define PRVM_DECLARE_serverfieldstring(x)
+#define PRVM_DECLARE_serverfieldedict(x)
+#define PRVM_DECLARE_serverfieldfunction(x)
+#define PRVM_DECLARE_clientfieldfloat(x)
+#define PRVM_DECLARE_clientfieldvector(x)
+#define PRVM_DECLARE_clientfieldstring(x)
+#define PRVM_DECLARE_clientfieldedict(x)
+#define PRVM_DECLARE_clientfieldfunction(x)
+#define PRVM_DECLARE_menufieldfloat(x)
+#define PRVM_DECLARE_menufieldvector(x)
+#define PRVM_DECLARE_menufieldstring(x)
+#define PRVM_DECLARE_menufieldedict(x)
+#define PRVM_DECLARE_menufieldfunction(x)
+#define PRVM_DECLARE_serverfunction(x)
+#define PRVM_DECLARE_clientfunction(x)
+#define PRVM_DECLARE_menufunction(x)
+#define PRVM_DECLARE_field(x)
+#define PRVM_DECLARE_global(x)
+#define PRVM_DECLARE_function(x)
+#include "prvm_offsets.h"
+#undef PRVM_DECLARE_serverglobalfloat
+#undef PRVM_DECLARE_serverglobalvector
+#undef PRVM_DECLARE_serverglobalstring
+#undef PRVM_DECLARE_serverglobaledict
+#undef PRVM_DECLARE_serverglobalfunction
+#undef PRVM_DECLARE_clientglobalfloat
+#undef PRVM_DECLARE_clientglobalvector
+#undef PRVM_DECLARE_clientglobalstring
+#undef PRVM_DECLARE_clientglobaledict
+#undef PRVM_DECLARE_clientglobalfunction
+#undef PRVM_DECLARE_menuglobalfloat
+#undef PRVM_DECLARE_menuglobalvector
+#undef PRVM_DECLARE_menuglobalstring
+#undef PRVM_DECLARE_menuglobaledict
+#undef PRVM_DECLARE_menuglobalfunction
+#undef PRVM_DECLARE_serverfieldfloat
+#undef PRVM_DECLARE_serverfieldvector
+#undef PRVM_DECLARE_serverfieldstring
+#undef PRVM_DECLARE_serverfieldedict
+#undef PRVM_DECLARE_serverfieldfunction
+#undef PRVM_DECLARE_clientfieldfloat
+#undef PRVM_DECLARE_clientfieldvector
+#undef PRVM_DECLARE_clientfieldstring
+#undef PRVM_DECLARE_clientfieldedict
+#undef PRVM_DECLARE_clientfieldfunction
+#undef PRVM_DECLARE_menufieldfloat
+#undef PRVM_DECLARE_menufieldvector
+#undef PRVM_DECLARE_menufieldstring
+#undef PRVM_DECLARE_menufieldedict
+#undef PRVM_DECLARE_menufieldfunction
+#undef PRVM_DECLARE_serverfunction
+#undef PRVM_DECLARE_clientfunction
+#undef PRVM_DECLARE_menufunction
+#undef PRVM_DECLARE_field
+#undef PRVM_DECLARE_global
+#undef PRVM_DECLARE_function
+};
+
 void CL_VM_Error (const char *format, ...) DP_FUNC_PRINTF(1);
 void CL_VM_Error (const char *format, ...)     //[515]: hope it will be never executed =)
 {
@@ -62,97 +218,82 @@ void CL_VM_Error (const char *format, ...) //[515]: hope it will be never execut
 }
 void CL_VM_UpdateDmgGlobals (int dmg_take, int dmg_save, vec3_t dmg_origin)
 {
-       prvm_eval_t *val;
        if(cl.csqc_loaded)
        {
                CSQC_BEGIN
-               val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.dmg_take);
-               if(val)
-                       val->_float = dmg_take;
-               val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.dmg_save);
-               if(val)
-                       val->_float = dmg_save;
-               val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.dmg_origin);
-               if(val)
-               {
-                       val->vector[0] = dmg_origin[0];
-                       val->vector[1] = dmg_origin[1];
-                       val->vector[2] = dmg_origin[2];
-               }
+               PRVM_clientglobalfloat(dmg_take) = dmg_take;
+               PRVM_clientglobalfloat(dmg_save) = dmg_save;
+               VectorCopy(dmg_origin, PRVM_clientglobalvector(dmg_origin));
                CSQC_END
        }
 }
 
 void CSQC_UpdateNetworkTimes(double newtime, double oldtime)
 {
-       prvm_eval_t *val;
        if(!cl.csqc_loaded)
                return;
        CSQC_BEGIN
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.servertime)))
-               val->_float = newtime;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.serverprevtime)))
-               val->_float = oldtime;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.serverdeltatime)))
-               val->_float = newtime - oldtime;
+       PRVM_clientglobalfloat(servertime) = newtime;
+       PRVM_clientglobalfloat(serverprevtime) = oldtime;
+       PRVM_clientglobalfloat(serverdeltatime) = newtime - oldtime;
        CSQC_END
 }
 
 //[515]: set globals before calling R_UpdateView, WEIRD CRAP
+void CSQC_R_RecalcView (void);
 static void CSQC_SetGlobals (void)
 {
-       prvm_eval_t *val;
        CSQC_BEGIN
-               prog->globals.client->time = cl.time;
-               prog->globals.client->frametime = max(0, cl.time - cl.oldtime);
-               prog->globals.client->servercommandframe = cls.servermovesequence;
-               prog->globals.client->clientcommandframe = cl.movecmd[0].sequence;
-               VectorCopy(cl.viewangles, prog->globals.client->input_angles);
-               VectorCopy(cl.viewangles, cl.csqc_angles);
+               PRVM_clientglobalfloat(time) = cl.time;
+               PRVM_clientglobalfloat(frametime) = max(0, cl.time - cl.oldtime);
+               PRVM_clientglobalfloat(servercommandframe) = cls.servermovesequence;
+               PRVM_clientglobalfloat(clientcommandframe) = cl.movecmd[0].sequence;
+               VectorCopy(cl.viewangles, PRVM_clientglobalvector(input_angles));
                // // FIXME: this actually belongs into getinputstate().. [12/17/2007 Black]
-               prog->globals.client->input_buttons = cl.movecmd[0].buttons;
-               VectorSet(prog->globals.client->input_movevalues, cl.movecmd[0].forwardmove, cl.movecmd[0].sidemove, cl.movecmd[0].upmove);
-               //VectorCopy(cl.movement_origin, cl.csqc_origin);
-               Matrix4x4_OriginFromMatrix(&cl.entities[cl.viewentity].render.matrix, cl.csqc_origin);
+               PRVM_clientglobalfloat(input_buttons) = cl.movecmd[0].buttons;
+               VectorSet(PRVM_clientglobalvector(input_movevalues), cl.movecmd[0].forwardmove, cl.movecmd[0].sidemove, cl.movecmd[0].upmove);
+               VectorCopy(cl.csqc_vieworiginfromengine, cl.csqc_vieworigin);
+               VectorCopy(cl.csqc_viewanglesfromengine, cl.csqc_viewangles);
 
                // LordHavoc: Spike says not to do this, but without pmove_org the
                // CSQC is useless as it can't alter the view origin without
                // completely replacing it
-               VectorCopy(cl.csqc_origin, prog->globals.client->pmove_org);
-               VectorCopy(cl.movement_velocity, prog->globals.client->pmove_vel);
-
-               if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.view_angles)))
-                       VectorCopy(cl.viewangles, val->vector);
-               if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.view_punchangle)))
-                       VectorCopy(cl.punchangle, val->vector);
-               if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.view_punchvector)))
-                       VectorCopy(cl.punchvector, val->vector);
-               prog->globals.client->maxclients = cl.maxclients;
+               Matrix4x4_OriginFromMatrix(&cl.entities[cl.viewentity].render.matrix, PRVM_clientglobalvector(pmove_org));
+               VectorCopy(cl.movement_velocity, PRVM_clientglobalvector(pmove_vel));
+               PRVM_clientglobalfloat(pmove_onground) = cl.onground;
+               PRVM_clientglobalfloat(pmove_inwater) = cl.inwater;
+
+               VectorCopy(cl.viewangles, PRVM_clientglobalvector(view_angles));
+               VectorCopy(cl.punchangle, PRVM_clientglobalvector(view_punchangle));
+               VectorCopy(cl.punchvector, PRVM_clientglobalvector(view_punchvector));
+               PRVM_clientglobalfloat(maxclients) = cl.maxclients;
+
+               CSQC_R_RecalcView();
        CSQC_END
 }
 
 void CSQC_Predraw (prvm_edict_t *ed)
 {
        int b;
-       if(!ed->fields.client->predraw)
+       if(!PRVM_clientedictfunction(ed, predraw))
                return;
-       b = prog->globals.client->self;
-       prog->globals.client->self = PRVM_EDICT_TO_PROG(ed);
-       PRVM_ExecuteProgram(ed->fields.client->predraw, "CSQC_Predraw: NULL function\n");
-       prog->globals.client->self = b;
+       b = PRVM_clientglobaledict(self);
+       PRVM_clientglobaledict(self) = PRVM_EDICT_TO_PROG(ed);
+       PRVM_ExecuteProgram(PRVM_clientedictfunction(ed, predraw), "CSQC_Predraw: NULL function\n");
+       PRVM_clientglobaledict(self) = b;
 }
 
 void CSQC_Think (prvm_edict_t *ed)
 {
        int b;
-       if(ed->fields.client->think)
-       if(ed->fields.client->nextthink && ed->fields.client->nextthink <= prog->globals.client->time)
+       if(PRVM_clientedictfunction(ed, think))
+       if(PRVM_clientedictfloat(ed, nextthink) && PRVM_clientedictfloat(ed, nextthink) <= PRVM_clientglobalfloat(time))
        {
-               ed->fields.client->nextthink = 0;
-               b = prog->globals.client->self;
-               prog->globals.client->self = PRVM_EDICT_TO_PROG(ed);
-               PRVM_ExecuteProgram(ed->fields.client->think, "CSQC_Think: NULL function\n");
-               prog->globals.client->self = b;
+               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");
+               PRVM_clientglobaledict(self) = b;
        }
 }
 
@@ -163,10 +304,8 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed, int edictnum)
        int renderflags;
        int c;
        float scale;
-       prvm_eval_t *val;
        entity_render_t *entrender;
        dp_model_t *model;
-       matrix4x4_t tagmatrix, matrix2;
 
        model = CL_GetModelFromEdict(ed);
        if (!model)
@@ -194,69 +333,42 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed, int edictnum)
                        return false;
        }
 
-       if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.userwavefunc_param0)))    entrender->userwavefunc_param[0] = val->_float;
-       if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.userwavefunc_param1)))    entrender->userwavefunc_param[1] = val->_float;
-       if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.userwavefunc_param2)))    entrender->userwavefunc_param[2] = val->_float;
-       if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.userwavefunc_param3)))    entrender->userwavefunc_param[3] = val->_float;
+       entrender->userwavefunc_param[0] = PRVM_clientedictfloat(ed, userwavefunc_param0);
+       entrender->userwavefunc_param[1] = PRVM_clientedictfloat(ed, userwavefunc_param1);
+       entrender->userwavefunc_param[2] = PRVM_clientedictfloat(ed, userwavefunc_param2);
+       entrender->userwavefunc_param[3] = PRVM_clientedictfloat(ed, userwavefunc_param3);
 
        entrender->model = model;
-       entrender->skinnum = (int)ed->fields.client->skin;
+       entrender->skinnum = (int)PRVM_clientedictfloat(ed, skin);
        entrender->effects |= entrender->model->effects;
-       scale = 1;
-       renderflags = 0;
-       if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.renderflags)) && val->_float)     renderflags = (int)val->_float;
-       if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.alpha)) && val->_float)           entrender->alpha = val->_float;
-       if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.scale)) && val->_float)           entrender->scale = scale = val->_float;
-       if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, entrender->colormod);
-       if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.glowmod)) && VectorLength2(val->vector))  VectorCopy(val->vector, entrender->glowmod);
-       if(ed->fields.client->effects)  entrender->effects |= (int)ed->fields.client->effects;
-       if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.tag_entity)) && val->edict)
-       {
-               int tagentity;
-               int tagindex = 0;
-               tagentity = val->edict;
-               if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.tag_index)) && val->_float)
-                       tagindex = (int)val->_float;
-               CL_GetTagMatrix (&tagmatrix, PRVM_PROG_TO_EDICT(tagentity), tagindex);
-       }
-       else
-               Matrix4x4_CreateIdentity(&tagmatrix);
+       renderflags = (int)PRVM_clientedictfloat(ed, renderflags);
+       entrender->alpha = PRVM_clientedictfloat(ed, alpha);
+       entrender->scale = scale = PRVM_clientedictfloat(ed, scale);
+       VectorCopy(PRVM_clientedictvector(ed, colormod), entrender->colormod);
+       VectorCopy(PRVM_clientedictvector(ed, glowmod), entrender->glowmod);
+       if(PRVM_clientedictfloat(ed, effects))  entrender->effects |= (int)PRVM_clientedictfloat(ed, effects);
+       if (!entrender->alpha)
+               entrender->alpha = 1.0f;
+       if (!entrender->scale)
+               entrender->scale = scale = 1.0f;
        if (!VectorLength2(entrender->colormod))
                VectorSet(entrender->colormod, 1, 1, 1);
        if (!VectorLength2(entrender->glowmod))
                VectorSet(entrender->glowmod, 1, 1, 1);
 
-       if (renderflags & RF_USEAXIS)
-       {
-               vec3_t left;
-               VectorNegate(prog->globals.client->v_right, left);
-               Matrix4x4_FromVectors(&matrix2, prog->globals.client->v_forward, left, prog->globals.client->v_up, ed->fields.client->origin);
-               Matrix4x4_Scale(&matrix2, scale, 1);
-       }
-       else
-       {
-               vec3_t angles;
-               VectorCopy(ed->fields.client->angles, angles);
-               // if model is alias, reverse pitch direction
-               if (entrender->model->type == mod_alias)
-                       angles[0] = -angles[0];
-
-               // set up the render matrix
-               Matrix4x4_CreateFromQuakeEntity(&matrix2, ed->fields.client->origin[0], ed->fields.client->origin[1], ed->fields.client->origin[2], angles[0], angles[1], angles[2], scale);
-       }
+       // LordHavoc: use the CL_GetTagMatrix function on self to ensure consistent behavior (duplicate code would be bad)
+       CL_GetTagMatrix(&entrender->matrix, ed, 0);
 
        // set up the animation data
        VM_GenerateFrameGroupBlend(ed->priv.server->framegroupblend, ed);
        VM_FrameBlendFromFrameGroupBlend(ed->priv.server->frameblend, ed->priv.server->framegroupblend, model);
        VM_UpdateEdictSkeleton(ed, model, ed->priv.server->frameblend);
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.shadertime))) entrender->shadertime = val->_float;
-
-       // concat the matrices to make the entity relative to its tag
-       Matrix4x4_Concat(&entrender->matrix, &tagmatrix, &matrix2);
+       if (PRVM_clientedictfloat(ed, shadertime)) // hack for csprogs.dat files that do not set shadertime, leaves the value at entity spawn time
+               entrender->shadertime = PRVM_clientedictfloat(ed, shadertime);
 
        // transparent offset
-       if ((renderflags & RF_USETRANSPARENTOFFSET) && (val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.transparent_offset)))
-               entrender->transparent_offset = val->_float;
+       if (renderflags & RF_USETRANSPARENTOFFSET)
+               entrender->transparent_offset = PRVM_clientglobalfloat(transparent_offset);
 
        if(renderflags)
        {
@@ -267,7 +379,7 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed, int edictnum)
                if(renderflags & RF_ADDITIVE)           entrender->flags |= RENDER_ADDITIVE;
        }
 
-       c = (int)ed->fields.client->colormap;
+       c = (int)PRVM_clientedictfloat(ed, colormap);
        if (c <= 0)
                CL_SetEntityColormapColors(entrender, -1);
        else if (c <= cl.maxclients && cl.scores != NULL)
@@ -315,7 +427,11 @@ 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)
 {
        qboolean r;
 
@@ -323,16 +439,16 @@ qboolean CL_VM_InputEvent (qboolean down, int key, int ascii)
                return false;
 
        CSQC_BEGIN
-               if (!prog->funcoffsets.CSQC_InputEvent)
+               if (!PRVM_clientfunction(CSQC_InputEvent))
                        r = false;
                else
                {
-                       prog->globals.client->time = cl.time;
-                       prog->globals.client->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(prog->funcoffsets.CSQC_InputEvent, "QC function CSQC_InputEvent is missing");
+                       PRVM_clientglobalfloat(time) = cl.time;
+                       PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity];
+                       PRVM_G_FLOAT(OFS_PARM0) = eventtype;
+                       PRVM_G_FLOAT(OFS_PARM1) = x; // key or x
+                       PRVM_G_FLOAT(OFS_PARM2) = y; // ascii or y
+                       PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_InputEvent), "QC function CSQC_InputEvent is missing");
                        r = CSQC_RETURNVAL != 0;
                }
        CSQC_END
@@ -351,8 +467,8 @@ qboolean CL_VM_UpdateView (void)
        R_TimeReport("pre-UpdateView");
        CSQC_BEGIN
                //VectorCopy(cl.viewangles, oldangles);
-               prog->globals.client->time = cl.time;
-               prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
+               PRVM_clientglobalfloat(time) = cl.time;
+               PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity];
                CSQC_SetGlobals();
                // clear renderable entity and light lists to prevent crashes if the
                // CSQC_UpdateView function does not call R_ClearScene as it should
@@ -361,7 +477,7 @@ 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(prog->funcoffsets.CSQC_UpdateView, "QC function CSQC_UpdateView is missing");
+               PRVM_ExecuteProgram(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);
@@ -378,13 +494,13 @@ qboolean CL_VM_ConsoleCommand (const char *cmd)
        if(!cl.csqc_loaded)
                return false;
        CSQC_BEGIN
-       if (prog->funcoffsets.CSQC_ConsoleCommand)
+       if (PRVM_clientfunction(CSQC_ConsoleCommand))
        {
-               prog->globals.client->time = cl.time;
-               prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
+               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(prog->funcoffsets.CSQC_ConsoleCommand, "QC function CSQC_ConsoleCommand is missing");
+               PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_ConsoleCommand), "QC function CSQC_ConsoleCommand is missing");
                vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
                r = CSQC_RETURNVAL != 0;
        }
@@ -399,12 +515,12 @@ qboolean CL_VM_Parse_TempEntity (void)
        if(!cl.csqc_loaded)
                return false;
        CSQC_BEGIN
-       if(prog->funcoffsets.CSQC_Parse_TempEntity)
+       if(PRVM_clientfunction(CSQC_Parse_TempEntity))
        {
                t = msg_readcount;
-               prog->globals.client->time = cl.time;
-               prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
-               PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Parse_TempEntity, "QC function CSQC_Parse_TempEntity is missing");
+               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");
                r = CSQC_RETURNVAL != 0;
                if(!r)
                {
@@ -482,13 +598,13 @@ void CL_VM_Parse_StuffCmd (const char *msg)
                return;
        }
        CSQC_BEGIN
-       if(prog->funcoffsets.CSQC_Parse_StuffCmd)
+       if(PRVM_clientfunction(CSQC_Parse_StuffCmd))
        {
-               prog->globals.client->time = cl.time;
-               prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
+               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(prog->funcoffsets.CSQC_Parse_StuffCmd, "QC function CSQC_Parse_StuffCmd is missing");
+               PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Parse_StuffCmd), "QC function CSQC_Parse_StuffCmd is missing");
                vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
        }
        else
@@ -499,11 +615,11 @@ void CL_VM_Parse_StuffCmd (const char *msg)
 static void CL_VM_Parse_Print (const char *msg)
 {
        int restorevm_tempstringsbuf_cursize;
-       prog->globals.client->time = cl.time;
-       prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
+       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(prog->funcoffsets.CSQC_Parse_Print, "QC function CSQC_Parse_Print is missing");
+       PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Parse_Print), "QC function CSQC_Parse_Print is missing");
        vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
 }
 
@@ -516,7 +632,7 @@ void CSQC_AddPrintText (const char *msg)
                return;
        }
        CSQC_BEGIN
-       if(prog->funcoffsets.CSQC_Parse_Print)
+       if(PRVM_clientfunction(CSQC_Parse_Print))
        {
                // FIXME: is this bugged?
                i = strlen(msg)-1;
@@ -549,13 +665,13 @@ void CL_VM_Parse_CenterPrint (const char *msg)
                return;
        }
        CSQC_BEGIN
-       if(prog->funcoffsets.CSQC_Parse_CenterPrint)
+       if(PRVM_clientfunction(CSQC_Parse_CenterPrint))
        {
-               prog->globals.client->time = cl.time;
-               prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
+               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(prog->funcoffsets.CSQC_Parse_CenterPrint, "QC function CSQC_Parse_CenterPrint is missing");
+               PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Parse_CenterPrint), "QC function CSQC_Parse_CenterPrint is missing");
                vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
        }
        else
@@ -565,25 +681,19 @@ void CL_VM_Parse_CenterPrint (const char *msg)
 
 void CL_VM_UpdateIntermissionState (int intermission)
 {
-       prvm_eval_t *val;
        if(cl.csqc_loaded)
        {
                CSQC_BEGIN
-               val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.intermission);
-               if(val)
-                       val->_float = intermission;
+               PRVM_clientglobalfloat(intermission) = intermission;
                CSQC_END
        }
 }
 void CL_VM_UpdateShowingScoresState (int showingscores)
 {
-       prvm_eval_t *val;
        if(cl.csqc_loaded)
        {
                CSQC_BEGIN
-               val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.sb_showscores);
-               if(val)
-                       val->_float = showingscores;
+               PRVM_clientglobalfloat(sb_showscores) = showingscores;
                CSQC_END
        }
 }
@@ -593,17 +703,19 @@ qboolean CL_VM_Event_Sound(int sound_num, float volume, int channel, float atten
        if(cl.csqc_loaded)
        {
                CSQC_BEGIN
-               if(prog->funcoffsets.CSQC_Event_Sound)
+               if(PRVM_clientfunction(CSQC_Event_Sound))
                {
-                       prog->globals.client->time = cl.time;
-                       prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
+                       PRVM_clientglobalfloat(time) = cl.time;
+                       PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity];
                        PRVM_G_FLOAT(OFS_PARM0) = ent;
-                       PRVM_G_FLOAT(OFS_PARM1) = channel;
+                       PRVM_G_FLOAT(OFS_PARM1) = CHAN_ENGINE2USER(channel);
                        PRVM_G_INT(OFS_PARM2) = PRVM_SetTempString(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_ExecuteProgram(prog->funcoffsets.CSQC_Event_Sound, "QC function CSQC_Event_Sound is missing");
+                       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");
                        r = CSQC_RETURNVAL != 0;
                }
                CSQC_END
@@ -617,7 +729,6 @@ void CL_VM_UpdateCoopDeathmatchGlobals (int gametype)
        int localcoop;
        int localdeathmatch;
 
-       prvm_eval_t *val;
        if(cl.csqc_loaded)
        {
                if(gametype == GAME_COOP)
@@ -639,12 +750,8 @@ void CL_VM_UpdateCoopDeathmatchGlobals (int gametype)
                        localdeathmatch = 0;
                }
                CSQC_BEGIN
-               val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.coop);
-               if(val)
-                       val->_float = localcoop;
-               val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.deathmatch);
-               if(val)
-                       val->_float = localdeathmatch;
+               PRVM_clientglobalfloat(coop) = localcoop;
+               PRVM_clientglobalfloat(deathmatch) = localdeathmatch;
                CSQC_END
        }
 }
@@ -654,12 +761,12 @@ float CL_VM_Event (float event)           //[515]: needed ? I'd say "YES", but don't know
        if(!cl.csqc_loaded)
                return 0;
        CSQC_BEGIN
-       if(prog->funcoffsets.CSQC_Event)
+       if(PRVM_clientfunction(CSQC_Event))
        {
-               prog->globals.client->time = cl.time;
-               prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
+               PRVM_clientglobalfloat(time) = cl.time;
+               PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity];
                PRVM_G_FLOAT(OFS_PARM0) = event;
-               PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Event, "QC function CSQC_Event is missing");
+               PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Event), "QC function CSQC_Event is missing");
                r = CSQC_RETURNVAL;
        }
        CSQC_END
@@ -676,20 +783,20 @@ void CSQC_ReadEntities (void)
        }
 
        CSQC_BEGIN
-               prog->globals.client->time = cl.time;
-               oldself = prog->globals.client->self;
+               PRVM_clientglobalfloat(time) = cl.time;
+               oldself = PRVM_clientglobaledict(self);
                while(1)
                {
                        entnum = MSG_ReadShort();
                        if(!entnum || msg_badread)
                                break;
                        realentnum = entnum & 0x7FFF;
-                       prog->globals.client->self = cl.csqc_server2csqcentitynumber[realentnum];
+                       PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[realentnum];
                        if(entnum & 0x8000)
                        {
-                               if(prog->globals.client->self)
+                               if(PRVM_clientglobaledict(self))
                                {
-                                       PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Ent_Remove, "QC function CSQC_Ent_Remove is missing");
+                                       PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Ent_Remove), "QC function CSQC_Ent_Remove is missing");
                                        cl.csqc_server2csqcentitynumber[realentnum] = 0;
                                }
                                else
@@ -703,14 +810,14 @@ void CSQC_ReadEntities (void)
                        }
                        else
                        {
-                               if(!prog->globals.client->self)
+                               if(!PRVM_clientglobaledict(self))
                                {
-                                       if(!prog->funcoffsets.CSQC_Ent_Spawn)
+                                       if(!PRVM_clientfunction(CSQC_Ent_Spawn))
                                        {
                                                prvm_edict_t    *ed;
                                                ed = PRVM_ED_Alloc();
-                                               ed->fields.client->entnum = realentnum;
-                                               prog->globals.client->self = cl.csqc_server2csqcentitynumber[realentnum] = PRVM_EDICT_TO_PROG(ed);
+                                               PRVM_clientedictfloat(ed, entnum) = realentnum;
+                                               PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[realentnum] = PRVM_EDICT_TO_PROG(ed);
                                        }
                                        else
                                        {
@@ -718,20 +825,20 @@ void CSQC_ReadEntities (void)
                                                // the qc function should set entnum, too (this way it also can return world [2/1/2008 Andreas]
                                                PRVM_G_FLOAT(OFS_PARM0) = (float) realentnum;
                                                // make sure no one gets wrong ideas
-                                               prog->globals.client->self = 0;
-                                               PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Ent_Spawn, "QC function CSQC_Ent_Spawn is missing");
-                                               prog->globals.client->self = cl.csqc_server2csqcentitynumber[realentnum] = PRVM_EDICT( PRVM_G_INT( OFS_RETURN ) );
+                                               PRVM_clientglobaledict(self) = 0;
+                                               PRVM_ExecuteProgram(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(prog->funcoffsets.CSQC_Ent_Update, "QC function CSQC_Ent_Update is missing");
+                                       PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Ent_Update), "QC function CSQC_Ent_Update is missing");
                                }
                                else {
                                        PRVM_G_FLOAT(OFS_PARM0) = 0;
-                                       PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Ent_Update, "QC function CSQC_Ent_Update is missing");
+                                       PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Ent_Update), "QC function CSQC_Ent_Update is missing");
                                }
                        }
                }
-               prog->globals.client->self = oldself;
+               PRVM_clientglobaledict(self) = oldself;
        CSQC_END
 }
 
@@ -771,7 +878,7 @@ void CL_VM_CB_FreeEdict(prvm_edict_t *ed)
        R_DecalSystem_Reset(&entrender->decalsystem);
        memset(entrender, 0, sizeof(*entrender));
        World_UnlinkEdict(ed);
-       memset(ed->fields.client, 0, sizeof(*ed->fields.client));
+       memset(ed->fields.vp, 0, prog->entityfields * 4);
        VM_RemoveEdictSkeleton(ed);
        World_Physics_RemoveFromEntity(&cl.world, ed);
        World_Physics_RemoveJointFromEntity(&cl.world, ed);
@@ -789,9 +896,9 @@ void CL_VM_CB_CountEdicts(void)
                if (ent->priv.server->free)
                        continue;
                active++;
-               if (ent->fields.client->solid)
+               if (PRVM_clientedictfloat(ent, solid))
                        solid++;
-               if (ent->fields.client->model)
+               if (PRVM_clientedictstring(ent, model))
                        models++;
        }
 
@@ -855,7 +962,6 @@ void CL_VM_Init (void)
        fs_offset_t csprogsdatasize;
        int csprogsdatacrc, requiredcrc;
        int requiredsize;
-       prvm_eval_t *val;
 
        // reset csqc_progcrc after reading it, so that changing servers doesn't
        // expect csqc on the next server
@@ -917,7 +1023,6 @@ void CL_VM_Init (void)
 
        // allocate the mempools
        prog->progs_mempool = Mem_AllocPool(csqc_progname.string, 0, NULL);
-       prog->headercrc = CL_PROGHEADER_CRC;
        prog->edictprivate_size = 0; // no private struct used
        prog->name = CL_NAME;
        prog->num_edicts = 1;
@@ -940,7 +1045,7 @@ void CL_VM_Init (void)
        prog->error_cmd = CL_VM_Error;
        prog->ExecuteProgram = CLVM_ExecuteProgram;
 
-       PRVM_LoadProgs(csprogsfn, cl_numrequiredfunc, cl_required_func, 0, NULL, 0, NULL);
+       PRVM_LoadProgs(csprogsfn, cl_numrequiredfunc, cl_required_func, CL_REQFIELDS, cl_reqfields, CL_REQGLOBALS, cl_reqglobals);
 
        if (!prog->loaded)
        {
@@ -982,21 +1087,19 @@ void CL_VM_Init (void)
                prog->flag |= PRVM_OP_STATE;
 
        // set time
-       prog->globals.client->time = cl.time;
-       prog->globals.client->self = 0;
+       PRVM_clientglobalfloat(time) = cl.time;
+       PRVM_clientglobaledict(self) = 0;
 
-       prog->globals.client->mapname = PRVM_SetEngineString(cl.worldname);
-       prog->globals.client->player_localentnum = cl.playerentity;
+       PRVM_clientglobalstring(mapname) = PRVM_SetEngineString(cl.worldname);
+       PRVM_clientglobalfloat(player_localentnum) = cl.playerentity;
 
        // set map description (use world entity 0)
-       val = PRVM_EDICTFIELDVALUE(prog->edicts, prog->fieldoffsets.message);
-       if(val)
-               val->string = PRVM_SetEngineString(cl.worldmessage);
-       VectorCopy(cl.world.mins, prog->edicts->fields.client->mins);
-       VectorCopy(cl.world.maxs, prog->edicts->fields.client->maxs);
+       PRVM_clientedictstring(prog->edicts, message) = PRVM_SetEngineString(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(prog->funcoffsets.CSQC_Init, "QC function CSQC_Init is missing");
+       PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Init), "QC function CSQC_Init is missing");
 
        PRVM_End;
        cl.csqc_loaded = true;
@@ -1016,10 +1119,10 @@ void CL_VM_ShutDown (void)
        if(!cl.csqc_loaded)
                return;
        CSQC_BEGIN
-               prog->globals.client->time = cl.time;
-               prog->globals.client->self = 0;
-               if (prog->funcoffsets.CSQC_Shutdown)
-                       PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Shutdown, "QC function CSQC_Shutdown is missing");
+               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();
        CSQC_END
        Con_DPrint("CSQC ^1unloaded\n");
@@ -1042,7 +1145,7 @@ qboolean CL_VM_GetEntitySoundOrigin(int entnum, vec3_t out)
        if(!ed->priv.required->free)
        {
                mod = CL_GetModelFromEdict(ed);
-               VectorCopy(ed->fields.client->origin, out);
+               VectorCopy(PRVM_clientedictvector(ed, origin), out);
                if(CL_GetTagMatrix (&matrix, ed, 0) == 0)
                        Matrix4x4_OriginFromMatrix(&matrix, out);
                if (mod && mod->soundfromcenter)
@@ -1059,7 +1162,6 @@ qboolean CL_VM_TransformView(int entnum, matrix4x4_t *viewmatrix, mplane_t *clip
 {
        qboolean ret = false;
        prvm_edict_t *ed;
-       prvm_eval_t *val, *valforward, *valright, *valup, *valendpos;
        vec3_t forward, left, up, origin, ang;
        matrix4x4_t mat, matq;
 
@@ -1067,38 +1169,31 @@ qboolean CL_VM_TransformView(int entnum, matrix4x4_t *viewmatrix, mplane_t *clip
                ed = PRVM_EDICT_NUM(entnum);
                // camera:
                //   camera_transform
-               if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.camera_transform)) && val->function)
+               if(PRVM_clientedictfunction(ed, camera_transform))
                {
                        ret = true;
                        if(viewmatrix || clipplane || visorigin)
                        {
-                               valforward = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_forward);
-                               valright = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_right);
-                               valup = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_up);
-                               valendpos = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_endpos);
-                               if(valforward && valright && valup && valendpos)
-                               {
-                                       Matrix4x4_ToVectors(viewmatrix, forward, left, up, origin);
-                                       AnglesFromVectors(ang, forward, up, false);
-                                       prog->globals.client->time = cl.time;
-                                       prog->globals.client->self = entnum;
-                                       VectorCopy(origin, PRVM_G_VECTOR(OFS_PARM0));
-                                       VectorCopy(ang, PRVM_G_VECTOR(OFS_PARM1));
-                                       VectorCopy(forward, valforward->vector);
-                                       VectorScale(left, -1, valright->vector);
-                                       VectorCopy(up, valup->vector);
-                                       VectorCopy(origin, valendpos->vector);
-                                       PRVM_ExecuteProgram(val->function, "QC function e.camera_transform is missing");
-                                       VectorCopy(PRVM_G_VECTOR(OFS_RETURN), origin);
-                                       VectorCopy(valforward->vector, forward);
-                                       VectorScale(valright->vector, -1, left);
-                                       VectorCopy(valup->vector, up);
-                                       VectorCopy(valendpos->vector, visorigin);
-                                       Matrix4x4_Invert_Full(&mat, viewmatrix);
-                                       Matrix4x4_FromVectors(viewmatrix, forward, left, up, origin);
-                                       Matrix4x4_Concat(&matq, viewmatrix, &mat);
-                                       Matrix4x4_TransformPositivePlane(&matq, clipplane->normal[0], clipplane->normal[1], clipplane->normal[2], clipplane->dist, &clipplane->normal[0]);
-                               }
+                               Matrix4x4_ToVectors(viewmatrix, forward, left, up, origin);
+                               AnglesFromVectors(ang, forward, up, false);
+                               PRVM_clientglobalfloat(time) = cl.time;
+                               PRVM_clientglobaledict(self) = entnum;
+                               VectorCopy(origin, PRVM_G_VECTOR(OFS_PARM0));
+                               VectorCopy(ang, PRVM_G_VECTOR(OFS_PARM1));
+                               VectorCopy(forward, PRVM_clientglobalvector(v_forward));
+                               VectorScale(left, -1, PRVM_clientglobalvector(v_right));
+                               VectorCopy(up, PRVM_clientglobalvector(v_up));
+                               VectorCopy(origin, PRVM_clientglobalvector(trace_endpos));
+                               PRVM_ExecuteProgram(PRVM_clientedictfunction(ed, camera_transform), "QC function e.camera_transform is missing");
+                               VectorCopy(PRVM_G_VECTOR(OFS_RETURN), origin);
+                               VectorCopy(PRVM_clientglobalvector(v_forward), forward);
+                               VectorScale(PRVM_clientglobalvector(v_right), -1, left);
+                               VectorCopy(PRVM_clientglobalvector(v_up), up);
+                               VectorCopy(PRVM_clientglobalvector(trace_endpos), visorigin);
+                               Matrix4x4_Invert_Full(&mat, viewmatrix);
+                               Matrix4x4_FromVectors(viewmatrix, forward, left, up, origin);
+                               Matrix4x4_Concat(&matq, viewmatrix, &mat);
+                               Matrix4x4_TransformPositivePlane(&matq, clipplane->normal[0], clipplane->normal[1], clipplane->normal[2], clipplane->dist, &clipplane->normal[0]);
                        }
                }
        CSQC_END
diff --git a/cvar.c b/cvar.c
index 707c54c5c0641b73528aa6c0b778b7845302d787..3dee0406d0351cc2ac9c39707dbca97ffb91e982 100644 (file)
--- a/cvar.c
+++ b/cvar.c
@@ -105,32 +105,41 @@ cvar_t *Cvar_FindVarLink (const char *var_name, cvar_t **parent, cvar_t ***link,
 Cvar_VariableValue
 ============
 */
-float Cvar_VariableValue (const char *var_name)
+float Cvar_VariableValueOr (const char *var_name, float def)
 {
        cvar_t *var;
 
        var = Cvar_FindVar (var_name);
        if (!var)
-               return 0;
+               return def;
        return atof (var->string);
 }
 
+float Cvar_VariableValue (const char *var_name)
+{
+       return Cvar_VariableValueOr(var_name, 0);
+}
 
 /*
 ============
 Cvar_VariableString
 ============
 */
-const char *Cvar_VariableString (const char *var_name)
+const char *Cvar_VariableStringOr (const char *var_name, const char *def)
 {
        cvar_t *var;
 
        var = Cvar_FindVar (var_name);
        if (!var)
-               return cvar_null_string;
+               return def;
        return var->string;
 }
 
+const char *Cvar_VariableString (const char *var_name)
+{
+       return Cvar_VariableStringOr(var_name, cvar_null_string);
+}
+
 /*
 ============
 Cvar_VariableDefString
@@ -265,31 +274,32 @@ static void Cvar_UpdateAutoCvar(cvar_t *var)
                // MUST BE SYNCED WITH prvm_edict.c PRVM_LoadProgs
                int j;
                const char *s;
-               prvm_eval_t *val = (prvm_eval_t *)(prog->globals.generic + prog->globaldefs[var->globaldefindex[i]].ofs);
+               vec3_t v;
                switch(prog->globaldefs[var->globaldefindex[i]].type & ~DEF_SAVEGLOBAL)
                {
                        case ev_float:
-                               val->_float = var->value;
+                               PRVM_GLOBALFIELDFLOAT(prog->globaldefs[var->globaldefindex[i]].ofs) = var->value;
                                break;
                        case ev_vector:
                                s = var->string;
-                               VectorClear(val->vector);
+                               VectorClear(v);
                                for (j = 0;j < 3;j++)
                                {
                                        while (*s && ISWHITESPACE(*s))
                                                s++;
                                        if (!*s)
                                                break;
-                                       val->vector[j] = atof(s);
+                                       v[j] = atof(s);
                                        while (!ISWHITESPACE(*s))
                                                s++;
                                        if (!*s)
                                                break;
                                }
+                               VectorCopy(v, PRVM_GLOBALFIELDVECTOR(prog->globaldefs[var->globaldefindex[i]].ofs));
                                break;
                        case ev_string:
                                PRVM_ChangeEngineString(var->globaldefindex_stringno[i], var->string);
-                               val->string = var->globaldefindex_stringno[i];
+                               PRVM_GLOBALFIELDSTRING(prog->globaldefs[var->globaldefindex[i]].ofs) = var->globaldefindex_stringno[i];
                                break;
                }
        }
diff --git a/cvar.h b/cvar.h
index e80edc071364066266f5317e08eb2ca88c7230bf..4fd177d65407b10c421e413cd21ffa7dc1051ab5 100644 (file)
--- a/cvar.h
+++ b/cvar.h
@@ -165,9 +165,15 @@ void Cvar_SetValue (const char *var_name, float value);
 void Cvar_SetQuick (cvar_t *var, const char *value);
 void Cvar_SetValueQuick (cvar_t *var, float value);
 
+float Cvar_VariableValueOr (const char *var_name, float def);
+// returns def if not defined
+
 float Cvar_VariableValue (const char *var_name);
 // returns 0 if not defined or non numeric
 
+const char *Cvar_VariableStringOr (const char *var_name, const char *def);
+// returns def if not defined
+
 const char *Cvar_VariableString (const char *var_name);
 // returns an empty string if not defined
 
index 7ff4fcaddc85db1ac6c3daf82c2cc19e71b60522..2100605d5e2ca8f72e8abca72510bec52e465beb 100644 (file)
@@ -458,6 +458,7 @@ vector (vector v) cs_project = #311;
 void(float width, vector pos1, vector pos2, float flag) drawline = #315;
 float(string name) iscachedpic = #316;
 string(string name, float trywad) precache_pic = #317;
+string(string name) precache_cubemap = #317;
 vector(string picname) draw_getimagesize = #318;
 void(string name) freepic = #319;
 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter = #320;
@@ -675,7 +676,7 @@ void(float theme) particletheme = #524; // restore p_ globals from saved theme
 float() particlethemesave = #525; // save p_ globals to new particletheme and return it's index
 void(float theme) particlethemeupdate = #525; // save p_ globals to new particletheme and return it's index
 void(float theme) particlethemefree = #526; // delete a particle theme
-float(vector org, vector vel) particle = #527; // returns 0 when failed, 1 when spawned
+float(vector org, vector vel) spawnparticle = #527; // returns 0 when failed, 1 when spawned
 float(vector org, vector vel, float theme) quickparticle = #527; // not reading globals, just theme, returns 0 when failed, 1 when spawned
 float(vector org, vector vel, float delay, float collisiondelay) delayedparticle = #528;
 float(vector org, vector vel, float delay, float collisiondelay, float theme) quickdelayedparticle = #528;
index 7602384076157d2c8c656e4a54ef93572cc1a766..91f5ee23d77bbf5278919618dc20daf4df2c7bd8 100644 (file)
@@ -278,6 +278,16 @@ float EF_LOWPRECISION = 4194304;
 //description:
 //controls rendering scale of the object, 0 is forced to be 1, darkplaces uses 1/16th accuracy and a limit of 15.9375, can be used to make an object larger or smaller.
 
+//DP_ENT_TRAILEFFECTNUM
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//field definitions:
+.float traileffectnum;
+//description:
+//use a custom effectinfo.txt effect on this entity, assign it like this:
+//self.traileffectnum = particleeffectnum("mycustomeffect");
+//this will do both the dlight and particle trail as described in the effect, basically equivalent to trailparticles() in CSQC but performed on a server entity.
+
 //DP_ENT_VIEWMODEL
 //idea: LordHavoc
 //darkplaces implementation: LordHavoc
@@ -286,29 +296,6 @@ float EF_LOWPRECISION = 4194304;
 //description:
 //this is a very special capability, attachs the entity to the view of the client specified, origin and angles become relative to the view of that client, all effects can be used (multiple skins on a weapon model etc)...  the entity is not visible to any other client.
 
-//DP_GECKO_SUPPORT
-//idea: Res2k, BlackHC
-//darkplaces implementation: Res2k, BlackHC
-//constant definitions:
-float GECKO_BUTTON_DOWN         = 0;
-float GECKO_BUTTON_UP           = 1;
-// either use down and up or just press but not all of them!
-float GECKO_BUTTON_PRESS        = 2;
-// use this for mouse events if needed?
-float GECKO_BUTTON_DOUBLECLICK  = 3;
-//builtin definitions:
-float(string name) gecko_create( string name ) = #487;
-void(string name) gecko_destroy( string name ) = #488;
-void(string name) gecko_navigate( string name, string URI ) = #489;
-float(string name) gecko_keyevent( string name, float key, float eventtype ) = #490;
-void gecko_mousemove( string name, float x, float y ) = #491;
-void gecko_resize( string name, float w, float h ) = #492;
-vector gecko_get_texture_extent( string name ) = #493;
-//engine-called QC prototypes:
-//string(string name, string query) Qecko_Query;
-//description:
-//provides an interface to the offscreengecko library and allows for internet browsing in games
-
 //DP_GFX_EXTERNALTEXTURES
 //idea: LordHavoc
 //darkplaces implementation: LordHavoc
@@ -476,6 +463,14 @@ void(entity e, entity tagentity, string tagname) setattachment = #443; // attach
 .float button6;
 .float button7;
 .float button8;
+.float button9;
+.float button10;
+.float button11;
+.float button12;
+.float button13;
+.float button14;
+.float button15;
+.float button16;
 //description:
 //set to the state of the +button3, +button4, +button5, +button6, +button7, and +button8 buttons from the client, this does not involve protocol changes (the extra 6 button bits were simply not used).
 //the exact mapping of protocol button bits on the server is:
@@ -525,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
@@ -583,11 +586,11 @@ float(float a) tan = #475; // returns tangent value (which is simply sin(a)/cos(
 //NOTE: copying a string-typed autocvar to another variable/field, and then
 //changing the cvar or returning from progs is UNDEFINED. Writing to autocvar
 //globals is UNDEFINED.  Accessing autocvar globals after cvar_set()ing that
-//cvar is IMPLEMENTATION DEFINED (an implementation may either yield the
-//previous, or the current, value). Whether autocvar globals, after restoring
-//a savegame, have the cvar's current value, or the original value at time of
-//saving, is UNDEFINED. Restoring a savegame however must not restore the
-//cvar values themselves.
+//cvar in the same frame is IMPLEMENTATION DEFINED (an implementation may
+//either yield the previous, or the current, value). Whether autocvar globals,
+//after restoring a savegame, have the cvar's current value, or the original
+//value at time of saving, is UNDEFINED. Restoring a savegame however must not
+//restore the cvar values themselves.
 //In case the cvar does NOT exist, then it is automatically created with the
 //value of the autocvar initializer, if given. This is possible with e.g.
 //frikqcc and fteqcc the following way:
@@ -1211,6 +1214,33 @@ float(string name, string value) registercvar = #93;
 //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
+//idea: divVerent
+//darkplaces implementation: divVerent
+//builtin definitions:
+void(entity e, float chan, string samp, float vol, float atten, float speed, float flags) sound7 = #8;
+float SOUNDFLAG_RELIABLE = 1;
+//description:
+//plays a sound, with some more flags
+//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"
+//- 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
+//- channel 0 is controlled by snd_channel0volume; channel 1 and -1 by
+//  snd_channel1volume, etc. (so, a channel shares the cvar with its respective
+//  auto-channel); however, the mod MUST define snd_channel8volume and upwards
+//  in default.cfg if they are to be used, as the engine does not create them
+//  to not litter the cvar list
+//- this extension applies to CSQC as well; CSQC_Event_Sound will get speed and
+//  flags as extra 7th and 8th argument
+//- WIP2 ideas: SOUNDFLAG_RELIABLE_TO_ONE, SOUNDFLAG_NOPHS, SOUNDFLAG_FORCELOOP
+//- NOTE: to check for this, ALSO OR a check with DP_SND_SOUND7 to also support
+//  the finished extension once done
+
 //DP_SND_OGGVORBIS
 //idea: Transfusion
 //darkplaces implementation: Elric
@@ -1584,6 +1614,7 @@ 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;
 //SOLID_BSP;
 //joint types:
 const float JOINTTYPE_POINT = 1;
@@ -1592,6 +1623,18 @@ const float JOINTTYPE_SLIDER = 3;
 const float JOINTTYPE_UNIVERSAL = 4;
 const float JOINTTYPE_HINGE2 = 5;
 const float JOINTTYPE_FIXED = -1;
+// common joint properties:
+// .entity aiment, enemy; // connected objects
+// .vector movedir;
+//   for a spring:
+//     movedir_x = spring constant (force multiplier, must be > 0)
+//     movedir_y = spring dampening constant to prevent oscillation (must be > 0)
+//     movedir_z = spring stop position (+/-)
+//   for a motor:
+//     movedir_x = desired motor velocity
+//     movedir_y = -1 * max motor force to use
+//     movedir_z = stop position (+/-), set to 0 for no stop
+//   note that ODE does not support both in one anyway
 //field definitions:
 .float mass; // ODE mass, standart value is 1
 .float bouncefactor;
@@ -1602,7 +1645,7 @@ void(entity e, float physics_enabled) physics_enable = #540; // enable or disabl
 void(entity e, vector force, vector force_pos) physics_addforce = #541; // apply a force from certain origin, length of force vector is power of force
 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 i loaded and ready, also to enable physics set "physice_ode" cvar to 1
+//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
 
@@ -2393,38 +2436,6 @@ void(float pause) setpause = #531;
 
 // EXPERIMENTAL (not finalized) EXTENSIONS:
 
-//DP_PHYSICS
-//idea: LordHavoc
-//darkplaces implementation: LordHavoc, divVerent
-//constant definitions:
-float SOLID_PHYSICS_BOX = 32;
-float SOLID_PHYSICS_SPHERE = 33;
-float SOLID_PHYSICS_CAPSULE = 34;
-float MOVETYPE_PHYSICS = 32;
-float JOINTTYPE_POINT = 1; // point; uses origin (anchor)
-float JOINTTYPE_HINGE = 2; // hinge; uses origin (anchor) and angles (axis)
-float JOINTTYPE_SLIDER = 3; // slider; uses angles (axis)
-float JOINTTYPE_UNIVERSAL = 4; // universal; uses origin (anchor) and angles (forward is axis1, up is axis2)
-float JOINTTYPE_HINGE2 = 5; // hinge2; uses origin (anchor), angles (axis1), velocity (axis2)
-//field definitions:
-.float mass;
-.float jointtype; // see JOINTTYPE_ definitions above
-// common joint properties:
-// .entity aiment, enemy; // connected objects
-// .vector movedir;
-//   for a spring:
-//     movedir_x = spring constant (force multiplier, must be > 0)
-//     movedir_y = spring dampening constant to prevent oscillation (must be > 0)
-//     movedir_z = spring stop position (+/-)
-//   for a motor:
-//     movedir_x = desired motor velocity
-//     movedir_y = -1 * max motor force to use
-//     movedir_z = stop position (+/-), set to 0 for no stop
-//   note that ODE does not support both in one anyway
-//description:
-//various physics properties can be defined in an entity and are executed via
-//ODE
-
 //DP_CRYPTO
 //idea: divVerent
 //darkplaces implementation: divVerent
index 5520844f473449e3cae9b4d579d3d3d3ce87877c..b23e6baf7af7673bb1d910de57690205253cdbbc 100644 (file)
@@ -465,3 +465,27 @@ string(float i) crypto_getmyidfp = #637; // retrieves the ID fingerprint of a gi
 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_GECKO_SUPPORT
+//idea: Res2k, BlackHC
+//darkplaces implementation: Res2k, BlackHC
+//constant definitions:
+float GECKO_BUTTON_DOWN         = 0;
+float GECKO_BUTTON_UP           = 1;
+// either use down and up or just press but not all of them!
+float GECKO_BUTTON_PRESS        = 2;
+// use this for mouse events if needed?
+float GECKO_BUTTON_DOUBLECLICK  = 3;
+//builtin definitions:
+float gecko_create( string name ) = #487;
+void gecko_destroy( string name ) = #488;
+void gecko_navigate( string name, string URI ) = #489;
+float gecko_keyevent( string name, float key, float eventtype ) = #490;
+void gecko_mousemove( string name, float x, float y ) = #491;
+void gecko_resize( string name, float w, float h ) = #492;
+vector gecko_get_texture_extent( string name ) = #493;
+//engine-called QC prototypes:
+//string(string name, string query) Qecko_Query;
+//description:
+//provides an interface to the offscreengecko library and allows for internet browsing in games
+
diff --git a/dpdefs/source_compare.pl b/dpdefs/source_compare.pl
new file mode 100755 (executable)
index 0000000..01dbfd4
--- /dev/null
@@ -0,0 +1,269 @@
+use strict;
+use warnings;
+
+my %vm = (
+       menu => {},
+       csprogs => {},
+       progs => {}
+);
+
+my $skip = 0;
+
+my $parsing_builtins = undef;
+my $parsing_builtin = 0;
+
+my $parsing_fields = undef;
+my $parsing_globals = undef;
+my $parsing_vm = undef;
+
+for(<../*.h>, <../*.c>)
+{
+       open my $fh, "<", $_
+               or die "<$_: $!";
+       while(<$fh>)
+       {
+               chomp;
+               if(/^#if 0$/)
+               {
+                       $skip = 1;
+               }
+               elsif(/^#else$/)
+               {
+                       $skip = 0;
+               }
+               elsif(/^#endif$/)
+               {
+                       $skip = 0;
+               }
+               elsif($skip)
+               {
+               }
+               elsif(/^prvm_builtin_t vm_m_/)
+               {
+                       $parsing_builtins = "menu";
+                       $parsing_builtin = 0;
+               }
+               elsif(/^prvm_builtin_t vm_cl_/)
+               {
+                       $parsing_builtins = "csprogs";
+                       $parsing_builtin = 0;
+               }
+               elsif(/^prvm_builtin_t vm_sv_/)
+               {
+                       $parsing_builtins = "progs";
+                       $parsing_builtin = 0;
+               }
+               elsif(/^\}/)
+               {
+                       $parsing_builtins = undef;
+                       $parsing_globals = undef;
+                       $parsing_fields = undef;
+                       $parsing_vm = undef;
+               }
+               elsif(/^typedef struct entvars_s$/)
+               {
+                       $parsing_fields = "fields";
+                       $parsing_vm = "progs";
+               }
+               elsif(/^typedef struct cl_entvars_s$/)
+               {
+                       $parsing_fields = "fields";
+                       $parsing_vm = "csprogs";
+               }
+               elsif(/^typedef struct prvm_prog_fieldoffsets_s$/)
+               {
+                       $parsing_fields = "fields";
+               }
+               elsif(/^typedef struct globalvars_s$/)
+               {
+                       $parsing_globals = "globals";
+                       $parsing_vm = "progs";
+               }
+               elsif(/^typedef struct cl_globalvars_s$/)
+               {
+                       $parsing_globals = "globals";
+                       $parsing_vm = "csprogs";
+               }
+               elsif(/^typedef struct m_globalvars_s$/)
+               {
+                       $parsing_globals = "globals";
+                       $parsing_vm = "menu";
+               }
+               elsif(/^typedef struct prvm_prog_globaloffsets_s$/)
+               {
+                       $parsing_globals = "globals";
+               }
+               elsif($parsing_builtins)
+               {
+                       s/\/\*.*?\*\// /g;
+                       if(/^\s*\/\//)
+                       {
+                       }
+                       elsif(/^NULL\b/)
+                       {
+                               $parsing_builtin += 1;
+                       }
+                       elsif(/^(\w+)\s*,?\s*\/\/\s+#(\d+)\s*(.*)/)
+                       {
+                               my $func = $1;
+                               my $builtin = int $2;
+                               my $descr = $3;
+                               my $extension = "DP_UNKNOWN";
+
+                               if($descr =~ s/\s+\(([0-9A-Z_]*)\)//)
+                               {
+                                       $extension = $1;
+                               }
+                               # 'void(vector ang) makevectors'
+
+                               if($descr eq "")
+                               {
+                               }
+                               elsif($descr eq "draw functions...")
+                               {
+                               }
+                               elsif($descr =~ /^\/\//)
+                               {
+                               }
+                               elsif($descr =~ /\) (\w+)/)
+                               {
+                                       $func = $1;
+                               }
+                               elsif($descr =~ /(\w+)\s*\(/)
+                               {
+                                       $func = $1;
+                               }
+                               elsif($descr =~ /^\w+$/)
+                               {
+                                       $func = $descr;
+                               }
+                               else
+                               {
+                                       warn "No function name found in $descr";
+                               }
+
+                               warn "builtin sequence error: #$builtin (expected: $parsing_builtin)"
+                                       if $builtin != $parsing_builtin;
+                               $parsing_builtin = $builtin + 1;
+                               $vm{$parsing_builtins}{builtins}[$builtin] = [0, $func, $extension];
+                       }
+                       else
+                       {
+                               warn "Fails to parse: $_";
+                       }
+               }
+               elsif($parsing_fields || $parsing_globals)
+               {
+                       my $f = $parsing_fields || $parsing_globals;
+                       if(/^\s*\/\//)
+                       {
+                       }
+                       elsif(/^\s+(?:int|float|string_t|vec3_t|func_t)\s+(\w+);\s*(?:\/\/(.*))?/)
+                       {
+                               my $name = $1;
+                               my $descr = $2 || "";
+                               my $extension = "DP_UNKNOWN";
+                               $extension = $1
+                                       if $descr =~ /\b([0-9A-Z_]+)\b/;
+                               my $found = undef;
+                               $vm{menu}{$f}{$name} = ($found = [0, $extension])
+                                       if $descr =~ /common|menu/;
+                               $vm{progs}{$f}{$name} = ($found = [0, $extension])
+                                       if $descr =~ /common|ssqc/;
+                               $vm{csprogs}{$f}{$name} = ($found = [0, $extension])
+                                       if $descr =~ /common|csqc/;
+                               $vm{$parsing_vm}{$f}{$name} = ($found = [0, $extension])
+                                       if not defined $found and defined $parsing_vm;
+                               warn "$descr does not yield info about target VM"
+                                       if not defined $found;
+                       }
+               }
+               elsif(/getglobal\w*\(\w+, "(\w+)"\)/)
+               {
+                       # hack for weird DP source 
+                       $vm{csprogs}{globals}{$1} = [0, "DP_CSQC_SPAWNPARTICLE"];
+               }
+       }
+       close $fh;
+}
+
+# now read in dpdefs
+for((
+       ["csprogsdefs.qc", "csprogs"],
+       ["dpextensions.qc", "progs"],
+       ["menudefs.qc", "menu"],
+       ["progsdefs.qc", "progs"]
+))
+{
+       my ($file, $v) = @$_;
+       open my $fh, "<", "$file"
+               or die "<$file: $!";
+       while(<$fh>)
+       {
+               s/\/\/.*//;
+               if(/^(?:float|entity|string|vector)\s+((?:\w+\s*,\s*)*\w+)\s*;/)
+               {
+                       for(split /\s*,\s*/, $1)
+                       {
+                               print "// $v: Global $_ declared but not defined\n"
+                                       if not $vm{$v}{globals}{$_};
+                               $vm{$v}{globals}{$_}[0] = 1; # documented!
+                       }
+               }
+               elsif(/^\.(?:float|entity|string|vector|void)(?:.*\))?\s+((?:\w+\s*,\s*)*\w+)\s*;/)
+               {
+                       for(split /\s*,\s*/, $1)
+                       {
+                               print "// $v: Field $_ declared but not defined\n"
+                                       if not $vm{$v}{fields}{$_};
+                               $vm{$v}{fields}{$_}[0] = 1; # documented!
+                       }
+               }
+               elsif(/#(\d+)/)
+               {
+                       print "// $v: Builtin #$1 declared but not defined\n"
+                               if not $vm{$v}{builtins}[$1];
+                       $vm{$v}{builtins}[$1][0] = 1; # documented!
+               }
+               else
+               {
+               }
+       }
+       close $fh;
+}
+
+# some dumb output
+for my $v(sort keys %vm)
+{
+       print "/******************************************\n";
+       print " * $v\n";
+       print " ******************************************/\n";
+       my $b = $vm{$v}{builtins};
+       for(0..@$b)
+       {
+               next if not defined $b->[$_];
+               my ($documented, $func, $extension) = @{$b->[$_]};
+               print "float $func(...) = #$_; // $extension\n"
+                       unless $documented;
+       }
+       my $g = $vm{$v}{globals};
+       for(sort keys %$g)
+       {
+               my ($documented, $extension) = @{$g->{$_}};
+               print "float $_; // $extension\n"
+                       unless $documented;
+       }
+       my $f = $vm{$v}{fields};
+       for(sort keys %$f)
+       {
+               my ($documented, $extension) = @{$f->{$_}};
+               print ".float $_; // $extension\n"
+                       unless $documented;
+       }
+
+}
+
+__END__
+use Data::Dumper;
+$Data::Dumper::Sortkeys = 1;
+print Dumper \%vm;
diff --git a/dpdefs/source_compare.txt b/dpdefs/source_compare.txt
new file mode 100644 (file)
index 0000000..4fb6d6b
--- /dev/null
@@ -0,0 +1,433 @@
+// progs: Builtin #487 declared but not defined
+// progs: Builtin #488 declared but not defined
+// progs: Builtin #489 declared but not defined
+// progs: Builtin #490 declared but not defined
+// progs: Builtin #491 declared but not defined
+// progs: Builtin #492 declared but not defined
+// progs: Builtin #493 declared but not defined
+// progs: Builtin #608 declared but not defined
+// progs: Field frame2 declared but not defined
+// progs: Field frame3 declared but not defined
+// progs: Field frame4 declared but not defined
+// progs: Field lerpfrac declared but not defined
+// progs: Field lerpfrac3 declared but not defined
+// progs: Field lerpfrac4 declared but not defined
+// progs: Field frame1time declared but not defined
+// progs: Field frame2time declared but not defined
+// progs: Field frame3time declared but not defined
+// progs: Field frame4time declared but not defined
+// menu: Global null_entity declared but not defined
+// progs: Global movedist declared but not defined
+// progs: Global gameover declared but not defined
+// progs: Global string_null declared but not defined
+// progs: Global newmis declared but not defined
+// progs: Global activator declared but not defined
+// progs: Global damage_attacker declared but not defined
+// progs: Global framecount declared but not defined
+// progs: Global skill declared but not defined
+// progs: Field map declared but not defined
+// progs: Field worldtype declared but not defined
+// progs: Field killtarget declared but not defined
+// progs: Field th_stand declared but not defined
+// progs: Field th_walk declared but not defined
+// progs: Field th_run declared but not defined
+// progs: Field th_missile declared but not defined
+// progs: Field th_melee declared but not defined
+// progs: Field th_pain declared but not defined
+// progs: Field th_die declared but not defined
+// progs: Field oldenemy declared but not defined
+// progs: Field speed declared but not defined
+// progs: Field lefty declared but not defined
+// progs: Field search_time declared but not defined
+// progs: Field attack_state declared but not defined
+// progs: Field attack_finished declared but not defined
+// progs: Field pain_finished declared but not defined
+// progs: Field invincible_finished declared but not defined
+// progs: Field invisible_finished declared but not defined
+// progs: Field super_damage_finished declared but not defined
+// progs: Field radsuit_finished declared but not defined
+// progs: Field spawnshieldtime declared but not defined
+// progs: Field invincible_time declared but not defined
+// progs: Field invincible_sound declared but not defined
+// progs: Field invisible_time declared but not defined
+// progs: Field invisible_sound declared but not defined
+// progs: Field super_time declared but not defined
+// progs: Field super_sound declared but not defined
+// progs: Field rad_time declared but not defined
+// progs: Field fly_sound declared but not defined
+// progs: Field show_hostile declared but not defined
+// progs: Field jump_flag declared but not defined
+// progs: Field swim_flag declared but not defined
+// progs: Field air_finished declared but not defined
+// progs: Field bubble_count declared but not defined
+// progs: Field deathtype declared but not defined
+// progs: Field mdl declared but not defined
+// progs: Field mangle declared but not defined
+// progs: Field t_length declared but not defined
+// progs: Field t_width declared but not defined
+// progs: Field dest declared but not defined
+// progs: Field dest1 declared but not defined
+// progs: Field dest2 declared but not defined
+// progs: Field wait declared but not defined
+// progs: Field delay declared but not defined
+// progs: Field trigger_field declared but not defined
+// progs: Field noise4 declared but not defined
+// progs: Field pausetime declared but not defined
+// progs: Field movetarget declared but not defined
+// progs: Field aflag declared but not defined
+// progs: Field dmg declared but not defined
+// progs: Field cnt declared but not defined
+// progs: Field think1 declared but not defined
+// progs: Field count declared but not defined
+// progs: Field lip declared but not defined
+// progs: Field state declared but not defined
+// progs: Field pos1 declared but not defined
+// progs: Field pos2 declared but not defined
+// progs: Field height declared but not defined
+// progs: Field waitmin declared but not defined
+// progs: Field waitmax declared but not defined
+// progs: Field cantrigger declared but not defined
+// progs: Global deathstring1 declared but not defined
+// progs: Global deathstring2 declared but not defined
+// progs: Global deathstring3 declared but not defined
+// progs: Global deathstring4 declared but not defined
+// progs: Global game declared but not defined
+// progs: Global darkmode declared but not defined
+// progs: Field bodyhealth declared but not defined
+// progs: Field iscorpse declared but not defined
+// progs: Field dest3 declared but not defined
+// progs: Field dest4 declared but not defined
+// progs: Field flame declared but not defined
+// progs: Field doobits declared but not defined
+// progs: Field rotate declared but not defined
+// progs: Field group declared but not defined
+// progs: Field keys_silver declared but not defined
+// progs: Field keys_gold declared but not defined
+// progs: Field havocattack declared but not defined
+// progs: Field havocpickup declared but not defined
+// progs: Field pickupevalfunc declared but not defined
+// progs: Field shoulddodge declared but not defined
+// progs: Field dangerrating declared but not defined
+// progs: Field bleedfunc declared but not defined
+// progs: Field count1 declared but not defined
+// progs: Field count2 declared but not defined
+// progs: Field count3 declared but not defined
+// progs: Field count4 declared but not defined
+// progs: Field count5 declared but not defined
+// progs: Field count6 declared but not defined
+// progs: Field cnt1 declared but not defined
+// progs: Field cnt2 declared but not defined
+// progs: Field obitfunc1 declared but not defined
+// progs: Field realowner declared but not defined
+// progs: Global maxclients declared but not defined
+// progs: Global numdecors declared but not defined
+// progs: Global maxdecors declared but not defined
+// progs: Field createdtime declared but not defined
+// progs: Field th_gib declared but not defined
+// progs: Field resist_bullet declared but not defined
+// progs: Field resist_explosive declared but not defined
+// progs: Field resist_energy declared but not defined
+// progs: Field resist_fire declared but not defined
+// progs: Field resist_ice declared but not defined
+// progs: Field resist_axe declared but not defined
+// progs: Field deathmsg declared but not defined
+// progs: Field regenthink declared but not defined
+// progs: Field isdecor declared but not defined
+// progs: Field radiusdamage_amount declared but not defined
+// progs: Field radiusdamage_force declared but not defined
+// progs: Field radiusdamage_hit declared but not defined
+// progs: Field radiusdamage_lasthit declared but not defined
+// progs: Field radiusdamage_ownerdamagescale declared but not defined
+// progs: Global raddamage_lasthit declared but not defined
+// progs: Field frozen declared but not defined
+// progs: Field thawtime declared but not defined
+// progs: Field thawedeffects declared but not defined
+// progs: Field thawedtouch declared but not defined
+// progs: Field thawedmovetype declared but not defined
+// progs: Field thawedthink declared but not defined
+// progs: Field thawedthinkdelay declared but not defined
+// progs: Field knockedloosefunc declared but not defined
+// progs: Field forcescale declared but not defined
+// progs: Field bleedratio declared but not defined
+// progs: Field damagemodifier declared but not defined
+// progs: Field healthregen declared but not defined
+// progs: Field healthlostthisframe declared but not defined
+// progs: Global monsterdamagescale declared but not defined
+// progs: Global monsterresistancescale declared but not defined
+// progs: Global playerdamagescale declared but not defined
+/******************************************
+ * csprogs
+ ******************************************/
+float VM_CL_checkpvs(...) = #240; // DP_UNKNOWN
+float skel_create(...) = #263; // FTE_CSQC_SKELETONOBJECTS
+float skel_build(...) = #264; // FTE_CSQC_SKELETONOBJECTS
+float skel_get_numbones(...) = #265; // FTE_CSQC_SKELETONOBJECTS
+float skel_get_bonename(...) = #266; // FTE_CSQC_SKELETONOBJECTS
+float skel_get_boneparent(...) = #267; // FTE_CSQC_SKELETONOBJECTS
+float skel_find_bone(...) = #268; // FTE_CSQC_SKELETONOBJECTS
+float skel_get_bonerel(...) = #269; // FTE_CSQC_SKELETONOBJECTS
+float skel_get_boneabs(...) = #270; // FTE_CSQC_SKELETONOBJECTS
+float skel_set_bone(...) = #271; // FTE_CSQC_SKELETONOBJECTS
+float skel_mul_bone(...) = #272; // FTE_CSQC_SKELETONOBJECTS
+float skel_mul_bones(...) = #273; // FTE_CSQC_SKELETONOBJECTS
+float skel_copybones(...) = #274; // FTE_CSQC_SKELETONOBJECTS
+float skel_delete(...) = #275; // FTE_CSQC_SKELETONOBJECTS
+float frameforname(...) = #276; // FTE_CSQC_SKELETONOBJECTS
+float frameduration(...) = #277; // FTE_CSQC_SKELETONOBJECTS
+float VM_drawsubpic(...) = #328; // DP_UNKNOWN
+float VM_drawrotpic(...) = #329; // DP_UNKNOWN
+float VM_CL_videoplaying(...) = #355; // DP_UNKNOWN
+float crc16(...) = #494; // DP_QC_CRC16
+float cvar_type(...) = #495; // DP_QC_CVAR_TYPE
+float numentityfields(...) = #496; // QP_QC_ENTITYDATA
+float entityfieldname(...) = #497; // DP_QC_ENTITYDATA
+float entityfieldtype(...) = #498; // DP_QC_ENTITYDATA
+float getentityfieldstring(...) = #499; // DP_QC_ENTITYDATA
+float putentityfieldstring(...) = #500; // DP_QC_ENTITYDATA
+float ReadPicture(...) = #501; // DP_UNKNOWN
+float boxparticles(...) = #502; // DP_CSQC_BOXPARTICLES
+float whichpack(...) = #503; // DP_UNKNOWN
+float uri_escape(...) = #510; // DP_UNKNOWN
+float uri_unescape(...) = #511; // DP_UNKNOWN
+float num_for_edict(...) = #512; // DP_QC_NUM_FOR_EDICT
+float tokenize_console(...) = #514; // DP_QC_TOKENIZE_CONSOLE
+float argv_start_index(...) = #515; // DP_QC_TOKENIZE_CONSOLE
+float argv_end_index(...) = #516; // DP_QC_TOKENIZE_CONSOLE
+float buf_cvarlist(...) = #517; // DP_QC_STRINGBUFFERS_CVARLIST
+float cvar_description(...) = #518; // DP_QC_CVAR_DESCRIPTION
+float gettime(...) = #519; // DP_QC_GETTIME
+float keynumtostring(...) = #520; // DP_UNKNOWN
+float findkeysforcommand(...) = #521; // DP_UNKNOWN
+float VM_loadfromdata(...) = #529; // DP_UNKNOWN
+float VM_loadfromfile(...) = #530; // DP_UNKNOWN
+float VM_log(...) = #532; // DP_UNKNOWN
+float getsoundtime(...) = #533; // DP_SND_GETSOUNDTIME
+float soundlength(...) = #534; // DP_SND_GETSOUNDTIME
+float physics_enable(...) = #540; // DP_PHYSICS_ODE
+float physics_addforce(...) = #541; // DP_PHYSICS_ODE
+float physics_addtorque(...) = #542; // DP_PHYSICS_ODE
+float VM_callfunction(...) = #605; // DP_UNKNOWN
+float VM_writetofile(...) = #606; // DP_UNKNOWN
+float VM_isfunction(...) = #607; // DP_UNKNOWN
+float VM_parseentitydata(...) = #613; // DP_UNKNOWN
+float getextresponse(...) = #624; // DP_UNKNOWN
+float sprintf(...) = #627; // DP_UNKNOWN
+float getsurfacenumpoints(...) = #628; // DP_QC_GETSURFACETRIANGLE
+float getsurfacepoint(...) = #629; // DP_QC_GETSURFACETRIANGLE
+float VM_CL_RotateMoves(...) = #638; // DP_UNKNOWN
+float CSQC_ConsoleCommand; // DP_UNKNOWN
+float CSQC_Init; // DP_UNKNOWN
+float CSQC_InputEvent; // DP_UNKNOWN
+float CSQC_Shutdown; // DP_UNKNOWN
+float CSQC_UpdateView; // DP_UNKNOWN
+float coop; // DP_UNKNOWN
+float deathmatch; // DP_UNKNOWN
+float dmg_origin; // DP_UNKNOWN
+float dmg_save; // DP_UNKNOWN
+float dmg_take; // DP_UNKNOWN
+float drawfontscale; // DP_UNKNOWN
+float gettaginfo_forward; // DP_UNKNOWN
+float gettaginfo_name; // DP_UNKNOWN
+float gettaginfo_offset; // DP_UNKNOWN
+float gettaginfo_parent; // DP_UNKNOWN
+float gettaginfo_right; // DP_UNKNOWN
+float gettaginfo_up; // DP_UNKNOWN
+float particles_alphamax; // DP_UNKNOWN
+float particles_alphamin; // DP_UNKNOWN
+float particles_colormax; // DP_UNKNOWN
+float particles_colormin; // DP_UNKNOWN
+float sb_showscores; // DP_UNKNOWN
+float serverdeltatime; // DP_UNKNOWN
+float serverprevtime; // DP_UNKNOWN
+float servertime; // DP_UNKNOWN
+float trace_dphitcontents; // DP_UNKNOWN
+float trace_dphitq3surfaceflags; // DP_UNKNOWN
+float trace_dphittexturename; // DP_UNKNOWN
+float trace_dpstartcontents; // DP_UNKNOWN
+float trace_networkentity; // DP_UNKNOWN
+.float aiment; // DP_UNKNOWN
+.float alpha; // DP_UNKNOWN
+.float camera_transform; // DP_UNKNOWN
+.float colormod; // DP_UNKNOWN
+.float dimension_hit; // DP_UNKNOWN
+.float dimension_solid; // DP_UNKNOWN
+.float dphitcontentsmask; // DP_UNKNOWN
+.float fatness; // DP_UNKNOWN
+.float forceshader; // DP_UNKNOWN
+.float frame1time; // DP_UNKNOWN
+.float frame2; // DP_UNKNOWN
+.float frame2time; // DP_UNKNOWN
+.float frame3; // DP_UNKNOWN
+.float frame3time; // DP_UNKNOWN
+.float frame4; // DP_UNKNOWN
+.float frame4time; // DP_UNKNOWN
+.float glowmod; // DP_UNKNOWN
+.float groundentity; // DP_UNKNOWN
+.float hull; // DP_UNKNOWN
+.float ideal_yaw; // DP_UNKNOWN
+.float idealpitch; // DP_UNKNOWN
+.float jointtype; // DP_UNKNOWN
+.float lerpfrac; // DP_UNKNOWN
+.float lerpfrac3; // DP_UNKNOWN
+.float lerpfrac4; // DP_UNKNOWN
+.float mass; // DP_UNKNOWN
+.float message; // DP_UNKNOWN
+.float movedir; // DP_UNKNOWN
+.float pitch_speed; // DP_UNKNOWN
+.float renderflags; // DP_UNKNOWN
+.float scale; // DP_UNKNOWN
+.float shadertime; // DP_UNKNOWN
+.float skeletonindex; // FTE_CSQC_SKELETONOBJECTS
+.float tag_entity; // DP_UNKNOWN
+.float tag_index; // DP_UNKNOWN
+.float userwavefunc_param0; // DP_UNKNOWN
+.float userwavefunc_param1; // DP_UNKNOWN
+.float userwavefunc_param2; // DP_UNKNOWN
+.float userwavefunc_param3; // DP_UNKNOWN
+.float yaw_speed; // DP_UNKNOWN
+/******************************************
+ * menu
+ ******************************************/
+float VM_itof(...) = #79; // DP_UNKNOWN
+float VM_ftoe(...) = #80; // DP_UNKNOWN
+float isString(...) = #81; // DP_UNKNOWN
+float VM_altstr_count(...) = #82; // DP_UNKNOWN
+float VM_altstr_prepare(...) = #83; // DP_UNKNOWN
+float VM_altstr_get(...) = #84; // DP_UNKNOWN
+float VM_altstr_set(...) = #85; // DP_UNKNOWN
+float VM_altstr_ins(...) = #86; // DP_UNKNOWN
+float VM_findflags(...) = #87; // DP_UNKNOWN
+float VM_findchainflags(...) = #88; // DP_UNKNOWN
+float VM_cvar_defstring(...) = #89; // DP_UNKNOWN
+float strstrofs(...) = #221; // FTE_STRINGS
+float str2chr(...) = #222; // FTE_STRINGS
+float chr2str(...) = #223; // FTE_STRINGS
+float strconv(...) = #224; // FTE_STRINGS
+float strpad(...) = #225; // FTE_STRINGS
+float infoadd(...) = #226; // FTE_STRINGS
+float infoget(...) = #227; // FTE_STRINGS
+float strncmp(...) = #228; // FTE_STRINGS
+float strcasecmp(...) = #229; // FTE_STRINGS
+float strncasecmp(...) = #230; // FTE_STRINGS
+float keynumtostring(...) = #340; // DP_UNKNOWN
+float VM_CL_isdemo(...) = #349; // DP_UNKNOWN
+float wasfreed(...) = #353; // DP_UNKNOWN
+float VM_CL_videoplaying(...) = #355; // DP_UNKNOWN
+float loadfont(...) = #356; // DP_GFX_FONTS
+float loadfont(...) = #357; // DP_GFX_FONTS
+float buf_create(...) = #440; // DP_QC_STRINGBUFFERS
+float buf_del(...) = #441; // DP_QC_STRINGBUFFERS
+float buf_getsize(...) = #442; // DP_QC_STRINGBUFFERS
+float buf_copy(...) = #443; // DP_QC_STRINGBUFFERS
+float buf_sort(...) = #444; // DP_QC_STRINGBUFFERS
+float buf_implode(...) = #445; // DP_QC_STRINGBUFFERS
+float bufstr_get(...) = #446; // DP_QC_STRINGBUFFERS
+float bufstr_set(...) = #447; // DP_QC_STRINGBUFFERS
+float bufstr_add(...) = #448; // DP_QC_STRINGBUFFERS
+float bufstr_free(...) = #449; // DP_QC_STRINGBUFFERS
+float VM_cin_open(...) = #461; // DP_UNKNOWN
+float VM_cin_close(...) = #462; // DP_UNKNOWN
+float VM_cin_setstate(...) = #463; // DP_UNKNOWN
+float VM_cin_getstate(...) = #464; // DP_UNKNOWN
+float VM_cin_restart(...) = #465; // DP_UNKNOWN
+float VM_drawline(...) = #466; // DP_UNKNOWN
+float VM_stringwidth(...) = #468; // DP_UNKNOWN
+float VM_drawsubpic(...) = #469; // DP_UNKNOWN
+float VM_drawrotpic(...) = #470; // DP_UNKNOWN
+float VM_asin(...) = #471; // DP_QC_ASINACOSATANATAN2TAN
+float VM_acos(...) = #472; // DP_QC_ASINACOSATANATAN2TAN
+float VM_atan(...) = #473; // DP_QC_ASINACOSATANATAN2TAN
+float VM_atan2(...) = #474; // DP_QC_ASINACOSATANATAN2TAN
+float VM_tan(...) = #475; // DP_QC_ASINACOSATANATAN2TAN
+float float(...) = #476; // DP_QC_STRINGCOLORFUNCTIONS
+float string(...) = #477; // DP_QC_STRINGCOLORFUNCTIONS
+float string(...) = #478; // DP_QC_STRFTIME
+float tokenizebyseparator(...) = #479; // DP_QC_TOKENIZEBYSEPARATOR
+float VM_strtolower(...) = #480; // DP_UNKNOWN
+float VM_strtoupper(...) = #481; // DP_UNKNOWN
+float strreplace(...) = #484; // DP_QC_STRREPLACE
+float strireplace(...) = #485; // DP_QC_STRREPLACE
+float gecko_create(...) = #487; // DP_UNKNOWN
+float gecko_destroy(...) = #488; // DP_UNKNOWN
+float gecko_navigate(...) = #489; // DP_UNKNOWN
+float gecko_keyevent(...) = #490; // DP_UNKNOWN
+float gecko_mousemove(...) = #491; // DP_UNKNOWN
+float gecko_resize(...) = #492; // DP_UNKNOWN
+float gecko_get_texture_extent(...) = #493; // DP_UNKNOWN
+float crc16(...) = #494; // DP_QC_CRC16
+float cvar_type(...) = #495; // DP_QC_CVAR_TYPE
+float whichpack(...) = #503; // DP_UNKNOWN
+float uri_escape(...) = #510; // DP_UNKNOWN
+float uri_unescape(...) = #511; // DP_UNKNOWN
+float num_for_edict(...) = #512; // DP_QC_NUM_FOR_EDICT
+float tokenize_console(...) = #514; // DP_QC_TOKENIZE_CONSOLE
+float argv_start_index(...) = #515; // DP_QC_TOKENIZE_CONSOLE
+float argv_end_index(...) = #516; // DP_QC_TOKENIZE_CONSOLE
+float buf_cvarlist(...) = #517; // DP_QC_STRINGBUFFERS_CVARLIST
+float cvar_description(...) = #518; // DP_QC_CVAR_DESCRIPTION
+float VM_log(...) = #532; // DP_UNKNOWN
+float getsoundtime(...) = #533; // DP_SND_GETSOUNDTIME
+float soundlength(...) = #534; // DP_SND_GETSOUNDTIME
+float parseentitydata(...) = #613; // DP_UNKNOWN
+float stringtokeynum(...) = #614; // DP_UNKNOWN
+float resethostcachemasks(...) = #615; // DP_UNKNOWN
+float sethostcachemaskstring(...) = #616; // DP_UNKNOWN
+float sethostcachemasknumber(...) = #617; // DP_UNKNOWN
+float resorthostcache(...) = #618; // DP_UNKNOWN
+float sethostcachesort(...) = #619; // DP_UNKNOWN
+float refreshhostcache(...) = #620; // DP_UNKNOWN
+float gethostcachenumber(...) = #621; // DP_UNKNOWN
+float gethostcacheindexforkey(...) = #622; // DP_UNKNOWN
+float addwantedhostcachekey(...) = #623; // DP_UNKNOWN
+float getextresponse(...) = #624; // DP_UNKNOWN
+float netaddress_resolve(...) = #625; // DP_UNKNOWN
+float getgamedirinfo(...) = #626; // DP_UNKNOWN
+float sprintf(...) = #627; // DP_UNKNOWN
+float drawfont; // DP_UNKNOWN
+float drawfontscale; // DP_UNKNOWN
+.float angles; // DP_UNKNOWN
+.float chain; // DP_UNKNOWN
+.float classname; // DP_UNKNOWN
+.float frame; // OP_STATE
+.float nextthink; // OP_STATE
+.float think; // OP_STATE
+/******************************************
+ * progs
+ ******************************************/
+float setmodelindex(...) = #333; // EXT_CSQC
+float modelnameforindex(...) = #334; // EXT_CSQC
+float isserver(...) = #350; // EXT_CSQC
+float serverkey(...) = #354; // EXT_CSQC
+float VM_parseentitydata(...) = #613; // DP_UNKNOWN
+float ClientConnect; // DP_UNKNOWN
+float ClientDisconnect; // DP_UNKNOWN
+float ClientKill; // DP_UNKNOWN
+float PlayerPostThink; // DP_UNKNOWN
+float PlayerPreThink; // DP_UNKNOWN
+float PutClientInServer; // DP_UNKNOWN
+float SV_InitCmd; // DP_UNKNOWN
+float SetChangeParms; // DP_UNKNOWN
+float SetNewParms; // DP_UNKNOWN
+float StartFrame; // DP_UNKNOWN
+float main; // DP_UNKNOWN
+float require_spawnfunc_prefix; // DP_UNKNOWN
+.float SendEntity; // DP_UNKNOWN
+.float SendFlags; // DP_UNKNOWN
+.float Version; // DP_UNKNOWN
+.float ammo_cells1; // DP_UNKNOWN
+.float ammo_lava_nails; // DP_UNKNOWN
+.float ammo_multi_rockets; // DP_UNKNOWN
+.float ammo_nails1; // DP_UNKNOWN
+.float ammo_plasma; // DP_UNKNOWN
+.float ammo_rockets1; // DP_UNKNOWN
+.float ammo_shells1; // DP_UNKNOWN
+.float dimension_hit; // DP_UNKNOWN
+.float dimension_solid; // DP_UNKNOWN
+.float fatness; // DP_UNKNOWN
+.float fullbright; // DP_UNKNOWN
+.float hull; // DP_UNKNOWN
+.float items2; // DP_UNKNOWN
+.float pmodel; // DP_UNKNOWN
+.float renderamt; // DP_UNKNOWN
+.float rendermode; // DP_UNKNOWN
+.float sendcomplexanimation; // DP_UNKNOWN
index 86d4f7b5cbc7d8a5da85e155a23124358cff7e9e..179a4d0c5fe93cae3b4668e1f4d9221c6a79082c 100644 (file)
@@ -249,9 +249,6 @@ typedef ATOMIC(struct DPSOFTRAST_State_Thread_s
        int depthtest;
        int depthfunc;
        int scissortest;
-       int alphatest;
-       int alphafunc;
-       float alphavalue;
        int viewport[4];
        int scissor[4];
        float depthrange[2];
@@ -1168,30 +1165,6 @@ void DPSOFTRAST_CullFace(int mode)
        command->mode = mode;
 }
 
-DEFCOMMAND(15, AlphaTest, int enable;)
-static void DPSOFTRAST_Interpret_AlphaTest(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_AlphaTest *command)
-{
-       thread->alphatest = command->enable;
-}
-void DPSOFTRAST_AlphaTest(int enable)
-{
-       DPSOFTRAST_Command_AlphaTest *command = DPSOFTRAST_ALLOCATECOMMAND(AlphaTest);
-       command->enable = enable;
-}
-
-DEFCOMMAND(16, AlphaFunc, int func; float ref;)
-static void DPSOFTRAST_Interpret_AlphaFunc(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_AlphaFunc *command)
-{
-       thread->alphafunc = command->func;
-       thread->alphavalue = command->ref;
-}
-void DPSOFTRAST_AlphaFunc(int func, float ref)
-{
-       DPSOFTRAST_Command_AlphaFunc *command = DPSOFTRAST_ALLOCATECOMMAND(AlphaFunc);
-       command->func = func;
-       command->ref = ref;
-}
-
 void DPSOFTRAST_Color4f(float r, float g, float b, float a)
 {
        dpsoftrast.color[0] = r;
@@ -2076,7 +2049,7 @@ void DPSOFTRAST_Draw_Span_FinishBGRA8(DPSOFTRAST_State_Thread *thread, const DPS
        pixel += (span->y * dpsoftrast.fb_width + span->x) * 4;
        pixeli += span->y * dpsoftrast.fb_width + span->x;
        // handle alphatest now (this affects depth writes too)
-       if (thread->alphatest)
+       if (thread->shader_permutation & SHADERPERMUTATION_ALPHAKILL)
                for (x = startx;x < endx;x++)
                        if (in4ub[x*4+3] < 128)
                                pixelmask[x] = false;
@@ -3333,7 +3306,7 @@ void DPSOFTRAST_PixelShader_FlatColor(DPSOFTRAST_State_Thread *thread, const DPS
        unsigned char buffer_FragColorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4];
        DPSOFTRAST_Draw_Span_Begin(thread, triangle, span, buffer_z);
        DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_colorbgra8, GL20TU_COLOR, 2, buffer_z);
-       if (thread->alphatest || thread->fb_blendmode != DPSOFTRAST_BLENDMODE_OPAQUE)
+       if ((thread->shader_permutation & SHADERPERMUTATION_ALPHAKILL) || thread->fb_blendmode != DPSOFTRAST_BLENDMODE_OPAQUE)
                pixel = buffer_FragColorbgra8;
        Color_Ambientm = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(&thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Ambient*4]), _mm_set1_ps(256.0f))), _MM_SHUFFLE(3, 0, 1, 2));
        Color_Ambientm = _mm_and_si128(Color_Ambientm, _mm_setr_epi32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0));
@@ -3386,7 +3359,7 @@ void DPSOFTRAST_PixelShader_VertexColor(DPSOFTRAST_State_Thread *thread, const D
        int arrayindex = DPSOFTRAST_ARRAY_COLOR;
        DPSOFTRAST_Draw_Span_Begin(thread, triangle, span, buffer_z);
        DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_colorbgra8, GL20TU_COLOR, 2, buffer_z);
-       if (thread->alphatest || thread->fb_blendmode != DPSOFTRAST_BLENDMODE_OPAQUE)
+       if ((thread->shader_permutation & SHADERPERMUTATION_ALPHAKILL) || thread->fb_blendmode != DPSOFTRAST_BLENDMODE_OPAQUE)
                pixel = buffer_FragColorbgra8;
        Color_Ambientm = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(&thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Ambient*4]), _mm_set1_ps(256.0f))), _MM_SHUFFLE(3, 0, 1, 2));
        Color_Ambientm = _mm_and_si128(Color_Ambientm, _mm_setr_epi32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0));
@@ -3461,7 +3434,7 @@ void DPSOFTRAST_PixelShader_Lightmap(DPSOFTRAST_State_Thread *thread, const DPSO
        DPSOFTRAST_Draw_Span_Begin(thread, triangle, span, buffer_z);
        DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_colorbgra8, GL20TU_COLOR, DPSOFTRAST_ARRAY_TEXCOORD0, buffer_z);
        DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_lightmapbgra8, GL20TU_LIGHTMAP, DPSOFTRAST_ARRAY_TEXCOORD4, buffer_z);
-       if (thread->alphatest || thread->fb_blendmode != DPSOFTRAST_BLENDMODE_OPAQUE)
+       if ((thread->shader_permutation & SHADERPERMUTATION_ALPHAKILL) || thread->fb_blendmode != DPSOFTRAST_BLENDMODE_OPAQUE)
                pixel = buffer_FragColorbgra8;
        Color_Ambientm = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(&thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Ambient*4]), _mm_set1_ps(256.0f))), _MM_SHUFFLE(3, 0, 1, 2));
        Color_Ambientm = _mm_and_si128(Color_Ambientm, _mm_setr_epi32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0));
@@ -4593,9 +4566,9 @@ void DPSOFTRAST_PixelShader_Water(DPSOFTRAST_State_Thread *thread, const DPSOFTR
        float EyeVectorslope[4];
 
        // uniforms
-       float ScreenScaleRefractReflect[2];
-       float ScreenCenterRefractReflect[2];
-       float DistortScaleRefractReflect[2];
+       float ScreenScaleRefractReflect[4];
+       float ScreenCenterRefractReflect[4];
+       float DistortScaleRefractReflect[4];
        float RefractColor[4];
        float ReflectColor[4];
        float ReflectFactor;
@@ -5486,8 +5459,6 @@ static void DPSOFTRAST_Draw_InterpretCommands(DPSOFTRAST_State_Thread *thread, i
                INTERPCOMMAND(DepthRange)
                INTERPCOMMAND(PolygonOffset)
                INTERPCOMMAND(CullFace)
-               INTERPCOMMAND(AlphaTest)
-               INTERPCOMMAND(AlphaFunc)
                INTERPCOMMAND(SetTexture)
                INTERPCOMMAND(SetShader)
                INTERPCOMMAND(Uniform4f)
@@ -5643,9 +5614,6 @@ int DPSOFTRAST_Init(int width, int height, int numthreads, int interlace, unsign
                thread->depthtest = true;
                thread->depthfunc = GL_LEQUAL;
                thread->scissortest = false;
-               thread->alphatest = false;
-               thread->alphafunc = GL_GREATER;
-               thread->alphavalue = 0.5f;
                thread->viewport[0] = 0;
                thread->viewport[1] = 0;
                thread->viewport[2] = dpsoftrast.fb_width;
index 6b7a706710b34905d4458caa04c4f5efd2974637..1d2f4d7c3b60c523b64d027cedb49e098c9e6288 100644 (file)
@@ -65,8 +65,6 @@ void DPSOFTRAST_DepthFunc(int comparemode);
 void DPSOFTRAST_DepthRange(float range0, float range1);
 void DPSOFTRAST_PolygonOffset(float alongnormal, float intoview);
 void DPSOFTRAST_CullFace(int mode);
-void DPSOFTRAST_AlphaTest(int enable);
-void DPSOFTRAST_AlphaFunc(int alphafunc, float alphavalue);
 void DPSOFTRAST_Color4f(float r, float g, float b, float a);
 void DPSOFTRAST_GetPixelsBGRA(int blockx, int blocky, int blockwidth, int blockheight, unsigned char *outpixels);
 void DPSOFTRAST_CopyRectangleToTexture(int index, int mip, int tx, int ty, int sx, int sy, int width, int height);
@@ -153,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)
@@ -196,8 +196,9 @@ typedef enum shaderpermutation_e
        SHADERPERMUTATION_NORMALMAPSCROLLBLEND = 1<<27, ///< (water) counter-direction normalmaps scrolling
        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_LIMIT = 1<<30, ///< size of permutations array
-       SHADERPERMUTATION_COUNT = 30 ///< size of shaderpermutationinfo array
+       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_t;
 
index 6ace51c0f6daada3d1c3368ab79b88117e6d8222..2cf5e82f6aa45a0d3c0576aed4a87e9677b94c78 100644 (file)
@@ -429,7 +429,7 @@ void dpvsimpledecode_close(void *stream)
        if (s->videopixels)
                Z_Free(s->videopixels);
        if (s->sndchan != -1)
-               S_StopChannel (s->sndchan, true);
+               S_StopChannel (s->sndchan, true, true);
        if (s->framedatablocks)
                hz_bitstream_read_blocks_free(s->framedatablocks);
        if (s->bitstream)
diff --git a/draw.h b/draw.h
index 7c3b6543766a46ad26c9d40a84b11f087587312f..c7f1bc273245a7237f9d7b65a320f7e42be95b41 100644 (file)
--- a/draw.h
+++ b/draw.h
@@ -39,6 +39,8 @@ typedef struct cachepic_s
        rtexture_t *tex;
        // used for hash lookups
        struct cachepic_s *chain;
+       // flags - CACHEPICFLAG_NEWPIC for example
+       unsigned int flags;
        // has alpha?
        qboolean hasalpha;
        // name of pic
@@ -51,7 +53,8 @@ typedef enum cachepicflags_e
        CACHEPICFLAG_NOTPERSISTENT = 1,
        CACHEPICFLAG_QUIET = 2,
        CACHEPICFLAG_NOCOMPRESSION = 4,
-       CACHEPICFLAG_NOCLAMP = 8
+       CACHEPICFLAG_NOCLAMP = 8,
+       CACHEPICFLAG_NEWPIC = 16 // disables matching texflags check, because a pic created with Draw_NewPic should not be subject to that
 }
 cachepicflags_t;
 
@@ -91,6 +94,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
 {
@@ -188,7 +192,11 @@ void DrawQ_Finish(void);
 void DrawQ_ProcessDrawFlag(int flags, qboolean alpha); // sets GL_DepthMask and GL_BlendFunc
 void DrawQ_RecalcView(void); // use this when changing r_refdef.view.* from e.g. csqc
 
+rtexture_t *Draw_GetPicTexture(cachepic_t *pic);
+
 void R_DrawGamma(void);
 
+extern rtexturepool_t *drawtexturepool; // used by ft2.c
+
 #endif
 
index 4bacbc15a1704029ff223c09b98a8c369bff8bf1..997116766de56c1bf599543a16cb69dc0d9dfa21 100644 (file)
@@ -117,22 +117,37 @@ void stringlistappend(stringlist_t *list, const char *text)
        list->numstrings++;
 }
 
-void stringlistsort(stringlist_t *list)
+static int stringlistsort_cmp(const void *a, const void *b)
+{
+       return strcasecmp(*(const char **)a, *(const char **)b);
+}
+
+void stringlistsort(stringlist_t *list, qboolean uniq)
 {
        int i, j;
-       char *temp;
-       // this is a selection sort (finds the best entry for each slot)
-       for (i = 0;i < list->numstrings - 1;i++)
+       if(list->numstrings < 1)
+               return;
+       qsort(&list->strings[0], list->numstrings, sizeof(list->strings[0]), stringlistsort_cmp);
+       if(uniq)
        {
-               for (j = i + 1;j < list->numstrings;j++)
+               // i: the item to read
+               // j: the item last written
+               for (i = 1, j = 0; i < list->numstrings; ++i)
                {
-                       if (strcasecmp(list->strings[i], list->strings[j]) > 0)
-                       {
-                               temp = list->strings[i];
-                               list->strings[i] = list->strings[j];
-                               list->strings[j] = temp;
-                       }
+                       char *save;
+                       if(!strcasecmp(list->strings[i], list->strings[j]))
+                               continue;
+                       ++j;
+                       save = list->strings[j];
+                       list->strings[j] = list->strings[i];
+                       list->strings[i] = save;
+               }
+               for(i = j+1; i < list->numstrings; ++i)
+               {
+                       if (list->strings[i])
+                               Z_Free(list->strings[i]);
                }
+               list->numstrings = j+1;
        }
 }
 
diff --git a/fs.c b/fs.c
index b26dd4f25cc13938c31ea2268b701a7819c6d063..d810ff541f1b6e497dc6489150dd1f38415d4c57 100644 (file)
--- a/fs.c
+++ b/fs.c
@@ -60,6 +60,7 @@
 
 // largefile support for Win32
 #ifdef WIN32
+#undef lseek
 # define lseek _lseeki64
 #endif
 
@@ -411,7 +412,46 @@ static dllfunction_t shfolderfuncs[] =
        {"SHGetFolderPathA", (void **) &qSHGetFolderPath},
        {NULL, NULL}
 };
+static const char* shfolderdllnames [] =
+{
+       "shfolder.dll",  // IE 4, or Win NT and higher
+       NULL
+};
 static dllhandle_t shfolder_dll = NULL;
+
+const GUID qFOLDERID_SavedGames = {0x4C5C32FF, 0xBB9D, 0x43b0, {0xB5, 0xB4, 0x2D, 0x72, 0xE5, 0x4E, 0xAA, 0xA4}}; 
+#define qREFKNOWNFOLDERID const GUID *
+#define qKF_FLAG_CREATE 0x8000
+#define qKF_FLAG_NO_ALIAS 0x1000
+static HRESULT (WINAPI *qSHGetKnownFolderPath) (qREFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath);
+static dllfunction_t shell32funcs[] =
+{
+       {"SHGetKnownFolderPath", (void **) &qSHGetKnownFolderPath},
+       {NULL, NULL}
+};
+static const char* shell32dllnames [] =
+{
+       "shell32.dll",  // Vista and higher
+       NULL
+};
+static dllhandle_t shell32_dll = NULL;
+
+static HRESULT (WINAPI *qCoInitializeEx)(LPVOID pvReserved, DWORD dwCoInit);
+static void (WINAPI *qCoUninitialize)(void);
+static void (WINAPI *qCoTaskMemFree)(LPVOID pv);
+static dllfunction_t ole32funcs[] =
+{
+       {"CoInitializeEx", (void **) &qCoInitializeEx},
+       {"CoUninitialize", (void **) &qCoUninitialize},
+       {"CoTaskMemFree", (void **) &qCoTaskMemFree},
+       {NULL, NULL}
+};
+static const char* ole32dllnames [] =
+{
+       "ole32.dll", // 2000 and higher
+       NULL
+};
+static dllhandle_t ole32_dll = NULL;
 #endif
 
 /*
@@ -1166,7 +1206,7 @@ void FS_AddGameDirectory (const char *dir)
 
        stringlistinit(&list);
        listdirectory(&list, "", dir);
-       stringlistsort(&list);
+       stringlistsort(&list, false);
 
        // add any PAK package in the directory
        for (i = 0;i < list.numstrings;i++)
@@ -1324,11 +1364,14 @@ void FS_Rescan (void)
        // gamedirname1 (typically id1)
        FS_AddGameHierarchy (gamedirname1);
        // update the com_modname (used for server info)
-       strlcpy(com_modname, gamedirname1, sizeof(com_modname));
+       if (gamedirname2 && gamedirname2[0])
+               strlcpy(com_modname, gamedirname2, sizeof(com_modname));
+       else
+               strlcpy(com_modname, gamedirname1, sizeof(com_modname));
 
        // add the game-specific path, if any
        // (only used for mission packs and the like, which should set fs_modified)
-       if (gamedirname2)
+       if (gamedirname2 && gamedirname2[0])
        {
                fs_modified = true;
                FS_AddGameHierarchy (gamedirname2);
@@ -1604,7 +1647,7 @@ static void FS_ListGameDirs(void)
        stringlistinit(&list);
        listdirectory(&list, va("%s/", fs_basedir), "");
        listdirectory(&list, va("%s/", fs_userdir), "");
-       stringlistsort(&list);
+       stringlistsort(&list, false);
 
        stringlistinit(&list2);
        for(i = 0; i < list.numstrings; ++i)
@@ -1640,6 +1683,13 @@ static void FS_ListGameDirs(void)
        }
 }
 
+/*
+#ifdef WIN32
+#pragma comment(lib, "shell32.lib")
+#include <ShlObj.h>
+#endif
+*/
+
 /*
 ================
 FS_Init_SelfPack
@@ -1692,138 +1742,173 @@ void FS_Init_SelfPack (void)
        }
 }
 
-/*
-================
-FS_Init
-================
-*/
-void FS_Init (void)
+int FS_ChooseUserDir(userdirmode_t userdirmode, char *userdir, size_t userdirsize)
 {
-       const char *p;
-       int i;
-#ifdef WIN32
-       TCHAR mydocsdir[MAX_PATH + 1];
+#if defined(__IPHONEOS__)
+       if (userdirmode == USERDIRMODE_HOME)
+       {
+               // fs_basedir is "" by default, to utilize this you can simply add your gamedir to the Resources in xcode
+               // fs_userdir stores configurations to the Documents folder of the app
+               strlcpy(userdir, maxlength, "../Documents/");
+               return 1;
+       }
+       return -1;
+
+#elif defined(WIN32)
+       char *homedir;
 #if _MSC_VER >= 1400
        size_t homedirlen;
 #endif
-#endif
-#ifndef __IPHONEOS__
-       char *homedir;
-#endif
-
-#ifdef WIN32
-       const char* dllnames [] =
+       TCHAR mydocsdir[MAX_PATH + 1];
+       wchar_t *savedgamesdirw;
+       char savedgamesdir[MAX_OSPATH];
+       int fd;
+       
+       userdir[0] = 0;
+       switch(userdirmode)
        {
-               "shfolder.dll",  // IE 4, or Win NT and higher
-               NULL
-       };
-       Sys_LoadLibrary(dllnames, &shfolder_dll, shfolderfuncs);
-       // don't care for the result; if it fails, %USERPROFILE% will be used instead
-#endif
-
-       *fs_basedir = 0;
-       *fs_userdir = 0;
-       *fs_gamedir = 0;
-
-#ifdef __IPHONEOS__
-       // fs_basedir is "" by default, to utilize this you can simply add your gamedir to the Resources in xcode
-       // fs_userdir stores configurations to the Documents folder of the app
-       strlcpy(fs_userdir, "../Documents/", sizeof(fs_userdir));
+       default:
+               return -1;
+       case USERDIRMODE_NOHOME:
+               strlcpy(userdir, fs_basedir, userdirsize);
+               break;
+       case USERDIRMODE_MYGAMES:
+               if (!shfolder_dll)
+                       Sys_LoadLibrary(shfolderdllnames, &shfolder_dll, shfolderfuncs);
+               mydocsdir[0] = 0;
+               if (qSHGetFolderPath && qSHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, mydocsdir) == S_OK)
+               {
+                       dpsnprintf(userdir, userdirsize, "%s/My Games/%s/", mydocsdir, gameuserdirname);
+                       break;
+               }
+#if _MSC_VER >= 1400
+               _dupenv_s(&homedir, &homedirlen, "USERPROFILE");
+               if(homedir)
+               {
+                       dpsnprintf(userdir, userdirsize, "%s/.%s/", homedir, gameuserdirname);
+                       free(homedir);
+                       break;
+               }
 #else
-       // Add the personal game directory
-       if((i = COM_CheckParm("-userdir")) && i < com_argc - 1)
-       {
-               dpsnprintf(fs_userdir, sizeof(fs_userdir), "%s/", com_argv[i+1]);
-       }
-       else if(COM_CheckParm("-nohome"))
-       {
-               *fs_userdir = 0;
-       }
-       else
-       {
-#ifdef WIN32
-               if(qSHGetFolderPath && (qSHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, mydocsdir) == S_OK))
+               homedir = getenv("USERPROFILE");
+               if(homedir)
                {
-                       dpsnprintf(fs_userdir, sizeof(fs_userdir), "%s/My Games/%s/", mydocsdir, gameuserdirname);
-                       Con_DPrintf("Obtained personal directory %s from SHGetFolderPath\n", fs_userdir);
+                       dpsnprintf(userdir, userdirsize, "%s/.%s/", homedir, gameuserdirname);
+                       break;
                }
-               else
+#endif
+               return -1;
+       case USERDIRMODE_SAVEDGAMES:
+               if (!shell32_dll)
+                       Sys_LoadLibrary(shell32dllnames, &shell32_dll, shell32funcs);
+               if (!ole32_dll)
+                       Sys_LoadLibrary(ole32dllnames, &ole32_dll, ole32funcs);
+               if (qSHGetKnownFolderPath && qCoInitializeEx && qCoTaskMemFree && qCoUninitialize)
                {
-                       // use the environment
-#if _MSC_VER >= 1400
-                       _dupenv_s (&homedir, &homedirlen, "USERPROFILE");
+                       savedgamesdir[0] = 0;
+                       qCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+/*
+#ifdef __cplusplus
+                       if (SHGetKnownFolderPath(FOLDERID_SavedGames, KF_FLAG_CREATE | KF_FLAG_NO_ALIAS, NULL, &savedgamesdirw) == S_OK)
 #else
-                       homedir = getenv("USERPROFILE");
+                       if (SHGetKnownFolderPath(&FOLDERID_SavedGames, KF_FLAG_CREATE | KF_FLAG_NO_ALIAS, NULL, &savedgamesdirw) == S_OK)
 #endif
-
-                       if(homedir)
+*/
+                       if (qSHGetKnownFolderPath(&qFOLDERID_SavedGames, qKF_FLAG_CREATE | qKF_FLAG_NO_ALIAS, NULL, &savedgamesdirw) == S_OK)
                        {
-                               dpsnprintf(fs_userdir, sizeof(fs_userdir), "%s/My Documents/My Games/%s/", homedir, gameuserdirname);
+                               memset(savedgamesdir, 0, sizeof(savedgamesdir));
 #if _MSC_VER >= 1400
-                               free(homedir);
+                               wcstombs_s(NULL, savedgamesdir, sizeof(savedgamesdir), savedgamesdirw, sizeof(savedgamesdir)-1);
+#else
+                               wcstombs(savedgamesdir, savedgamesdirw, sizeof(savedgamesdir)-1);
 #endif
-                               Con_DPrintf("Obtained personal directory %s from environment\n", fs_userdir);
+                               qCoTaskMemFree(savedgamesdirw);
+                       }
+                       qCoUninitialize();
+                       if (savedgamesdir[0])
+                       {
+                               dpsnprintf(userdir, userdirsize, "%s/%s/", savedgamesdir, gameuserdirname);
+                               break;
                        }
                }
-
-               if(!*fs_userdir)
-                       Con_DPrintf("Could not obtain home directory; not supporting -mygames\n");
+               return -1;
+       }
 #else
-               homedir = getenv ("HOME");
+       int fd;
+       char *homedir;
+       userdir[0] = 0;
+       switch(userdirmode)
+       {
+       default:
+               return -1;
+       case USERDIRMODE_NOHOME:
+               strlcpy(userdir, fs_basedir, userdirsize);
+               break;
+       case USERDIRMODE_HOME:
+               homedir = getenv("HOME");
                if(homedir)
                {
-#ifdef __APPLE__
-                       dpsnprintf(fs_userdir, sizeof(fs_userdir), "%s/Library/Application Support/%s/", homedir, gameuserdirname);
+                       dpsnprintf(userdir, userdirsize, "%s/.%s/", homedir, gameuserdirname);
+                       break;
+               }
+               return -1;
+       case USERDIRMODE_SAVEDGAMES:
+               homedir = getenv("HOME");
+               if(homedir)
+               {
+#ifdef MACOSX
+                       dpsnprintf(userdir, userdirsize, "%s/Library/Application Support/%s/", homedir, gameuserdirname);
 #else
-                       dpsnprintf(fs_userdir, sizeof(fs_userdir), "%s/.%s/", homedir, gameuserdirname);
+                       // the XDG say some files would need to go in:
+                       // XDG_CONFIG_HOME (or ~/.config/%s/)
+                       // XDG_DATA_HOME (or ~/.local/share/%s/)
+                       // XDG_CACHE_HOME (or ~/.cache/%s/)
+                       // and also search the following global locations if defined:
+                       // XDG_CONFIG_DIRS (normally /etc/xdg/%s/)
+                       // XDG_DATA_DIRS (normally /usr/share/%s/)
+                       // this would be too complicated...
+                       return -1;
 #endif
+                       break;
                }
-
-               if(!*fs_userdir)
-                       Con_DPrintf("Could not obtain home directory; assuming -nohome\n");
+               return -1;
+       }
 #endif
 
+
 #ifdef WIN32
-               if(!COM_CheckParm("-mygames"))
-               {
+       // historical behavior...
+       if (userdirmode == USERDIRMODE_NOHOME && strcmp(gamedirname1, "id1"))
+               return 0; // don't bother checking if the basedir folder is writable, it's annoying...  unless it is Quake on Windows where NOHOME is the default preferred and we have to check for an error case
+#endif
+       // see if we can write to this path (note: won't create path)
 #if _MSC_VER >= 1400
-                       int fd;
-                       _sopen_s(&fd, va("%s%s/config.cfg", fs_basedir, gamedirname1), O_WRONLY | O_CREAT, _SH_DENYNO, _S_IREAD | _S_IWRITE); // note: no O_TRUNC here!
+       _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!
 #else
-                       int fd = open (va("%s%s/config.cfg", fs_basedir, gamedirname1), O_WRONLY | O_CREAT, 0666); // note: no O_TRUNC here!
-#endif
-                       if(fd >= 0)
-                       {
-                               close(fd);
-                               *fs_userdir = 0; // we have write access to the game dir, so let's use it
-                       }
-               }
+       fd = open (va("%s%s/config.cfg", userdir, gamedirname1), O_WRONLY | O_CREAT, 0666); // note: no O_TRUNC here!
 #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
+}
 
-       strlcpy(fs_gamedir, "", sizeof(fs_gamedir));
+/*
+================
+FS_Init
+================
+*/
+void FS_Init (void)
+{
+       const char *p;
+       int i;
 
-// If the base directory is explicitly defined by the compilation process
-#ifdef DP_FS_BASEDIR
-       strlcpy(fs_basedir, DP_FS_BASEDIR, sizeof(fs_basedir));
-#else
        *fs_basedir = 0;
-
-#ifdef MACOSX
-       // FIXME: is there a better way to find the directory outside the .app?
-       if (strstr(com_argv[0], ".app/"))
-       {
-               char *split;
-
-               split = strstr(com_argv[0], ".app/");
-               while (split > com_argv[0] && *split != '/')
-                       split--;
-               strlcpy(fs_basedir, com_argv[0], sizeof(fs_basedir));
-               fs_basedir[split - com_argv[0]] = 0;
-       }
-#endif
-#endif
-#endif
+       *fs_userdir = 0;
+       *fs_gamedir = 0;
 
        // -basedir <path>
        // Overrides the system supplied base directory (under GAMENAME)
@@ -1836,11 +1921,101 @@ void FS_Init (void)
                if (i > 0 && (fs_basedir[i-1] == '\\' || fs_basedir[i-1] == '/'))
                        fs_basedir[i-1] = 0;
        }
+       else
+       {
+// If the base directory is explicitly defined by the compilation process
+#ifdef DP_FS_BASEDIR
+               strlcpy(fs_basedir, DP_FS_BASEDIR, sizeof(fs_basedir));
+#elif defined(MACOSX)
+               // FIXME: is there a better way to find the directory outside the .app, without using Objective-C?
+               if (strstr(com_argv[0], ".app/"))
+               {
+                       char *split;
+                       strlcpy(fs_basedir, com_argv[0], sizeof(fs_basedir));
+                       split = strstr(fs_basedir, ".app/");
+                       if (split)
+                       {
+                               struct stat statresult;
+                               // 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)
+                               {
+                                       // found gamedir inside Resources, use it
+                                       strlcat(fs_basedir, "Contents/Resources/", sizeof(fs_basedir));
+                               }
+                               else
+                               {
+                                       // no gamedir found in Resources, gamedir is probably
+                                       // outside the .app, remove .app part of path
+                                       while (split > fs_basedir && *split != '/')
+                                               split--;
+                                       *split = 0;
+                               }
+                       }
+               }
+#endif
+       }
 
+       // make sure the appending of a path separator won't create an unterminated string
+       memset(fs_basedir + sizeof(fs_basedir) - 2, 0, 2);
        // add a path separator to the end of the basedir if it lacks one
        if (fs_basedir[0] && fs_basedir[strlen(fs_basedir) - 1] != '/' && fs_basedir[strlen(fs_basedir) - 1] != '\\')
                strlcat(fs_basedir, "/", sizeof(fs_basedir));
 
+       // Add the personal game directory
+       if((i = COM_CheckParm("-userdir")) && i < com_argc - 1)
+               dpsnprintf(fs_userdir, sizeof(fs_userdir), "%s/", com_argv[i+1]);
+       else if (COM_CheckParm("-nohome"))
+               *fs_userdir = 0; // user wants roaming installation, no userdir
+       else
+       {
+               int dirmode;
+               int highestuserdirmode = USERDIRMODE_COUNT - 1;
+               int preferreduserdirmode = USERDIRMODE_COUNT - 1;
+               int userdirstatus[USERDIRMODE_COUNT];
+#ifdef WIN32
+               // historical behavior...
+               if (!strcmp(gamedirname1, "id1"))
+                       preferreduserdirmode = USERDIRMODE_NOHOME;
+#endif
+               // check what limitations the user wants to impose
+               if (COM_CheckParm("-home")) preferreduserdirmode = USERDIRMODE_HOME;
+               if (COM_CheckParm("-mygames")) preferreduserdirmode = USERDIRMODE_MYGAMES;
+               if (COM_CheckParm("-savedgames")) preferreduserdirmode = USERDIRMODE_SAVEDGAMES;
+               // gather the status of the possible userdirs
+               for (dirmode = 0;dirmode < USERDIRMODE_COUNT;dirmode++)
+               {
+                       userdirstatus[dirmode] = FS_ChooseUserDir((userdirmode_t)dirmode, fs_userdir, sizeof(fs_userdir));
+                       if (userdirstatus[dirmode] == 1)
+                               Con_DPrintf("userdir %i = %s (writable)\n", dirmode, fs_userdir);
+                       else if (userdirstatus[dirmode] == 0)
+                               Con_DPrintf("userdir %i = %s (not writable or does not exist)\n", dirmode, fs_userdir);
+                       else
+                               Con_DPrintf("userdir %i (not applicable)\n", dirmode);
+               }
+               // some games may prefer writing to basedir, but if write fails we
+               // have to search for a real userdir...
+               if (preferreduserdirmode == 0 && userdirstatus[0] < 1)
+                       preferreduserdirmode = highestuserdirmode;
+               // check for an existing userdir and continue using it if possible...
+               for (dirmode = USERDIRMODE_COUNT - 1;dirmode > 0;dirmode--)
+                       if (userdirstatus[dirmode] == 1)
+                               break;
+               // if no existing userdir found, make a new one...
+               if (dirmode == 0 && preferreduserdirmode > 0)
+                       for (dirmode = preferreduserdirmode;dirmode > 0;dirmode--)
+                               if (userdirstatus[dirmode] >= 0)
+                                       break;
+               // and finally, we picked one...
+               FS_ChooseUserDir((userdirmode_t)dirmode, fs_userdir, sizeof(fs_userdir));
+               Con_DPrintf("userdir %i is the winner\n", dirmode);
+       }
+
+       // if userdir equal to basedir, clear it to avoid confusion later
+       if (!strcmp(fs_basedir, fs_userdir))
+               fs_userdir[0] = 0;
+
        FS_ListGameDirs();
 
        p = FS_CheckGameDir(gamedirname1);
@@ -1908,6 +2083,8 @@ void FS_Shutdown (void)
 
 #ifdef WIN32
        Sys_UnloadLibrary (&shfolder_dll);
+       Sys_UnloadLibrary (&shell32_dll);
+       Sys_UnloadLibrary (&ole32_dll);
 #endif
 }
 
@@ -3335,7 +3512,7 @@ fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet)
 
        if (resultlist.numstrings)
        {
-               stringlistsort(&resultlist);
+               stringlistsort(&resultlist, true);
                numfiles = resultlist.numstrings;
                numchars = 0;
                for (resultlistindex = 0;resultlistindex < resultlist.numstrings;resultlistindex++)
@@ -3439,7 +3616,7 @@ int FS_ListDirectory(const char *pattern, int oneperline)
 static void FS_ListDirectoryCmd (const char* cmdname, int oneperline)
 {
        const char *pattern;
-       if (Cmd_Argc() > 3)
+       if (Cmd_Argc() >= 3)
        {
                Con_Printf("usage:\n%s [path/pattern]\n", cmdname);
                return;
diff --git a/ft2.c b/ft2.c
index 91a6f871cc4c6a6142c951813a1f844c6f14a466..269cb11780c5e94930ad91f23e455675d63810df 100644 (file)
--- a/ft2.c
+++ b/ft2.c
@@ -6,6 +6,7 @@
 #include "ft2.h"
 #include "ft2_defs.h"
 #include "ft2_fontdefs.h"
+#include "image.h"
 
 static int img_fontmap[256] = {
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -36,6 +37,9 @@ cvar_t r_font_disable_freetype = {CVAR_SAVE, "r_font_disable_freetype", "1", "di
 cvar_t r_font_use_alpha_textures = {CVAR_SAVE, "r_font_use_alpha_textures", "0", "use alpha-textures for font rendering, this should safe memory"};
 cvar_t r_font_size_snapping = {CVAR_SAVE, "r_font_size_snapping", "1", "stick to good looking font sizes whenever possible - bad when the mod doesn't support it!"};
 cvar_t r_font_kerning = {CVAR_SAVE, "r_font_kerning", "1", "Use kerning if available"};
+cvar_t r_font_diskcache = {CVAR_SAVE, "r_font_diskcache", "0", "save font textures to disk for future loading rather than generating them every time"};
+cvar_t r_font_compress = {CVAR_SAVE, "r_font_compress", "0", "use texture compression on font textures to save video memory"};
+cvar_t r_font_nonpoweroftwo = {CVAR_SAVE, "r_font_nonpoweroftwo", "1", "use nonpoweroftwo textures for font (saves memory, potentially slower)"};
 cvar_t developer_font = {CVAR_SAVE, "developer_font", "0", "prints debug messages about fonts"};
 
 /*
@@ -134,7 +138,6 @@ static dllhandle_t ft2_dll = NULL;
 
 /// Memory pool for fonts
 static mempool_t *font_mempool= NULL;
-static rtexturepool_t *font_texturepool = NULL;
 
 /// FreeType library handle
 static FT_Library font_ft2lib = NULL;
@@ -237,8 +240,6 @@ void Font_CloseLibrary (void)
        fontfilecache_FreeAll();
        if (font_mempool)
                Mem_FreePool(&font_mempool);
-       if (font_texturepool)
-               R_FreeTexturePool(&font_texturepool);
        if (font_ft2lib && qFT_Done_FreeType)
        {
                qFT_Done_FreeType(font_ft2lib);
@@ -312,14 +313,6 @@ void font_start(void)
                Font_CloseLibrary();
                return;
        }
-
-       font_texturepool = R_AllocTexturePool();
-       if (!font_texturepool)
-       {
-               Con_Print("ERROR: Failed to allocate FONT texture pool!\n");
-               Font_CloseLibrary();
-               return;
-       }
 }
 
 void font_shutdown(void)
@@ -342,10 +335,13 @@ void font_newmap(void)
 
 void Font_Init(void)
 {
+       Cvar_RegisterVariable(&r_font_nonpoweroftwo);
        Cvar_RegisterVariable(&r_font_disable_freetype);
        Cvar_RegisterVariable(&r_font_use_alpha_textures);
        Cvar_RegisterVariable(&r_font_size_snapping);
        Cvar_RegisterVariable(&r_font_kerning);
+       Cvar_RegisterVariable(&r_font_diskcache);
+       Cvar_RegisterVariable(&r_font_compress);
        Cvar_RegisterVariable(&developer_font);
 
        // let's open it at startup already
@@ -673,11 +669,13 @@ 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)
 {
        int x, y;
+
+       // calculate gauss table
        Font_Postprocess_Update(fnt, bpp, w, h);
+
        if(imagedata)
        {
                // enlarge buffer
-
                // perform operation, not exceeding the passed padding values,
                // but possibly reducing them
                *pad_l = min(*pad_l, pp.padding_l);
@@ -685,8 +683,6 @@ void Font_Postprocess(ft2_font_t *fnt, unsigned char *imagedata, int pitch, int
                *pad_t = min(*pad_t, pp.padding_t);
                *pad_b = min(*pad_b, pp.padding_b);
 
-               // calculate gauss table
-               
                // outline the font (RGBA only)
                if(bpp == 4 && (pp.outline > 0 || pp.blur > 0 || pp.shadowx != 0 || pp.shadowy != 0 || pp.shadowz != 0)) // we can only do this in BGRA
                {
@@ -773,6 +769,15 @@ void Font_Postprocess(ft2_font_t *fnt, unsigned char *imagedata, int pitch, int
                                }
                }
        }
+       else if(pitch)
+       {
+               // perform operation, not exceeding the passed padding values,
+               // but possibly reducing them
+               *pad_l = min(*pad_l, pp.padding_l);
+               *pad_r = min(*pad_r, pp.padding_r);
+               *pad_t = min(*pad_t, pp.padding_t);
+               *pad_b = min(*pad_b, pp.padding_b);
+       }
        else
        {
                // just calculate parameters
@@ -825,7 +830,9 @@ static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only)
 
        memset(&temp, 0, sizeof(temp));
        temp.size = size;
-       temp.glyphSize = CeilPowerOf2(size*2 + max(gpad_l + gpad_r, gpad_t + gpad_b));
+       temp.glyphSize = size*2 + max(gpad_l + gpad_r, gpad_t + gpad_b);
+       if (!(r_font_nonpoweroftwo.integer && vid.support.arb_texture_non_power_of_two))
+               temp.glyphSize = CeilPowerOf2(temp.glyphSize);
        temp.sfx = (1.0/64.0)/(double)size;
        temp.sfy = (1.0/64.0)/(double)size;
        temp.intSize = -1; // negative value: LoadMap must search now :)
@@ -1021,10 +1028,10 @@ qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left,
 
 static void UnloadMapRec(ft2_font_map_t *map)
 {
-       if (map->texture)
+       if (map->pic)
        {
-               R_FreeTexture(map->texture);
-               map->texture = NULL;
+               //Draw_FreePic(map->pic); // FIXME: refcounting needed...
+               map->pic = NULL;
        }
        if (map->next)
                UnloadMapRec(map->next);
@@ -1096,7 +1103,7 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
 {
        char map_identifier[MAX_QPATH];
        unsigned long mapidx = _ch / FONT_CHARS_PER_MAP;
-       unsigned char *data;
+       unsigned char *data = NULL;
        FT_ULong ch, mapch;
        int status;
        int tp;
@@ -1206,6 +1213,29 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
                return false;
        }
 
+       // create a totally unique name for this map, then we will use it to make a unique cachepic_t to avoid redundant textures
+       dpsnprintf(map_identifier, sizeof(map_identifier),
+               "%s_cache_%g_%d_%g_%g_%g_%g_%g_%u",
+               font->name,
+               (double) mapstart->intSize,
+               (int) load_flags,
+               (double) font->settings->blur,
+               (double) font->settings->outline,
+               (double) font->settings->shadowx,
+               (double) font->settings->shadowy,
+               (double) font->settings->shadowz,
+               (unsigned) mapidx);
+
+       // create a cachepic_t from the data now, or reuse an existing one
+       map->pic = Draw_CachePic_Flags(map_identifier, CACHEPICFLAG_QUIET);
+       if (developer_font.integer)
+       {
+               if (map->pic->tex == r_texture_notexture)
+                       Con_Printf("Generating font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize);
+               else
+                       Con_Printf("Using cached font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize);
+       }
+
        Font_Postprocess(font, NULL, 0, bytesPerPixel, mapstart->size*2, mapstart->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b);
 
        // copy over the information
@@ -1216,28 +1246,31 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
        map->sfy = mapstart->sfy;
 
        pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel;
-       data = (unsigned char *)Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
-       if (!data)
+       if (map->pic->tex == r_texture_notexture)
        {
-               Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
-               Mem_Free(map);
-               return false;
-       }
-       memset(map->width_of, 0, sizeof(map->width_of));
-
-       // initialize as white texture with zero alpha
-       tp = 0;
-       while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
-       {
-               if (bytesPerPixel == 4)
+               data = (unsigned char *)Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch);
+               if (!data)
                {
-                       data[tp++] = 0xFF;
-                       data[tp++] = 0xFF;
-                       data[tp++] = 0xFF;
+                       Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size);
+                       Mem_Free(map);
+                       return false;
+               }
+               // initialize as white texture with zero alpha
+               tp = 0;
+               while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch)
+               {
+                       if (bytesPerPixel == 4)
+                       {
+                               data[tp++] = 0xFF;
+                               data[tp++] = 0xFF;
+                               data[tp++] = 0xFF;
+                       }
+                       data[tp++] = 0x00;
                }
-               data[tp++] = 0x00;
        }
 
+       memset(map->width_of, 0, sizeof(map->width_of));
+
        // insert the map
        map->start = mapidx * FONT_CHARS_PER_MAP;
        next = mapstart;
@@ -1256,7 +1289,7 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
                int w, h, x, y;
                FT_GlyphSlot glyph;
                FT_Bitmap *bmp;
-               unsigned char *imagedata, *dst, *src;
+               unsigned char *imagedata = NULL, *dst, *src;
                glyph_slot_t *mapglyph;
                FT_Face face;
                int pad_l, pad_r, pad_t, pad_b;
@@ -1273,8 +1306,11 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
                        ++gR;
                }
 
-               imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
-               imagedata += gpad_t * pitch + gpad_l * bytesPerPixel;
+               if (data)
+               {
+                       imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel;
+                       imagedata += gpad_t * pitch + gpad_l * bytesPerPixel;
+               }
                //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER);
                // we need the glyphIndex
                face = (FT_Face)font->face;
@@ -1339,91 +1375,103 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
                                h = map->glyphSize;
                }
 
-               switch (bmp->pixel_mode)
-               {
-               case FT_PIXEL_MODE_MONO:
-                       if (developer_font.integer)
-                               Con_DPrint("glyphinfo:   Pixel Mode: MONO\n");
-                       break;
-               case FT_PIXEL_MODE_GRAY2:
-                       if (developer_font.integer)
-                               Con_DPrint("glyphinfo:   Pixel Mode: GRAY2\n");
-                       break;
-               case FT_PIXEL_MODE_GRAY4:
-                       if (developer_font.integer)
-                               Con_DPrint("glyphinfo:   Pixel Mode: GRAY4\n");
-                       break;
-               case FT_PIXEL_MODE_GRAY:
-                       if (developer_font.integer)
-                               Con_DPrint("glyphinfo:   Pixel Mode: GRAY\n");
-                       break;
-               default:
-                       if (developer_font.integer)
-                               Con_DPrintf("glyphinfo:   Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
-                       Mem_Free(data);
-                       Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
-                       return false;
-               }
-               for (y = 0; y < h; ++y)
+               if (imagedata)
                {
-                       dst = imagedata + y * pitch;
-                       src = bmp->buffer + y * bmp->pitch;
-
                        switch (bmp->pixel_mode)
                        {
                        case FT_PIXEL_MODE_MONO:
-                               dst += bytesPerPixel - 1; // shift to alpha byte
-                               for (x = 0; x < bmp->width; x += 8)
-                               {
-                                       unsigned char ch = *src++;
-                                       *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
-                                       *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
-                                       *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
-                                       *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
-                                       *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
-                                       *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
-                                       *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
-                                       *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
-                               }
+                               if (developer_font.integer)
+                                       Con_DPrint("glyphinfo:   Pixel Mode: MONO\n");
                                break;
                        case FT_PIXEL_MODE_GRAY2:
-                               dst += bytesPerPixel - 1; // shift to alpha byte
-                               for (x = 0; x < bmp->width; x += 4)
-                               {
-                                       unsigned char ch = *src++;
-                                       *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
-                                       *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
-                                       *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
-                                       *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
-                               }
+                               if (developer_font.integer)
+                                       Con_DPrint("glyphinfo:   Pixel Mode: GRAY2\n");
                                break;
                        case FT_PIXEL_MODE_GRAY4:
-                               dst += bytesPerPixel - 1; // shift to alpha byte
-                               for (x = 0; x < bmp->width; x += 2)
-                               {
-                                       unsigned char ch = *src++;
-                                       *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
-                                       *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
-                               }
+                               if (developer_font.integer)
+                                       Con_DPrint("glyphinfo:   Pixel Mode: GRAY4\n");
                                break;
                        case FT_PIXEL_MODE_GRAY:
-                               // in this case pitch should equal width
-                               for (tp = 0; tp < bmp->pitch; ++tp)
-                                       dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
-
-                               //memcpy((void*)dst, (void*)src, bmp->pitch);
-                               //dst += bmp->pitch;
+                               if (developer_font.integer)
+                                       Con_DPrint("glyphinfo:   Pixel Mode: GRAY\n");
                                break;
                        default:
-                               break;
+                               if (developer_font.integer)
+                                       Con_DPrintf("glyphinfo:   Pixel Mode: Unknown: %i\n", bmp->pixel_mode);
+                               Mem_Free(data);
+                               Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode);
+                               return false;
                        }
+                       for (y = 0; y < h; ++y)
+                       {
+                               dst = imagedata + y * pitch;
+                               src = bmp->buffer + y * bmp->pitch;
+
+                               switch (bmp->pixel_mode)
+                               {
+                               case FT_PIXEL_MODE_MONO:
+                                       dst += bytesPerPixel - 1; // shift to alpha byte
+                                       for (x = 0; x < bmp->width; x += 8)
+                                       {
+                                               unsigned char ch = *src++;
+                                               *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel;
+                                               *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel;
+                                               *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel;
+                                               *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel;
+                                               *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel;
+                                               *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel;
+                                               *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel;
+                                               *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel;
+                                       }
+                                       break;
+                               case FT_PIXEL_MODE_GRAY2:
+                                       dst += bytesPerPixel - 1; // shift to alpha byte
+                                       for (x = 0; x < bmp->width; x += 4)
+                                       {
+                                               unsigned char ch = *src++;
+                                               *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
+                                               *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
+                                               *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
+                                               *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel;
+                                       }
+                                       break;
+                               case FT_PIXEL_MODE_GRAY4:
+                                       dst += bytesPerPixel - 1; // shift to alpha byte
+                                       for (x = 0; x < bmp->width; x += 2)
+                                       {
+                                               unsigned char ch = *src++;
+                                               *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel;
+                                               *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel;
+                                       }
+                                       break;
+                               case FT_PIXEL_MODE_GRAY:
+                                       // in this case pitch should equal width
+                                       for (tp = 0; tp < bmp->pitch; ++tp)
+                                               dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes
+
+                                       //memcpy((void*)dst, (void*)src, bmp->pitch);
+                                       //dst += bmp->pitch;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+
+                       pad_l = gpad_l;
+                       pad_r = gpad_r;
+                       pad_t = gpad_t;
+                       pad_b = gpad_b;
+                       Font_Postprocess(font, imagedata, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
+               }
+               else
+               {
+                       pad_l = gpad_l;
+                       pad_r = gpad_r;
+                       pad_t = gpad_t;
+                       pad_b = gpad_b;
+                       Font_Postprocess(font, NULL, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
                }
 
-               pad_l = gpad_l;
-               pad_r = gpad_r;
-               pad_t = gpad_t;
-               pad_b = gpad_b;
-               Font_Postprocess(font, imagedata, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b);
 
                // now fill map->glyphs[ch - map->start]
                mapglyph = &map->glyphs[mapch];
@@ -1474,33 +1522,41 @@ static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _
                map->glyphs[mapch].image = false;
        }
 
-       // create a texture from the data now
-
-       if (developer_font.integer > 100)
+       if (map->pic->tex == r_texture_notexture)
        {
-               // LordHavoc: why are we writing this?  And why not write it as TGA using the appropriate function?
-               // view using `display -depth 8 -size 512x512 name_page.rgba` (be sure to use a correct -size parameter)
-               dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u.rgba", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
-               FS_WriteFile(map_identifier, data, pitch * FONT_CHAR_LINES * map->glyphSize);
+               int w = map->glyphSize * FONT_CHARS_PER_LINE;
+               int h = map->glyphSize * FONT_CHAR_LINES;
+               rtexture_t *tex;
+               // abuse the Draw_CachePic system to keep track of this texture
+               tex = R_LoadTexture2D(drawtexturepool, map_identifier, w, h, data, r_font_use_alpha_textures.integer ? TEXTYPE_ALPHA : TEXTYPE_RGBA, TEXF_ALPHA | (r_font_compress.integer > 0 ? TEXF_COMPRESS : 0), -1, NULL);
+               // if tex is NULL for any reason, the pic->tex will remain set to r_texture_notexture
+               if (tex)
+                       map->pic->tex = tex;
+
+               if (r_font_diskcache.integer >= 1)
+               {
+                       // swap to BGRA for tga writing...
+                       int s = w * h;
+                       int x;
+                       int b;
+                       for (x = 0;x < s;x++)
+                       {
+                               b = data[x*4+0];
+                               data[x*4+0] = data[x*4+2];
+                               data[x*4+2] = b;
+                       }
+                       Image_WriteTGABGRA(va("%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);
+#endif
+               }
        }
-       dpsnprintf(map_identifier, sizeof(map_identifier), "%s_%u", font->name, (unsigned)map->start/FONT_CHARS_PER_MAP);
 
-       // probably use bytesPerPixel here instead?
-       if (r_font_use_alpha_textures.integer)
-       {
-               map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
-                                              map->glyphSize * FONT_CHARS_PER_LINE,
-                                              map->glyphSize * FONT_CHAR_LINES,
-                                              data, TEXTYPE_ALPHA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, -1, NULL);
-       } else {
-               map->texture = R_LoadTexture2D(font_texturepool, map_identifier,
-                                              map->glyphSize * FONT_CHARS_PER_LINE,
-                                              map->glyphSize * FONT_CHAR_LINES,
-                                              data, TEXTYPE_RGBA, TEXF_ALPHA /*gone: | TEXF_ALWAYSPRECACHE*/ /* | TEXF_MIPMAP*/, -1, NULL);
-       }
+       if(data)
+               Mem_Free(data);
 
-       Mem_Free(data);
-       if (!map->texture)
+       if (map->pic->tex == r_texture_notexture)
        {
                // if the first try isn't successful, keep it with a broken texture
                // otherwise we retry to load it every single frame where ft2 rendering is used
index 34c1637014c9ef7863e44987a90ba113f065d6bf..3f08187db52e355bc65d1058273c3f75e0ac49da 100644 (file)
@@ -34,7 +34,7 @@ struct ft2_font_map_s
        float                  intSize;
        int                    glyphSize;
 
-       rtexture_t            *texture;
+       cachepic_t            *pic;
        qboolean               static_tex;
        glyph_slot_t           glyphs[FONT_CHARS_PER_MAP];
 
index dc46cc719dcd21016f55b6e36522f0dced00ab9d..a89ef857aced5b8dfb9aba1012d1c4d8545ffe2a 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
@@ -137,6 +225,7 @@ typedef struct gl_state_s
        int alphatest;
        int alphafunc;
        float alphafuncvalue;
+       qboolean alphatocoverage;
        int scissortest;
        unsigned int unit;
        unsigned int clientunit;
@@ -330,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
@@ -1090,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
@@ -1097,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
@@ -1144,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
        }
 }
 
@@ -1154,7 +1245,7 @@ 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
        }
 }
 
@@ -1172,11 +1263,11 @@ int R_Mesh_CreateFramebufferObject(rtexture_t *depthtexture, rtexture_t *colorte
                        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
+               if (depthtexture) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthtexture->gltexturetypeenum, R_GetTexture(depthtexture), 0);CHECKGLERROR
+               if (colortexture) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colortexture->gltexturetypeenum, R_GetTexture(colortexture), 0);CHECKGLERROR
+               if (colortexture2) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, colortexture2->gltexturetypeenum, R_GetTexture(colortexture2), 0);CHECKGLERROR
+               if (colortexture3) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, colortexture3->gltexturetypeenum, R_GetTexture(colortexture3), 0);CHECKGLERROR
+               if (colortexture4) qglFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, colortexture4->gltexturetypeenum, R_GetTexture(colortexture4), 0);CHECKGLERROR
                return temp;
        case RENDERPATH_D3D9:
        case RENDERPATH_D3D10:
@@ -1257,7 +1348,7 @@ void R_Mesh_ResetRenderTargets(void)
                if (gl_state.framebufferobject)
                {
                        gl_state.framebufferobject = 0;
-                       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, gl_state.defaultframebufferobject);
+                       qglBindFramebufferEXT(GL_FRAMEBUFFER, gl_state.defaultframebufferobject);
                }
                break;
        case RENDERPATH_D3D9:
@@ -1301,7 +1392,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);
+                       qglBindFramebufferEXT(GL_FRAMEBUFFER, gl_state.framebufferobject ? gl_state.framebufferobject : gl_state.defaultframebufferobject);
                }
                break;
        case RENDERPATH_D3D9:
@@ -1381,6 +1472,7 @@ static int d3dstencilopforglfunc(int f)
 }
 #endif
 
+extern cvar_t r_transparent_alphatocoverage;
 
 static void GL_Backend_ResetState(void)
 {
@@ -1390,6 +1482,7 @@ static void GL_Backend_ResetState(void)
        gl_state.alphatest = false;
        gl_state.alphafunc = GL_GEQUAL;
        gl_state.alphafuncvalue = 0.5f;
+       gl_state.alphatocoverage = false;
        gl_state.blendfunc1 = GL_ONE;
        gl_state.blendfunc2 = GL_ZERO;
        gl_state.blend = false;
@@ -1411,9 +1504,6 @@ static void GL_Backend_ResetState(void)
 #ifdef SUPPORTD3D
                {
                        IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_COLORWRITEENABLE, gl_state.colormask);
-                       IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ALPHATESTENABLE, gl_state.alphatest);
-                       IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ALPHAFUNC, d3dcmpforglfunc(gl_state.alphafunc));
-                       IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ALPHAREF, (int)bound(0, gl_state.alphafuncvalue * 256.0f, 255));
                        IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CULLMODE, D3DCULL_NONE);
                        IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZFUNC, d3dcmpforglfunc(gl_state.depthfunc));
                        IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZENABLE, gl_state.depthtest);
@@ -1432,6 +1522,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 +1539,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);
+                       //qglBindRenderbufferEXT(GL_RENDERBUFFER, 0);
+                       qglBindFramebufferEXT(GL_FRAMEBUFFER, 0);
                }
 
                qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), NULL);CHECKGLERROR
@@ -1466,7 +1557,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);
+                       qglBindFramebufferEXT(GL_FRAMEBUFFER, gl_state.framebufferobject);
 
                gl_state.unit = MAX_TEXTUREUNITS;
                gl_state.clientunit = MAX_TEXTUREUNITS;
@@ -1483,8 +1574,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,10 +1586,10 @@ 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);
-               DPSOFTRAST_AlphaTest(gl_state.alphatest);
                DPSOFTRAST_BlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);
                DPSOFTRAST_CullFace(gl_state.cullface);
                DPSOFTRAST_DepthFunc(gl_state.depthfunc);
@@ -1519,18 +1610,13 @@ static void GL_Backend_ResetState(void)
                qglEnable(GL_DEPTH_TEST);CHECKGLERROR
                qglDepthMask(gl_state.depthmask);CHECKGLERROR
                qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]);
-       //      if (vid.renderpath == RENDERPATH_GL20)
-       //      {
-       //              qglAlphaFunc(gl_state.alphafunc, gl_state.alphafuncvalue);CHECKGLERROR
-       //              qglDisable(GL_ALPHA_TEST);CHECKGLERROR
-       //      }
                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);
+                       qglBindFramebufferEXT(GL_FRAMEBUFFER, gl_state.defaultframebufferobject);
                qglEnableVertexAttribArray(GLSLATTRIB_POSITION);
                qglVertexAttribPointer(GLSLATTRIB_POSITION, 3, GL_FLOAT, false, sizeof(float[3]), NULL);CHECKGLERROR
                qglDisableVertexAttribArray(GLSLATTRIB_COLOR);
@@ -1548,7 +1634,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++)
@@ -1577,7 +1663,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;
@@ -1604,7 +1690,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;
@@ -1817,7 +1903,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
@@ -1873,6 +1963,7 @@ void R_SetStencilSeparate(qboolean enable, int writemask, int frontfail, int fro
                }
                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
@@ -1882,6 +1973,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:
@@ -1933,7 +2025,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
@@ -2129,6 +2223,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)
@@ -2139,21 +2234,50 @@ void GL_AlphaTest(int state)
                        {
                                qglDisable(GL_ALPHA_TEST);CHECKGLERROR
                        }
-                       break;
-               case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
-//                     IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ALPHATESTENABLE, gl_state.alphatest);
 #endif
                        break;
+               case RENDERPATH_D3D9:
                case RENDERPATH_D3D10:
-                       break;
                case RENDERPATH_D3D11:
+               case RENDERPATH_SOFT:
+               case RENDERPATH_GL20:
+               case RENDERPATH_GLES2:
                        break;
+               }
+       }
+}
+
+void GL_AlphaToCoverage(qboolean state)
+{
+       if (gl_state.alphatocoverage != state)
+       {
+               gl_state.alphatocoverage = state;
+               switch(vid.renderpath)
+               {
+               case RENDERPATH_GL11:
+               case RENDERPATH_GL13:
+               case RENDERPATH_GLES1:
+               case RENDERPATH_GLES2:
+               case RENDERPATH_D3D9:
+               case RENDERPATH_D3D10:
+               case RENDERPATH_D3D11:
                case RENDERPATH_SOFT:
-//                     DPSOFTRAST_AlphaTest(gl_state.alphatest);
                        break;
                case RENDERPATH_GL20:
-               case RENDERPATH_GLES2:
+#ifdef GL_SAMPLE_ALPHA_TO_COVERAGE_ARB
+                       // alpha to coverage turns the alpha value of the pixel into 0%, 25%, 50%, 75% or 100% by masking the multisample fragments accordingly
+                       CHECKGLERROR
+                       if (gl_state.alphatocoverage)
+                       {
+                               qglEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);CHECKGLERROR
+//                             qglEnable(GL_MULTISAMPLE_ARB);CHECKGLERROR
+                       }
+                       else
+                       {
+                               qglDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);CHECKGLERROR
+//                             qglDisable(GL_MULTISAMPLE_ARB);CHECKGLERROR
+                       }
+#endif
                        break;
                }
        }
@@ -2326,7 +2450,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)
                {
@@ -2439,7 +2567,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++)
@@ -2479,8 +2607,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;
@@ -2498,7 +2628,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.
@@ -2694,137 +2824,221 @@ 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);
-                               for (i = 0;i < (unsigned int) numtriangles * 3;i++)
+                               if(vid.renderpath == RENDERPATH_GL20)
                                {
-                                       if (element3i)
-                                               element = element3i[i];
-                                       else if (element3s)
-                                               element = element3s[i];
-                                       else
-                                               element = firstvertex + i;
-                                       for (j = 0;j < vid.texarrayunits;j++)
+                                       for (i = 0;i < (unsigned int) numtriangles * 3;i++)
                                        {
-                                               if (gl_state.units[j].pointer_texcoord_pointer && gl_state.units[j].arrayenabled)
+                                               if (element3i)
+                                                       element = element3i[i];
+                                               else if (element3s)
+                                                       element = element3s[i];
+                                               else
+                                                       element = firstvertex + i;
+                                               for (j = 0;j < vid.texarrayunits;j++)
                                                {
-                                                       if (gl_state.units[j].pointer_texcoord_gltype == GL_FLOAT)
+                                                       if (gl_state.units[j].pointer_texcoord_pointer && gl_state.units[j].arrayenabled)
                                                        {
-                                                               p = (const GLfloat *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
-                                                               if (vid.texarrayunits > 1)
+                                                               if (gl_state.units[j].pointer_texcoord_gltype == GL_FLOAT)
                                                                {
+                                                                       p = (const GLfloat *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
                                                                        if (gl_state.units[j].pointer_texcoord_components == 4)
-                                                                               qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]);
+                                                                               qglVertexAttrib4f(GLSLATTRIB_TEXCOORD0 + 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]);
+                                                                               qglVertexAttrib3f(GLSLATTRIB_TEXCOORD0 + 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]);
+                                                                               qglVertexAttrib2f(GLSLATTRIB_TEXCOORD0 + j, p[0], p[1]);
                                                                        else
-                                                                               qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
+                                                                               qglVertexAttrib1f(GLSLATTRIB_TEXCOORD0 + j, p[0]);
                                                                }
-                                                               else
+                                                               else if (gl_state.units[j].pointer_texcoord_gltype == GL_SHORT)
                                                                {
+                                                                       const GLshort *s = (const GLshort *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
                                                                        if (gl_state.units[j].pointer_texcoord_components == 4)
-                                                                               qglTexCoord4f(p[0], p[1], p[2], p[3]);
+                                                                               qglVertexAttrib4f(GLSLATTRIB_TEXCOORD0 + j, s[0], s[1], s[2], s[3]);
                                                                        else if (gl_state.units[j].pointer_texcoord_components == 3)
-                                                                               qglTexCoord3f(p[0], p[1], p[2]);
+                                                                               qglVertexAttrib3f(GLSLATTRIB_TEXCOORD0 + j, s[0], s[1], s[2]);
                                                                        else if (gl_state.units[j].pointer_texcoord_components == 2)
-                                                                               qglTexCoord2f(p[0], p[1]);
-                                                                       else
-                                                                               qglTexCoord1f(p[0]);
-                                                               }
-                                                       }
-                                                       else if (gl_state.units[j].pointer_texcoord_gltype == GL_SHORT)
-                                                       {
-                                                               const GLshort *s = (const GLshort *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
-                                                               if (vid.texarrayunits > 1)
-                                                               {
-                                                                       if (gl_state.units[j].pointer_texcoord_components == 4)
-                                                                               qglMultiTexCoord4f(GL_TEXTURE0_ARB + 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]);
-                                                                       else if (gl_state.units[j].pointer_texcoord_components == 2)
-                                                                               qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, s[0], s[1]);
+                                                                               qglVertexAttrib2f(GLSLATTRIB_TEXCOORD0 + j, s[0], s[1]);
                                                                        else if (gl_state.units[j].pointer_texcoord_components == 1)
-                                                                               qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, s[0]);
+                                                                               qglVertexAttrib1f(GLSLATTRIB_TEXCOORD0 + j, s[0]);
                                                                }
-                                                               else
+                                                               else if (gl_state.units[j].pointer_texcoord_gltype == GL_BYTE)
                                                                {
+                                                                       const GLbyte *sb = (const GLbyte *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
                                                                        if (gl_state.units[j].pointer_texcoord_components == 4)
-                                                                               qglTexCoord4f(s[0], s[1], s[2], s[3]);
+                                                                               qglVertexAttrib4f(GLSLATTRIB_TEXCOORD0 + j, sb[0], sb[1], sb[2], sb[3]);
                                                                        else if (gl_state.units[j].pointer_texcoord_components == 3)
-                                                                               qglTexCoord3f(s[0], s[1], s[2]);
+                                                                               qglVertexAttrib3f(GLSLATTRIB_TEXCOORD0 + j, sb[0], sb[1], sb[2]);
                                                                        else if (gl_state.units[j].pointer_texcoord_components == 2)
-                                                                               qglTexCoord2f(s[0], s[1]);
+                                                                               qglVertexAttrib2f(GLSLATTRIB_TEXCOORD0 + j, sb[0], sb[1]);
                                                                        else if (gl_state.units[j].pointer_texcoord_components == 1)
-                                                                               qglTexCoord1f(s[0]);
+                                                                               qglVertexAttrib1f(GLSLATTRIB_TEXCOORD0 + j, sb[0]);
                                                                }
                                                        }
-                                                       else if (gl_state.units[j].pointer_texcoord_gltype == GL_BYTE)
+                                               }
+                                               if (gl_state.pointer_color_pointer && gl_state.pointer_color_enabled && gl_state.pointer_color_components == 4)
+                                               {
+                                                       if (gl_state.pointer_color_gltype == GL_FLOAT)
                                                        {
-                                                               const GLbyte *sb = (const GLbyte *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
-                                                               if (vid.texarrayunits > 1)
+                                                               p = (const GLfloat *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
+                                                               qglVertexAttrib4f(GLSLATTRIB_COLOR, p[0], p[1], p[2], p[3]);
+                                                       }
+                                                       else if (gl_state.pointer_color_gltype == GL_UNSIGNED_BYTE)
+                                                       {
+                                                               const GLubyte *ub = (const GLubyte *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
+                                                               qglVertexAttrib4Nub(GLSLATTRIB_COLOR, ub[0], ub[1], ub[2], ub[3]);
+                                                       }
+                                               }
+                                               if (gl_state.pointer_vertex_gltype == GL_FLOAT)
+                                               {
+                                                       p = (const GLfloat *)((const unsigned char *)gl_state.pointer_vertex_pointer + element * gl_state.pointer_vertex_stride);
+                                                       if (gl_state.pointer_vertex_components == 4)
+                                                               qglVertexAttrib4f(GLSLATTRIB_POSITION, p[0], p[1], p[2], p[3]);
+                                                       else if (gl_state.pointer_vertex_components == 3)
+                                                               qglVertexAttrib3f(GLSLATTRIB_POSITION, p[0], p[1], p[2]);
+                                                       else
+                                                               qglVertexAttrib2f(GLSLATTRIB_POSITION, p[0], p[1]);
+                                               }
+                                       }
+                               }
+                               else
+                               {
+                                       for (i = 0;i < (unsigned int) numtriangles * 3;i++)
+                                       {
+                                               if (element3i)
+                                                       element = element3i[i];
+                                               else if (element3s)
+                                                       element = element3s[i];
+                                               else
+                                                       element = firstvertex + i;
+                                               for (j = 0;j < vid.texarrayunits;j++)
+                                               {
+                                                       if (gl_state.units[j].pointer_texcoord_pointer && gl_state.units[j].arrayenabled)
+                                                       {
+                                                               if (gl_state.units[j].pointer_texcoord_gltype == GL_FLOAT)
                                                                {
-                                                                       if (gl_state.units[j].pointer_texcoord_components == 4)
-                                                                               qglMultiTexCoord4f(GL_TEXTURE0_ARB + 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]);
-                                                                       else if (gl_state.units[j].pointer_texcoord_components == 2)
-                                                                               qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, sb[0], sb[1]);
-                                                                       else if (gl_state.units[j].pointer_texcoord_components == 1)
-                                                                               qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, sb[0]);
+                                                                       p = (const GLfloat *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
+                                                                       if (vid.texarrayunits > 1)
+                                                                       {
+                                                                               if (gl_state.units[j].pointer_texcoord_components == 4)
+                                                                                       qglMultiTexCoord4f(GL_TEXTURE0 + j, p[0], p[1], p[2], p[3]);
+                                                                               else if (gl_state.units[j].pointer_texcoord_components == 3)
+                                                                                       qglMultiTexCoord3f(GL_TEXTURE0 + j, p[0], p[1], p[2]);
+                                                                               else if (gl_state.units[j].pointer_texcoord_components == 2)
+                                                                                       qglMultiTexCoord2f(GL_TEXTURE0 + j, p[0], p[1]);
+                                                                               else
+                                                                                       qglMultiTexCoord1f(GL_TEXTURE0 + j, p[0]);
+                                                                       }
+                                                                       else
+                                                                       {
+                                                                               if (gl_state.units[j].pointer_texcoord_components == 4)
+                                                                                       qglTexCoord4f(p[0], p[1], p[2], p[3]);
+                                                                               else if (gl_state.units[j].pointer_texcoord_components == 3)
+                                                                                       qglTexCoord3f(p[0], p[1], p[2]);
+                                                                               else if (gl_state.units[j].pointer_texcoord_components == 2)
+                                                                                       qglTexCoord2f(p[0], p[1]);
+                                                                               else
+                                                                                       qglTexCoord1f(p[0]);
+                                                                       }
                                                                }
-                                                               else
+                                                               else if (gl_state.units[j].pointer_texcoord_gltype == GL_SHORT)
                                                                {
-                                                                       if (gl_state.units[j].pointer_texcoord_components == 4)
-                                                                               qglTexCoord4f(sb[0], sb[1], sb[2], sb[3]);
-                                                                       else if (gl_state.units[j].pointer_texcoord_components == 3)
-                                                                               qglTexCoord3f(sb[0], sb[1], sb[2]);
-                                                                       else if (gl_state.units[j].pointer_texcoord_components == 2)
-                                                                               qglTexCoord2f(sb[0], sb[1]);
-                                                                       else if (gl_state.units[j].pointer_texcoord_components == 1)
-                                                                               qglTexCoord1f(sb[0]);
+                                                                       const GLshort *s = (const GLshort *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
+                                                                       if (vid.texarrayunits > 1)
+                                                                       {
+                                                                               if (gl_state.units[j].pointer_texcoord_components == 4)
+                                                                                       qglMultiTexCoord4f(GL_TEXTURE0 + j, s[0], s[1], s[2], s[3]);
+                                                                               else if (gl_state.units[j].pointer_texcoord_components == 3)
+                                                                                       qglMultiTexCoord3f(GL_TEXTURE0 + j, s[0], s[1], s[2]);
+                                                                               else if (gl_state.units[j].pointer_texcoord_components == 2)
+                                                                                       qglMultiTexCoord2f(GL_TEXTURE0 + j, s[0], s[1]);
+                                                                               else if (gl_state.units[j].pointer_texcoord_components == 1)
+                                                                                       qglMultiTexCoord1f(GL_TEXTURE0 + j, s[0]);
+                                                                       }
+                                                                       else
+                                                                       {
+                                                                               if (gl_state.units[j].pointer_texcoord_components == 4)
+                                                                                       qglTexCoord4f(s[0], s[1], s[2], s[3]);
+                                                                               else if (gl_state.units[j].pointer_texcoord_components == 3)
+                                                                                       qglTexCoord3f(s[0], s[1], s[2]);
+                                                                               else if (gl_state.units[j].pointer_texcoord_components == 2)
+                                                                                       qglTexCoord2f(s[0], s[1]);
+                                                                               else if (gl_state.units[j].pointer_texcoord_components == 1)
+                                                                                       qglTexCoord1f(s[0]);
+                                                                       }
+                                                               }
+                                                               else if (gl_state.units[j].pointer_texcoord_gltype == GL_BYTE)
+                                                               {
+                                                                       const GLbyte *sb = (const GLbyte *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride);
+                                                                       if (vid.texarrayunits > 1)
+                                                                       {
+                                                                               if (gl_state.units[j].pointer_texcoord_components == 4)
+                                                                                       qglMultiTexCoord4f(GL_TEXTURE0 + j, sb[0], sb[1], sb[2], sb[3]);
+                                                                               else if (gl_state.units[j].pointer_texcoord_components == 3)
+                                                                                       qglMultiTexCoord3f(GL_TEXTURE0 + j, sb[0], sb[1], sb[2]);
+                                                                               else if (gl_state.units[j].pointer_texcoord_components == 2)
+                                                                                       qglMultiTexCoord2f(GL_TEXTURE0 + j, sb[0], sb[1]);
+                                                                               else if (gl_state.units[j].pointer_texcoord_components == 1)
+                                                                                       qglMultiTexCoord1f(GL_TEXTURE0 + j, sb[0]);
+                                                                       }
+                                                                       else
+                                                                       {
+                                                                               if (gl_state.units[j].pointer_texcoord_components == 4)
+                                                                                       qglTexCoord4f(sb[0], sb[1], sb[2], sb[3]);
+                                                                               else if (gl_state.units[j].pointer_texcoord_components == 3)
+                                                                                       qglTexCoord3f(sb[0], sb[1], sb[2]);
+                                                                               else if (gl_state.units[j].pointer_texcoord_components == 2)
+                                                                                       qglTexCoord2f(sb[0], sb[1]);
+                                                                               else if (gl_state.units[j].pointer_texcoord_components == 1)
+                                                                                       qglTexCoord1f(sb[0]);
+                                                                       }
                                                                }
                                                        }
                                                }
-                                       }
-                                       if (gl_state.pointer_color_pointer && gl_state.pointer_color_enabled && gl_state.pointer_color_components == 4)
-                                       {
-                                               if (gl_state.pointer_color_gltype == GL_FLOAT)
+                                               if (gl_state.pointer_color_pointer && gl_state.pointer_color_enabled && gl_state.pointer_color_components == 4)
                                                {
-                                                       p = (const GLfloat *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
-                                                       qglColor4f(p[0], p[1], p[2], p[3]);
+                                                       if (gl_state.pointer_color_gltype == GL_FLOAT)
+                                                       {
+                                                               p = (const GLfloat *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
+                                                               qglColor4f(p[0], p[1], p[2], p[3]);
+                                                       }
+                                                       else if (gl_state.pointer_color_gltype == GL_UNSIGNED_BYTE)
+                                                       {
+                                                               const GLubyte *ub = (const GLubyte *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
+                                                               qglColor4ub(ub[0], ub[1], ub[2], ub[3]);
+                                                       }
                                                }
-                                               else if (gl_state.pointer_color_gltype == GL_UNSIGNED_BYTE)
+                                               if (gl_state.pointer_vertex_gltype == GL_FLOAT)
                                                {
-                                                       const GLubyte *ub = (const GLubyte *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride);
-                                                       qglColor4ub(ub[0], ub[1], ub[2], ub[3]);
+                                                       p = (const GLfloat *)((const unsigned char *)gl_state.pointer_vertex_pointer + element * gl_state.pointer_vertex_stride);
+                                                       if (gl_state.pointer_vertex_components == 4)
+                                                               qglVertex4f(p[0], p[1], p[2], p[3]);
+                                                       else if (gl_state.pointer_vertex_components == 3)
+                                                               qglVertex3f(p[0], p[1], p[2]);
+                                                       else
+                                                               qglVertex2f(p[0], p[1]);
                                                }
                                        }
-                                       if (gl_state.pointer_vertex_gltype == GL_FLOAT)
-                                       {
-                                               p = (const GLfloat *)((const unsigned char *)gl_state.pointer_vertex_pointer + element * gl_state.pointer_vertex_stride);
-                                               if (gl_state.pointer_vertex_components == 4)
-                                                       qglVertex4f(p[0], p[1], p[2], p[3]);
-                                               else if (gl_state.pointer_vertex_components == 3)
-                                                       qglVertex3f(p[0], p[1], p[2]);
-                                               else
-                                                       qglVertex2f(p[0], p[1]);
-                                       }
                                }
                                qglEnd();
                                CHECKGLERROR
+#endif
                        }
                        else if (bufferobject3s)
                        {
                                GL_BindEBO(bufferobject3s);
+#ifndef USE_GLES2
                                if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
                                {
                                        qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, (void *)bufferoffset3s);
                                        CHECKGLERROR
                                }
                                else
+#endif
                                {
                                        qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, (void *)(firsttriangle * sizeof(unsigned short[3])));
                                        CHECKGLERROR
@@ -2833,12 +3047,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
@@ -2847,12 +3063,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
@@ -2861,12 +3079,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
@@ -2928,8 +3148,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
@@ -3019,7 +3239,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
@@ -3197,6 +3417,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)
                {
@@ -3233,6 +3454,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:
@@ -3292,6 +3514,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)
                {
@@ -3327,6 +3550,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:
@@ -3380,7 +3604,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;
 }
@@ -3483,7 +3707,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:
@@ -3504,7 +3728,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;
                        }
@@ -3559,18 +3783,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:
@@ -3637,6 +3861,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
@@ -3667,6 +3892,7 @@ void R_Mesh_TexMatrix(unsigned int unitnum, const matrix4x4_t *matrix)
                                qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
                        }
                }
+#endif
                break;
        case RENDERPATH_D3D9:
        case RENDERPATH_D3D10:
@@ -3689,6 +3915,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;
@@ -3701,31 +3928,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)
                        {
@@ -3743,9 +3970,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)
@@ -3754,6 +3983,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:
@@ -4376,3 +4606,61 @@ void R_Mesh_PrepareVertices_Mesh(int numvertices, const r_vertexmesh_t *vertex,
                break;
        }
 }
+
+void GL_BlendEquationSubtract(qboolean negated)
+{
+       if(negated)
+       {
+               switch(vid.renderpath)
+               {
+               case RENDERPATH_GL11:
+               case RENDERPATH_GL13:
+               case RENDERPATH_GL20:
+               case RENDERPATH_GLES1:
+               case RENDERPATH_GLES2:
+                       qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT);
+                       break;
+               case RENDERPATH_D3D9:
+#ifdef SUPPORTD3D
+                       IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
+#endif
+                       break;
+               case RENDERPATH_D3D10:
+                       Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+                       break;
+               case RENDERPATH_D3D11:
+                       Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+                       break;
+               case RENDERPATH_SOFT:
+                       DPSOFTRAST_BlendSubtract(true);
+                       break;
+               }
+       }
+       else
+       {
+               switch(vid.renderpath)
+               {
+               case RENDERPATH_GL11:
+               case RENDERPATH_GL13:
+               case RENDERPATH_GL20:
+               case RENDERPATH_GLES1:
+               case RENDERPATH_GLES2:
+                       qglBlendEquationEXT(GL_FUNC_ADD);
+                       break;
+               case RENDERPATH_D3D9:
+#ifdef SUPPORTD3D
+                       IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
+#endif
+                       break;
+               case RENDERPATH_D3D10:
+                       Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+                       break;
+               case RENDERPATH_D3D11:
+                       Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
+                       break;
+               case RENDERPATH_SOFT:
+                       DPSOFTRAST_BlendSubtract(false);
+                       break;
+               }
+       }
+}
index 82b9ed4f0a654eb6abd9f0b0e3aa6227708d6ad4..0a35233621018c4c26ccc3381f40e34d4a8d0c41 100644 (file)
@@ -31,6 +31,7 @@ void R_GetViewport(r_viewport_t *v);
 void GL_Finish(void);
 
 void GL_BlendFunc(int blendfunc1, int blendfunc2);
+void GL_BlendEquationSubtract(qboolean negated);
 void GL_DepthMask(int state);
 void GL_DepthTest(int state);
 void GL_DepthFunc(int state);
@@ -40,6 +41,7 @@ void R_SetStencil(qboolean enable, int writemask, int fail, int zfail, int zpass
 void GL_PolygonOffset(float planeoffset, float depthoffset);
 void GL_CullFace(int state);
 void GL_AlphaTest(int state);
+void GL_AlphaToCoverage(qboolean state);
 void GL_ColorMask(int r, int g, int b, int a);
 void GL_Color(float cr, float cg, float cb, float ca);
 void GL_ActiveTexture(unsigned int num);
index 9850142f6bdbbac40454ea474f544a7a2dcefd45..aa6a0c387bb90bcb13ddb3e51674259480fe4ca8 100644 (file)
--- a/gl_draw.c
+++ b/gl_draw.c
@@ -53,7 +53,7 @@ static cachepic_t *cachepichash[CACHEPICHASHSIZE];
 static cachepic_t cachepics[MAX_CACHED_PICS];
 static int numcachepics;
 
-static rtexturepool_t *drawtexturepool;
+rtexturepool_t *drawtexturepool;
 
 static const unsigned char concharimage[FONT_FILESIZE] =
 {
@@ -302,6 +302,7 @@ static rtexture_t *draw_generatepic(const char *name, qboolean quiet)
        return r_texture_notexture;
 }
 
+int draw_frame = 1;
 
 /*
 ================
@@ -312,26 +313,34 @@ Draw_CachePic
 cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags)
 {
        int crc, hashkey;
-       unsigned char *pixels;
+       unsigned char *pixels = NULL;
        cachepic_t *pic;
        fs_offset_t lmpsize;
        unsigned char *lmpdata;
        char lmpname[MAX_QPATH];
        int texflags;
        int j;
+       qboolean ddshasalpha;
+       float ddsavgcolor[4];
+       qboolean loaded = false;
 
        texflags = TEXF_ALPHA;
        if (!(cachepicflags & CACHEPICFLAG_NOCLAMP))
                texflags |= TEXF_CLAMP;
-       if (!(cachepicflags & CACHEPICFLAG_NOCOMPRESSION) && gl_texturecompression_2d.integer)
+       if (!(cachepicflags & CACHEPICFLAG_NOCOMPRESSION) && gl_texturecompression_2d.integer && gl_texturecompression.integer)
                texflags |= TEXF_COMPRESS;
 
        // check whether the picture has already been cached
        crc = CRC_Block((unsigned char *)path, strlen(path));
        hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
        for (pic = cachepichash[hashkey];pic;pic = pic->chain)
+       {
                if (!strcmp (path, pic->name))
-                       if(!((pic->texflags ^ texflags) & ~(TEXF_COMPRESS))) // ignore TEXF_COMPRESS when comparing, because fallback pics remove the flag
+               {
+                       // if it was created (or replaced) by Draw_NewPic, just return it
+                       if(pic->flags & CACHEPICFLAG_NEWPIC)
+                               return pic;
+                       if (!((pic->texflags ^ texflags) & ~(TEXF_COMPRESS))) // ignore TEXF_COMPRESS when comparing, because fallback pics remove the flag
                        {
                                if(!(cachepicflags & CACHEPICFLAG_NOTPERSISTENT))
                                {
@@ -342,6 +351,8 @@ cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags)
                                }
                                return pic;
                        }
+               }
+       }
 
        if (numcachepics == MAX_CACHED_PICS)
        {
@@ -357,6 +368,7 @@ cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags)
 
 reload:
        // 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 ) {
@@ -369,13 +381,20 @@ reload:
        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
-       pixels = loadimagepixelsbgra(path, false, true, false, NULL);
-       if (pixels == NULL && !strncmp(path, "gfx/", 4))
-               pixels = loadimagepixelsbgra(path+4, false, true, false, NULL);
-       if (pixels)
+       if (!loaded && r_texture_dds_load.integer != 0 && (pic->tex = R_LoadTextureDDSFile(drawtexturepool, va("dds/%s.dds", pic->name), pic->texflags, &ddshasalpha, ddsavgcolor, 0)))
        {
+               // note this loads even if autoload is true, otherwise we can't get the width/height
+               loaded = true;
+               pic->hasalpha = ddshasalpha;
+               pic->width = R_TextureWidth(pic->tex);
+               pic->height = R_TextureHeight(pic->tex);
+       }
+       if (!loaded && ((pixels = loadimagepixelsbgra(pic->name, false, true, false, NULL)) || (!strncmp(pic->name, "gfx/", 4) && (pixels = loadimagepixelsbgra(pic->name+4, false, true, false, NULL)))))
+       {
+               loaded = true;
                pic->hasalpha = false;
                if (pic->texflags & TEXF_ALPHA)
                {
@@ -392,9 +411,15 @@ reload:
                pic->width = image_width;
                pic->height = image_height;
                if (!pic->autoload)
-                       pic->tex = R_LoadTexture2D(drawtexturepool, path, image_width, image_height, pixels, r_texture_sRGB_2d.integer ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, pic->texflags & (pic->hasalpha ? ~0 : ~TEXF_ALPHA), -1, NULL);
+               {
+                       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);
+#endif
+               }
        }
-       else
+       if (!loaded)
        {
                pic->autoload = false;
                // never compress the fallback images
@@ -405,43 +430,52 @@ reload:
        // size from that even if we don't upload the texture, this way the pics
        // show up the right size in the menu even if they were replaced with
        // higher or lower resolution versions
-       dpsnprintf(lmpname, sizeof(lmpname), "%s.lmp", path);
-       if (!strncmp(path, "gfx/", 4) && (lmpdata = FS_LoadFile(lmpname, tempmempool, false, &lmpsize)))
+       dpsnprintf(lmpname, sizeof(lmpname), "%s.lmp", pic->name);
+       if (!strncmp(pic->name, "gfx/", 4) && (lmpdata = FS_LoadFile(lmpname, tempmempool, false, &lmpsize)))
        {
                if (developer_loading.integer)
-                       Con_Printf("loading lump \"%s\"\n", path);
+                       Con_Printf("loading lump \"%s\"\n", pic->name);
 
                if (lmpsize >= 9)
                {
                        pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216;
                        pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216;
                        // if no high quality replacement image was found, upload the original low quality texture
-                       if (!pixels)
-                               pic->tex = R_LoadTexture2D(drawtexturepool, path, pic->width, pic->height, lmpdata + 8, TEXTYPE_PALETTE, pic->texflags, -1, palette_bgra_transparent);
+                       if (!loaded)
+                       {
+                               loaded = true;
+                               pic->tex = R_LoadTexture2D(drawtexturepool, pic->name, pic->width, pic->height, lmpdata + 8, vid.sRGB2D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, pic->texflags, -1, palette_bgra_transparent);
+                       }
                }
                Mem_Free(lmpdata);
        }
-       else if ((lmpdata = W_GetLumpName (path + 4)))
+       else if ((lmpdata = W_GetLumpName (pic->name + 4)))
        {
                if (developer_loading.integer)
-                       Con_Printf("loading gfx.wad lump \"%s\"\n", path + 4);
+                       Con_Printf("loading gfx.wad lump \"%s\"\n", pic->name + 4);
 
-               if (!strcmp(path, "gfx/conchars"))
+               if (!strcmp(pic->name, "gfx/conchars"))
                {
                        // conchars is a raw image and with color 0 as transparent instead of 255
                        pic->width = 128;
                        pic->height = 128;
                        // if no high quality replacement image was found, upload the original low quality texture
-                       if (!pixels)
-                               pic->tex = R_LoadTexture2D(drawtexturepool, path, 128, 128, lmpdata, TEXTYPE_PALETTE, pic->texflags, -1, palette_bgra_font);
+                       if (!loaded)
+                       {
+                               loaded = true;
+                               pic->tex = R_LoadTexture2D(drawtexturepool, pic->name, 128, 128, lmpdata, vid.sRGB2D != 0 ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, pic->texflags, -1, palette_bgra_font);
+                       }
                }
                else
                {
                        pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216;
                        pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216;
                        // if no high quality replacement image was found, upload the original low quality texture
-                       if (!pixels)
-                               pic->tex = R_LoadTexture2D(drawtexturepool, path, pic->width, pic->height, lmpdata + 8, TEXTYPE_PALETTE, pic->texflags, -1, palette_bgra_transparent);
+                       if (!loaded)
+                       {
+                               loaded = true;
+                               pic->tex = R_LoadTexture2D(drawtexturepool, pic->name, pic->width, pic->height, lmpdata + 8, vid.sRGB2D != 0 ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, pic->texflags, -1, palette_bgra_transparent);
+                       }
                }
        }
 
@@ -450,10 +484,10 @@ reload:
                Mem_Free(pixels);
                pixels = NULL;
        }
-       else if (pic->tex == NULL)
+       if (!loaded)
        {
                // if it's not found on disk, generate an image
-               pic->tex = draw_generatepic(path, (cachepicflags & CACHEPICFLAG_QUIET) != 0);
+               pic->tex = draw_generatepic(pic->name, (cachepicflags & CACHEPICFLAG_QUIET) != 0);
                pic->width = R_TextureWidth(pic->tex);
                pic->height = R_TextureHeight(pic->tex);
        }
@@ -466,15 +500,32 @@ cachepic_t *Draw_CachePic (const char *path)
        return Draw_CachePic_Flags (path, 0); // default to persistent!
 }
 
-int draw_frame = 1;
-
 rtexture_t *Draw_GetPicTexture(cachepic_t *pic)
 {
        if (pic->autoload && !pic->tex)
        {
-               pic->tex = loadtextureimage(drawtexturepool, pic->name, false, pic->texflags, true, r_texture_sRGB_2d.integer != 0);
+               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);
+               }
+               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);
+#endif
+               }
                if (pic->tex == NULL && !strncmp(pic->name, "gfx/", 4))
-                       pic->tex = loadtextureimage(drawtexturepool, pic->name+4, false, pic->texflags, true, r_texture_sRGB_2d.integer != 0);
+               {
+                       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);
+#endif
+               }
                if (pic->tex == NULL)
                        pic->tex = draw_generatepic(pic->name, true);
        }
@@ -514,7 +565,7 @@ cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, u
 
        if (pic)
        {
-               if (pic->tex && pic->width == width && pic->height == height)
+               if (pic->flags == CACHEPICFLAG_NEWPIC && pic->tex && pic->width == width && pic->height == height)
                {
                        R_UpdateTexture(pic->tex, pixels_bgra, 0, 0, 0, width, height, 1);
                        return pic;
@@ -538,6 +589,7 @@ cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, u
                }
        }
 
+       pic->flags = CACHEPICFLAG_NEWPIC; // disable texflags checks in Draw_CachePic
        pic->width = width;
        pic->height = height;
        if (pic->tex)
@@ -1095,7 +1147,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);
+               R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true);
 
 #if 0
       // AK07: lets be texel correct on the corners
@@ -1111,7 +1163,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);
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true);
 
        floats[2] = floats[5] = floats[8] = floats[11] = 0;
        floats[0] = floats[9] = x;
@@ -1144,10 +1196,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);
+               R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true);
        }
        else
-               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true);
 
        floats[2] = floats[5] = floats[8] = floats[11] = 0;
 
@@ -1189,7 +1241,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);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true);
 
        floats[2] = floats[5] = floats[8] = floats[11] = 0;
        floats[0] = floats[9] = x;
@@ -1516,7 +1568,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);
+       R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true);
 
        ac = color4f;
        at = texcoord2f;
@@ -1652,7 +1704,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);
+                                               R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true);
                                                map = ft2_oldstyle_map;
                                        }
                                }
@@ -1721,7 +1773,7 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
                                                        break;
                                                }
                                        }
-                                       R_SetupShader_Generic(map->texture, NULL, GL_MODULATE, 1);
+                                       R_SetupShader_Generic(map->pic->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true);
                                }
 
                                mapch = ch - map->start;
@@ -1865,10 +1917,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);
+               R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true);
        }
        else
-               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true);
 
        floats[2] = floats[5] = floats[8] = floats[11] = 0;
        floats[0] = floats[9] = x;
@@ -1897,7 +1949,7 @@ void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags, qboolean hasalpha)
        DrawQ_ProcessDrawFlag(flags, hasalpha);
 
 //     R_Mesh_ResetTextureState();
-       R_SetupShader_Generic(mesh->texture, NULL, GL_MODULATE, 1);
+       R_SetupShader_Generic(mesh->texture, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true);
 
        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);
@@ -1917,6 +1969,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++)
@@ -1927,6 +1980,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__);
@@ -1954,13 +2008,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);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, (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
@@ -1972,6 +2027,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__);
@@ -2012,7 +2068,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);
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true);
 
                //qglLineWidth(width);CHECKGLERROR
 
@@ -2117,11 +2173,41 @@ void R_DrawGamma(void)
        }
        // all the blends ignore depth
 //     R_Mesh_ResetTextureState();
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, true, true);
        GL_DepthMask(true);
        GL_DepthRange(0, 1);
        GL_PolygonOffset(0, 0);
        GL_DepthTest(false);
+
+       // interpretation of brightness and contrast:
+       //   color range := brightness .. (brightness + contrast)
+       // i.e. "c *= contrast; c += brightness"
+       // plausible values for brightness thus range from -contrast to 1
+
+       // apply pre-brightness (subtractive brightness, for where contrast was >= 1)
+       if (vid.support.ext_blend_subtract)
+       {
+               if (v_color_enable.integer)
+               {
+                       c[0] = -v_color_black_r.value / v_color_white_r.value;
+                       c[1] = -v_color_black_g.value / v_color_white_g.value;
+                       c[2] = -v_color_black_b.value / v_color_white_b.value;
+               }
+               else
+                       c[0] = c[1] = c[2] = -v_brightness.value / v_contrast.value;
+               if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
+               {
+                       // need SUBTRACTIVE blending to do this!
+                       GL_BlendEquationSubtract(true);
+                       GL_BlendFunc(GL_ONE, GL_ONE);
+                       GL_Color(c[0], c[1], c[2], 1);
+                       R_Mesh_PrepareVertices_Generic_Arrays(3, blendvertex3f, NULL, NULL);
+                       R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+                       GL_BlendEquationSubtract(false);
+               }
+       }
+
+       // apply contrast
        if (v_color_enable.integer)
        {
                c[0] = v_color_white_r.value;
@@ -2130,17 +2216,32 @@ void R_DrawGamma(void)
        }
        else
                c[0] = c[1] = c[2] = v_contrast.value;
-       if (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
+       if (c[0] >= 1.003f || c[1] >= 1.003f || c[2] >= 1.003f)
        {
                GL_BlendFunc(GL_DST_COLOR, GL_ONE);
-               while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f)
+               while (c[0] >= 1.003f || c[1] >= 1.003f || c[2] >= 1.003f)
                {
-                       GL_Color(c[0] - 1, c[1] - 1, c[2] - 1, 1);
+                       float cc[4];
+                       cc[0] = bound(0, c[0] - 1, 1);
+                       cc[1] = bound(0, c[1] - 1, 1);
+                       cc[2] = bound(0, c[2] - 1, 1);
+                       GL_Color(cc[0], cc[1], cc[2], 1);
                        R_Mesh_PrepareVertices_Generic_Arrays(3, blendvertex3f, NULL, NULL);
                        R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
-                       VectorScale(c, 0.5, c);
+                       c[0] /= 1 + cc[0];
+                       c[1] /= 1 + cc[1];
+                       c[2] /= 1 + cc[2];
                }
        }
+       if (c[0] <= 0.997f || c[1] <= 0.997f || c[2] <= 0.997f)
+       {
+               GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
+               GL_Color(c[0], c[1], c[2], 1);
+               R_Mesh_PrepareVertices_Generic_Arrays(3, blendvertex3f, NULL, NULL);
+               R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
+       }
+
+       // apply post-brightness (additive brightness, for where contrast was <= 1)
        if (v_color_enable.integer)
        {
                c[0] = v_color_black_r.value;
@@ -2152,7 +2253,7 @@ void R_DrawGamma(void)
        if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f)
        {
                GL_BlendFunc(GL_ONE, GL_ONE);
-               GL_Color(c[0] - 1, c[1] - 1, c[2] - 1, 1);
+               GL_Color(c[0], c[1], c[2], 1);
                R_Mesh_PrepareVertices_Generic_Arrays(3, blendvertex3f, NULL, NULL);
                R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
        }
index ffcf1e68c74b45c2ae63d470df67fc4644875b93..435cefe566289a665eefe3492695b77b1bf378ca 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"};
@@ -72,6 +76,7 @@ cvar_t r_farclip_world = {0, "r_farclip_world", "2", "adds map size to farclip m
 cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip plane" };
 cvar_t r_deformvertexes = {0, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
 cvar_t r_transparent = {0, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
+cvar_t r_transparent_alphatocoverage = {0, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
 cvar_t r_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)"};
@@ -121,6 +126,8 @@ 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_sortmaxdist = {CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
+cvar_t r_transparent_sortarraysize = {CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
 
 cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
@@ -134,14 +141,6 @@ cvar_t gl_skyclip = {0, "gl_skyclip", "4608", "nehahra farclip distance - the re
 cvar_t r_texture_dds_load = {CVAR_SAVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
 cvar_t r_texture_dds_save = {CVAR_SAVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
 
-cvar_t r_texture_sRGB_2d = {0, "r_texture_sRGB_2d", "0", "load textures as sRGB"};
-cvar_t r_texture_sRGB_skin_diffuse = {0, "r_texture_sRGB_skin_diffuse", "0", "load textures as sRGB"};
-cvar_t r_texture_sRGB_skin_gloss = {0, "r_texture_sRGB_skin_gloss", "0", "load textures as sRGB"};
-cvar_t r_texture_sRGB_skin_glow = {0, "r_texture_sRGB_skin_glow", "0", "load textures as sRGB"};
-cvar_t r_texture_sRGB_skin_reflect = {0, "r_texture_sRGB_skin_reflect", "0", "load textures as sRGB"};
-cvar_t r_texture_sRGB_cubemap = {0, "r_texture_sRGB_cubemap", "0", "load textures as sRGB"};
-cvar_t r_texture_sRGB_skybox = {0, "r_texture_sRGB_skybox", "0", "load textures as sRGB"};
-
 cvar_t r_textureunits = {0, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
 static cvar_t gl_combine = {CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
 static cvar_t r_glsl = {CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
@@ -178,6 +177,7 @@ cvar_t r_water_resolutionmultiplier = {CVAR_SAVE, "r_water_resolutionmultiplier"
 cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
 cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
 cvar_t r_water_scissormode = {0, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
+cvar_t r_water_lowquality = {0, "r_water_lowquality", "0", "special option to accelerate water rendering, 1 disables shadows and particles, 2 disables all dynamic lights"};
 
 cvar_t r_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"};
@@ -201,7 +201,8 @@ cvar_t r_hdr_irisadaptation_multiplier = {CVAR_SAVE, "r_hdr_irisadaptation_multi
 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_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"};
 
@@ -210,14 +211,6 @@ cvar_t developer_texturelogging = {0, "developer_texturelogging", "0", "produces
 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers)"};
 
 cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
-cvar_t r_track_sprites = {CVAR_SAVE, "r_track_sprites", "1", "track SPR_LABEL* sprites by putting them as indicator at the screen border to rotate to"};
-cvar_t r_track_sprites_flags = {CVAR_SAVE, "r_track_sprites_flags", "1", "1: Rotate sprites accordingly, 2: Make it a continuous rotation"};
-cvar_t r_track_sprites_scalew = {CVAR_SAVE, "r_track_sprites_scalew", "1", "width scaling of tracked sprites"};
-cvar_t r_track_sprites_scaleh = {CVAR_SAVE, "r_track_sprites_scaleh", "1", "height scaling of tracked sprites"};
-cvar_t r_overheadsprites_perspective = {CVAR_SAVE, "r_overheadsprites_perspective", "5", "fake perspective effect for SPR_OVERHEAD sprites"};
-cvar_t r_overheadsprites_pushback = {CVAR_SAVE, "r_overheadsprites_pushback", "15", "how far to pull the SPR_OVERHEAD sprites toward the eye (used to avoid intersections with 3D models)"};
-cvar_t r_overheadsprites_scalex = {CVAR_SAVE, "r_overheadsprites_scalex", "1", "additional scale for overhead sprites for x axis"};
-cvar_t r_overheadsprites_scaley = {CVAR_SAVE, "r_overheadsprites_scaley", "1", "additional scale for overhead sprites for y axis"};
 
 cvar_t r_glsl_saturation = {CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
 cvar_t r_glsl_saturation_redcompensate = {CVAR_SAVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
@@ -227,6 +220,7 @@ 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;
 
@@ -287,7 +281,7 @@ typedef struct cubemapinfo_s
 cubemapinfo_t;
 
 int r_texture_numcubemaps;
-cubemapinfo_t r_texture_cubemaps[MAX_CUBEMAPS];
+cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
 
 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
 unsigned int r_numqueries;
@@ -682,6 +676,7 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
        {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
        {"#define USEBOUNCEGRID\n", " bouncegrid"},
        {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"},
+       {"#define USETRIPPY\n", " trippy"},
 };
 
 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
@@ -689,13 +684,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"},
@@ -716,6 +713,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"},
+       {"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"},
        {"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"},
@@ -1904,17 +1903,37 @@ 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)
+void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale, qboolean usegamma, qboolean notrippy)
 {
+       unsigned int permutation = 0;
+       if (r_trippy.integer && !notrippy)
+               permutation |= SHADERPERMUTATION_TRIPPY;
+       permutation |= SHADERPERMUTATION_VIEWTINT;
+       if (first)
+               permutation |= SHADERPERMUTATION_DIFFUSE;
+       if (second)
+               permutation |= SHADERPERMUTATION_SPECULAR;
+       if (texturemode == GL_MODULATE)
+               permutation |= SHADERPERMUTATION_COLORMAPPING;
+       if (usegamma && v_glslgamma.integer && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
+               permutation |= SHADERPERMUTATION_GAMMARAMPS;
+       else if (texturemode == GL_ADD)
+               permutation |= SHADERPERMUTATION_GLOW;
+       else if (texturemode == GL_DECAL)
+               permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
        if (!second)
                texturemode = GL_MODULATE;
+       if (vid.allowalphatocoverage)
+               GL_AlphaToCoverage(false);
        switch (vid.renderpath)
        {
        case RENDERPATH_D3D9:
 #ifdef SUPPORTD3D
-               R_SetupShader_SetPermutationHLSL(SHADERMODE_GENERIC, SHADERPERMUTATION_VIEWTINT | (first ? SHADERPERMUTATION_DIFFUSE : 0) | (second ? SHADERPERMUTATION_SPECULAR : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
+               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:
@@ -1925,9 +1944,11 @@ void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemod
                break;
        case RENDERPATH_GL20:
        case RENDERPATH_GLES2:
-               R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, SHADERPERMUTATION_VIEWTINT | (first ? SHADERPERMUTATION_DIFFUSE : 0) | (second ? SHADERPERMUTATION_SPECULAR : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
+               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:
@@ -1941,20 +1962,25 @@ void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemod
                R_Mesh_TexBind(0, first );
                break;
        case RENDERPATH_SOFT:
-               R_SetupShader_SetPermutationSoft(SHADERMODE_GENERIC, SHADERPERMUTATION_VIEWTINT | (first ? SHADERPERMUTATION_DIFFUSE : 0) | (second ? SHADERPERMUTATION_SPECULAR : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
+               R_SetupShader_SetPermutationSoft(SHADERMODE_GENERIC, permutation);
                R_Mesh_TexBind(GL20TU_FIRST , first );
                R_Mesh_TexBind(GL20TU_SECOND, second);
                break;
        }
 }
 
-void R_SetupShader_DepthOrShadow(void)
+void R_SetupShader_DepthOrShadow(qboolean notrippy)
 {
+       unsigned int permutation = 0;
+       if (r_trippy.integer && !notrippy)
+               permutation |= SHADERPERMUTATION_TRIPPY;
+       if (vid.allowalphatocoverage)
+               GL_AlphaToCoverage(false);
        switch (vid.renderpath)
        {
        case RENDERPATH_D3D9:
 #ifdef SUPPORTD3D
-               R_SetupShader_SetPermutationHLSL(SHADERMODE_DEPTH_OR_SHADOW, 0);
+               R_SetupShader_SetPermutationHLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
 #endif
                break;
        case RENDERPATH_D3D10:
@@ -1965,7 +1991,7 @@ void R_SetupShader_DepthOrShadow(void)
                break;
        case RENDERPATH_GL20:
        case RENDERPATH_GLES2:
-               R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, 0);
+               R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
                break;
        case RENDERPATH_GL13:
        case RENDERPATH_GLES1:
@@ -1976,18 +2002,23 @@ void R_SetupShader_DepthOrShadow(void)
                R_Mesh_TexBind(0, 0);
                break;
        case RENDERPATH_SOFT:
-               R_SetupShader_SetPermutationSoft(SHADERMODE_DEPTH_OR_SHADOW, 0);
+               R_SetupShader_SetPermutationSoft(SHADERMODE_DEPTH_OR_SHADOW, permutation);
                break;
        }
 }
 
-void R_SetupShader_ShowDepth(void)
+void R_SetupShader_ShowDepth(qboolean notrippy)
 {
+       int permutation = 0;
+       if (r_trippy.integer && !notrippy)
+               permutation |= SHADERPERMUTATION_TRIPPY;
+       if (vid.allowalphatocoverage)
+               GL_AlphaToCoverage(false);
        switch (vid.renderpath)
        {
        case RENDERPATH_D3D9:
 #ifdef SUPPORTHLSL
-               R_SetupShader_SetPermutationHLSL(SHADERMODE_SHOWDEPTH, 0);
+               R_SetupShader_SetPermutationHLSL(SHADERMODE_SHOWDEPTH, permutation);
 #endif
                break;
        case RENDERPATH_D3D10:
@@ -1998,7 +2029,7 @@ void R_SetupShader_ShowDepth(void)
                break;
        case RENDERPATH_GL20:
        case RENDERPATH_GLES2:
-               R_SetupShader_SetPermutationGLSL(SHADERMODE_SHOWDEPTH, 0);
+               R_SetupShader_SetPermutationGLSL(SHADERMODE_SHOWDEPTH, permutation);
                break;
        case RENDERPATH_GL13:
        case RENDERPATH_GLES1:
@@ -2006,7 +2037,7 @@ void R_SetupShader_ShowDepth(void)
        case RENDERPATH_GL11:
                break;
        case RENDERPATH_SOFT:
-               R_SetupShader_SetPermutationSoft(SHADERMODE_SHOWDEPTH, 0);
+               R_SetupShader_SetPermutationSoft(SHADERMODE_SHOWDEPTH, permutation);
                break;
        }
 }
@@ -2082,7 +2113,7 @@ static int R_BlendFuncFlags(int src, int dst)
        return r;
 }
 
-void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane)
+void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qboolean notrippy)
 {
        // select a permutation of the lighting shader appropriate to this
        // combination of texture, entity, light source, and fogging, only use the
@@ -2096,6 +2127,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
        float m16f[16];
        matrix4x4_t tempmatrix;
        r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
+       if (r_trippy.integer && !notrippy)
+               permutation |= SHADERPERMUTATION_TRIPPY;
        if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
                permutation |= SHADERPERMUTATION_ALPHAKILL;
        if (rsurface.texture->r_water_waterscroll[0] && rsurface.texture->r_water_waterscroll[1])
@@ -2132,6 +2165,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        GL_BlendFunc(GL_ONE, GL_ZERO);
                        blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
                }
+               if (vid.allowalphatocoverage)
+                       GL_AlphaToCoverage(false);
        }
        else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
        {
@@ -2151,6 +2186,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                mode = SHADERMODE_DEFERREDGEOMETRY;
                GL_BlendFunc(GL_ONE, GL_ZERO);
                blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
+               if (vid.allowalphatocoverage)
+                       GL_AlphaToCoverage(false);
        }
        else if (rsurfacepass == RSURFPASS_RTLIGHT)
        {
@@ -2195,6 +2232,8 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        permutation |= SHADERPERMUTATION_REFLECTCUBE;
                GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
                blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
+               if (vid.allowalphatocoverage)
+                       GL_AlphaToCoverage(false);
        }
        else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
        {
@@ -2237,6 +2276,17 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                        permutation |= SHADERPERMUTATION_REFLECTCUBE;
                GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
                blendfuncflags = R_BlendFuncFlags(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
+               // when using alphatocoverage, we don't need alphakill
+               if (vid.allowalphatocoverage)
+               {
+                       if (r_transparent_alphatocoverage.integer)
+                       {
+                               GL_AlphaToCoverage((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
+                               permutation &= ~SHADERPERMUTATION_ALPHAKILL;
+                       }
+                       else
+                               GL_AlphaToCoverage(false);
+               }
        }
        else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT_DIRECTIONAL)
        {
@@ -2281,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)
@@ -2289,6 +2339,17 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                }
                GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
                blendfuncflags = R_BlendFuncFlags(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
+               // when using alphatocoverage, we don't need alphakill
+               if (vid.allowalphatocoverage)
+               {
+                       if (r_transparent_alphatocoverage.integer)
+                       {
+                               GL_AlphaToCoverage((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
+                               permutation &= ~SHADERPERMUTATION_ALPHAKILL;
+                       }
+                       else
+                               GL_AlphaToCoverage(false);
+               }
        }
        else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
        {
@@ -2330,7 +2391,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)
@@ -2338,6 +2399,17 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                }
                GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
                blendfuncflags = R_BlendFuncFlags(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
+               // when using alphatocoverage, we don't need alphakill
+               if (vid.allowalphatocoverage)
+               {
+                       if (r_transparent_alphatocoverage.integer)
+                       {
+                               GL_AlphaToCoverage((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
+                               permutation &= ~SHADERPERMUTATION_ALPHAKILL;
+                       }
+                       else
+                               GL_AlphaToCoverage(false);
+               }
        }
        else
        {
@@ -2397,10 +2469,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;
@@ -2415,7 +2490,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)
@@ -2423,6 +2498,17 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting,
                }
                GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
                blendfuncflags = R_BlendFuncFlags(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
+               // when using alphatocoverage, we don't need alphakill
+               if (vid.allowalphatocoverage)
+               {
+                       if (r_transparent_alphatocoverage.integer)
+                       {
+                               GL_AlphaToCoverage((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
+                               permutation &= ~SHADERPERMUTATION_ALPHAKILL;
+                       }
+                       else
+                               GL_AlphaToCoverage(false);
+               }
        }
        if(!(blendfuncflags & BLENDFUNC_ALLOWS_COLORMOD))
                colormod = dummy_colormod;
@@ -2923,6 +3009,8 @@ void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
                else if (r_shadow_shadowmappcf)
                        permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
        }
+       if (vid.allowalphatocoverage)
+               GL_AlphaToCoverage(false);
        Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
        Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
        Matrix4x4_Invert_Simple(&viewtolight, &lighttoview);
@@ -3233,7 +3321,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        {
                basepixels_width = image_width;
                basepixels_height = image_height;
-               skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, r_texture_sRGB_skin_diffuse.integer != 0 ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
+               skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
                if (textureflags & TEXF_ALPHA)
                {
                        for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
@@ -3255,16 +3343,18 @@ 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 ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
+                               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);
                                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), true, skinframe->hasalpha);
+                       R_SaveTextureDDSFile(skinframe->base, va("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), true, true);
+                       R_SaveTextureDDSFile(skinframe->fog, va("dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
+#endif
        }
 
        if (r_loaddds)
@@ -3286,7 +3376,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
                mymiplevel = savemiplevel;
                if ((pixels = loadimagepixelsbgra(va("%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 ? ~0 : ~TEXF_COMPRESS), 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);
                        Mem_Free(pixels);
                        pixels = NULL;
                }
@@ -3294,7 +3384,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
                {
                        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 ? ~0 : ~TEXF_COMPRESS), 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);
                        Mem_Free(pixels);
                        Mem_Free(bumppixels);
                }
@@ -3302,11 +3392,13 @@ 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 ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
+                       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);
                        Mem_Free(pixels);
                }
+#ifndef USE_GLES2
                if (r_savedds && qglGetCompressedTexImageARB && skinframe->nmap)
-                       R_SaveTextureDDSFile(skinframe->nmap, va("dds/%s_norm.dds", skinframe->basename), true, true);
+                       R_SaveTextureDDSFile(skinframe->nmap, va("dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
+#endif
        }
 
        // _luma is supported only for tenebrae compatibility
@@ -3314,18 +3406,22 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        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))))
        {
-               skinframe->glow = R_LoadTexture2D (r_main_texturepool, va("%s_glow", skinframe->basename), image_width, image_height, pixels, r_texture_sRGB_skin_glow.integer != 0 ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_glow.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
+               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);
+#ifndef USE_GLES2
                if (r_savedds && qglGetCompressedTexImageARB && skinframe->glow)
-                       R_SaveTextureDDSFile(skinframe->glow, va("dds/%s_glow.dds", skinframe->basename), true, true);
+                       R_SaveTextureDDSFile(skinframe->glow, va("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)))
        {
-               skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va("%s_gloss", skinframe->basename), image_width, image_height, pixels, r_texture_sRGB_skin_gloss.integer != 0 ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_gloss.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
+               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);
+#ifndef USE_GLES2
                if (r_savedds && qglGetCompressedTexImageARB && skinframe->gloss)
-                       R_SaveTextureDDSFile(skinframe->gloss, va("dds/%s_gloss.dds", skinframe->basename), true, true);
+                       R_SaveTextureDDSFile(skinframe->gloss, va("dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
+#endif
                Mem_Free(pixels);
                pixels = NULL;
        }
@@ -3333,9 +3429,11 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        mymiplevel = savemiplevel;
        if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va("%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, r_texture_sRGB_skin_diffuse.integer != 0 ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
+               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);
+#ifndef USE_GLES2
                if (r_savedds && qglGetCompressedTexImageARB && skinframe->pants)
-                       R_SaveTextureDDSFile(skinframe->pants, va("dds/%s_pants.dds", skinframe->basename), true, false);
+                       R_SaveTextureDDSFile(skinframe->pants, va("dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
+#endif
                Mem_Free(pixels);
                pixels = NULL;
        }
@@ -3343,9 +3441,11 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        mymiplevel = savemiplevel;
        if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va("%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, r_texture_sRGB_skin_diffuse.integer != 0 ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
+               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);
+#ifndef USE_GLES2
                if (r_savedds && qglGetCompressedTexImageARB && skinframe->shirt)
-                       R_SaveTextureDDSFile(skinframe->shirt, va("dds/%s_shirt.dds", skinframe->basename), true, false);
+                       R_SaveTextureDDSFile(skinframe->shirt, va("dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
+#endif
                Mem_Free(pixels);
                pixels = NULL;
        }
@@ -3353,9 +3453,11 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
        mymiplevel = savemiplevel;
        if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va("%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, r_texture_sRGB_skin_reflect.integer != 0 ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_reflectmask.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
+               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);
+#ifndef USE_GLES2
                if (r_savedds && qglGetCompressedTexImageARB && skinframe->reflect)
-                       R_SaveTextureDDSFile(skinframe->reflect, va("dds/%s_reflect.dds", skinframe->basename), true, true);
+                       R_SaveTextureDDSFile(skinframe->reflect, va("dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
+#endif
                Mem_Free(pixels);
                pixels = NULL;
        }
@@ -3535,20 +3637,20 @@ static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboo
        if (skinframe->qgenerateglow)
        {
                skinframe->qgenerateglow = false;
-               skinframe->glow = R_LoadTexture2D(r_main_texturepool, va("%s_glow", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow
+               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
        }
 
        if (colormapped)
        {
                skinframe->qgeneratebase = false;
-               skinframe->base  = R_LoadTexture2D(r_main_texturepool, va("%s_nospecial", skinframe->basename), width, height, skindata, 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, TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_pantsaswhite);
-               skinframe->shirt = R_LoadTexture2D(r_main_texturepool, va("%s_shirt", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_shirtaswhite);
+               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);
        }
        else
        {
                skinframe->qgeneratemerged = false;
-               skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete);
+               skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete);
        }
 
        if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
@@ -3724,7 +3826,7 @@ rtexture_t *R_LoadCubemap(const char *basename)
                if (developer_loading.integer)
                        Con_Printf("loading cubemap \"%s\"\n", basename);
 
-               cubemaptexture = R_LoadTextureCubeMap(r_main_texturepool, basename, cubemapsize, cubemappixels, r_texture_sRGB_cubemap.integer != 0 ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
+               cubemaptexture = R_LoadTextureCubeMap(r_main_texturepool, basename, cubemapsize, cubemappixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer && gl_texturecompression.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
                Mem_Free(cubemappixels);
        }
        else
@@ -3746,14 +3848,36 @@ rtexture_t *R_GetCubemap(const char *basename)
 {
        int i;
        for (i = 0;i < r_texture_numcubemaps;i++)
-               if (!strcasecmp(r_texture_cubemaps[i].basename, basename))
-                       return r_texture_cubemaps[i].texture ? r_texture_cubemaps[i].texture : r_texture_whitecube;
-       if (i >= MAX_CUBEMAPS)
+               if (r_texture_cubemaps[i] != NULL)
+                       if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
+                               return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
+       if (i >= MAX_CUBEMAPS || !r_main_mempool)
                return r_texture_whitecube;
        r_texture_numcubemaps++;
-       strlcpy(r_texture_cubemaps[i].basename, basename, sizeof(r_texture_cubemaps[i].basename));
-       r_texture_cubemaps[i].texture = R_LoadCubemap(r_texture_cubemaps[i].basename);
-       return r_texture_cubemaps[i].texture;
+       r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
+       strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
+       r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
+       return r_texture_cubemaps[i]->texture;
+}
+
+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)
@@ -3762,9 +3886,13 @@ void R_FreeCubemaps(void)
        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].texture)
-                       R_FreeTexture(r_texture_cubemaps[i].texture);
+                       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;
 }
@@ -3916,6 +4044,9 @@ void gl_main_start(void)
        hlslshaderstring = NULL;
        memset(&r_svbsp, 0, sizeof (r_svbsp));
 
+       memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
+       r_texture_numcubemaps = 0;
+
        r_refdef.fogmasktable_density = 0;
 }
 
@@ -3933,8 +4064,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__);
@@ -4037,13 +4170,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);
@@ -4055,6 +4192,7 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_nearclip);
        Cvar_RegisterVariable(&r_deformvertexes);
        Cvar_RegisterVariable(&r_transparent);
+       Cvar_RegisterVariable(&r_transparent_alphatocoverage);
        Cvar_RegisterVariable(&r_showoverdraw);
        Cvar_RegisterVariable(&r_showbboxes);
        Cvar_RegisterVariable(&r_showsurfaces);
@@ -4101,15 +4239,10 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_fog_clear);
        Cvar_RegisterVariable(&r_drawfog);
        Cvar_RegisterVariable(&r_transparentdepthmasking);
+       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_texture_sRGB_2d);
-       Cvar_RegisterVariable(&r_texture_sRGB_skin_diffuse);
-       Cvar_RegisterVariable(&r_texture_sRGB_skin_gloss);
-       Cvar_RegisterVariable(&r_texture_sRGB_skin_glow);
-       Cvar_RegisterVariable(&r_texture_sRGB_skin_reflect);
-       Cvar_RegisterVariable(&r_texture_sRGB_cubemap);
-       Cvar_RegisterVariable(&r_texture_sRGB_skybox);
        Cvar_RegisterVariable(&r_textureunits);
        Cvar_RegisterVariable(&gl_combine);
        Cvar_RegisterVariable(&r_viewfbo);
@@ -4144,6 +4277,8 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_water_refractdistort);
        Cvar_RegisterVariable(&r_water_reflectdistort);
        Cvar_RegisterVariable(&r_water_scissormode);
+       Cvar_RegisterVariable(&r_water_lowquality);
+
        Cvar_RegisterVariable(&r_lerpsprites);
        Cvar_RegisterVariable(&r_lerpmodels);
        Cvar_RegisterVariable(&r_lerplightstyles);
@@ -4164,7 +4299,8 @@ void GL_Main_Init(void)
        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_smoothnormals_areaweighting);
        Cvar_RegisterVariable(&developer_texturelogging);
        Cvar_RegisterVariable(&gl_lightmaps);
@@ -4176,15 +4312,6 @@ void GL_Main_Init(void)
        if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
                Cvar_SetValue("r_fullbrights", 0);
        R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
-
-       Cvar_RegisterVariable(&r_track_sprites);
-       Cvar_RegisterVariable(&r_track_sprites_flags);
-       Cvar_RegisterVariable(&r_track_sprites_scalew);
-       Cvar_RegisterVariable(&r_track_sprites_scaleh);
-       Cvar_RegisterVariable(&r_overheadsprites_perspective);
-       Cvar_RegisterVariable(&r_overheadsprites_pushback);
-       Cvar_RegisterVariable(&r_overheadsprites_scalex);
-       Cvar_RegisterVariable(&r_overheadsprites_scaley);
 }
 
 extern void R_Textures_Init(void);
@@ -4223,6 +4350,7 @@ void Render_Init(void)
 GL_Init
 ===============
 */
+#ifndef USE_GLES2
 extern char *ENGINE_EXTENSIONS;
 void GL_Init (void)
 {
@@ -4250,11 +4378,14 @@ 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)
 {
        int i;
        mplane_t *p;
+       if (r_trippy.integer)
+               return false;
        for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
        {
                // skip nearclip plane, it often culls portals when you are very close, and is almost never useful
@@ -4305,6 +4436,8 @@ int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, c
 {
        int i;
        const mplane_t *p;
+       if (r_trippy.integer)
+               return false;
        for (i = 0;i < numplanes;i++)
        {
                p = planes + i;
@@ -4550,7 +4683,7 @@ qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qbool
        else
        {
                // see if this ent is worth caching
-               if (!model || !model->Draw || !model->surfmesh.isanimated || !model->AnimateVertices || (ent->frameblend[0].lerp == 1 && ent->frameblend[0].subframe == 0 && !ent->skeleton))
+               if (!model || !model->Draw || !model->surfmesh.isanimated || !model->AnimateVertices)
                        return false;
                // get some memory for this entity and generate mesh data
                numvertices = model->surfmesh.num_vertices;
@@ -4604,6 +4737,8 @@ void R_AnimCache_CacheVisibleEntities(void)
 
 //==================================================================================
 
+extern cvar_t r_overheadsprites_pushback;
+
 static void R_View_UpdateEntityLighting (void)
 {
        int i;
@@ -4786,7 +4921,7 @@ static void R_View_UpdateEntityVisible (void)
                        r_refdef.viewcache.entityvisible[i] = !(ent->flags & renderimask) && ((ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)) || !R_CullBox(ent->mins, ent->maxs));
                }
        }
-       if(r_cullentities_trace.integer && r_refdef.scene.worldmodel->brush.TraceLineOfSight && !r_refdef.view.useclipplane)
+       if(r_cullentities_trace.integer && r_refdef.scene.worldmodel->brush.TraceLineOfSight && !r_refdef.view.useclipplane && !r_trippy.integer)
                // sorry, this check doesn't work for portal/reflection/refraction renders as the view origin is not useful for culling
        {
                for (i = 0;i < r_refdef.scene.numentities;i++)
@@ -4840,6 +4975,17 @@ static void R_DrawModels(void)
                        continue;
                ent = r_refdef.scene.entities[i];
                r_refdef.stats.entities++;
+               /*
+               if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
+               {
+                       vec3_t f, l, u, o;
+                       Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
+                       Con_Printf("R_DrawModels\n");
+                       Con_Printf("model %s O %f %f %f F %f %f %f L %f %f %f U %f %f %f\n", ent->model->name, o[0], o[1], o[2], f[0], f[1], f[2], l[0], l[1], l[2], u[0], u[1], u[2]);
+                       Con_Printf("group: %i %f %i %f %i %f %i %f\n", ent->framegroupblend[0].frame, ent->framegroupblend[0].lerp, ent->framegroupblend[1].frame, ent->framegroupblend[1].lerp, ent->framegroupblend[2].frame, ent->framegroupblend[2].lerp, ent->framegroupblend[3].frame, ent->framegroupblend[3].lerp);
+                       Con_Printf("blend: %i %f %i %f %i %f %i %f %i %f %i %f %i %f %i %f\n", ent->frameblend[0].subframe, ent->frameblend[0].lerp, ent->frameblend[1].subframe, ent->frameblend[1].lerp, ent->frameblend[2].subframe, ent->frameblend[2].lerp, ent->frameblend[3].subframe, ent->frameblend[3].lerp, ent->frameblend[4].subframe, ent->frameblend[4].lerp, ent->frameblend[5].subframe, ent->frameblend[5].lerp, ent->frameblend[6].subframe, ent->frameblend[6].lerp, ent->frameblend[7].subframe, ent->frameblend[7].lerp);
+               }
+               */
                if (ent->model && ent->model->Draw != NULL)
                        ent->model->Draw(ent);
                else
@@ -4901,19 +5047,17 @@ void R_HDR_UpdateIrisAdaptation(const vec3_t point)
                vec3_t diffusenormal;
                vec_t brightness;
                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);
                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);
        }
@@ -5364,8 +5508,7 @@ static void R_Water_StartFrame(void)
 
        // set waterwidth and waterheight to the water resolution that will be
        // used (often less than the screen resolution for faster rendering)
-       waterwidth = (int)bound(1, vid.width * r_water_resolutionmultiplier.value, vid.width);
-       waterheight = (int)bound(1, vid.height * r_water_resolutionmultiplier.value, vid.height);
+       R_GetScaledViewSize(bound(1, vid.width * r_water_resolutionmultiplier.value, vid.width), bound(1, vid.height * r_water_resolutionmultiplier.value, vid.height), &waterwidth, &waterheight);
 
        // calculate desired texture sizes
        // can't use water if the card does not support the texture size
@@ -5411,17 +5554,20 @@ static void R_Water_StartFrame(void)
 
        if (r_waterstate.texturewidth)
        {
+               int scaledwidth, scaledheight;
+
                r_waterstate.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);
 
                // set up variables that will be used in shader setup
-               r_waterstate.screenscale[0] = 0.5f * (float)r_waterstate.waterwidth / (float)r_waterstate.texturewidth;
-               r_waterstate.screenscale[1] = 0.5f * (float)r_waterstate.waterheight / (float)r_waterstate.textureheight;
-               r_waterstate.screencenter[0] = 0.5f * (float)r_waterstate.waterwidth / (float)r_waterstate.texturewidth;
-               r_waterstate.screencenter[1] = 0.5f * (float)r_waterstate.waterheight / (float)r_waterstate.textureheight;
+               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_waterstate.maxwaterplanes = MAX_WATERPLANES;
@@ -5512,17 +5658,44 @@ 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)
 {
        int myscissor[4];
        r_refdef_view_t originalview;
        r_refdef_view_t myview;
-       int planeindex;
+       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;
 
        originalview = r_refdef.view;
 
+       // lowquality hack, temporarily shut down some cvars and restore afterwards
+       qualityreduction = r_water_lowquality.integer;
+       if (qualityreduction > 0)
+       {
+               if (qualityreduction >= 1)
+               {
+                       old_r_shadows = r_shadows.integer;
+                       old_r_worldrtlight = r_shadow_realtime_world.integer;
+                       old_r_dlight = r_shadow_realtime_dlight.integer;
+                       Cvar_SetValueQuick(&r_shadows, 0);
+                       Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
+                       Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
+               }
+               if (qualityreduction >= 2)
+               {
+                       old_r_dynamic = r_dynamic.integer;
+                       old_r_particles = r_drawparticles.integer;
+                       old_r_decals = r_drawdecals.integer;
+                       Cvar_SetValueQuick(&r_dynamic, 0);
+                       Cvar_SetValueQuick(&r_drawparticles, 0);
+                       Cvar_SetValueQuick(&r_drawdecals, 0);
+               }
+       }
+
        // make sure enough textures are allocated
        for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
        {
@@ -5575,7 +5748,6 @@ static void R_Water_ProcessPlanes(void)
                        // update the r_refdef.view.origin because otherwise the sky renders at the wrong location (amongst other problems)
                        Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
                        r_refdef.view.clipplane = p->plane;
-
                        // reverse the cullface settings for this render
                        r_refdef.view.cullface_front = GL_FRONT;
                        r_refdef.view.cullface_back = GL_BACK;
@@ -5702,13 +5874,29 @@ static void R_Water_ProcessPlanes(void)
        R_ResetViewRendering3D();
        R_ClearScreen(r_refdef.fogenabled);
        R_View_Update();
-       return;
+       goto finish;
 error:
        r_refdef.view = originalview;
        r_waterstate.renderingscene = false;
        Cvar_SetValueQuick(&r_water, 0);
        Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
-       return;
+finish:
+       // lowquality hack, restore cvars
+       if (qualityreduction > 0)
+       {
+               if (qualityreduction >= 1)
+               {
+                       Cvar_SetValueQuick(&r_shadows, old_r_shadows);
+                       Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
+                       Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
+               }
+               if (qualityreduction >= 2)
+               {
+                       Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
+                       Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
+                       Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
+               }
+       }
 }
 
 void R_Bloom_StartFrame(void)
@@ -5843,16 +6031,18 @@ void R_Bloom_StartFrame(void)
                        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);
+#ifndef USE_GLES2
                        // render depth into one texture and normalmap into the other
                        if (qglDrawBuffer)
                        {
                                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)
+                               qglDrawBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR
+                               qglReadBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR
+                               status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER);CHECKGLERROR
+                               if (status != GL_FRAMEBUFFER_COMPLETE)
                                        Con_Printf("R_Bloom_StartFrame: glCheckFramebufferStatusEXT returned %i\n", status);
                        }
+#endif
                }
                r_bloomstate.bloomtexturewidth = bloomtexturewidth;
                r_bloomstate.bloomtextureheight = bloomtextureheight;
@@ -5956,7 +6146,7 @@ void R_Bloom_CopyBloomTexture(float colorscale)
                break;
        }
        // TODO: do boxfilter scale-down in shader?
-       R_SetupShader_Generic(r_bloomstate.texture_screen, NULL, GL_MODULATE, 1);
+       R_SetupShader_Generic(r_bloomstate.texture_screen, NULL, GL_MODULATE, 1, false, 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;
 
@@ -5992,7 +6182,7 @@ void R_Bloom_MakeTexture(void)
                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);
+               R_SetupShader_Generic(r_bloomstate.texture_bloom, NULL, GL_MODULATE, 1, false, 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;
 
@@ -6008,7 +6198,7 @@ void R_Bloom_MakeTexture(void)
        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);
+       R_SetupShader_Generic(r_bloomstate.texture_bloom, NULL, GL_MODULATE, 1, false, true);
 
        for (dir = 0;dir < 2;dir++)
        {
@@ -6143,31 +6333,42 @@ static void R_BlendView(void)
                        if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))
                        {
                                // declare variables
-                               float speed;
-                               static float avgspeed;
-
-                               speed = VectorLength(cl.movement_velocity);
-
-                               cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_vcoeff.value), 1);
-                               avgspeed = avgspeed * (1 - cl.motionbluralpha) + speed * cl.motionbluralpha;
-
-                               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;
+                               float blur_factor, blur_mouseaccel, blur_velocity;
+                               static float blur_average; 
+                               static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
+
+                               // set a goal for the factoring
+                               blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
+                                       / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
+                               blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
+                                       / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
+                               blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
+                                       + (blur_mouseaccel * r_motionblur_mousefactor.value));
+
+                               // from the goal, pick an averaged value between goal and last value
+                               cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
+                               blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
+                               
+                               // enforce minimum amount of blur 
+                               blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
+                               
+                               //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
 
                                // calculate values into a standard alpha
                                cl.motionbluralpha = 1 - exp(-
                                                (
-                                                (r_motionblur.value * 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)
                                {
@@ -6189,10 +6390,13 @@ static void R_BlendView(void)
                                                R_Mesh_PrepareVertices_Generic_Arrays(4, r_d3dscreenvertex3f, NULL, r_bloomstate.screentexcoord2f);
                                                break;
                                        }
-                                       R_SetupShader_Generic(r_bloomstate.texture_screen, NULL, GL_MODULATE, 1);
+                                       R_SetupShader_Generic(r_bloomstate.texture_screen, NULL, GL_MODULATE, 1, false, 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;
                                }
+                               
+                               // updates old view angles for next pass 
+                               VectorCopy(cl.viewangles, blur_oldangles);
                        }
 
                        // copy view into the screen texture
@@ -6208,7 +6412,7 @@ static void R_BlendView(void)
                                R_ResetViewRendering2D();
                                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);
+                               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, 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);
                        }
@@ -6316,7 +6520,7 @@ static void R_BlendView(void)
                        R_ResetViewRendering2D();
                        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);
+                       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, 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);
                }
@@ -6536,6 +6740,8 @@ 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;
@@ -6625,6 +6831,10 @@ void R_RenderView(void)
        if (r_timereport_active)
                R_TimeReport("visibility");
 
+       R_Shadow_UpdateBounceGridTexture();
+       if (r_timereport_active && r_shadow_bouncegrid.integer)
+               R_TimeReport("bouncegrid");
+
        r_waterstate.numwaterplanes = 0;
        if (r_waterstate.enabled)
                R_RenderWaterPlanes();
@@ -6968,7 +7178,7 @@ 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);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
        R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
 }
 
@@ -6984,14 +7194,14 @@ static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtligh
                return;
 
        GL_CullFace(GL_NONE);
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
 
        prog = 0;
        SV_VM_Begin();
        for (i = 0;i < numsurfaces;i++)
        {
                edict = PRVM_EDICT_NUM(surfacelist[i]);
-               switch ((int)edict->fields.server->solid)
+               switch ((int)PRVM_serveredictfloat(edict, solid))
                {
                        case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
                        case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
@@ -7029,9 +7239,9 @@ static void R_DrawEntityBBoxes(void)
                if (edict->priv.server->free)
                        continue;
                // exclude the following for now, as they don't live in world coordinate space and can't be solid:
-               if(PRVM_EDICTFIELDVALUE(edict, prog->fieldoffsets.tag_entity)->edict != 0)
+               if(PRVM_serveredictedict(edict, tag_entity) != 0)
                        continue;
-               if(PRVM_EDICTFIELDVALUE(edict, prog->fieldoffsets.viewmodelforclient)->edict != 0)
+               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);
@@ -7134,7 +7344,7 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight
                }
        }
 //     R_Mesh_ResetTextureState();
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
        R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
        R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
 }
@@ -7314,7 +7524,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;
 }
@@ -7322,7 +7532,7 @@ static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
 {
        double index, f;
-       index = parms[2] + r_refdef.scene.time * parms[3];
+       index = parms[2] + rsurface.shadertime * parms[3];
        index -= floor(index);
        switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
        {
@@ -7340,7 +7550,9 @@ static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
                index *= 4;
                f = index - floor(index);
                if (index < 1)
-                       f = f;
+               {
+                       // f = f;
+               }
                else if (index < 2)
                        f = 1 - f;
                else if (index < 3)
@@ -7351,14 +7563,15 @@ 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)
 {
        int w, h, idx;
-       float f;
+       double f;
+       double offsetd[2];
        float tcmat[12];
        matrix4x4_t matrix, temp;
        switch(tcmod->tcmod)
@@ -7377,19 +7590,22 @@ void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *t
                        break;
                case Q3TCMOD_ROTATE:
                        Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
-                       Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * r_refdef.scene.time, 0, 0, 1);
+                       Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
                        Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
                        break;
                case Q3TCMOD_SCALE:
                        Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
                        break;
                case Q3TCMOD_SCROLL:
-                       Matrix4x4_CreateTranslate(&matrix, tcmod->parms[0] * r_refdef.scene.time, tcmod->parms[1] * r_refdef.scene.time, 0);
+                       // extra care is needed because of precision breakdown with large values of time
+                       offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
+                       offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
+                       Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
                        break;
                case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
                        w = (int) tcmod->parms[0];
                        h = (int) tcmod->parms[1];
-                       f = r_refdef.scene.time / (tcmod->parms[2] * w * h);
+                       f = rsurface.shadertime / (tcmod->parms[2] * w * h);
                        f = f - floor(f);
                        idx = (int) floor(f * w * h);
                        Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
@@ -7416,7 +7632,7 @@ void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *t
 
 void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
 {
-       int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP | TEXF_COMPRESS;
+       int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
        char name[MAX_QPATH];
        skinframe_t *skinframe;
        unsigned char pixels[296*194];
@@ -7467,7 +7683,7 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                if (model->skinscenes)
                {
                        if (model->skinscenes[s].framecount > 1)
-                               s = model->skinscenes[s].firstframe + (unsigned int) (r_refdef.scene.time * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
+                               s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
                        else
                                s = model->skinscenes[s].firstframe;
                }
@@ -7478,9 +7694,9 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                        // use an alternate animation if the entity's frame is not 0,
                        // and only if the texture has an alternate animation
                        if (rsurface.ent_alttextures && t->anim_total[1])
-                               t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(r_refdef.scene.time * 5.0f) % t->anim_total[1]) : 0];
+                               t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
                        else
-                               t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(r_refdef.scene.time * 5.0f) % t->anim_total[0]) : 0];
+                               t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
                }
                texture->currentframe = t;
        }
@@ -7500,16 +7716,16 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                        R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
                t->currentskinframe = r_qwskincache[i].skinframe;
                if (t->currentskinframe == NULL)
-                       t->currentskinframe = t->skinframes[(unsigned int)(t->skinframerate * (cl.time - rsurface.ent_shadertime)) % t->numskinframes];
+                       t->currentskinframe = t->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->skinframerate, t->numskinframes)];
        }
        else if (t->numskinframes >= 2)
-               t->currentskinframe = t->skinframes[(unsigned int)(t->skinframerate * (cl.time - rsurface.ent_shadertime)) % t->numskinframes];
+               t->currentskinframe = t->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->skinframerate, t->numskinframes)];
        if (t->backgroundnumskinframes >= 2)
-               t->backgroundcurrentskinframe = t->backgroundskinframes[(unsigned int)(t->backgroundskinframerate * (cl.time - rsurface.ent_shadertime)) % t->backgroundnumskinframes];
+               t->backgroundcurrentskinframe = t->backgroundskinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundskinframerate, t->backgroundnumskinframes)];
 
        t->currentmaterialflags = t->basematerialflags;
        t->currentalpha = rsurface.colormod[3];
-       if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer))
+       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)
                t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
@@ -7546,6 +7762,11 @@ texture_t *R_GetCurrentTexture(texture_t *t)
        }
        else
                t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
+       if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
+       {
+               // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
+               t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
+       }
        if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
                t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
 
@@ -7750,8 +7971,8 @@ void RSurf_ActiveWorldEntity(void)
        memset(rsurface.userwavefunc_param, 0, sizeof(rsurface.userwavefunc_param));
        rsurface.ent_skinnum = 0;
        rsurface.ent_qwskin = -1;
-       rsurface.ent_shadertime = 0;
        rsurface.ent_flags = r_refdef.scene.worldentity->flags;
+       rsurface.shadertime = r_refdef.scene.time;
        rsurface.matrix = identitymatrix;
        rsurface.inversematrix = identitymatrix;
        rsurface.matrixscale = 1;
@@ -7861,8 +8082,8 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
        memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
        rsurface.ent_skinnum = ent->skinnum;
        rsurface.ent_qwskin = (ent->entitynumber <= cl.maxclients && ent->entitynumber >= 1 && cls.protocol == PROTOCOL_QUAKEWORLD && cl.scores[ent->entitynumber - 1].qw_skin[0] && !strcmp(ent->model->name, "progs/player.mdl")) ? (ent->entitynumber - 1) : -1;
-       rsurface.ent_shadertime = ent->shadertime;
        rsurface.ent_flags = ent->flags;
+       rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
        rsurface.matrix = ent->matrix;
        rsurface.inversematrix = ent->inversematrix;
        rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
@@ -7891,7 +8112,7 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
                rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
                rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
        }
-       if (model->surfmesh.isanimated && model->AnimateVertices && (rsurface.frameblend[0].lerp != 1 || rsurface.frameblend[0].subframe != 0))
+       if (model->surfmesh.isanimated && model->AnimateVertices)
        {
                if (ent->animcache_vertex3f)
                {
@@ -8030,8 +8251,8 @@ void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inve
        rsurface.skeleton = NULL;
        rsurface.ent_skinnum = 0;
        rsurface.ent_qwskin = -1;
-       rsurface.ent_shadertime = shadertime;
        rsurface.ent_flags = entflags;
+       rsurface.shadertime = r_refdef.scene.time - shadertime;
        rsurface.modelnumvertices = numvertices;
        rsurface.modelnumtriangles = numtriangles;
        rsurface.matrix = *matrix;
@@ -8543,20 +8764,53 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
                        if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
                        {
                                if (batchneed & BATCHNEED_ARRAY_VERTEX)
-                                       memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
-                               if ((batchneed & BATCHNEED_ARRAY_NORMAL) && rsurface.modelnormal3f)
-                                       memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
-                               if ((batchneed & BATCHNEED_ARRAY_VECTOR) && rsurface.modelsvector3f)
                                {
-                                       memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
-                                       memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
+                                       if (rsurface.batchvertex3f)
+                                               memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
+                                       else
+                                               memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
+                               }
+                               if (batchneed & BATCHNEED_ARRAY_NORMAL)
+                               {
+                                       if (rsurface.modelnormal3f)
+                                               memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
+                                       else
+                                               memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
+                               }
+                               if (batchneed & BATCHNEED_ARRAY_VECTOR)
+                               {
+                                       if (rsurface.modelsvector3f)
+                                       {
+                                               memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
+                                               memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
+                                       }
+                                       else
+                                       {
+                                               memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
+                                               memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
+                                       }
+                               }
+                               if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
+                               {
+                                       if (rsurface.modellightmapcolor4f)
+                                               memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
+                                       else
+                                               memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
+                               }
+                               if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
+                               {
+                                       if (rsurface.modeltexcoordtexture2f)
+                                               memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
+                                       else
+                                               memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
+                               }
+                               if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
+                               {
+                                       if (rsurface.modeltexcoordlightmap2f)
+                                               memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
+                                       else
+                                               memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
                                }
-                               if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && rsurface.modellightmapcolor4f)
-                                       memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
-                               if ((batchneed & BATCHNEED_ARRAY_TEXCOORD) && rsurface.modeltexcoordtexture2f)
-                                       memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
-                               if ((batchneed & BATCHNEED_ARRAY_LIGHTMAP) && rsurface.modeltexcoordlightmap2f)
-                                       memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
                        }
                        RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
                        numvertices += surfacenumvertices;
@@ -8680,6 +8934,11 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
 //                     rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
 //                     rsurface.batchnormal3f_vertexbuffer = NULL;
 //                     rsurface.batchnormal3f_bufferoffset = 0;
+                       // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
+                       if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
+                               Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
+                       if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
+                               Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
                        // a single autosprite surface can contain multiple sprites...
                        for (j = 0;j < batchnumvertices - 3;j += 4)
                        {
@@ -8816,9 +9075,9 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
                                float vertex[3];
                                float *normal = rsurface.batchnormal3f + 3*j;
                                VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
-                               normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]);
-                               normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]);
-                               normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]);
+                               normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
+                               normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
+                               normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
                                VectorNormalize(normal);
                        }
                        if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
@@ -8882,7 +9141,7 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
 //                     rsurface.batchnormal3f_bufferoffset = 0;
                        for (j = 0;j < batchnumvertices;j++)
                        {
-                               scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + r_refdef.scene.time * deform->parms[2]) * deform->parms[1];
+                               scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
                                VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
                        }
                        // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
@@ -8976,7 +9235,7 @@ void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const
        if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
        {
                amplitude = rsurface.texture->tcmods[0].parms[1];
-               animpos = rsurface.texture->tcmods[0].parms[2] + r_refdef.scene.time * rsurface.texture->tcmods[0].parms[3];
+               animpos = rsurface.texture->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->tcmods[0].parms[3];
 //             rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
 //             rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
 //             rsurface.batchtexcoordtexture2f_bufferoffset = 0;
@@ -9396,7 +9655,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);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
        skyrenderlater = true;
        RSurf_SetupDepthAndCulling();
        GL_DepthMask(true);
@@ -9406,12 +9665,12 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_
        // in Quake3 maps as it causes problems with q3map2 sky tricks,
        // and skymasking also looks very bad when noclipping outside the
        // level, so don't use it then either.
-       if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->type == mod_brushq1 && r_q1bsp_skymasking.integer && !r_refdef.viewcache.world_novis)
+       if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->type == mod_brushq1 && r_q1bsp_skymasking.integer && !r_refdef.viewcache.world_novis && !r_trippy.integer)
        {
                R_Mesh_ResetTextureState();
                if (skyrendermasked)
                {
-                       R_SetupShader_DepthOrShadow();
+                       R_SetupShader_DepthOrShadow(false);
                        // depth-only (masking)
                        GL_ColorMask(0,0,0,0);
                        // just to make sure that braindead drivers don't draw
@@ -9425,7 +9684,7 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_
                }
                else
                {
-                       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+                       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
                        // fog sky
                        GL_BlendFunc(GL_ONE, GL_ZERO);
                        RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
@@ -9450,9 +9709,8 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface
        {
                // render screenspace normalmap to texture
                GL_DepthMask(true);
-               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL);
+               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
@@ -9478,18 +9736,18 @@ 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));
+                               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);
                                RSurf_DrawBatch();
                                // blend surface on top
                                GL_DepthMask(false);
-                               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL);
+                               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
                                RSurf_DrawBatch();
                        }
                        else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
                        {
                                // render surface with reflection texture as input
                                GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
-                               R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_waterstate.waterplanes + startplaneindex));
+                               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);
                                RSurf_DrawBatch();
                        }
                }
@@ -9498,7 +9756,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface
 
        // render surface batch normally
        GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
-       R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL);
+       R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0);
        RSurf_DrawBatch();
 }
 
@@ -9721,7 +9979,7 @@ static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const
        float c[4];
 
 //     R_Mesh_ResetTextureState();
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
 
        if(rsurface.texture && rsurface.texture->currentskinframe)
        {
@@ -9827,7 +10085,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);
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
                RSurf_DrawBatch();
        }
        else if (!r_refdef.view.showdebug)
@@ -9965,8 +10223,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
        int texturenumsurfaces, endsurface;
        texture_t *texture;
        const msurface_t *surface;
-#define MAXBATCH_TRANSPARENTSURFACES 256
-       const msurface_t *texturesurfacelist[MAXBATCH_TRANSPARENTSURFACES];
+       const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
 
        // if the model is static it doesn't matter what value we give for
        // wantnormals and wanttangents, so this logic uses only rules applicable
@@ -10030,7 +10287,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();
+                               R_SetupShader_DepthOrShadow(false);
                        }
                        RSurf_SetupDepthAndCulling();
                        RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, texturenumsurfaces, texturesurfacelist);
@@ -10051,7 +10308,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const
                texture = surface->texture;
                rsurface.texture = R_GetCurrentTexture(texture);
                // scan ahead until we find a different texture
-               endsurface = min(i + MAXBATCH_TRANSPARENTSURFACES, numsurfaces);
+               endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
                texturenumsurfaces = 0;
                texturesurfacelist[texturenumsurfaces++] = surface;
                if(FAKELIGHT_ENABLED)
@@ -10343,7 +10600,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);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
        R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
 }
 
@@ -10797,10 +11054,10 @@ static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
        lifetime = cl_decals_time.value + cl_decals_fadetime.value;
 
        if (decalsystem->lastupdatetime)
-               frametime = (cl.time - decalsystem->lastupdatetime);
+               frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
        else
                frametime = 0;
-       decalsystem->lastupdatetime = cl.time;
+       decalsystem->lastupdatetime = r_refdef.scene.time;
        decal = decalsystem->decals;
        numdecals = decalsystem->numdecals;
 
@@ -10877,7 +11134,7 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
        else
                RSurf_ActiveModelEntity(ent, false, false, false);
 
-       decalsystem->lastupdatetime = cl.time;
+       decalsystem->lastupdatetime = r_refdef.scene.time;
        decal = decalsystem->decals;
 
        faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
@@ -10961,7 +11218,7 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent)
 
                // now render the decals all at once
                // (this assumes they all use one particle font texture!)
-               RSurf_ActiveCustomEntity(&rsurface.matrix, &rsurface.inversematrix, rsurface.ent_flags, rsurface.ent_shadertime, 1, 1, 1, 1, numdecals*3, decalsystem->vertex3f, decalsystem->texcoord2f, NULL, NULL, NULL, decalsystem->color4f, numtris, decalsystem->element3i, decalsystem->element3s, false, false);
+               RSurf_ActiveCustomEntity(&rsurface.matrix, &rsurface.inversematrix, rsurface.ent_flags, ent->shadertime, 1, 1, 1, 1, numdecals*3, decalsystem->vertex3f, decalsystem->texcoord2f, NULL, NULL, NULL, decalsystem->color4f, numtris, decalsystem->element3i, decalsystem->element3s, false, false);
 //             R_Mesh_ResetTextureState();
                R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
                GL_DepthMask(false);
@@ -10970,7 +11227,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);
+               R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1, false, false);
                R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
        }
 }
@@ -11027,7 +11284,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);
+               R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
                GL_DepthTest(false);
                GL_DepthMask(false);
                GL_DepthRange(0, 1);
@@ -11057,7 +11314,7 @@ void R_DrawDebugModel(void)
        flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
 
 //     R_Mesh_ResetTextureState();
-       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
        GL_DepthRange(0, 1);
        GL_DepthTest(!r_showdisabledepthtest.integer);
        GL_DepthMask(false);
@@ -11113,6 +11370,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)
@@ -11169,7 +11427,7 @@ void R_DrawDebugModel(void)
                        {
                                RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
                                qglBegin(GL_LINES);
-                               if (r_shownormals.value < 0)
+                               if (r_shownormals.value < 0 && rsurface.batchnormal3f)
                                {
                                        for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
                                        {
@@ -11192,6 +11450,9 @@ void R_DrawDebugModel(void)
                                                GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
                                                qglVertex3f(v[0], v[1], v[2]);
                                        }
+                               }
+                               if (r_shownormals.value > 0 && rsurface.batchtvector3f)
+                               {
                                        for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
                                        {
                                                VectorCopy(rsurface.batchvertex3f + l * 3, v);
@@ -11201,6 +11462,9 @@ void R_DrawDebugModel(void)
                                                GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
                                                qglVertex3f(v[0], v[1], v[2]);
                                        }
+                               }
+                               if (r_shownormals.value > 0 && rsurface.batchnormal3f)
+                               {
                                        for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
                                        {
                                                VectorCopy(rsurface.batchvertex3f + l * 3, v);
@@ -11217,6 +11481,7 @@ void R_DrawDebugModel(void)
                }
                rsurface.texture = NULL;
        }
+#endif
 }
 
 extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
index 06d8fb03fe48b4fb1c946bb68bc2b84e0cb51056..ed5534ae5abc6567b330527d5e6c28c2f3782a63 100644 (file)
@@ -362,7 +362,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);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
        R_Mesh_Draw(0, numpoints, 0, numpoints - 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
 }
 
@@ -446,7 +446,7 @@ void R_View_WorldVisibility(qboolean forcenovis)
 
                // if floating around in the void (no pvs data available, and no
                // portals available), simply use all on-screen leafs.
-               if (!viewleaf || viewleaf->clusterindex < 0 || forcenovis)
+               if (!viewleaf || viewleaf->clusterindex < 0 || forcenovis || r_trippy.integer)
                {
                        // no visibility method: (used when floating around in the void)
                        // simply cull each leaf to the frustum (view pyramid)
@@ -454,6 +454,8 @@ void R_View_WorldVisibility(qboolean forcenovis)
                        r_refdef.viewcache.world_novis = true;
                        for (j = 0, leaf = model->brush.data_leafs;j < model->brush.num_leafs;j++, leaf++)
                        {
+                               if (leaf->clusterindex < 0)
+                                       continue;
                                // if leaf is in current pvs and on the screen, mark its surfaces
                                if (!R_CullBox(leaf->mins, leaf->maxs))
                                {
@@ -475,6 +477,8 @@ void R_View_WorldVisibility(qboolean forcenovis)
                        // similar to quake's RecursiveWorldNode but without cache misses
                        for (j = 0, leaf = model->brush.data_leafs;j < model->brush.num_leafs;j++, leaf++)
                        {
+                               if (leaf->clusterindex < 0)
+                                       continue;
                                // if leaf is in current pvs and on the screen, mark its surfaces
                                if (CHECKPVSBIT(r_refdef.viewcache.world_pvsbits, leaf->clusterindex) && !R_CullBox(leaf->mins, leaf->maxs))
                                {
@@ -507,6 +511,8 @@ void R_View_WorldVisibility(qboolean forcenovis)
                                leaf = leafstack[--leafstackpos];
                                if (r_refdef.viewcache.world_leafvisible[leaf - model->brush.data_leafs])
                                        continue;
+                               if (leaf->clusterindex < 0)
+                                       continue;
                                r_refdef.stats.world_leafs++;
                                r_refdef.viewcache.world_leafvisible[leaf - model->brush.data_leafs] = true;
                                // mark any surfaces bounding this leaf
@@ -629,7 +635,7 @@ void R_Q1BSP_DrawDepth(entity_render_t *ent)
        GL_BlendFunc(GL_ONE, GL_ZERO);
        GL_DepthMask(true);
 //     R_Mesh_ResetTextureState();
-       R_SetupShader_DepthOrShadow();
+       R_SetupShader_DepthOrShadow(false);
        if (ent == r_refdef.scene.worldentity)
                R_DrawWorldSurfaces(false, false, true, false, false);
        else
@@ -1487,7 +1493,8 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surface
                        for (kend = k;kend < batchnumsurfaces && tex == batchsurfacelist[kend]->texture;kend++)
                                ;
                        // now figure out what to do with this particular range of surfaces
-                       if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
+                       // VorteX: added MATERIALFLAG_NORTLIGHT
+                       if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WALL + MATERIALFLAG_NORTLIGHT)) != MATERIALFLAG_WALL)
                                continue;
                        if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
                                continue;
index 976128e53ef8e6fa011ce59ea413cbb09b10a522..06038a3eb1ea8df402b71f2b438dc873a8bbd3ba 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%"};
@@ -31,9 +35,10 @@ cvar_t gl_texturecompression_q3bspdeluxemaps = {CVAR_SAVE, "gl_texturecompressio
 cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"};
 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
 cvar_t gl_texturecompression_reflectmask = {CVAR_SAVE, "gl_texturecompression_reflectmask", "1", "whether to compress reflection cubemap masks (mask of which areas of the texture should reflect the generic shiny cubemap)"};
+cvar_t gl_texturecompression_sprites = {CVAR_SAVE, "gl_texturecompression_sprites", "1", "whether to compress sprites"};
 cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "0", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"};
 cvar_t r_texture_dds_load_alphamode = {0, "r_texture_dds_load_alphamode", "1", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambiguous, 2: texture format only"};
-cvar_t r_texture_dds_load_logfailure = {0, "r_texture_dds_load_logfailure", "1", "log missing DDS textures to ddstexturefailures.log"};
+cvar_t r_texture_dds_load_logfailure = {0, "r_texture_dds_load_logfailure", "0", "log missing DDS textures to ddstexturefailures.log"};
 cvar_t r_texture_dds_swdecode = {0, "r_texture_dds_swdecode", "0", "0: don't software decode DDS, 1: software decode DDS if unsupported, 2: always software decode DDS"};
 
 qboolean       gl_filter_force = false;
@@ -64,6 +69,7 @@ static memexpandablearray_t texturearray;
 
 typedef struct textypeinfo_s
 {
+       const char *name;
        textype_t textype;
        int inputbytesperpixel;
        int internalbytesperpixel;
@@ -74,43 +80,62 @@ typedef struct textypeinfo_s
 }
 textypeinfo_t;
 
+#ifdef USE_GLES2
 // framebuffer texture formats
-static textypeinfo_t textype_shadowmap16                 = {TEXTYPE_SHADOWMAP     ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16_ARB              , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
-static textypeinfo_t textype_shadowmap24                 = {TEXTYPE_SHADOWMAP     ,  4,  4,  4.0f, GL_DEPTH_COMPONENT24_ARB              , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT  };
-static textypeinfo_t textype_colorbuffer                 = {TEXTYPE_COLORBUFFER   ,  4,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_colorbuffer16f              = {TEXTYPE_COLORBUFFER16F,  8,  8,  8.0f, GL_RGBA16F_ARB                        , GL_RGBA           , GL_FLOAT         };
-static textypeinfo_t textype_colorbuffer32f              = {TEXTYPE_COLORBUFFER32F, 16, 16, 16.0f, GL_RGBA32F_ARB                        , GL_RGBA           , GL_FLOAT         };
+// GLES2 devices rarely support depth textures, so we actually use a renderbuffer there
+static textypeinfo_t textype_shadowmap16                 = {"shadowmap16",              TEXTYPE_SHADOWMAP     ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16                  , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+static textypeinfo_t textype_shadowmap24                 = {"shadowmap24",              TEXTYPE_SHADOWMAP     ,  2,  2,  2.0f, GL_DEPTH_COMPONENT16                  , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
+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_RGBA                               , GL_RGBA           , GL_FLOAT         };
+static textypeinfo_t textype_colorbuffer32f              = {"colorbuffer32f",           TEXTYPE_COLORBUFFER32F, 16, 16, 16.0f, GL_RGBA                               , GL_RGBA           , GL_FLOAT         };
 
 // image formats:
-static textypeinfo_t textype_alpha                       = {TEXTYPE_ALPHA         ,  1,  4,  4.0f, GL_ALPHA                              , GL_ALPHA          , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_palette                     = {TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_RGB                                , GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_palette_alpha               = {TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_rgba                        = {TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_RGB                                , GL_RGBA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_rgba_alpha                  = {TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_RGBA                               , GL_RGBA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_rgba_compress               = {TEXTYPE_RGBA          ,  4,  4,  0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT       , GL_RGBA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_rgba_alpha_compress         = {TEXTYPE_RGBA          ,  4,  4,  1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT      , GL_RGBA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_bgra                        = {TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_RGB                                , GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_bgra_alpha                  = {TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_bgra_compress               = {TEXTYPE_BGRA          ,  4,  4,  0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT       , GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_bgra_alpha_compress         = {TEXTYPE_BGRA          ,  4,  4,  1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT      , GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_dxt1                        = {TEXTYPE_DXT1          ,  4,  0,  0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT       , 0                 , 0                };
-static textypeinfo_t textype_dxt1a                       = {TEXTYPE_DXT1A         ,  4,  0,  0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT      , 0                 , 0                };
-static textypeinfo_t textype_dxt3                        = {TEXTYPE_DXT3          ,  4,  0,  1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT      , 0                 , 0                };
-static textypeinfo_t textype_dxt5                        = {TEXTYPE_DXT5          ,  4,  0,  1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT      , 0                 , 0                };
-static textypeinfo_t textype_sRGB_palette                = {TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_SRGB_EXT                           , GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_sRGB_palette_alpha          = {TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_SRGB_ALPHA_EXT                     , GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_sRGB_rgba                   = {TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_SRGB_EXT                           , GL_RGBA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_sRGB_rgba_alpha             = {TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_SRGB_ALPHA_EXT                     , GL_RGBA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_sRGB_rgba_compress          = {TEXTYPE_RGBA          ,  4,  4,  0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT      , GL_RGBA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_sRGB_rgba_alpha_compress    = {TEXTYPE_RGBA          ,  4,  4,  1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_sRGB_bgra                   = {TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_SRGB_EXT                           , GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_sRGB_bgra_alpha             = {TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_SRGB_ALPHA_EXT                     , GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_sRGB_bgra_compress          = {TEXTYPE_BGRA          ,  4,  4,  0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT      , GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_sRGB_bgra_alpha_compress    = {TEXTYPE_BGRA          ,  4,  4,  1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_BGRA           , GL_UNSIGNED_BYTE };
-static textypeinfo_t textype_sRGB_dxt1                   = {TEXTYPE_DXT1          ,  4,  0,  0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT      , 0                 , 0                };
-static textypeinfo_t textype_sRGB_dxt1a                  = {TEXTYPE_DXT1A         ,  4,  0,  0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0                 , 0                };
-static textypeinfo_t textype_sRGB_dxt3                   = {TEXTYPE_DXT3          ,  4,  0,  1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0                 , 0                };
-static textypeinfo_t textype_sRGB_dxt5                   = {TEXTYPE_DXT5          ,  4,  0,  1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0                 , 0                };
+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         };
+
+// image formats:
+static textypeinfo_t textype_alpha                       = {"alpha",                    TEXTYPE_ALPHA         ,  1,  4,  4.0f, GL_ALPHA                              , GL_ALPHA          , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_palette                     = {"palette",                  TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_RGB                                , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_palette_alpha               = {"palette_alpha",            TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_rgba                        = {"rgba",                     TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_RGB                                , GL_RGBA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_rgba_alpha                  = {"rgba_alpha",               TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_RGBA                               , GL_RGBA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_rgba_compress               = {"rgba_compress",            TEXTYPE_RGBA          ,  4,  4,  0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT       , GL_RGBA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_rgba_alpha_compress         = {"rgba_alpha_compress",      TEXTYPE_RGBA          ,  4,  4,  1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT      , GL_RGBA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_bgra                        = {"bgra",                     TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_RGB                                , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_bgra_alpha                  = {"bgra_alpha",               TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_RGBA                               , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_bgra_compress               = {"bgra_compress",            TEXTYPE_BGRA          ,  4,  4,  0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT       , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_bgra_alpha_compress         = {"bgra_alpha_compress",      TEXTYPE_BGRA          ,  4,  4,  1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT      , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_dxt1                        = {"dxt1",                     TEXTYPE_DXT1          ,  4,  0,  0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT       , 0                 , 0                };
+static textypeinfo_t textype_dxt1a                       = {"dxt1a",                    TEXTYPE_DXT1A         ,  4,  0,  0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT      , 0                 , 0                };
+static textypeinfo_t textype_dxt3                        = {"dxt3",                     TEXTYPE_DXT3          ,  4,  0,  1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT      , 0                 , 0                };
+static textypeinfo_t textype_dxt5                        = {"dxt5",                     TEXTYPE_DXT5          ,  4,  0,  1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT      , 0                 , 0                };
+static textypeinfo_t textype_sRGB_palette                = {"sRGB_palette",             TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_SRGB_EXT                           , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_palette_alpha          = {"sRGB_palette_alpha",       TEXTYPE_PALETTE       ,  1,  4,  4.0f, GL_SRGB_ALPHA_EXT                     , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_rgba                   = {"sRGB_rgba",                TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_SRGB_EXT                           , GL_RGBA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_rgba_alpha             = {"sRGB_rgba_alpha",          TEXTYPE_RGBA          ,  4,  4,  4.0f, GL_SRGB_ALPHA_EXT                     , GL_RGBA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_rgba_compress          = {"sRGB_rgba_compress",       TEXTYPE_RGBA          ,  4,  4,  0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT      , GL_RGBA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_rgba_alpha_compress    = {"sRGB_rgba_alpha_compress", TEXTYPE_RGBA          ,  4,  4,  1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_bgra                   = {"sRGB_bgra",                TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_SRGB_EXT                           , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_bgra_alpha             = {"sRGB_bgra_alpha",          TEXTYPE_BGRA          ,  4,  4,  4.0f, GL_SRGB_ALPHA_EXT                     , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_bgra_compress          = {"sRGB_bgra_compress",       TEXTYPE_BGRA          ,  4,  4,  0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT      , GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_bgra_alpha_compress    = {"sRGB_bgra_alpha_compress", TEXTYPE_BGRA          ,  4,  4,  1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_BGRA           , GL_UNSIGNED_BYTE };
+static textypeinfo_t textype_sRGB_dxt1                   = {"sRGB_dxt1",                TEXTYPE_DXT1          ,  4,  0,  0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT      , 0                 , 0                };
+static textypeinfo_t textype_sRGB_dxt1a                  = {"sRGB_dxt1a",               TEXTYPE_DXT1A         ,  4,  0,  0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0                 , 0                };
+static textypeinfo_t textype_sRGB_dxt3                   = {"sRGB_dxt3",                TEXTYPE_DXT3          ,  4,  0,  1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0                 , 0                };
+static textypeinfo_t textype_sRGB_dxt5                   = {"sRGB_dxt5",                TEXTYPE_DXT5          ,  4,  0,  1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0                 , 0                };
+#endif
 
 typedef enum gltexturetype_e
 {
@@ -121,16 +146,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
@@ -227,6 +252,22 @@ static const unsigned char *texturebuffer;
 
 static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
 {
+#ifdef USE_GLES2
+       switch(textype)
+       {
+       case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
+       case TEXTYPE_RGBA: return ((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba);
+       case TEXTYPE_BGRA: return ((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;
+       default:
+               Host_Error("R_GetTexTypeInfo: unknown texture format");
+               break;
+       }
+#else
        switch(textype)
        {
        case TEXTYPE_DXT1: return &textype_dxt1;
@@ -234,8 +275,8 @@ static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
        case TEXTYPE_DXT3: return &textype_dxt3;
        case TEXTYPE_DXT5: return &textype_dxt5;
        case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette;
-       case TEXTYPE_RGBA: return ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && 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) && gl_texturecompression.integer >= 1 && 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_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;
@@ -246,12 +287,13 @@ static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
        case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3;
        case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5;
        case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette;
-       case TEXTYPE_SRGB_RGBA: return ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_sRGB_rgba_alpha_compress : &textype_sRGB_rgba_compress) : ((flags & TEXF_ALPHA) ? &textype_sRGB_rgba_alpha : &textype_sRGB_rgba);
-       case TEXTYPE_SRGB_BGRA: return ((flags & TEXF_COMPRESS) && gl_texturecompression.integer >= 1 && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_sRGB_bgra_alpha_compress : &textype_sRGB_bgra_compress) : ((flags & TEXF_ALPHA) ? &textype_sRGB_bgra_alpha : &textype_sRGB_bgra);
+       case TEXTYPE_SRGB_RGBA: return ((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_sRGB_rgba_alpha_compress : &textype_sRGB_rgba_compress) : ((flags & TEXF_ALPHA) ? &textype_sRGB_rgba_alpha : &textype_sRGB_rgba);
+       case TEXTYPE_SRGB_BGRA: return ((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_sRGB_bgra_alpha_compress : &textype_sRGB_bgra_compress) : ((flags & TEXF_ALPHA) ? &textype_sRGB_bgra_alpha : &textype_sRGB_bgra);
        default:
                Host_Error("R_GetTexTypeInfo: unknown texture format");
                break;
        }
+#endif
        return NULL;
 }
 
@@ -690,7 +732,7 @@ void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean print
                                poolloadedp += glt->inputdatasize;
                        }
                        if (printeach)
-                               Con_Printf("%c%4i%c%c%4i%c %s %s %s %s\n", isloaded ? '[' : ' ', (glsize + 1023) / 1024, isloaded ? ']' : ' ', glt->inputtexels ? '[' : ' ', (glt->inputdatasize + 1023) / 1024, glt->inputtexels ? ']' : ' ', isloaded ? "loaded" : "      ", (glt->flags & TEXF_MIPMAP) ? "mip" : "   ", (glt->flags & TEXF_ALPHA) ? "alpha" : "     ", glt->identifier);
+                               Con_Printf("%c%4i%c%c%4i%c %-24s %s %s %s %s\n", isloaded ? '[' : ' ', (glsize + 1023) / 1024, isloaded ? ']' : ' ', glt->inputtexels ? '[' : ' ', (glt->inputdatasize + 1023) / 1024, glt->inputtexels ? ']' : ' ', glt->textype->name, isloaded ? "loaded" : "      ", (glt->flags & TEXF_MIPMAP) ? "mip" : "   ", (glt->flags & TEXF_ALPHA) ? "alpha" : "     ", glt->identifier);
                }
                if (printpool)
                        Con_Printf("texturepool %10p total: %i (%.3fMB, %.3fMB original), uploaded %i (%.3fMB, %.3fMB original), upload on demand %i (%.3fMB, %.3fMB original)\n", (void *)pool, pooltotal, pooltotalt / 1048576.0, pooltotalp / 1048576.0, poolloaded, poolloadedt / 1048576.0, poolloadedp / 1048576.0, pooltotal - poolloaded, (pooltotalt - poolloadedt) / 1048576.0, (pooltotalp - poolloadedp) / 1048576.0);
@@ -896,6 +938,7 @@ void R_Textures_Init (void)
        Cvar_RegisterVariable (&gl_texturecompression_sky);
        Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
        Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
+       Cvar_RegisterVariable (&gl_texturecompression_sprites);
        Cvar_RegisterVariable (&gl_nopartialtextureupdates);
        Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
        Cvar_RegisterVariable (&r_texture_dds_load_logfailure);
@@ -1001,10 +1044,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)
@@ -1051,6 +1096,7 @@ static void GL_SetupTextureParameters(int flags, textype_t textype, int texturet
                qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
        }
 
+#ifndef USE_GLES2
        if (textype == TEXTYPE_SHADOWMAP)
        {
                if (vid.support.arb_shadow)
@@ -1067,6 +1113,7 @@ static void GL_SetupTextureParameters(int flags, textype_t textype, int texturet
                }
                qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);CHECKGLERROR
        }
+#endif
 
        CHECKGLERROR
 }
@@ -1218,6 +1265,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]);
                qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR
 
+#ifdef GL_TEXTURE_COMPRESSION_HINT_ARB
                if (qglGetCompressedTexImageARB)
                {
                        if (gl_texturecompression.integer >= 2)
@@ -1226,6 +1274,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                                qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST);
                        CHECKGLERROR
                }
+#endif
                switch(glt->texturetype)
                {
                case GLTEXTURETYPE_2D:
@@ -1241,6 +1290,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                        }
                        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)
                        {
@@ -1251,6 +1301,7 @@ static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data)
                                        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,
@@ -1505,6 +1556,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)
        {
@@ -1520,7 +1592,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;
        }
 
@@ -1816,6 +1889,9 @@ rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *i
 
 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;
@@ -1908,11 +1984,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);
@@ -1941,6 +2017,7 @@ 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
@@ -1998,6 +2075,7 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
        {
                // very sloppy BGRA 32bit identification
                textype = TEXTYPE_BGRA;
+               flags &= ~TEXF_COMPRESS; // don't let the textype be wrong
                bytesperblock = 0;
                bytesperpixel = 4;
                size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel);
@@ -2428,11 +2506,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;
index 120c453ed238af0abe07e5acd8997dbe41da516b..d09554a2626d77ea570e51cb3510178bd0645f6f 100644 (file)
--- a/glquake.h
+++ b/glquake.h
@@ -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);
@@ -505,58 +520,58 @@ extern void (GLAPIENTRY *qglBufferDataARB) (GLenum target, GLsizeiptrARB size, c
 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
+#ifndef GL_FRAMEBUFFER
+#define GL_FRAMEBUFFER                                   0x8D40
+#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_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_3D_ZOFFSET     0x8CD4
+#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_FRAMEBUFFER_COMPLETE                          0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT             0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT     0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS             0x8CD9
+#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS                0x8CDA
+#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER            0x8CDB
+#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER            0x8CDC
+#define GL_FRAMEBUFFER_UNSUPPORTED                       0x8CDD
+#define GL_FRAMEBUFFER_BINDING                           0x8CA6
+#define GL_RENDERBUFFER_BINDING                          0x8CA7
+#define GL_MAX_COLOR_ATTACHMENTS                         0x8CDF
+#define GL_MAX_RENDERBUFFER_SIZE                         0x84E8
+#define GL_INVALID_FRAMEBUFFER_OPERATION                 0x0506
 #endif
 extern GLboolean (GLAPIENTRY *qglIsRenderbufferEXT)(GLuint renderbuffer);
 extern void (GLAPIENTRY *qglBindRenderbufferEXT)(GLenum target, GLuint renderbuffer);
@@ -667,6 +682,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);
@@ -989,6 +1005,21 @@ extern void (GLAPIENTRY *qglGetQueryObjectuivARB)(GLuint qid, GLenum pname, GLui
 
 //GL_ARB_texture_gather
 
+//GL_ARB_multisample
+#define GL_MULTISAMPLE_ARB              0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_ARB      0x809F
+#define GL_SAMPLE_COVERAGE_ARB          0x80A0
+#define GL_SAMPLE_BUFFERS_ARB           0x80A8
+#define GL_SAMPLES_ARB                  0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE_ARB    0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT_ARB   0x80AB
+#define GL_MULTISAMPLE_BIT_ARB          0x20000000
+extern void (GLAPIENTRY *qglSampleCoverageARB)(GLclampf value, GLboolean invert);
+
+extern void (GLAPIENTRY *qglPointSize)(GLfloat size);
+#endif
+
 #define DEBUGGL
 
 #ifdef DEBUGGL
@@ -999,5 +1030,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 qglFramebufferRenderbufferEXT glFramebufferRenderbuffer
+#define qglFramebufferTexture2DEXT glFramebufferTexture2D
+#define qglFramebufferTexture3DEXT glFramebufferTexture3D
+#define qglGenBuffersARB glGenBuffers
+#define qglGenFramebuffersEXT glGenFramebuffers
+//#define qglGenQueriesARB glGenQueries
+#define qglGenRenderbuffersEXT glGenRenderbuffers
+#define qglGenTextures glGenTextures
+#define qglGenerateMipmapEXT glGenerateMipmap
+#define qglGetActiveAttrib glGetActiveAttrib
+#define qglGetActiveUniform glGetActiveUniform
+#define qglGetAttachedShaders glGetAttachedShaders
+#define qglGetBooleanv glGetBooleanv
+//#define qglGetCompressedTexImageARB glGetCompressedTexImage
+#define qglGetDoublev glGetDoublev
+#define qglGetFloatv glGetFloatv
+#define qglGetFramebufferAttachmentParameterivEXT glGetFramebufferAttachmentParameteriv
+#define qglGetProgramInfoLog glGetProgramInfoLog
+#define qglGetShaderInfoLog glGetShaderInfoLog
+#define qglGetIntegerv glGetIntegerv
+#define qglGetShaderiv glGetShaderiv
+#define qglGetProgramiv glGetProgramiv
+//#define qglGetQueryObjectivARB glGetQueryObjectiv
+//#define qglGetQueryObjectuivARB glGetQueryObjectuiv
+//#define qglGetQueryivARB glGetQueryiv
+#define qglGetRenderbufferParameterivEXT glGetRenderbufferParameteriv
+#define qglGetShaderSource glGetShaderSource
+#define qglGetTexImage glGetTexImage
+#define qglGetTexLevelParameterfv glGetTexLevelParameterfv
+#define qglGetTexLevelParameteriv glGetTexLevelParameteriv
+#define qglGetTexParameterfv glGetTexParameterfv
+#define qglGetTexParameteriv glGetTexParameteriv
+#define qglGetUniformfv glGetUniformfv
+#define qglGetUniformiv glGetUniformiv
+#define qglHint glHint
+#define qglLineWidth glLineWidth
+#define qglLinkProgram glLinkProgram
+#define qglLoadIdentity glLoadIdentity
+#define qglLoadMatrixf glLoadMatrixf
+#define qglMatrixMode glMatrixMode
+#define qglMultiTexCoord1f glMultiTexCoord1f
+#define qglMultiTexCoord2f glMultiTexCoord2f
+#define qglMultiTexCoord3f glMultiTexCoord3f
+#define qglMultiTexCoord4f glMultiTexCoord4f
+#define qglNormalPointer glNormalPointer
+#define qglPixelStorei glPixelStorei
+#define qglPointSize glPointSize
+//#define qglPolygonMode glPolygonMode
+#define qglPolygonOffset glPolygonOffset
+//#define qglPolygonStipple glPolygonStipple
+#define qglReadBuffer glReadBuffer
+#define qglReadPixels glReadPixels
+#define qglRenderbufferStorageEXT glRenderbufferStorage
+#define qglScissor glScissor
+#define qglShaderSource glShaderSource
+#define qglStencilFunc glStencilFunc
+#define qglStencilFuncSeparate glStencilFuncSeparate
+#define qglStencilMask glStencilMask
+#define qglStencilOp glStencilOp
+#define qglStencilOpSeparate glStencilOpSeparate
+#define qglTexCoord1f glTexCoord1f
+#define qglTexCoord2f glTexCoord2f
+#define qglTexCoord3f glTexCoord3f
+#define qglTexCoord4f glTexCoord4f
+#define qglTexCoordPointer glTexCoordPointer
+#define qglTexEnvf glTexEnvf
+#define qglTexEnvfv glTexEnvfv
+#define qglTexEnvi glTexEnvi
+#define qglTexImage2D glTexImage2D
+#define qglTexImage3D glTexImage3D
+#define qglTexParameterf glTexParameterf
+#define qglTexParameterfv glTexParameterfv
+#define qglTexParameteri glTexParameteri
+#define qglTexSubImage2D glTexSubImage2D
+#define qglTexSubImage3D glTexSubImage3D
+#define qglUniform1f glUniform1f
+#define qglUniform1fv glUniform1fv
+#define qglUniform1i glUniform1i
+#define qglUniform1iv glUniform1iv
+#define qglUniform2f glUniform2f
+#define qglUniform2fv glUniform2fv
+#define qglUniform2i glUniform2i
+#define qglUniform2iv glUniform2iv
+#define qglUniform3f glUniform3f
+#define qglUniform3fv glUniform3fv
+#define qglUniform3i glUniform3i
+#define qglUniform3iv glUniform3iv
+#define qglUniform4f glUniform4f
+#define qglUniform4fv glUniform4fv
+#define qglUniform4i glUniform4i
+#define qglUniform4iv glUniform4iv
+#define qglUniformMatrix2fv glUniformMatrix2fv
+#define qglUniformMatrix3fv glUniformMatrix3fv
+#define qglUniformMatrix4fv glUniformMatrix4fv
+#define qglUseProgram glUseProgram
+#define qglValidateProgram glValidateProgram
+#define qglVertex2f glVertex2f
+#define qglVertex3f glVertex3f
+#define qglVertex4f glVertex4f
+#define qglVertexAttribPointer glVertexAttribPointer
+#define qglVertexPointer glVertexPointer
+#define qglViewport glViewport
+#define qglVertexAttrib1f glVertexAttrib1f
+//#define qglVertexAttrib1s glVertexAttrib1s
+//#define qglVertexAttrib1d glVertexAttrib1d
+#define qglVertexAttrib2f glVertexAttrib2f
+//#define qglVertexAttrib2s glVertexAttrib2s
+//#define qglVertexAttrib2d glVertexAttrib2d
+#define qglVertexAttrib3f glVertexAttrib3f
+//#define qglVertexAttrib3s glVertexAttrib3s
+//#define qglVertexAttrib3d glVertexAttrib3d
+#define qglVertexAttrib4f glVertexAttrib4f
+//#define qglVertexAttrib4s glVertexAttrib4s
+//#define qglVertexAttrib4d glVertexAttrib4d
+//#define qglVertexAttrib4Nub glVertexAttrib4Nub
+#define qglVertexAttrib1fv glVertexAttrib1fv
+//#define qglVertexAttrib1sv glVertexAttrib1sv
+//#define qglVertexAttrib1dv glVertexAttrib1dv
+#define qglVertexAttrib2fv glVertexAttrib2fv
+//#define qglVertexAttrib2sv glVertexAttrib2sv
+//#define qglVertexAttrib2dv glVertexAttrib2dv
+#define qglVertexAttrib3fv glVertexAttrib3fv
+//#define qglVertexAttrib3sv glVertexAttrib3sv
+//#define qglVertexAttrib3dv glVertexAttrib3dv
+#define qglVertexAttrib4fv glVertexAttrib4fv
+//#define qglVertexAttrib4sv glVertexAttrib4sv
+//#define qglVertexAttrib4dv glVertexAttrib4dv
+//#define qglVertexAttrib4iv glVertexAttrib4iv
+//#define qglVertexAttrib4bv glVertexAttrib4bv
+//#define qglVertexAttrib4ubv glVertexAttrib4ubv
+//#define qglVertexAttrib4usv glVertexAttrib4usv
+//#define qglVertexAttrib4uiv glVertexAttrib4uiv
+//#define qglVertexAttrib4Nbv glVertexAttrib4Nbv
+//#define qglVertexAttrib4Nsv glVertexAttrib4Nsv
+//#define qglVertexAttrib4Niv glVertexAttrib4Niv
+//#define qglVertexAttrib4Nubv glVertexAttrib4Nubv
+//#define qglVertexAttrib4Nusv glVertexAttrib4Nusv
+//#define qglVertexAttrib4Nuiv glVertexAttrib4Nuiv
+//#define qglGetVertexAttribdv glGetVertexAttribdv
+#define qglGetVertexAttribfv glGetVertexAttribfv
+#define qglGetVertexAttribiv glGetVertexAttribiv
+#define qglGetVertexAttribPointerv glGetVertexAttribPointerv
+#endif
+
 #endif
 
diff --git a/host.c b/host.c
index 812c2146e60787e13d27640cbeaa53591794b148..dbc88c59b052280183ab5de951a5d49c57872ae5 100644 (file)
--- a/host.c
+++ b/host.c
@@ -468,11 +468,11 @@ void SV_DropClient(qboolean crash)
        {
                // call the prog function for removing a client
                // this will set the body to a dead frame, among other things
-               int saveSelf = prog->globals.server->self;
+               int saveSelf = PRVM_serverglobaledict(self);
                host_client->clientconnectcalled = false;
-               prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
-               PRVM_ExecuteProgram(prog->globals.server->ClientDisconnect, "QC function ClientDisconnect is missing");
-               prog->globals.server->self = saveSelf;
+               PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
+               PRVM_ExecuteProgram(PRVM_serverfunction(ClientDisconnect), "QC function ClientDisconnect is missing");
+               PRVM_serverglobaledict(self) = saveSelf;
        }
 
        if (host_client->netconnection)
@@ -567,10 +567,10 @@ void Host_ShutdownServer(void)
        SV_VM_Begin();
        World_End(&sv.world);
        if(prog->loaded)
-               if(prog->funcoffsets.SV_Shutdown)
+               if(PRVM_serverfunction(SV_Shutdown))
                {
-                       func_t s = prog->funcoffsets.SV_Shutdown;
-                       prog->funcoffsets.SV_Shutdown = 0; // prevent it from getting called again
+                       func_t s = PRVM_serverfunction(SV_Shutdown);
+                       PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again
                        PRVM_ExecuteProgram(s,"SV_Shutdown() required");
                }
        for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
@@ -861,7 +861,7 @@ void Host_Main(void)
                        
                        if (sv.paused == 1 && realtime > sv.pausedstart && sv.pausedstart > 0) {
                                prog->globals.generic[OFS_PARM0] = realtime - sv.pausedstart;
-                               PRVM_ExecuteProgram(prog->funcoffsets.SV_PausedTic, "QC function SV_PausedTic is missing");
+                               PRVM_ExecuteProgram(PRVM_serverfunction(SV_PausedTic), "QC function SV_PausedTic is missing");
                        }
 
                        // end the server VM frame
@@ -1082,7 +1082,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 +1096,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;
index 9b2ee2707248e9b436ca1b8f9dab1d73cb07ca4d..9a37055ed931a24dd1a58e680dfe7ecf31b606ba 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"};
@@ -155,9 +156,10 @@ void Host_Status_f (void)
 
                frags = client->frags;
 
-               if(sv_status_show_qcstatus.integer && prog->fieldoffsets.clientstatus >= 0)
+               if(sv_status_show_qcstatus.integer)
                {
-                       const char *str = PRVM_E_STRING(PRVM_EDICT_NUM(i + 1), prog->fieldoffsets.clientstatus);
+                       prvm_edict_t *ed = PRVM_EDICT_NUM(i + 1);
+                       const char *str = PRVM_GetString(PRVM_serveredictstring(ed, clientstatus));
                        if(str && *str)
                        {
                                char *p;
@@ -217,8 +219,8 @@ void Host_God_f (void)
                return;
        }
 
-       host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags ^ FL_GODMODE;
-       if (!((int)host_client->edict->fields.server->flags & FL_GODMODE) )
+       PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_GODMODE;
+       if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_GODMODE) )
                SV_ClientPrint("godmode OFF\n");
        else
                SV_ClientPrint("godmode ON\n");
@@ -232,8 +234,8 @@ void Host_Notarget_f (void)
                return;
        }
 
-       host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags ^ FL_NOTARGET;
-       if (!((int)host_client->edict->fields.server->flags & FL_NOTARGET) )
+       PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_NOTARGET;
+       if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_NOTARGET) )
                SV_ClientPrint("notarget OFF\n");
        else
                SV_ClientPrint("notarget ON\n");
@@ -249,16 +251,16 @@ void Host_Noclip_f (void)
                return;
        }
 
-       if (host_client->edict->fields.server->movetype != MOVETYPE_NOCLIP)
+       if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_NOCLIP)
        {
                noclip_anglehack = true;
-               host_client->edict->fields.server->movetype = MOVETYPE_NOCLIP;
+               PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_NOCLIP;
                SV_ClientPrint("noclip ON\n");
        }
        else
        {
                noclip_anglehack = false;
-               host_client->edict->fields.server->movetype = MOVETYPE_WALK;
+               PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
                SV_ClientPrint("noclip OFF\n");
        }
 }
@@ -278,14 +280,14 @@ void Host_Fly_f (void)
                return;
        }
 
-       if (host_client->edict->fields.server->movetype != MOVETYPE_FLY)
+       if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_FLY)
        {
-               host_client->edict->fields.server->movetype = MOVETYPE_FLY;
+               PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_FLY;
                SV_ClientPrint("flymode ON\n");
        }
        else
        {
-               host_client->edict->fields.server->movetype = MOVETYPE_WALK;
+               PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK;
                SV_ClientPrint("flymode OFF\n");
        }
 }
@@ -577,7 +579,7 @@ 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(prog->edicts->fields.server->message), (int)prog->globals.server->killed_monsters, (int)prog->globals.server->total_monsters);
+               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));
        else
                dpsnprintf(comment, sizeof(comment), "(crash dump of %s progs)", PRVM_NAME);
        // convert space to _ to make stdio happy
@@ -699,6 +701,7 @@ Host_Savegame_f
 void Host_Savegame_f (void)
 {
        char    name[MAX_QPATH];
+       qboolean deadflag = false;
 
        if (!sv.active)
        {
@@ -706,6 +709,10 @@ 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)
        {
                // singleplayer checks
@@ -715,7 +722,7 @@ void Host_Savegame_f (void)
                        return;
                }
 
-               if (svs.clients[0].active && svs.clients[0].edict->fields.server->deadflag)
+               if (deadflag)
                {
                        Con_Print("Can't savegame with a dead player\n");
                        return;
@@ -943,7 +950,7 @@ void Host_Loadgame_f (void)
                        while (entnum >= prog->max_edicts)
                                PRVM_MEM_IncreaseEdicts();
                        ent = PRVM_EDICT_NUM(entnum);
-                       memset (ent->fields.server, 0, prog->progs->entityfields * 4);
+                       memset(ent->fields.vp, 0, prog->entityfields * 4);
                        ent->priv.server->free = false;
 
                        if(developer_entityparsing.integer)
@@ -1120,11 +1127,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));
@@ -1194,7 +1201,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);
 
-       host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
+       PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(host_client->name);
        if (strcmp(host_client->old_name, host_client->name))
        {
                if (host_client->spawned)
@@ -1254,8 +1261,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));
-       if( prog->fieldoffsets.playermodel >= 0 )
-               PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
+       PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(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));
@@ -1311,8 +1317,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));
-       if( prog->fieldoffsets.playerskin >= 0 )
-               PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
+       PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(host_client->playerskin);
        if (strcmp(host_client->old_skin, host_client->playerskin))
        {
                //if (host_client->spawned)
@@ -1389,7 +1394,7 @@ void Host_Say(qboolean teamonly)
        // note: save is not a valid edict if fromServer is true
        save = host_client;
        for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++)
-               if (host_client->active && (!teamonly || host_client->edict->fields.server->team == save->edict->fields.server->team))
+               if (host_client->active && (!teamonly || PRVM_serveredictfloat(host_client->edict, team) == PRVM_serveredictfloat(save->edict, team)))
                        SV_ClientPrint(text);
        host_client = save;
 
@@ -1573,22 +1578,20 @@ void Host_Color(int changetop, int changebottom)
        if (cls.protocol == PROTOCOL_QUAKEWORLD)
                return;
 
-       if (host_client->edict && prog->funcoffsets.SV_ChangeTeam)
+       if (host_client->edict && PRVM_clientfunction(SV_ChangeTeam))
        {
                Con_DPrint("Calling SV_ChangeTeam\n");
-               prog->globals.server->time = sv.time;
+               PRVM_serverglobalfloat(time) = sv.time;
                prog->globals.generic[OFS_PARM0] = playercolor;
-               prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
-               PRVM_ExecuteProgram(prog->funcoffsets.SV_ChangeTeam, "QC function SV_ChangeTeam is missing");
+               PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
+               PRVM_ExecuteProgram(PRVM_clientfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing");
        }
        else
        {
-               prvm_eval_t *val;
                if (host_client->edict)
                {
-                       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
-                               val->_float = playercolor;
-                       host_client->edict->fields.server->team = bottom + 1;
+                       PRVM_serveredictfloat(host_client->edict, clientcolors) = playercolor;
+                       PRVM_serveredictfloat(host_client->edict, team) = bottom + 1;
                }
                host_client->colors = playercolor;
                if (host_client->old_colors != host_client->colors)
@@ -1677,15 +1680,15 @@ Host_Kill_f
 */
 void Host_Kill_f (void)
 {
-       if (host_client->edict->fields.server->health <= 0)
+       if (PRVM_serveredictfloat(host_client->edict, health) <= 0)
        {
                SV_ClientPrint("Can't suicide -- already dead!\n");
                return;
        }
 
-       prog->globals.server->time = sv.time;
-       prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
-       PRVM_ExecuteProgram (prog->globals.server->ClientKill, "QC function ClientKill is missing");
+       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");
 }
 
 
@@ -1719,7 +1722,6 @@ cvar_t cl_pmodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_pmodel", "0", "interna
 static void Host_PModel_f (void)
 {
        int i;
-       prvm_eval_t *val;
 
        if (Cmd_Argc () == 1)
        {
@@ -1738,8 +1740,7 @@ static void Host_PModel_f (void)
                return;
        }
 
-       if (host_client->edict && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.pmodel)))
-               val->_float = i;
+       PRVM_serveredictfloat(host_client->edict, pmodel) = i;
 }
 
 //===========================================================================
@@ -1800,32 +1801,32 @@ void Host_Spawn_f (void)
        if (sv.loadgame)
        {
                // loaded games are fully initialized already
-               if (prog->funcoffsets.RestoreGame)
+               if (PRVM_serverfunction(RestoreGame))
                {
                        Con_DPrint("Calling RestoreGame\n");
-                       prog->globals.server->time = sv.time;
-                       prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
-                       PRVM_ExecuteProgram(prog->funcoffsets.RestoreGame, "QC function RestoreGame is missing");
+                       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");
                }
        }
        else
        {
-               //Con_Printf("Host_Spawn_f: host_client->edict->netname = %s, host_client->edict->netname = %s, host_client->name = %s\n", PRVM_GetString(host_client->edict->fields.server->netname), PRVM_GetString(host_client->edict->fields.server->netname), host_client->name);
+               //Con_Printf("Host_Spawn_f: host_client->edict->netname = %s, host_client->edict->netname = %s, host_client->name = %s\n", PRVM_GetString(PRVM_serveredictstring(host_client->edict, netname)), PRVM_GetString(PRVM_serveredictstring(host_client->edict, netname)), host_client->name);
 
                // copy spawn parms out of the client_t
                for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
-                       (&prog->globals.server->parm1)[i] = host_client->spawn_parms[i];
+                       (&PRVM_serverglobalfloat(parm1))[i] = host_client->spawn_parms[i];
 
                // call the spawn function
                host_client->clientconnectcalled = true;
-               prog->globals.server->time = sv.time;
-               prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
-               PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
+               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");
 
                if (cls.state == ca_dedicated)
                        Con_Printf("%s connected\n", host_client->name);
 
-               PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
+               PRVM_ExecuteProgram (PRVM_serverfunction(PutClientInServer), "QC function PutClientInServer is missing");
        }
 
        if (!host_client->netconnection)
@@ -1865,19 +1866,19 @@ void Host_Spawn_f (void)
        // send some stats
        MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
        MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALSECRETS);
-       MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_secrets);
+       MSG_WriteLong (&host_client->netconnection->message, (int)PRVM_serverglobalfloat(total_secrets));
 
        MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
        MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALMONSTERS);
-       MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_monsters);
+       MSG_WriteLong (&host_client->netconnection->message, (int)PRVM_serverglobalfloat(total_monsters));
 
        MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
        MSG_WriteByte (&host_client->netconnection->message, STAT_SECRETS);
-       MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->found_secrets);
+       MSG_WriteLong (&host_client->netconnection->message, (int)PRVM_serverglobalfloat(found_secrets));
 
        MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
        MSG_WriteByte (&host_client->netconnection->message, STAT_MONSTERS);
-       MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->killed_monsters);
+       MSG_WriteLong (&host_client->netconnection->message, (int)PRVM_serverglobalfloat(killed_monsters));
 
        // send a fixangle
        // Never send a roll angle, because savegames can catch the server
@@ -1887,15 +1888,15 @@ void Host_Spawn_f (void)
        if (sv.loadgame)
        {
                MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
-               MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[0], sv.protocol);
-               MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[1], sv.protocol);
+               MSG_WriteAngle (&host_client->netconnection->message, PRVM_serveredictvector(host_client->edict, v_angle)[0], sv.protocol);
+               MSG_WriteAngle (&host_client->netconnection->message, PRVM_serveredictvector(host_client->edict, v_angle)[1], sv.protocol);
                MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
        }
        else
        {
                MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
-               MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[0], sv.protocol);
-               MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[1], sv.protocol);
+               MSG_WriteAngle (&host_client->netconnection->message, PRVM_serveredictvector(host_client->edict, angles)[0], sv.protocol);
+               MSG_WriteAngle (&host_client->netconnection->message, PRVM_serveredictvector(host_client->edict, angles)[1], sv.protocol);
                MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
        }
 
@@ -2029,7 +2030,6 @@ void Host_Give_f (void)
 {
        const char *t;
        int v;
-       prvm_eval_t *val;
 
        if (!allowcheats)
        {
@@ -2058,114 +2058,91 @@ void Host_Give_f (void)
                        if (t[0] == '6')
                        {
                                if (t[1] == 'a')
-                                       host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_PROXIMITY_GUN;
+                                       PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_PROXIMITY_GUN;
                                else
-                                       host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | IT_GRENADE_LAUNCHER;
+                                       PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | IT_GRENADE_LAUNCHER;
                        }
                        else if (t[0] == '9')
-                               host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_LASER_CANNON;
+                               PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_LASER_CANNON;
                        else if (t[0] == '0')
-                               host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_MJOLNIR;
+                               PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_MJOLNIR;
                        else if (t[0] >= '2')
-                               host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
+                               PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2'));
                }
                else
                {
                        if (t[0] >= '2')
-                               host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
+                               PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2'));
                }
                break;
 
        case 's':
-               if (gamemode == GAME_ROGUE && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_shells1)))
-                       val->_float = v;
+               if (gamemode == GAME_ROGUE)
+                       PRVM_serveredictfloat(host_client->edict, ammo_shells1) = v;
 
-               host_client->edict->fields.server->ammo_shells = v;
+               PRVM_serveredictfloat(host_client->edict, ammo_shells) = v;
                break;
        case 'n':
                if (gamemode == GAME_ROGUE)
                {
-                       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_nails1)))
-                       {
-                               val->_float = v;
-                               if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
-                                       host_client->edict->fields.server->ammo_nails = v;
-                       }
+                       PRVM_serveredictfloat(host_client->edict, ammo_nails1) = v;
+                       if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
+                               PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
                }
                else
                {
-                       host_client->edict->fields.server->ammo_nails = v;
+                       PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
                }
                break;
        case 'l':
                if (gamemode == GAME_ROGUE)
                {
-                       val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_lava_nails);
-                       if (val)
-                       {
-                               val->_float = v;
-                               if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
-                                       host_client->edict->fields.server->ammo_nails = v;
-                       }
+                       PRVM_serveredictfloat(host_client->edict, ammo_lava_nails) = v;
+                       if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
+                               PRVM_serveredictfloat(host_client->edict, ammo_nails) = v;
                }
                break;
        case 'r':
                if (gamemode == GAME_ROGUE)
                {
-                       val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_rockets1);
-                       if (val)
-                       {
-                               val->_float = v;
-                               if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
-                                       host_client->edict->fields.server->ammo_rockets = v;
-                       }
+                       PRVM_serveredictfloat(host_client->edict, ammo_rockets1) = v;
+                       if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
+                               PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
                }
                else
                {
-                       host_client->edict->fields.server->ammo_rockets = v;
+                       PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
                }
                break;
        case 'm':
                if (gamemode == GAME_ROGUE)
                {
-                       val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_multi_rockets);
-                       if (val)
-                       {
-                               val->_float = v;
-                               if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
-                                       host_client->edict->fields.server->ammo_rockets = v;
-                       }
+                       PRVM_serveredictfloat(host_client->edict, ammo_multi_rockets) = v;
+                       if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
+                               PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v;
                }
                break;
        case 'h':
-               host_client->edict->fields.server->health = v;
+               PRVM_serveredictfloat(host_client->edict, health) = v;
                break;
        case 'c':
                if (gamemode == GAME_ROGUE)
                {
-                       val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_cells1);
-                       if (val)
-                       {
-                               val->_float = v;
-                               if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
-                                       host_client->edict->fields.server->ammo_cells = v;
-                       }
+                       PRVM_serveredictfloat(host_client->edict, ammo_cells1) = v;
+                       if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING)
+                               PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
                }
                else
                {
-                       host_client->edict->fields.server->ammo_cells = v;
+                       PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
                }
                break;
        case 'p':
                if (gamemode == GAME_ROGUE)
                {
-                       val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_plasma);
-                       if (val)
-                       {
-                               val->_float = v;
-                               if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
-                                       host_client->edict->fields.server->ammo_cells = v;
-                       }
+                       PRVM_serveredictfloat(host_client->edict, ammo_plasma) = v;
+                       if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING)
+                               PRVM_serveredictfloat(host_client->edict, ammo_cells) = v;
                }
                break;
        }
@@ -2179,7 +2156,7 @@ prvm_edict_t      *FindViewthing (void)
        for (i=0 ; i<prog->num_edicts ; i++)
        {
                e = PRVM_EDICT_NUM(i);
-               if (!strcmp (PRVM_GetString(e->fields.server->classname), "viewthing"))
+               if (!strcmp (PRVM_GetString(PRVM_serveredictstring(e, classname)), "viewthing"))
                        return e;
        }
        Con_Print("No viewthing on map\n");
@@ -2212,8 +2189,8 @@ void Host_Viewmodel_f (void)
                return;
        }
 
-       e->fields.server->frame = 0;
-       cl.model_precache[(int)e->fields.server->modelindex] = m;
+       PRVM_serveredictfloat(e, frame) = 0;
+       cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)] = m;
 }
 
 /*
@@ -2235,13 +2212,13 @@ void Host_Viewframe_f (void)
        SV_VM_End();
        if (!e)
                return;
-       m = cl.model_precache[(int)e->fields.server->modelindex];
+       m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
 
        f = atoi(Cmd_Argv(1));
        if (f >= m->numframes)
                f = m->numframes-1;
 
-       e->fields.server->frame = f;
+       PRVM_serveredictfloat(e, frame) = f;
 }
 
 
@@ -2271,13 +2248,13 @@ void Host_Viewnext_f (void)
        SV_VM_End();
        if (!e)
                return;
-       m = cl.model_precache[(int)e->fields.server->modelindex];
+       m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
 
-       e->fields.server->frame = e->fields.server->frame + 1;
-       if (e->fields.server->frame >= m->numframes)
-               e->fields.server->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)e->fields.server->frame);
+       PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
 }
 
 /*
@@ -2299,13 +2276,13 @@ void Host_Viewprev_f (void)
        if (!e)
                return;
 
-       m = cl.model_precache[(int)e->fields.server->modelindex];
+       m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)];
 
-       e->fields.server->frame = e->fields.server->frame - 1;
-       if (e->fields.server->frame < 0)
-               e->fields.server->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)e->fields.server->frame);
+       PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame));
 }
 
 /*
@@ -2407,7 +2384,7 @@ void Host_SendCvar_f (void)
                        Cmd_ForwardStringToServer(va("sentcvar %s \"%s\"", c->name, c->string));
                return;
        }
-       if(!sv.active)// || !prog->funcoffsets.SV_ParseClientCommand)
+       if(!sv.active)// || !PRVM_serverfunction(SV_ParseClientCommand))
                return;
 
        old = host_client;
@@ -2992,6 +2969,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)
diff --git a/image.c b/image.c
index e35dd33df11b34fadb5c7592646c145ed1ce6954..c556f3930bfbc7cd0170ceaeeb439908673d9718 100644 (file)
--- a/image.c
+++ b/image.c
@@ -804,7 +804,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] = i < 11 ? (int)(i / 12.92f) : (int)(pow((i/256.0f + 0.055f)/1.0555f, 2.4f)*256.0f);
+                       image_linearfromsrgb[i] = (unsigned char)(Image_LinearFloatFromsRGB(i) * 256.0f);
        for (i = 0;i < numpixels;i++)
        {
                pout[i*4+0] = image_linearfromsrgb[pin[i*4+0]];
diff --git a/image.h b/image.h
index 10d190dd902d40b9ca24c45b642a0d383f4d9a73..60fbcce681c1aa93311efc3d4e3e1dd6f61de373 100644 (file)
--- a/image.h
+++ b/image.h
@@ -49,6 +49,8 @@ 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))
+
 void Image_MakeLinearColorsFromsRGB(unsigned char *pout, const unsigned char *pin, int numpixels);
 
 #endif
diff --git a/keys.c b/keys.c
index e08765fe09869c777a2ed9ca13244287a9192181..d16d44286b23ab43799ce77356e6a08f198d9d70 100644 (file)
--- a/keys.c
+++ b/keys.c
@@ -473,6 +473,36 @@ static const keyname_t   keynames[] = {
        {"AUX31", K_AUX31},
        {"AUX32", K_AUX32},
 
+       {"X360_DPAD_UP", K_X360_DPAD_UP},
+       {"X360_DPAD_DOWN", K_X360_DPAD_DOWN},
+       {"X360_DPAD_LEFT", K_X360_DPAD_LEFT},
+       {"X360_DPAD_RIGHT", K_X360_DPAD_RIGHT},
+       {"X360_START", K_X360_START},
+       {"X360_BACK", K_X360_BACK},
+       {"X360_LEFT_THUMB", K_X360_LEFT_THUMB},
+       {"X360_RIGHT_THUMB", K_X360_RIGHT_THUMB},
+       {"X360_LEFT_SHOULDER", K_X360_LEFT_SHOULDER},
+       {"X360_RIGHT_SHOULDER", K_X360_RIGHT_SHOULDER},
+       {"X360_A", K_X360_A},
+       {"X360_B", K_X360_B},
+       {"X360_X", K_X360_X},
+       {"X360_Y", K_X360_Y},
+       {"X360_LEFT_TRIGGER", K_X360_LEFT_TRIGGER},
+       {"X360_RIGHT_TRIGGER", K_X360_RIGHT_TRIGGER},
+       {"X360_LEFT_THUMB_UP", K_X360_LEFT_THUMB_UP},
+       {"X360_LEFT_THUMB_DOWN", K_X360_LEFT_THUMB_DOWN},
+       {"X360_LEFT_THUMB_LEFT", K_X360_LEFT_THUMB_LEFT},
+       {"X360_LEFT_THUMB_RIGHT", K_X360_LEFT_THUMB_RIGHT},
+       {"X360_RIGHT_THUMB_UP", K_X360_RIGHT_THUMB_UP},
+       {"X360_RIGHT_THUMB_DOWN", K_X360_RIGHT_THUMB_DOWN},
+       {"X360_RIGHT_THUMB_LEFT", K_X360_RIGHT_THUMB_LEFT},
+       {"X360_RIGHT_THUMB_RIGHT", K_X360_RIGHT_THUMB_RIGHT},
+
+       {"JOY_UP", K_JOY_UP},
+       {"JOY_DOWN", K_JOY_DOWN},
+       {"JOY_LEFT", K_JOY_LEFT},
+       {"JOY_RIGHT", K_JOY_RIGHT},
+
        {"SEMICOLON", ';'},                     // because a raw semicolon separates commands
        {"TILDE", '~'},
        {"BACKQUOTE", '`'},
@@ -1669,7 +1699,7 @@ void Key_FindKeysForCommand (const char *command, int *keys, int numkeys, int bi
        }
 }
 
-qboolean CL_VM_InputEvent (qboolean down, int key, int ascii);
+extern qboolean CL_VM_InputEvent (int eventtype, int x, int y);
 
 /*
 ===================
@@ -1835,7 +1865,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;
@@ -1919,7 +1949,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)
                        {
@@ -1942,6 +1972,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
diff --git a/keys.h b/keys.h
index c330454b3f0a0c2f5658d694dc4b8474ba296523..e471a235a74ceb3255e0ed5732e76f79d8d29ac8 100644 (file)
--- a/keys.h
+++ b/keys.h
@@ -188,6 +188,38 @@ typedef enum keynum_e
        K_AUX31,
        K_AUX32,
 
+       // Microsoft Xbox 360 Controller For Windows
+       K_X360_DPAD_UP,
+       K_X360_DPAD_DOWN,
+       K_X360_DPAD_LEFT,
+       K_X360_DPAD_RIGHT,
+       K_X360_START,
+       K_X360_BACK,
+       K_X360_LEFT_THUMB,
+       K_X360_RIGHT_THUMB,
+       K_X360_LEFT_SHOULDER,
+       K_X360_RIGHT_SHOULDER,
+       K_X360_A,
+       K_X360_B,
+       K_X360_X,
+       K_X360_Y,
+       K_X360_LEFT_TRIGGER,
+       K_X360_RIGHT_TRIGGER,
+       K_X360_LEFT_THUMB_UP,
+       K_X360_LEFT_THUMB_DOWN,
+       K_X360_LEFT_THUMB_LEFT,
+       K_X360_LEFT_THUMB_RIGHT,
+       K_X360_RIGHT_THUMB_UP,
+       K_X360_RIGHT_THUMB_DOWN,
+       K_X360_RIGHT_THUMB_LEFT,
+       K_X360_RIGHT_THUMB_RIGHT,
+
+       // generic joystick emulation for menu
+       K_JOY_UP,
+       K_JOY_DOWN,
+       K_JOY_LEFT,
+       K_JOY_RIGHT,
+
        K_MIDINOTE0 = 896, // to this, the note number is added
        K_MIDINOTE1,
        K_MIDINOTE2,
@@ -345,7 +377,8 @@ 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 7d3f73a3f29b043860cfe1df3b861504acfde199..84db7512929f70e67687b17d5bb9840f6fe0247b 100644 (file)
--- a/makefile
+++ b/makefile
@@ -47,6 +47,12 @@ else
        UNIX_X11LIBPATH:=/usr/X11R6/lib
 endif
 
+# default targets
+TARGETS_DEBUG=sv-debug cl-debug sdl-debug
+TARGETS_PROFILE=sv-profile cl-profile sdl-profile
+TARGETS_RELEASE=sv-release cl-release sdl-release
+TARGETS_RELEASE_PROFILE=sv-release-profile cl-release-profile sdl-release-profile
+TARGETS_NEXUIZ=sv-nexuiz cl-nexuiz sdl-nexuiz
 
 # Linux configuration
 ifeq ($(DP_MAKE_TARGET), linux)
@@ -109,6 +115,14 @@ ifeq ($(DP_MAKE_TARGET), macosx)
        # we don't currently link to libjpeg on Mac because the OS does not have an easy way to load libjpeg and we provide our own in the .app
        CFLAGS_LIBJPEG=
        LIB_JPEG=
+
+       # on OS X, we don't build the CL by default because it uses deprecated
+       # and not-implemented-in-64bit Carbon
+       TARGETS_DEBUG=sv-debug sdl-debug
+       TARGETS_PROFILE=sv-profile sdl-profile
+       TARGETS_RELEASE=sv-release sdl-release
+       TARGETS_RELEASE_PROFILE=sv-release-profile sdl-release-profile
+       TARGETS_NEXUIZ=sv-nexuiz sdl-nexuiz
 endif
 
 # SunOS configuration (Solaris)
index 01e2999679df0dd3da9635fc6068320b3d5a719c..fc63f7d41fd9ebdaa682ec3a901da2d6b8cf55bf 100644 (file)
@@ -210,9 +210,9 @@ DO_CC=$(CC) $(CFLAGS) -c $< -o $@
 
 
 # Link
-LDFLAGS_DEBUG=-g -ggdb $(OPTIM_DEBUG) -DSVNREVISION=`test -d .svn && svnversion || echo -` -DBUILDTYPE=debug
-LDFLAGS_PROFILE=-g -pg -fprofile-arcs $(OPTIM_RELEASE) -DSVNREVISION=`test -d .svn && svnversion || echo -` -DBUILDTYPE=profile
-LDFLAGS_RELEASE=$(OPTIM_RELEASE) -DSVNREVISION=`test -d .svn && svnversion || echo -` -DBUILDTYPE=release -lircclient
+LDFLAGS_DEBUG=-g -ggdb $(OPTIM_DEBUG) -DSVNREVISION=`{ test -d .svn && svnversion; } || { test -d .git && git describe --always; } || echo -` -DBUILDTYPE=debug
+LDFLAGS_PROFILE=-g -pg -fprofile-arcs $(OPTIM_RELEASE) -DSVNREVISION=`{ test -d .svn && svnversion; } || { test -d .git && git describe --always; } || echo -` -DBUILDTYPE=profile
+LDFLAGS_RELEASE=$(OPTIM_RELEASE) -DSVNREVISION=`{ test -d .svn && svnversion; } || { test -d .git && git describe --always; } || echo -` -DBUILDTYPE=release -lircclient
 
 
 ##### UNIX specific variables #####
@@ -359,19 +359,19 @@ help:
        @echo
 
 debug :
-       $(MAKE) sv-debug cl-debug sdl-debug
+       $(MAKE) $(TARGETS_DEBUG)
 
 profile :
-       $(MAKE) sv-profile cl-profile sdl-profile
+       $(MAKE) $(TARGETS_PROFILE)
 
 release :
-       $(MAKE) sv-release cl-release sdl-release
+       $(MAKE) $(TARGETS_RELEASE)
 
 release-profile :
-       $(MAKE) sv-release-profile cl-release-profile sdl-release-profile
+       $(MAKE) $(TARGETS_RELEASE_PROFILE)
 
 nexuiz :
-       $(MAKE) sv-nexuiz cl-nexuiz sdl-nexuiz
+       $(MAKE) $(TARGETS_NEXUIZ)
 
 cl-debug :
        $(MAKE) bin-debug \
index d6170d28977c27645f71b9987887854670d34916..dae0de50ba070a4f144e6830e47e5fa4da125700 100644 (file)
--- a/mathlib.c
+++ b/mathlib.c
@@ -756,3 +756,12 @@ void BoxFromPoints(vec3_t mins, vec3_t maxs, int numpoints, vec_t *point3f)
        }
 }
 
+// LordHavoc: this has to be done right or you get severe precision breakdown
+int LoopingFrameNumberFromDouble(double t, int loopframes)
+{
+       if (loopframes)
+               return (int)(t - floor(t/loopframes)*loopframes);
+       else
+               return (int)t;
+}
+
index b3a9f7ea3c319b80f01ab78d1c5b09e0eebeac7e..e1c7f647d8eb17f90d1fd9065fc9c48dd432071e 100644 (file)
--- a/mathlib.h
+++ b/mathlib.h
@@ -291,5 +291,7 @@ int Math_atov(const char *s, vec3_t out);
 
 void BoxFromPoints(vec3_t mins, vec3_t maxs, int numpoints, vec_t *point3f);
 
+int LoopingFrameNumberFromDouble(double t, int loopframes);
+
 #endif
 
diff --git a/menu.c b/menu.c
index bb82b8d487529ebe96f703f4e929c7aa821ed1c7..c09abda45607d87d3a67eb22f02c091db70456e1 100644 (file)
--- a/menu.c
+++ b/menu.c
@@ -4515,7 +4515,7 @@ void ModList_RebuildList(void)
 
        stringlistinit(&list);
        listdirectory(&list, fs_basedir, "");
-       stringlistsort(&list);
+       stringlistsort(&list, true);
        modlist_count = 0;
        modlist_numenabled = fs_numgamedirs;
        for (i = 0;i < list.numstrings;i++)
@@ -5015,6 +5015,164 @@ static const char *m_required_func[] = {
 
 static int m_numrequiredfunc = sizeof(m_required_func) / sizeof(char*);
 
+static prvm_required_field_t m_required_fields[] =
+{
+#define PRVM_DECLARE_serverglobalfloat(x)
+#define PRVM_DECLARE_serverglobalvector(x)
+#define PRVM_DECLARE_serverglobalstring(x)
+#define PRVM_DECLARE_serverglobaledict(x)
+#define PRVM_DECLARE_serverglobalfunction(x)
+#define PRVM_DECLARE_clientglobalfloat(x)
+#define PRVM_DECLARE_clientglobalvector(x)
+#define PRVM_DECLARE_clientglobalstring(x)
+#define PRVM_DECLARE_clientglobaledict(x)
+#define PRVM_DECLARE_clientglobalfunction(x)
+#define PRVM_DECLARE_menuglobalfloat(x)
+#define PRVM_DECLARE_menuglobalvector(x)
+#define PRVM_DECLARE_menuglobalstring(x)
+#define PRVM_DECLARE_menuglobaledict(x)
+#define PRVM_DECLARE_menuglobalfunction(x)
+#define PRVM_DECLARE_serverfieldfloat(x)
+#define PRVM_DECLARE_serverfieldvector(x)
+#define PRVM_DECLARE_serverfieldstring(x)
+#define PRVM_DECLARE_serverfieldedict(x)
+#define PRVM_DECLARE_serverfieldfunction(x)
+#define PRVM_DECLARE_clientfieldfloat(x)
+#define PRVM_DECLARE_clientfieldvector(x)
+#define PRVM_DECLARE_clientfieldstring(x)
+#define PRVM_DECLARE_clientfieldedict(x)
+#define PRVM_DECLARE_clientfieldfunction(x)
+#define PRVM_DECLARE_menufieldfloat(x) {ev_float, #x},
+#define PRVM_DECLARE_menufieldvector(x) {ev_vector, #x},
+#define PRVM_DECLARE_menufieldstring(x) {ev_string, #x},
+#define PRVM_DECLARE_menufieldedict(x) {ev_entity, #x},
+#define PRVM_DECLARE_menufieldfunction(x) {ev_function, #x},
+#define PRVM_DECLARE_serverfunction(x)
+#define PRVM_DECLARE_clientfunction(x)
+#define PRVM_DECLARE_menufunction(x)
+#define PRVM_DECLARE_field(x)
+#define PRVM_DECLARE_global(x)
+#define PRVM_DECLARE_function(x)
+#include "prvm_offsets.h"
+#undef PRVM_DECLARE_serverglobalfloat
+#undef PRVM_DECLARE_serverglobalvector
+#undef PRVM_DECLARE_serverglobalstring
+#undef PRVM_DECLARE_serverglobaledict
+#undef PRVM_DECLARE_serverglobalfunction
+#undef PRVM_DECLARE_clientglobalfloat
+#undef PRVM_DECLARE_clientglobalvector
+#undef PRVM_DECLARE_clientglobalstring
+#undef PRVM_DECLARE_clientglobaledict
+#undef PRVM_DECLARE_clientglobalfunction
+#undef PRVM_DECLARE_menuglobalfloat
+#undef PRVM_DECLARE_menuglobalvector
+#undef PRVM_DECLARE_menuglobalstring
+#undef PRVM_DECLARE_menuglobaledict
+#undef PRVM_DECLARE_menuglobalfunction
+#undef PRVM_DECLARE_serverfieldfloat
+#undef PRVM_DECLARE_serverfieldvector
+#undef PRVM_DECLARE_serverfieldstring
+#undef PRVM_DECLARE_serverfieldedict
+#undef PRVM_DECLARE_serverfieldfunction
+#undef PRVM_DECLARE_clientfieldfloat
+#undef PRVM_DECLARE_clientfieldvector
+#undef PRVM_DECLARE_clientfieldstring
+#undef PRVM_DECLARE_clientfieldedict
+#undef PRVM_DECLARE_clientfieldfunction
+#undef PRVM_DECLARE_menufieldfloat
+#undef PRVM_DECLARE_menufieldvector
+#undef PRVM_DECLARE_menufieldstring
+#undef PRVM_DECLARE_menufieldedict
+#undef PRVM_DECLARE_menufieldfunction
+#undef PRVM_DECLARE_serverfunction
+#undef PRVM_DECLARE_clientfunction
+#undef PRVM_DECLARE_menufunction
+#undef PRVM_DECLARE_field
+#undef PRVM_DECLARE_global
+#undef PRVM_DECLARE_function
+};
+
+static int m_numrequiredfields = sizeof(m_required_fields) / sizeof(m_required_fields[0]);
+
+static prvm_required_field_t m_required_globals[] =
+{
+#define PRVM_DECLARE_serverglobalfloat(x)
+#define PRVM_DECLARE_serverglobalvector(x)
+#define PRVM_DECLARE_serverglobalstring(x)
+#define PRVM_DECLARE_serverglobaledict(x)
+#define PRVM_DECLARE_serverglobalfunction(x)
+#define PRVM_DECLARE_clientglobalfloat(x)
+#define PRVM_DECLARE_clientglobalvector(x)
+#define PRVM_DECLARE_clientglobalstring(x)
+#define PRVM_DECLARE_clientglobaledict(x)
+#define PRVM_DECLARE_clientglobalfunction(x)
+#define PRVM_DECLARE_menuglobalfloat(x) {ev_float, #x},
+#define PRVM_DECLARE_menuglobalvector(x) {ev_vector, #x},
+#define PRVM_DECLARE_menuglobalstring(x) {ev_string, #x},
+#define PRVM_DECLARE_menuglobaledict(x) {ev_entity, #x},
+#define PRVM_DECLARE_menuglobalfunction(x) {ev_function, #x},
+#define PRVM_DECLARE_serverfieldfloat(x)
+#define PRVM_DECLARE_serverfieldvector(x)
+#define PRVM_DECLARE_serverfieldstring(x)
+#define PRVM_DECLARE_serverfieldedict(x)
+#define PRVM_DECLARE_serverfieldfunction(x)
+#define PRVM_DECLARE_clientfieldfloat(x)
+#define PRVM_DECLARE_clientfieldvector(x)
+#define PRVM_DECLARE_clientfieldstring(x)
+#define PRVM_DECLARE_clientfieldedict(x)
+#define PRVM_DECLARE_clientfieldfunction(x)
+#define PRVM_DECLARE_menufieldfloat(x)
+#define PRVM_DECLARE_menufieldvector(x)
+#define PRVM_DECLARE_menufieldstring(x)
+#define PRVM_DECLARE_menufieldedict(x)
+#define PRVM_DECLARE_menufieldfunction(x)
+#define PRVM_DECLARE_serverfunction(x)
+#define PRVM_DECLARE_clientfunction(x)
+#define PRVM_DECLARE_menufunction(x)
+#define PRVM_DECLARE_field(x)
+#define PRVM_DECLARE_global(x)
+#define PRVM_DECLARE_function(x)
+#include "prvm_offsets.h"
+#undef PRVM_DECLARE_serverglobalfloat
+#undef PRVM_DECLARE_serverglobalvector
+#undef PRVM_DECLARE_serverglobalstring
+#undef PRVM_DECLARE_serverglobaledict
+#undef PRVM_DECLARE_serverglobalfunction
+#undef PRVM_DECLARE_clientglobalfloat
+#undef PRVM_DECLARE_clientglobalvector
+#undef PRVM_DECLARE_clientglobalstring
+#undef PRVM_DECLARE_clientglobaledict
+#undef PRVM_DECLARE_clientglobalfunction
+#undef PRVM_DECLARE_menuglobalfloat
+#undef PRVM_DECLARE_menuglobalvector
+#undef PRVM_DECLARE_menuglobalstring
+#undef PRVM_DECLARE_menuglobaledict
+#undef PRVM_DECLARE_menuglobalfunction
+#undef PRVM_DECLARE_serverfieldfloat
+#undef PRVM_DECLARE_serverfieldvector
+#undef PRVM_DECLARE_serverfieldstring
+#undef PRVM_DECLARE_serverfieldedict
+#undef PRVM_DECLARE_serverfieldfunction
+#undef PRVM_DECLARE_clientfieldfloat
+#undef PRVM_DECLARE_clientfieldvector
+#undef PRVM_DECLARE_clientfieldstring
+#undef PRVM_DECLARE_clientfieldedict
+#undef PRVM_DECLARE_clientfieldfunction
+#undef PRVM_DECLARE_menufieldfloat
+#undef PRVM_DECLARE_menufieldvector
+#undef PRVM_DECLARE_menufieldstring
+#undef PRVM_DECLARE_menufieldedict
+#undef PRVM_DECLARE_menufieldfunction
+#undef PRVM_DECLARE_serverfunction
+#undef PRVM_DECLARE_clientfunction
+#undef PRVM_DECLARE_menufunction
+#undef PRVM_DECLARE_field
+#undef PRVM_DECLARE_global
+#undef PRVM_DECLARE_function
+};
+
+static int m_numrequiredglobals = sizeof(m_required_globals) / sizeof(m_required_globals[0]);
+
 void MR_SetRouting (qboolean forceold);
 
 void MP_Error(const char *format, ...) DP_FUNC_PRINTF(1);
@@ -5062,9 +5220,9 @@ void MP_KeyEvent (int key, int ascii, qboolean downevent)
        prog->globals.generic[OFS_PARM0] = (float) key;
        prog->globals.generic[OFS_PARM1] = (float) ascii;
        if (downevent)
-               PRVM_ExecuteProgram(prog->funcoffsets.m_keydown,"m_keydown(float key, float ascii) required");
-       else if (prog->funcoffsets.m_keyup)
-               PRVM_ExecuteProgram(prog->funcoffsets.m_keyup,"m_keyup(float key, float ascii) required");
+               PRVM_ExecuteProgram(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;
 }
@@ -5091,7 +5249,7 @@ void MP_Draw (void)
 
        // FIXME: this really shouldnt error out lest we have a very broken refdef state...?
        // or does it kill the server too?
-       PRVM_ExecuteProgram(prog->funcoffsets.m_draw,"m_draw() required");
+       PRVM_ExecuteProgram(PRVM_menufunction(m_draw),"m_draw() required");
 
        PRVM_End;
 
@@ -5107,7 +5265,7 @@ void MP_ToggleMenu(int mode)
        PRVM_SetProg(PRVM_MENUPROG);
 
        prog->globals.generic[OFS_PARM0] = (float) mode;
-       PRVM_ExecuteProgram(prog->funcoffsets.m_toggle,"m_toggle() required");
+       PRVM_ExecuteProgram(PRVM_menufunction(m_toggle),"m_toggle() required");
 
        PRVM_End;
 }
@@ -5116,8 +5274,8 @@ void MP_NewMap(void)
 {
        PRVM_Begin;
        PRVM_SetProg(PRVM_MENUPROG);
-       if (prog->funcoffsets.m_newmap)
-               PRVM_ExecuteProgram(prog->funcoffsets.m_newmap,"m_newmap() required");
+       if (PRVM_menufunction(m_newmap))
+               PRVM_ExecuteProgram(PRVM_menufunction(m_newmap),"m_newmap() required");
        PRVM_End;
 }
 
@@ -5126,7 +5284,7 @@ void MP_Shutdown (void)
        PRVM_Begin;
        PRVM_SetProg(PRVM_MENUPROG);
 
-       PRVM_ExecuteProgram(prog->funcoffsets.m_shutdown,"m_shutdown() required");
+       PRVM_ExecuteProgram(PRVM_menufunction(m_shutdown),"m_shutdown() required");
 
        // reset key_dest
        key_dest = key_game;
@@ -5142,7 +5300,6 @@ void MP_Init (void)
        PRVM_Begin;
        PRVM_InitProg(PRVM_MENUPROG);
 
-       prog->headercrc = M_PROGHEADER_CRC;
        prog->edictprivate_size = 0; // no private struct used
        prog->name = M_NAME;
        prog->num_edicts = 1;
@@ -5158,7 +5315,7 @@ void MP_Init (void)
        // allocate the mempools
        prog->progs_mempool = Mem_AllocPool(M_PROG_FILENAME, 0, NULL);
 
-       PRVM_LoadProgs(M_PROG_FILENAME, m_numrequiredfunc, m_required_func, 0, NULL, 0, NULL);
+       PRVM_LoadProgs(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
@@ -5166,7 +5323,7 @@ void MP_Init (void)
        in_client_mouse = true;
 
        // call the prog init
-       PRVM_ExecuteProgram(prog->funcoffsets.m_init,"m_init() required");
+       PRVM_ExecuteProgram(PRVM_menufunction(m_init),"m_init() required");
 
        PRVM_End;
 }
index a5510be722631f7b7d196e555dff081c8027ad1f..d21ba627aec464dc0e7fa359d06e169319b5bb9f 100644 (file)
@@ -13,6 +13,12 @@ typedef struct meshqueue_s
 }
 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;
 meshqueue_t *mqt_array;
@@ -53,43 +59,62 @@ void R_MeshQueue_AddTransparent(const vec3_t center, void (*callback)(const enti
 
 void R_MeshQueue_RenderTransparent(void)
 {
-       int i;
-       int hashdist;
-       int batchnumsurfaces;
+       int i, hashindex, maxhashindex, batchnumsurfaces;
        float distscale;
        const entity_render_t *ent;
        const rtlight_t *rtlight;
        void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfaceindices);
+       int batchsurfaceindex[MESHQUEUE_TRANSPARENT_BATCHSIZE];
        meshqueue_t *mqt;
-       static meshqueue_t *hash[4096], **hashpointer[4096];
-       int batchsurfaceindex[256];
+
        if (!mqt_count)
                return;
-       memset(hash, 0, sizeof(hash));
-       for (i = 0;i < 4096;i++)
-               hashpointer[i] = &hash[i];
-       distscale = 4095.0f / max(mqt_viewmaxdist, 4095);
-       for (i = 0, mqt = mqt_array;i < mqt_count;i++, mqt++)
+
+       // 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));
+
+       // update hash array
+       if (trans_sortarraysize != r_transparent_sortarraysize.integer)
        {
-               // generate index
-               hashdist = (int) (mqt->dist * distscale);
-               hashdist = bound(0, hashdist, 4095);
+               trans_sortarraysize = r_transparent_sortarraysize.integer;
+               if (trans_hash)
+                       Mem_Free(trans_hash);
+               trans_hash = (meshqueue_t **)Mem_Alloc(cls.permanentmempool, sizeof(trans_hash) * trans_sortarraysize); 
+               if (trans_hashpointer)
+                       Mem_Free(trans_hashpointer);
+               trans_hashpointer = (meshqueue_t ***)Mem_Alloc(cls.permanentmempool, sizeof(trans_hashpointer) * trans_sortarraysize); 
+       }
+
+       // build index
+       memset(trans_hash, 0, sizeof(trans_hash) * trans_sortarraysize);
+       for (i = 0; i < trans_sortarraysize; i++)
+               trans_hashpointer[i] = &trans_hash[i];
+       distscale = (trans_sortarraysize - 1) / min(mqt_viewmaxdist, r_transparent_sortmaxdist.integer);
+       maxhashindex = trans_sortarraysize - 1;
+       for (i = 0, mqt = mqt_array; i < mqt_count; i++, mqt++)
+       {
+               hashindex = bound(0, (int)(min(mqt->dist, r_transparent_sortmaxdist.integer) * distscale), maxhashindex);
                // link to tail of hash chain (to preserve render order)
                mqt->next = NULL;
-               *hashpointer[hashdist] = mqt;
-               hashpointer[hashdist] = &mqt->next;
+               *trans_hashpointer[hashindex] = mqt;
+               trans_hashpointer[hashindex] = &mqt->next;
        }
        callback = NULL;
        ent = NULL;
        rtlight = NULL;
        batchnumsurfaces = 0;
-       for (i = 4095;i >= 0;i--)
+
+       // draw
+       for (i = maxhashindex; i >= 0; i--)
        {
-               if (hash[i])
+               if (trans_hash[i])
                {
-                       for (mqt = hash[i];mqt;mqt = mqt->next)
+                       for (mqt = trans_hash[i]; mqt; mqt = mqt->next)
                        {
-                               if (ent != mqt->ent || rtlight != mqt->rtlight || callback != mqt->callback || batchnumsurfaces >= 256)
+                               if (ent != mqt->ent || rtlight != mqt->rtlight || callback != mqt->callback || batchnumsurfaces >= MESHQUEUE_TRANSPARENT_BATCHSIZE)
                                {
                                        if (batchnumsurfaces)
                                                callback(ent, rtlight, batchnumsurfaces, batchsurfaceindex);
index 8e5b36e77702d6b77c47cb4ff00c3c39ec8e23ca..f54c4ce39e3e0320d12f2a230ebf4dd38ff39451 100644 (file)
@@ -2,6 +2,9 @@
 #ifndef MESHQUEUE_H
 #define MESHQUEUE_H
 
+// VorteX: seems this value is hardcoded in other several defines as it's changing makes mess
+#define MESHQUEUE_TRANSPARENT_BATCHSIZE 256
+
 void R_MeshQueue_BeginScene(void);
 void R_MeshQueue_AddTransparent(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);
index 98b0673f7806d382f7d31d85aec07f3d5dbe5a97..214c960d6a606600ebb53162d0387fdab1ebbcf9 100644 (file)
@@ -785,7 +785,7 @@ static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *ski
        if (texture->currentskinframe->hasalpha)
                texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
        texture->currentmaterialflags = texture->basematerialflags;
-       texture->offsetmapping = OFFSETMAPPING_OFF;
+       texture->offsetmapping = OFFSETMAPPING_DEFAULT;
        texture->offsetscale = 1;
        texture->specularscalemod = 1;
        texture->specularpowermod = 1;
@@ -1054,7 +1054,9 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
        loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
        if (r_enableshadowvolumes.integer)
+       {
                loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
+       }
        Mod_MDL_LoadFrames (startframes, numverts, vertremap);
        if (loadmodel->surfmesh.data_neighbor3i)
                Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
@@ -1282,7 +1284,9 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]);
        loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
        if (r_enableshadowvolumes.integer)
+       {
                loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
+       }
 
        loadmodel->synctype = ST_RAND;
 
@@ -1563,11 +1567,15 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
        loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
        if (r_enableshadowvolumes.integer)
+       {
                loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
+       }
        loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]);
        loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t);
        if (meshvertices <= 65536)
+       {
                loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]);
+       }
 
        meshvertices = 0;
        meshtriangles = 0;
@@ -1820,7 +1828,9 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->surfmesh.num_triangles = meshtriangles;
        loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
        if (r_enableshadowvolumes.integer)
+       {
                loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
+       }
        loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
        loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
        loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
@@ -1830,7 +1840,9 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->surfmesh.num_blends = 0;
        loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
        if (loadmodel->surfmesh.num_vertices <= 65536)
+       {
                loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
+       }
        loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
        loadmodel->surfmesh.data_blendweights = NULL;
 
@@ -2127,7 +2139,9 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->surfmesh.num_triangles = meshtriangles;
        loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
        if (r_enableshadowvolumes.integer)
+       {
                loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
+       }
        loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
        loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
        loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
@@ -2140,7 +2154,9 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        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));
 
@@ -2765,7 +2781,9 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t);
        loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
        if (r_enableshadowvolumes.integer)
+       {
                loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]);
+       }
        loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
        loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
        loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
@@ -2778,7 +2796,9 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->surfmesh.num_blends = 0;
        loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short);
        if (loadmodel->surfmesh.num_vertices <= 65536)
+       {
                loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]);
+       }
        loadmodel->data_poses6s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[6]);
        loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t));
 
@@ -2950,31 +2970,48 @@ 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;
-       iqmjoint_t *joint;
-       iqmanim_t *anim;
-       iqmpose_t *pose;
-       iqmmesh_t *mesh;
-       iqmbounds_t *bounds;
-       iqmvertexarray_t *va;
-       unsigned short *framedata;
        float biggestorigin;
-       const int *inelements;
+       const unsigned int *inelements;
        int *outelements;
+       const int *inneighbors;
+       int *outneighbors;
        float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector;
+       // 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 unsigned char *vblendindexes = NULL;
+       const unsigned char *vblendweights = NULL;
+       const unsigned short *framedata = NULL;
+       // temporary memory allocations (because the data in the file may be misaligned)
+       iqmanim_t *anims = NULL;
+       iqmbounds_t *bounds = NULL;
+       iqmjoint1_t *joint1 = NULL;
+       iqmjoint_t *joint = NULL;
+       iqmmesh_t *meshes = NULL;
+       iqmpose1_t *pose1 = NULL;
+       iqmpose_t *pose = NULL;
+       iqmvertexarray_t *vas = NULL;
 
        pbase = (unsigned char *)buffer;
        pend = (unsigned char *)bufferend;
-       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)
-               Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 models are currently supported (name = %s)", loadmodel->name);
+       if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2)
+               Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name);
 
        loadmodel->modeldatatypestring = "IQM";
 
@@ -2982,114 +3019,136 @@ 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)
+       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;
        }
-       if (header->num_frames < 1 || header->num_anims < 1)
+
+       if (header.version == 1)
        {
-               Con_Printf("%s has no animations\n", loadmodel->name);
-               return;
+               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 (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)
+       else
+       {
+               if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend ||
+                       pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend)
+               {
+                       Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
+                       return;
+               }
+       }
+       if (pbase + header.ofs_text + header.num_text > pend ||
+               pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend ||
+               pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend ||
+               pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend ||
+               (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) ||
+               pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend ||
+               pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend ||
+               (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) ||
+               pbase + header.ofs_comment + header.num_comment > pend)
        {
                Con_Printf("%s has invalid size or offset information\n", loadmodel->name);
                return;
        }
 
-       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;
                }
        }
-       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;
@@ -3112,18 +3171,18 @@ 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;
 
-       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]) + (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);
@@ -3131,7 +3190,9 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->surfmesh.num_triangles = meshtriangles;
        loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]);
        if (r_enableshadowvolumes.integer)
+       {
                loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]);
+       }
        loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]);
        loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]);
        loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]);
@@ -3141,12 +3202,18 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        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++)
        {
@@ -3157,138 +3224,276 @@ void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        }
 
        // load the bone info
-       joint = (iqmjoint_t *) (pbase + header->ofs_joints);
-       for (i = 0;i < loadmodel->num_bones;i++)
+       if (header.version == 1)
        {
-               matrix4x4_t relbase, relinvbase, pinvbase, invbase;
-               joint[i].name = LittleLong(joint[i].name);
-               joint[i].parent = LittleLong(joint[i].parent);
-               for (j = 0;j < 3;j++)
+               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++)
                {
-                       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]);
+                       matrix4x4_t relbase, relinvbase, pinvbase, invbase;
+                       joint1[i].name = LittleLong(injoint1[i].name);
+                       joint1[i].parent = LittleLong(injoint1[i].parent);
+                       for (j = 0;j < 3;j++)
+                       {
+                               joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]);
+                               joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]);
+                               joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]);
+                       }
+                       strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name));
+                       loadmodel->data_bones[i].parent = joint1[i].parent;
+                       if (loadmodel->data_bones[i].parent >= i)
+                               Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
+                       Matrix4x4_FromDoom3Joint(&relbase, joint1[i].origin[0], joint1[i].origin[1], joint1[i].origin[2], joint1[i].rotation[0], joint1[i].rotation[1], joint1[i].rotation[2]);
+                       Matrix4x4_Invert_Simple(&relinvbase, &relbase);
+                       if (loadmodel->data_bones[i].parent >= 0)
+                       {
+                               Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
+                               Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
+                               Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
+                       }
+                       else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
                }
-               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);
-               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)
+       }
+       else
+       {
+               iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints);
+               if (header.num_joints)
+                       joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t));
+               for (i = 0;i < loadmodel->num_bones;i++)
                {
-                       Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
-                       Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
-                       Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
-               }       
-               else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
+                       matrix4x4_t relbase, relinvbase, pinvbase, invbase;
+                       joint[i].name = LittleLong(injoint[i].name);
+                       joint[i].parent = LittleLong(injoint[i].parent);
+                       for (j = 0;j < 3;j++)
+                       {
+                               joint[i].origin[j] = LittleFloat(injoint[i].origin[j]);
+                               joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]);
+                               joint[i].scale[j] = LittleFloat(injoint[i].scale[j]);
+                       }
+                       joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]);
+                       strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name));
+                       loadmodel->data_bones[i].parent = joint[i].parent;
+                       if (loadmodel->data_bones[i].parent >= i)
+                               Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i);
+                       if (joint[i].rotation[3] > 0)
+                               Vector4Negate(joint[i].rotation, joint[i].rotation);
+                       Vector4Normalize2(joint[i].rotation, joint[i].rotation);
+                       Matrix4x4_FromDoom3Joint(&relbase, joint[i].origin[0], joint[i].origin[1], joint[i].origin[2], joint[i].rotation[0], joint[i].rotation[1], joint[i].rotation[2]);
+                       Matrix4x4_Invert_Simple(&relinvbase, &relbase);
+                       if (loadmodel->data_bones[i].parent >= 0)
+                       {
+                               Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent);
+                               Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase);
+                               Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i);
+                       }       
+                       else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i);
+               }
        }
 
        // set up the animscenes based on the anims
-       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;
-       }
-       
-       pose = (iqmpose_t *) (pbase + header->ofs_poses);
+       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;
+       }
+
        biggestorigin = 0;
-       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].channeloffset[0] = LittleFloat(pose[i].channeloffset[0]);
-               pose[i].channeloffset[1] = LittleFloat(pose[i].channeloffset[1]);
-               pose[i].channeloffset[2] = LittleFloat(pose[i].channeloffset[2]);       
-               pose[i].channeloffset[3] = LittleFloat(pose[i].channeloffset[3]);
-               pose[i].channeloffset[4] = LittleFloat(pose[i].channeloffset[4]);
-               pose[i].channeloffset[5] = LittleFloat(pose[i].channeloffset[5]);
-               pose[i].channeloffset[6] = LittleFloat(pose[i].channeloffset[6]);
-               pose[i].channeloffset[7] = LittleFloat(pose[i].channeloffset[7]);
-               pose[i].channeloffset[8] = LittleFloat(pose[i].channeloffset[8]);
-               pose[i].channelscale[0] = LittleFloat(pose[i].channelscale[0]);
-               pose[i].channelscale[1] = LittleFloat(pose[i].channelscale[1]);
-               pose[i].channelscale[2] = LittleFloat(pose[i].channelscale[2]);
-               pose[i].channelscale[3] = LittleFloat(pose[i].channelscale[3]);
-               pose[i].channelscale[4] = LittleFloat(pose[i].channelscale[4]);
-               pose[i].channelscale[5] = LittleFloat(pose[i].channelscale[5]);
-               pose[i].channelscale[6] = LittleFloat(pose[i].channelscale[6]);
-               pose[i].channelscale[7] = LittleFloat(pose[i].channelscale[7]);
-               pose[i].channelscale[8] = LittleFloat(pose[i].channelscale[8]);
-               f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
-               f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
-               f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
-               f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
-               f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
-               f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
+       if (header.version == 1)
+       {
+               iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses);
+               if (header.num_poses)
+                       pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t));
+               for (i = 0;i < (int)header.num_poses;i++)
+               {
+                       float f;
+                       pose1[i].parent = LittleLong(inpose1[i].parent);
+                       pose1[i].channelmask = LittleLong(inpose1[i].channelmask);
+                       for (j = 0;j < 9;j++)
+                       {
+                               pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]);
+                               pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]);
+                       }
+                       f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
+                       f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
+                       f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
+                       f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
+                       f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
+                       f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
+               }
+               if (header.num_frames <= 0)
+               {
+                       for (i = 0;i < loadmodel->num_bones;i++)
+                       {
+                               float f;
+                               f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f);
+                               f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f);
+                               f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f);
+                       }
+               }
+       }
+       else
+       {
+               iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses);
+               if (header.num_poses)
+                       pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t));
+               for (i = 0;i < (int)header.num_poses;i++)
+               {
+                       float f;
+                       pose[i].parent = LittleLong(inpose[i].parent);
+                       pose[i].channelmask = LittleLong(inpose[i].channelmask);
+                       for (j = 0;j < 10;j++)
+                       {
+                               pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]);
+                               pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]);
+                       }
+                       f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f);
+                       f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f);
+                       f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f);
+                       f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f);
+                       f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f);
+                       f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f);
+               }
+               if (header.num_frames <= 0)
+               {
+                       for (i = 0;i < loadmodel->num_bones;i++)
+                       {
+                               float f;
+                               f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f);
+                               f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f);
+                               f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f);
+                       }
+               }
        }
        loadmodel->num_posescale = biggestorigin / 32767.0f;
        loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale;
 
        // load the pose data
-       framedata = (unsigned short *) (pbase + header->ofs_frames);
-       for (i = 0, k = 0;i < (int)header->num_frames;i++)      
+       // this unaligned memory access is safe (LittleShort reads as bytes)
+       framedata = (const unsigned short *)(pbase + header.ofs_frames);
+       if (header.version == 1)
+       {
+               for (i = 0, k = 0;i < (int)header.num_frames;i++)
+               {
+                       for (j = 0;j < (int)header.num_poses;j++, k++)
+                       {
+                               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));
+                               loadmodel->data_poses6s[k*6 + 2] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[2] + (pose1[j].channelmask&4 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[2] : 0));
+                               loadmodel->data_poses6s[k*6 + 3] = 32767.0f * (pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0));
+                               loadmodel->data_poses6s[k*6 + 4] = 32767.0f * (pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0));
+                               loadmodel->data_poses6s[k*6 + 5] = 32767.0f * (pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0));
+                               // skip scale data for now
+                               if(pose1[j].channelmask&64) framedata++;
+                               if(pose1[j].channelmask&128) framedata++;
+                               if(pose1[j].channelmask&256) framedata++;
+                       }
+               }
+               if (header.num_frames <= 0)
+               {
+                       for (i = 0;i < loadmodel->num_bones;i++)
+                       {
+                               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 (j = 0;j < (int)header->num_poses;j++, k++)
+               for (i = 0, k = 0;i < (int)header.num_frames;i++)       
                {
-                       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));
-                       loadmodel->data_poses6s[k*6 + 1] = loadmodel->num_poseinvscale * (pose[j].channeloffset[1] + (pose[j].channelmask&2 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[1] : 0));
-                       loadmodel->data_poses6s[k*6 + 2] = loadmodel->num_poseinvscale * (pose[j].channeloffset[2] + (pose[j].channelmask&4 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[2] : 0));
-                       loadmodel->data_poses6s[k*6 + 3] = 32767.0f * (pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0));
-                       loadmodel->data_poses6s[k*6 + 4] = 32767.0f * (pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0));
-                       loadmodel->data_poses6s[k*6 + 5] = 32767.0f * (pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0));
-                       // skip scale data for now
-                       if(pose[j].channelmask&64) framedata++;
-                       if(pose[j].channelmask&128) framedata++;
-                       if(pose[j].channelmask&256) framedata++;
+                       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));
+                               loadmodel->data_poses6s[k*6 + 1] = loadmodel->num_poseinvscale * (pose[j].channeloffset[1] + (pose[j].channelmask&2 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[1] : 0));
+                               loadmodel->data_poses6s[k*6 + 2] = loadmodel->num_poseinvscale * (pose[j].channeloffset[2] + (pose[j].channelmask&4 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[2] : 0));
+                               rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0);
+                               rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0);
+                               rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0);
+                               rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0);
+                               if (rot[3] > 0)
+                                       Vector4Negate(rot, rot);
+                               Vector4Normalize2(rot, rot);
+                               loadmodel->data_poses6s[k*6 + 3] = 32767.0f * rot[0];
+                               loadmodel->data_poses6s[k*6 + 4] = 32767.0f * rot[1];
+                               loadmodel->data_poses6s[k*6 + 5] = 32767.0f * rot[2];
+                               // skip scale data for now
+                               if(pose[j].channelmask&128) framedata++;
+                               if(pose[j].channelmask&256) framedata++;
+                               if(pose[j].channelmask&512) framedata++;
+                       }
+               }
+               if (header.num_frames <= 0)
+               {
+                       for (i = 0;i < loadmodel->num_bones;i++)
+                       {
+                               loadmodel->data_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;
@@ -3301,35 +3506,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]);
@@ -3339,7 +3547,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]);
@@ -3347,10 +3556,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]);
@@ -3360,12 +3570,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]);
@@ -3381,36 +3592,40 @@ 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)
        {
-               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);
+               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);
+               }
        }
 
        // 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);
@@ -3424,9 +3639,9 @@ 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;
@@ -3440,6 +3655,9 @@ 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;
+}
index 7f7a2e1461f482b1c337c536dbfdddcdd2467f34..50e961e3a0375c6a34084ca5ae8d8fbad273fb70 100644 (file)
@@ -38,6 +38,7 @@ cvar_t r_subdivisions_collision_tolerance = {0, "r_subdivisions_collision_tolera
 cvar_t r_subdivisions_collision_mintess = {0, "r_subdivisions_collision_mintess", "0", "minimum number of subdivisions (values above 0 will smooth curves that don't need it)"};
 cvar_t r_subdivisions_collision_maxtess = {0, "r_subdivisions_collision_maxtess", "1024", "maximum number of subdivisions (prevents curves beyond a certain detail level, limits smoothing)"};
 cvar_t r_subdivisions_collision_maxvertices = {0, "r_subdivisions_collision_maxvertices", "4225", "maximum vertices allowed per subdivided curve"};
+cvar_t r_trippy = {0, "r_trippy", "0", "easter egg"};
 cvar_t mod_noshader_default_offsetmapping = {CVAR_SAVE, "mod_noshader_default_offsetmapping", "1", "use offsetmapping by default on all surfaces that are not using q3 shader files"};
 cvar_t mod_q3bsp_curves_collisions = {0, "mod_q3bsp_curves_collisions", "1", "enables collisions with curves (SLOW)"};
 cvar_t mod_q3bsp_curves_collisions_stride = {0, "mod_q3bsp_curves_collisions_stride", "16", "collisions against curves: optimize performance by doing a combined collision check for this triangle amount first (-1 avoids any box tests)"};
@@ -75,6 +76,7 @@ void Mod_BrushInit(void)
        Cvar_RegisterVariable(&r_subdivisions_collision_mintess);
        Cvar_RegisterVariable(&r_subdivisions_collision_maxtess);
        Cvar_RegisterVariable(&r_subdivisions_collision_maxvertices);
+       Cvar_RegisterVariable(&r_trippy);
        Cvar_RegisterVariable(&mod_noshader_default_offsetmapping);
        Cvar_RegisterVariable(&mod_q3bsp_curves_collisions);
        Cvar_RegisterVariable(&mod_q3bsp_curves_collisions_stride);
@@ -1578,8 +1580,8 @@ void R_Q1BSP_LoadSplitSky (unsigned char *src, int width, int height, int bytesp
                }
        }
 
-       loadmodel->brush.solidskyskinframe = R_SkinFrame_LoadInternalBGRA("sky_solidtexture", 0         , (unsigned char *) solidpixels, w, h, bytesperpixel == 4 && r_texture_sRGB_skybox.integer);
-       loadmodel->brush.alphaskyskinframe = R_SkinFrame_LoadInternalBGRA("sky_alphatexture", TEXF_ALPHA, (unsigned char *) alphapixels, w, h, bytesperpixel == 4 && r_texture_sRGB_skybox.integer);
+       loadmodel->brush.solidskyskinframe = R_SkinFrame_LoadInternalBGRA("sky_solidtexture", 0         , (unsigned char *) solidpixels, w, h, vid.sRGB3D);
+       loadmodel->brush.alphaskyskinframe = R_SkinFrame_LoadInternalBGRA("sky_alphatexture", TEXF_ALPHA, (unsigned char *) alphapixels, w, h, vid.sRGB3D);
        Mem_Free(solidpixels);
        Mem_Free(alphapixels);
 }
@@ -1657,7 +1659,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l)
                tx->reflectfactor = 1;
                Vector4Set(tx->reflectcolor4f, 1, 1, 1, 1);
                tx->r_water_wateralpha = 1;
-               tx->offsetmapping = OFFSETMAPPING_OFF;
+               tx->offsetmapping = OFFSETMAPPING_DEFAULT;
                tx->offsetscale = 1;
                tx->specularscalemod = 1;
                tx->specularpowermod = 1;
@@ -1770,9 +1772,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, r_texture_sRGB_skin_diffuse.integer != 0, NULL);
+                               data = loadimagepixelsbgra(gamemode == GAME_TENEBRAE ? tx->name : va("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, r_texture_sRGB_skin_diffuse.integer != 0, NULL);
+                                       data = loadimagepixelsbgra(gamemode == GAME_TENEBRAE ? tx->name : va("textures/%s", tx->name), false, false, false, NULL);
                                if (data && image_width == image_height * 2)
                                {
                                        R_Q1BSP_LoadSplitSky(data, image_width, image_height, 4);
@@ -1786,6 +1788,8 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l)
                                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);
                                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);
+                               if (skinframe)
+                                       tx->offsetmapping = OFFSETMAPPING_DEFAULT; // allow offsetmapping on external textures without a q3 shader
                                if (!skinframe)
                                {
                                        // did not find external texture, load it from the bsp or wad3
@@ -1814,43 +1818,44 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l)
                                if (skinframe)
                                        tx->skinframes[0] = skinframe;
                        }
-
-                       tx->basematerialflags = MATERIALFLAG_WALL;
-                       if (tx->name[0] == '*')
-                       {
-                               // LordHavoc: some turbulent textures should not be affected by wateralpha
-                               if (!strncmp(tx->name, "*glassmirror", 12)) // Tenebrae
-                               {
-                                       // replace the texture with transparent black
-                                       tx->skinframes[0] = R_SkinFrame_LoadInternalBGRA(tx->name, TEXF_MIPMAP | TEXF_ALPHA, zerotrans, 1, 1, false);
-                                       tx->basematerialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_REFLECTION;
-                               }
-                               else if (!strncmp(tx->name,"*lava",5)
-                                || !strncmp(tx->name,"*teleport",9)
-                                || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
-                                       tx->basematerialflags |= MATERIALFLAG_WATERSCROLL | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_NOSHADOW;
-                               else
-                                       tx->basematerialflags |= MATERIALFLAG_WATERSCROLL | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_NOSHADOW | MATERIALFLAG_WATERALPHA | MATERIALFLAG_WATERSHADER;
-                               if (tx->skinframes[0] && tx->skinframes[0]->hasalpha)
-                                       tx->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
-                       }
+                       // LordHavoc: some Tenebrae textures get replaced by black
+                       if (!strncmp(tx->name, "*glassmirror", 12)) // Tenebrae
+                               tx->skinframes[0] = R_SkinFrame_LoadInternalBGRA(tx->name, TEXF_MIPMAP | TEXF_ALPHA, zerotrans, 1, 1, false);
                        else if (!strncmp(tx->name, "mirror", 6)) // Tenebrae
-                       {
-                               // replace the texture with black
                                tx->skinframes[0] = R_SkinFrame_LoadInternalBGRA(tx->name, 0, zeroopaque, 1, 1, false);
-                               tx->basematerialflags |= MATERIALFLAG_REFLECTION;
-                       }
-                       else if (!strncmp(tx->name, "sky", 3))
-                               tx->basematerialflags = MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW;
-                       else if (!strcmp(tx->name, "caulk"))
-                               tx->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
-                       else if (tx->skinframes[0] && tx->skinframes[0]->hasalpha)
-                               tx->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
+               }
 
-                       // start out with no animation
-                       tx->currentframe = tx;
-                       tx->currentskinframe = tx->skinframes[0];
+               tx->basematerialflags = MATERIALFLAG_WALL;
+               if (tx->name[0] == '*')
+               {
+                       // LordHavoc: some turbulent textures should not be affected by wateralpha
+                       if (!strncmp(tx->name, "*glassmirror", 12)) // Tenebrae
+                               tx->basematerialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_REFLECTION;
+                       else if (!strncmp(tx->name,"*lava",5)
+                        || !strncmp(tx->name,"*teleport",9)
+                        || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
+                               tx->basematerialflags |= MATERIALFLAG_WATERSCROLL | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_NOSHADOW;
+                       else
+                               tx->basematerialflags |= MATERIALFLAG_WATERSCROLL | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_NOSHADOW | MATERIALFLAG_WATERALPHA | MATERIALFLAG_WATERSHADER;
+                       if (tx->skinframes[0] && tx->skinframes[0]->hasalpha)
+                               tx->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
                }
+               else if (!strncmp(tx->name, "mirror", 6)) // Tenebrae
+               {
+                       // replace the texture with black
+                       tx->basematerialflags |= MATERIALFLAG_REFLECTION;
+               }
+               else if (!strncmp(tx->name, "sky", 3))
+                       tx->basematerialflags = MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW;
+               else if (!strcmp(tx->name, "caulk"))
+                       tx->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
+               else if (tx->skinframes[0] && tx->skinframes[0]->hasalpha)
+                       tx->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
+
+               // start out with no animation
+               tx->currentframe = tx;
+               tx->currentskinframe = tx->skinframes[0];
+               tx->currentmaterialflags = tx->basematerialflags;
        }
 
        // sequence the animations
@@ -3567,7 +3572,7 @@ static int Mod_Q1BSP_FatPVS(dp_model_t *model, const vec3_t org, vec_t radius, u
 {
        int bytes = model->brush.num_pvsclusterbytes;
        bytes = min(bytes, pvsbufferlength);
-       if (r_novis.integer || !model->brush.num_pvsclusters || !Mod_Q1BSP_GetPVS(model, org))
+       if (r_novis.integer || r_trippy.integer || !model->brush.num_pvsclusters || !Mod_Q1BSP_GetPVS(model, org))
        {
                memset(pvsbuffer, 0xFF, bytes);
                return bytes;
@@ -3695,7 +3700,10 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
 
        mod->soundfromcenter = true;
        mod->TraceBox = Mod_Q1BSP_TraceBox;
-       mod->TraceLine = Mod_Q1BSP_TraceLineAgainstSurfaces; // LordHavoc: use the surface-hitting version of TraceLine in all cases
+       if (sv_gameplayfix_q1bsptracelinereportstexture.integer)
+               mod->TraceLine = Mod_Q1BSP_TraceLineAgainstSurfaces; // LordHavoc: use the surface-hitting version of TraceLine in all cases
+       else
+               mod->TraceLine = Mod_Q1BSP_TraceLine;
        mod->TracePoint = Mod_Q1BSP_TracePoint;
        mod->PointSuperContents = Mod_Q1BSP_PointSuperContents;
        mod->TraceLineAgainstSurfaces = Mod_Q1BSP_TraceLineAgainstSurfaces;
@@ -4972,7 +4980,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++)
index cec784638b5c7b608c11b92476399fe4f71b83bd..906594ad4c893db4dc623ca2e12c10151c435070 100644 (file)
@@ -116,6 +116,8 @@ mplane_t;
 #define MATERIALFLAG_TRANSDEPTH 33554432
 // like refraction, but doesn't distort etc.
 #define MATERIALFLAG_CAMERA 67108864
+// disable rtlight on surface, use R_LightPoint instead
+#define MATERIALFLAG_NORTLIGHT 134217728
 // combined mask of all attributes that require depth sorted rendering
 #define MATERIALFLAGMASK_DEPTHSORTED (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)
 // combined mask of all attributes that cause some sort of transparency
index a56829b4a1ddfc24f80a9aa9962fef3f25e87f8c..1dbb940c65b98ccafea62b95cf153594a0f57717 100644 (file)
@@ -57,20 +57,36 @@ typedef struct iqmtriangle_s
 }
 iqmtriangle_t;
 
-typedef struct iqmjoint_s
+typedef struct iqmjoint1_s
 {
        unsigned int name;
        signed int parent;
        float origin[3], rotation[3], scale[3];
 }
+iqmjoint1_t;
+
+typedef struct iqmjoint_s
+{
+       unsigned int name;
+       signed int parent;
+       float origin[3], rotation[4], scale[3];
+}
 iqmjoint_t;
 
-typedef struct iqmpose_s
+typedef struct iqmpose1_s
 {
        signed int parent;
        unsigned int channelmask;
        float channeloffset[9], channelscale[9];
 }
+iqmpose1_t;
+
+typedef struct iqmpose_s
+{
+       signed int parent;
+       unsigned int channelmask;
+       float channeloffset[10], channelscale[10];
+}
 iqmpose_t;
 
 typedef struct iqmanim_s
index 9ea0751a5a981d366d728029b1351fd0c35809df..0fc772824c4a23e4da119883ab14376c9a31c09c 100644 (file)
@@ -2073,6 +2073,8 @@ void Mod_LoadQ3Shaders(void)
                                        shader.dpshadow = true;
                                else if (!strcasecmp(parameter[0], "dpnoshadow"))
                                        shader.dpnoshadow = true;
+                               else if (!strcasecmp(parameter[0], "dpnortlight"))
+                                       shader.dpnortlight = true;
                                else if (!strcasecmp(parameter[0], "dpreflectcube"))
                                        strlcpy(shader.dpreflectcube, parameter[1], sizeof(shader.dpreflectcube));
                                else if (!strcasecmp(parameter[0], "dpmeshcollisions"))
@@ -2153,6 +2155,10 @@ void Mod_LoadQ3Shaders(void)
                                {
                                        shader.specularpowermod = atof(parameter[1]);
                                }
+                               else if (!strcasecmp(parameter[0], "dprtlightambient") && numparameters >= 2)
+                               {
+                                       shader.rtlightambient = atof(parameter[1]);
+                               }
                                else if (!strcasecmp(parameter[0], "dpoffsetmapping") && numparameters >= 3)
                                {
                                        if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "off"))
@@ -2420,6 +2426,8 @@ nothing                GL_ZERO GL_ONE
                        texture->basematerialflags &= ~MATERIALFLAG_NOSHADOW;
                if (shader->dpnoshadow)
                        texture->basematerialflags |= MATERIALFLAG_NOSHADOW;
+               if (shader->dpnortlight)
+                       texture->basematerialflags |= MATERIALFLAG_NORTLIGHT;
                memcpy(texture->deforms, shader->deforms, sizeof(texture->deforms));
                texture->reflectmin = shader->reflectmin;
                texture->reflectmax = shader->reflectmax;
@@ -2433,6 +2441,7 @@ nothing                GL_ZERO GL_ONE
                texture->offsetscale = shader->offsetscale;
                texture->specularscalemod = shader->specularscalemod;
                texture->specularpowermod = shader->specularpowermod;
+               texture->rtlightambient = shader->rtlightambient;
                if (shader->dpreflectcube[0])
                        texture->reflectcubetexture = R_GetCubemap(shader->dpreflectcube);
 
@@ -2521,6 +2530,7 @@ nothing                GL_ZERO GL_ONE
                if(cls.state == ca_dedicated)
                {
                        texture->skinframes[0] = NULL;
+                       success = false;
                }
                else
                {
index b79c1330fe0999c77808a46531ca390b5a137e25..8b73377e53f1c6ce1fae104337d6bf13858e6b99 100644 (file)
@@ -445,6 +445,7 @@ typedef struct q3shaderinfo_s
        // dp-specific additions:
 
        // shadow control
+       qboolean dpnortlight;
        qboolean dpshadow;
        qboolean dpnoshadow;
 
@@ -474,6 +475,9 @@ typedef struct q3shaderinfo_s
        // gloss
        float specularscalemod;
        float specularpowermod;
+
+       // rtlightning ambient addition
+       float rtlightambient;
 #define Q3SHADERINFO_COMPARE_END specularpowermod
 }
 q3shaderinfo_t;
@@ -612,6 +616,9 @@ typedef struct texture_s
        // gloss
        float specularscalemod;
        float specularpowermod;
+
+       // diffuse and ambient
+       float rtlightambient;
 }
  texture_t;
 
@@ -1098,13 +1105,6 @@ qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qbool
 extern cvar_t r_mipskins;
 extern cvar_t r_mipnormalmaps;
 
-typedef struct skeleton_s
-{
-       const dp_model_t *model;
-       matrix4x4_t *relativetransforms;
-}
-skeleton_t;
-
 typedef struct skinfileitem_s
 {
        struct skinfileitem_s *next;
index 3588c61dd088f4deb0bf49119bc2f3d949b520c6..4dc97dfb97c84ce4b16e8bab4cc1682b2e504d06 100644 (file)
@@ -28,6 +28,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 cvar_t r_mipsprites = {CVAR_SAVE, "r_mipsprites", "1", "mipmaps sprites so they render faster in the distance and do not display noise artifacts"};
 cvar_t r_labelsprites_scale = {CVAR_SAVE, "r_labelsprites_scale", "1", "global scale to apply to label sprites before conversion to HUD coordinates"};
 cvar_t r_labelsprites_roundtopixels = {CVAR_SAVE, "r_labelsprites_roundtopixels", "1", "try to make label sprites sharper by rounding their size to 0.5x or 1x and by rounding their position to whole pixels if possible"};
+cvar_t r_overheadsprites_perspective = {CVAR_SAVE, "r_overheadsprites_perspective", "5", "fake perspective effect for SPR_OVERHEAD sprites"};
+cvar_t r_overheadsprites_pushback = {CVAR_SAVE, "r_overheadsprites_pushback", "15", "how far to pull the SPR_OVERHEAD sprites toward the eye (used to avoid intersections with 3D models)"};
+cvar_t r_overheadsprites_scalex = {CVAR_SAVE, "r_overheadsprites_scalex", "1", "additional scale for overhead sprites for x axis"};
+cvar_t r_overheadsprites_scaley = {CVAR_SAVE, "r_overheadsprites_scaley", "1", "additional scale for overhead sprites for y axis"};
+cvar_t r_track_sprites = {CVAR_SAVE, "r_track_sprites", "1", "track SPR_LABEL* sprites by putting them as indicator at the screen border to rotate to"};
+cvar_t r_track_sprites_flags = {CVAR_SAVE, "r_track_sprites_flags", "1", "1: Rotate sprites accordingly, 2: Make it a continuous rotation"};
+cvar_t r_track_sprites_scalew = {CVAR_SAVE, "r_track_sprites_scalew", "1", "width scaling of tracked sprites"};
+cvar_t r_track_sprites_scaleh = {CVAR_SAVE, "r_track_sprites_scaleh", "1", "height scaling of tracked sprites"};
 
 /*
 ===============
@@ -39,6 +47,14 @@ void Mod_SpriteInit (void)
        Cvar_RegisterVariable(&r_mipsprites);
        Cvar_RegisterVariable(&r_labelsprites_scale);
        Cvar_RegisterVariable(&r_labelsprites_roundtopixels);
+       Cvar_RegisterVariable(&r_overheadsprites_perspective);
+       Cvar_RegisterVariable(&r_overheadsprites_pushback);
+       Cvar_RegisterVariable(&r_overheadsprites_scalex);
+       Cvar_RegisterVariable(&r_overheadsprites_scaley);
+       Cvar_RegisterVariable(&r_track_sprites);
+       Cvar_RegisterVariable(&r_track_sprites_flags);
+       Cvar_RegisterVariable(&r_track_sprites_scalew);
+       Cvar_RegisterVariable(&r_track_sprites_scaleh);
 }
 
 static void Mod_SpriteSetupTexture(texture_t *texture, skinframe_t *skinframe, qboolean fullbright, qboolean additive)
@@ -65,6 +81,8 @@ static void Mod_SpriteSetupTexture(texture_t *texture, skinframe_t *skinframe, q
                texture->supercontents |= SUPERCONTENTS_OPAQUE;
 }
 
+extern cvar_t gl_texturecompression_sprites;
+
 static void Mod_Sprite_SharedSetup(const unsigned char *datapointer, int version, const unsigned int *palette, qboolean additive)
 {
        int                                     i, j, groupframes, realframes, x, y, origin[2], width, height;
@@ -77,7 +95,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) | 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)
@@ -213,6 +231,7 @@ static void Mod_Sprite_SharedSetup(const unsigned char *datapointer, int version
                                                else //if (version == SPRITEHL_VERSION || version == SPRITE_VERSION)
                                                        Image_Copy8bitBGRA(datapointer, pixels, width*height, palette ? palette : palette_bgra_transparent);
                                                skinframe = R_SkinFrame_LoadInternalBGRA(name, texflags, pixels, width, height, false);
+                                               // texflags |= TEXF_COMPRESS;
                                                Mem_Free(pixels);
                                        }
                                }
index 3ca5093fa2578c278ce1f98c95c662d66eb9030e..c7993b7dd85b2eb61ccab8f3d86338a7c525da9a 100644 (file)
@@ -1,14 +1,22 @@
 
+#ifndef MPROGDEFS_H
+#define MPROGDEFS_H
+
 /* file generated by qcc, do not modify */
 
+/*
 typedef struct m_globalvars_s
 {
        int     pad[28];
        int     self;
 } m_globalvars_t;
 
-/*typedef struct m_entvars_s
+typedef struct m_entvars_s
 {
-} m_entvars_t;*/
+} m_entvars_t;
 
 #define M_PROGHEADER_CRC 10020
+
+*/
+
+#endif
index 41c476cf035e329271230fb032ad99ba66d64d61..9d154b4969510e8ac968bfac217618d382589925 100644 (file)
@@ -736,7 +736,7 @@ static void VM_M_copyentity (void)
        VM_SAFEPARMCOUNT(2,VM_M_copyentity);
        in = PRVM_G_EDICT(OFS_PARM0);
        out = PRVM_G_EDICT(OFS_PARM1);
-       memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
+       memcpy(out->fields.vp, in->fields.vp, prog->entityfields * 4);
 }
 
 //#66 vector() getmousepos (EXT_CSQC)
index e2095d9197bc82c13ca13c6f2d7a9da77ba5e6b5..eefae3ad4c67e99c2ae5ab05c60d3f038a7eb23c 100755 (executable)
--- a/netconn.c
+++ b/netconn.c
@@ -62,7 +62,7 @@ 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}
 };
 
@@ -2287,6 +2287,7 @@ static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg
        int length;
        char teambuf[3];
        const char *crypto_idstring;
+       const char *str;
 
        SV_VM_Begin();
 
@@ -2302,19 +2303,16 @@ static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg
        }
 
        *qcstatus = 0;
-       if(prog->globaloffsets.worldstatus >= 0)
+       str = PRVM_GetString(PRVM_serverglobalstring(worldstatus));
+       if(str && *str)
        {
-               const char *str = PRVM_G_STRING(prog->globaloffsets.worldstatus);
-               if(str && *str)
-               {
-                       char *p;
-                       const char *q;
-                       p = qcstatus;
-                       for(q = str; *q && p - qcstatus < (ptrdiff_t)(sizeof(qcstatus)) - 1; ++q)
-                               if(*q != '\\' && *q != '\n')
-                                       *p++ = *q;
-                       *p = 0;
-               }
+               char *p;
+               const char *q;
+               p = qcstatus;
+               for(q = str; *q && (size_t)(p - qcstatus) < (sizeof(qcstatus) - 1); ++q)
+                       if(*q != '\\' && *q != '\n')
+                               *p++ = *q;
+               *p = 0;
        }
 
        /// \TODO: we should add more information for the full status string
@@ -2358,6 +2356,8 @@ static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg
                                int nameind, cleanind, pingvalue;
                                char curchar;
                                char cleanname [sizeof(cl->name)];
+                               const char *str;
+                               prvm_edict_t *ed;
 
                                // Remove all characters '"' and '\' in the player name
                                nameind = 0;
@@ -2381,19 +2381,17 @@ static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg
                                        pingvalue = 0;
 
                                *qcstatus = 0;
-                               if(prog->fieldoffsets.clientstatus >= 0)
+                               ed = PRVM_EDICT_NUM(i + 1);
+                               str = PRVM_GetString(PRVM_serveredictstring(ed, clientstatus));
+                               if(str && *str)
                                {
-                                       const char *str = PRVM_E_STRING(PRVM_EDICT_NUM(i + 1), prog->fieldoffsets.clientstatus);
-                                       if(str && *str)
-                                       {
-                                               char *p;
-                                               const char *q;
-                                               p = qcstatus;
-                                               for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
-                                                       if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
-                                                               *p++ = *q;
-                                               *p = 0;
-                                       }
+                                       char *p;
+                                       const char *q;
+                                       p = qcstatus;
+                                       for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
+                                               if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
+                                                       *p++ = *q;
+                                       *p = 0;
                                }
 
                                if ((gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) && (teamplay.integer > 0))
index 0ffe578c726d21126d96385bb1eb8ee8bc7225e9..d1643b628e15be619dc3b02115222b0e4c2852ce 100644 (file)
--- a/pr_comp.h
+++ b/pr_comp.h
@@ -42,7 +42,7 @@ typedef enum etype_e {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_fie
 #define        RESERVED_OFS    28
 
 
-enum opcode_e
+typedef enum opcode_e
 {
        OP_DONE,
        OP_MUL_F,
@@ -119,7 +119,8 @@ enum opcode_e
 
        OP_BITAND,
        OP_BITOR
-};
+}
+opcode_t;
 
 
 typedef struct statement_s
@@ -183,6 +184,14 @@ typedef struct mfunction_s
 }
 mfunction_t;
 
+typedef struct mstatement_s
+{
+       opcode_t        op;
+       int                     operand[3]; // always a global or -1 for unused
+       int                     jumpabsolute; // only used by IF, IFNOT, GOTO
+}
+mstatement_t;
+
 
 #define        PROG_VERSION    6
 typedef struct dprograms_s
index 6d11e3501c432014ed4a4c4bc23b1f9208e9d434..60c3f212f0bc31a1b7e8991fc900d8458f09403d 100644 (file)
--- a/progsvm.h
+++ b/progsvm.h
@@ -110,13 +110,112 @@ typedef struct prvm_edict_s
        union
        {
                vec_t *vp;
-               entvars_t               *server;
-               cl_entvars_t    *client;
+//             entvars_t               *server;
+//             cl_entvars_t    *client;
        } fields;
 } prvm_edict_t;
 
-#define PRVM_EDICTFIELDVALUE(ed, fieldoffset) (fieldoffset >= 0 ? (prvm_eval_t *)((int *)ed->fields.vp + fieldoffset) : NULL)
-#define PRVM_GLOBALFIELDVALUE(fieldoffset) (fieldoffset >= 0 ? (prvm_eval_t *)((int *)prog->globals.generic + fieldoffset) : NULL)
+extern prvm_eval_t prvm_badvalue;
+
+#define PRVM_alledictfloat(ed, fieldname)    (PRVM_EDICTFIELDFLOAT(ed, prog->fieldoffsets.fieldname))
+#define PRVM_alledictvector(ed, fieldname)   (PRVM_EDICTFIELDVECTOR(ed, prog->fieldoffsets.fieldname))
+#define PRVM_alledictstring(ed, fieldname)   (PRVM_EDICTFIELDSTRING(ed, prog->fieldoffsets.fieldname))
+#define PRVM_alledictedict(ed, fieldname)    (PRVM_EDICTFIELDEDICT(ed, prog->fieldoffsets.fieldname))
+#define PRVM_alledictfunction(ed, fieldname) (PRVM_EDICTFIELDFUNCTION(ed, prog->fieldoffsets.fieldname))
+#define PRVM_allglobalfloat(fieldname)       (PRVM_GLOBALFIELDFLOAT(prog->globaloffsets.fieldname))
+#define PRVM_allglobalvector(fieldname)      (PRVM_GLOBALFIELDVECTOR(prog->globaloffsets.fieldname))
+#define PRVM_allglobalstring(fieldname)      (PRVM_GLOBALFIELDSTRING(prog->globaloffsets.fieldname))
+#define PRVM_allglobaledict(fieldname)       (PRVM_GLOBALFIELDEDICT(prog->globaloffsets.fieldname))
+#define PRVM_allglobalfunction(fieldname)    (PRVM_GLOBALFIELDFUNCTION(prog->globaloffsets.fieldname))
+#define PRVM_allfunction(funcname)           (prog->funcoffsets.funcname)
+
+#define PRVM_drawedictfloat(ed, fieldname)    (PRVM_EDICTFIELDFLOAT(ed, prog->fieldoffsets.fieldname))
+#define PRVM_drawedictvector(ed, fieldname)   (PRVM_EDICTFIELDVECTOR(ed, prog->fieldoffsets.fieldname))
+#define PRVM_drawedictstring(ed, fieldname)   (PRVM_EDICTFIELDSTRING(ed, prog->fieldoffsets.fieldname))
+#define PRVM_drawedictedict(ed, fieldname)    (PRVM_EDICTFIELDEDICT(ed, prog->fieldoffsets.fieldname))
+#define PRVM_drawedictfunction(ed, fieldname) (PRVM_EDICTFIELDFUNCTION(ed, prog->fieldoffsets.fieldname))
+#define PRVM_drawglobalfloat(fieldname)       (PRVM_GLOBALFIELDFLOAT(prog->globaloffsets.fieldname))
+#define PRVM_drawglobalvector(fieldname)      (PRVM_GLOBALFIELDVECTOR(prog->globaloffsets.fieldname))
+#define PRVM_drawglobalstring(fieldname)      (PRVM_GLOBALFIELDSTRING(prog->globaloffsets.fieldname))
+#define PRVM_drawglobaledict(fieldname)       (PRVM_GLOBALFIELDEDICT(prog->globaloffsets.fieldname))
+#define PRVM_drawglobalfunction(fieldname)    (PRVM_GLOBALFIELDFUNCTION(prog->globaloffsets.fieldname))
+#define PRVM_drawfunction(funcname)           (prog->funcoffsets.funcname)
+
+#define PRVM_gameedictfloat(ed, fieldname)    (PRVM_EDICTFIELDFLOAT(ed, prog->fieldoffsets.fieldname))
+#define PRVM_gameedictvector(ed, fieldname)   (PRVM_EDICTFIELDVECTOR(ed, prog->fieldoffsets.fieldname))
+#define PRVM_gameedictstring(ed, fieldname)   (PRVM_EDICTFIELDSTRING(ed, prog->fieldoffsets.fieldname))
+#define PRVM_gameedictedict(ed, fieldname)    (PRVM_EDICTFIELDEDICT(ed, prog->fieldoffsets.fieldname))
+#define PRVM_gameedictfunction(ed, fieldname) (PRVM_EDICTFIELDFUNCTION(ed, prog->fieldoffsets.fieldname))
+#define PRVM_gameglobalfloat(fieldname)       (PRVM_GLOBALFIELDFLOAT(prog->globaloffsets.fieldname))
+#define PRVM_gameglobalvector(fieldname)      (PRVM_GLOBALFIELDVECTOR(prog->globaloffsets.fieldname))
+#define PRVM_gameglobalstring(fieldname)      (PRVM_GLOBALFIELDSTRING(prog->globaloffsets.fieldname))
+#define PRVM_gameglobaledict(fieldname)       (PRVM_GLOBALFIELDEDICT(prog->globaloffsets.fieldname))
+#define PRVM_gameglobalfunction(fieldname)    (PRVM_GLOBALFIELDFUNCTION(prog->globaloffsets.fieldname))
+#define PRVM_gamefunction(funcname)           (prog->funcoffsets.funcname)
+
+#define PRVM_serveredictfloat(ed, fieldname)    (PRVM_EDICTFIELDFLOAT(ed, prog->fieldoffsets.fieldname))
+#define PRVM_serveredictvector(ed, fieldname)   (PRVM_EDICTFIELDVECTOR(ed, prog->fieldoffsets.fieldname))
+#define PRVM_serveredictstring(ed, fieldname)   (PRVM_EDICTFIELDSTRING(ed, prog->fieldoffsets.fieldname))
+#define PRVM_serveredictedict(ed, fieldname)    (PRVM_EDICTFIELDEDICT(ed, prog->fieldoffsets.fieldname))
+#define PRVM_serveredictfunction(ed, fieldname) (PRVM_EDICTFIELDFUNCTION(ed, prog->fieldoffsets.fieldname))
+#define PRVM_serverglobalfloat(fieldname)       (PRVM_GLOBALFIELDFLOAT(prog->globaloffsets.fieldname))
+#define PRVM_serverglobalvector(fieldname)      (PRVM_GLOBALFIELDVECTOR(prog->globaloffsets.fieldname))
+#define PRVM_serverglobalstring(fieldname)      (PRVM_GLOBALFIELDSTRING(prog->globaloffsets.fieldname))
+#define PRVM_serverglobaledict(fieldname)       (PRVM_GLOBALFIELDEDICT(prog->globaloffsets.fieldname))
+#define PRVM_serverglobalfunction(fieldname)    (PRVM_GLOBALFIELDFUNCTION(prog->globaloffsets.fieldname))
+#define PRVM_serverfunction(funcname)           (prog->funcoffsets.funcname)
+
+#define PRVM_clientedictfloat(ed, fieldname)    (PRVM_EDICTFIELDFLOAT(ed, prog->fieldoffsets.fieldname))
+#define PRVM_clientedictvector(ed, fieldname)   (PRVM_EDICTFIELDVECTOR(ed, prog->fieldoffsets.fieldname))
+#define PRVM_clientedictstring(ed, fieldname)   (PRVM_EDICTFIELDSTRING(ed, prog->fieldoffsets.fieldname))
+#define PRVM_clientedictedict(ed, fieldname)    (PRVM_EDICTFIELDEDICT(ed, prog->fieldoffsets.fieldname))
+#define PRVM_clientedictfunction(ed, fieldname) (PRVM_EDICTFIELDFUNCTION(ed, prog->fieldoffsets.fieldname))
+#define PRVM_clientglobalfloat(fieldname)       (PRVM_GLOBALFIELDFLOAT(prog->globaloffsets.fieldname))
+#define PRVM_clientglobalvector(fieldname)      (PRVM_GLOBALFIELDVECTOR(prog->globaloffsets.fieldname))
+#define PRVM_clientglobalstring(fieldname)      (PRVM_GLOBALFIELDSTRING(prog->globaloffsets.fieldname))
+#define PRVM_clientglobaledict(fieldname)       (PRVM_GLOBALFIELDEDICT(prog->globaloffsets.fieldname))
+#define PRVM_clientglobalfunction(fieldname)    (PRVM_GLOBALFIELDFUNCTION(prog->globaloffsets.fieldname))
+#define PRVM_clientfunction(funcname)           (prog->funcoffsets.funcname)
+
+#define PRVM_menuedictfloat(ed, fieldname)    (PRVM_EDICTFIELDFLOAT(ed, prog->fieldoffsets.fieldname))
+#define PRVM_menuedictvector(ed, fieldname)   (PRVM_EDICTFIELDVECTOR(ed, prog->fieldoffsets.fieldname))
+#define PRVM_menuedictstring(ed, fieldname)   (PRVM_EDICTFIELDSTRING(ed, prog->fieldoffsets.fieldname))
+#define PRVM_menuedictedict(ed, fieldname)    (PRVM_EDICTFIELDEDICT(ed, prog->fieldoffsets.fieldname))
+#define PRVM_menuedictfunction(ed, fieldname) (PRVM_EDICTFIELDFUNCTION(ed, prog->fieldoffsets.fieldname))
+#define PRVM_menuglobalfloat(fieldname)       (PRVM_GLOBALFIELDFLOAT(prog->globaloffsets.fieldname))
+#define PRVM_menuglobalvector(fieldname)      (PRVM_GLOBALFIELDVECTOR(prog->globaloffsets.fieldname))
+#define PRVM_menuglobalstring(fieldname)      (PRVM_GLOBALFIELDSTRING(prog->globaloffsets.fieldname))
+#define PRVM_menuglobaledict(fieldname)       (PRVM_GLOBALFIELDEDICT(prog->globaloffsets.fieldname))
+#define PRVM_menuglobalfunction(fieldname)    (PRVM_GLOBALFIELDFUNCTION(prog->globaloffsets.fieldname))
+#define PRVM_menufunction(funcname)           (prog->funcoffsets.funcname)
+
+#if 1
+#define PRVM_EDICTFIELDVALUE(ed, fieldoffset)    (fieldoffset < 0 ? Con_Printf("Invalid fieldoffset at %s:%i\n", __FILE__, __LINE__), &prvm_badvalue : (prvm_eval_t *)((int *)ed->fields.vp + fieldoffset))
+#define PRVM_EDICTFIELDFLOAT(ed, fieldoffset)    (PRVM_EDICTFIELDVALUE(ed, fieldoffset)->_float)
+#define PRVM_EDICTFIELDVECTOR(ed, fieldoffset)   (PRVM_EDICTFIELDVALUE(ed, fieldoffset)->vector)
+#define PRVM_EDICTFIELDSTRING(ed, fieldoffset)   (PRVM_EDICTFIELDVALUE(ed, fieldoffset)->string)
+#define PRVM_EDICTFIELDEDICT(ed, fieldoffset)    (PRVM_EDICTFIELDVALUE(ed, fieldoffset)->edict)
+#define PRVM_EDICTFIELDFUNCTION(ed, fieldoffset) (PRVM_EDICTFIELDVALUE(ed, fieldoffset)->function)
+#define PRVM_GLOBALFIELDVALUE(fieldoffset)       (fieldoffset < 0 ? Con_Printf("Invalid fieldoffset at %s:%i\n", __FILE__, __LINE__), &prvm_badvalue : (prvm_eval_t *)((int *)prog->globals.generic + fieldoffset))
+#define PRVM_GLOBALFIELDFLOAT(fieldoffset)       (PRVM_GLOBALFIELDVALUE(fieldoffset)->_float)
+#define PRVM_GLOBALFIELDVECTOR(fieldoffset)      (PRVM_GLOBALFIELDVALUE(fieldoffset)->vector)
+#define PRVM_GLOBALFIELDSTRING(fieldoffset)      (PRVM_GLOBALFIELDVALUE(fieldoffset)->string)
+#define PRVM_GLOBALFIELDEDICT(fieldoffset)       (PRVM_GLOBALFIELDVALUE(fieldoffset)->edict)
+#define PRVM_GLOBALFIELDFUNCTION(fieldoffset)    (PRVM_GLOBALFIELDVALUE(fieldoffset)->function)
+#else
+#define PRVM_EDICTFIELDVALUE(ed, fieldoffset) ((prvm_eval_t *)((int *)ed->fields.vp + fieldoffset))
+#define PRVM_EDICTFIELDFLOAT(ed, fieldoffset) (((prvm_eval_t *)((int *)ed->fields.vp + fieldoffset))->_float)
+#define PRVM_EDICTFIELDVECTOR(ed, fieldoffset) (((prvm_eval_t *)((int *)ed->fields.vp + fieldoffset))->vector)
+#define PRVM_EDICTFIELDSTRING(ed, fieldoffset) (((prvm_eval_t *)((int *)ed->fields.vp + fieldoffset))->string)
+#define PRVM_EDICTFIELDEDICT(ed, fieldoffset) (((prvm_eval_t *)((int *)ed->fields.vp + fieldoffset))->edict)
+#define PRVM_EDICTFIELDFUNCTION(ed, fieldoffset) (((prvm_eval_t *)((int *)ed->fields.vp + fieldoffset))->function)
+#define PRVM_GLOBALFIELDVALUE(fieldoffset) ((prvm_eval_t *)((int *)prog->globals.generic + fieldoffset))
+#define PRVM_GLOBALFIELDFLOAT(fieldoffset) (((prvm_eval_t *)((int *)prog->globals.generic + fieldoffset))->_float)
+#define PRVM_GLOBALFIELDVECTOR(fieldoffset) (((prvm_eval_t *)((int *)prog->globals.generic + fieldoffset))->vector)
+#define PRVM_GLOBALFIELDSTRING(fieldoffset) (((prvm_eval_t *)((int *)prog->globals.generic + fieldoffset))->string)
+#define PRVM_GLOBALFIELDEDICT(fieldoffset) (((prvm_eval_t *)((int *)prog->globals.generic + fieldoffset))->edict)
+#define PRVM_GLOBALFIELDFUNCTION(fieldoffset) (((prvm_eval_t *)((int *)prog->globals.generic + fieldoffset))->function)
+#endif
 
 //============================================================================
 #define PRVM_OP_STATE          1
@@ -142,243 +241,237 @@ typedef void (*prvm_builtin_t) (void);
 // NOTE: field offsets use -1 for NULL
 typedef struct prvm_prog_fieldoffsets_s
 {
-       // server and client use a lot of similar fields, so this is combined
-       int SendEntity; // ssqc
-       int SendFlags; // ssqc
-       int Version; // ssqc (legacy)
-       int alpha; // ssqc / csqc
-       int ammo_cells1; // ssqc - Dissolution of Eternity mission pack
-       int ammo_lava_nails; // ssqc - Dissolution of Eternity mission pack
-       int ammo_multi_rockets; // ssqc - Dissolution of Eternity mission pack
-       int ammo_nails1; // ssqc - Dissolution of Eternity mission pack
-       int ammo_plasma; // ssqc - Dissolution of Eternity mission pack
-       int ammo_rockets1; // ssqc - Dissolution of Eternity mission pack
-       int ammo_shells1; // ssqc - Dissolution of Eternity mission pack
-       int angles; // common - used by changeyaw/changepitch
-       int button3; // ssqc
-       int button4; // ssqc
-       int button5; // ssqc
-       int button6; // ssqc
-       int button7; // ssqc
-       int button8; // ssqc
-       int button9; // ssqc
-       int button10; // ssqc
-       int button11; // ssqc
-       int button12; // ssqc
-       int button13; // ssqc
-       int button14; // ssqc
-       int button15; // ssqc
-       int button16; // ssqc
-       int buttonchat; // ssqc
-       int buttonuse; // ssqc
-       int chain; // common - used by find builtins
-       int classname; // common
-       int clientcamera; // ssqc
-       int clientcolors; // ssqc
-       int clientstatus; // ssqc
-       int color; // ssqc
-       int colormod; // ssqc / csqc
-       int contentstransition; // ssqc
-       int cursor_active; // ssqc
-       int cursor_screen; // ssqc
-       int cursor_trace_endpos; // ssqc
-       int cursor_trace_ent; // ssqc
-       int cursor_trace_start; // ssqc
-       int customizeentityforclient; // ssqc
-       int dimension_hit; // ssqc / csqc
-       int dimension_solid; // ssqc / csqc
-       int disableclientprediction; // ssqc
-       int discardabledemo; // ssqc
-       int dphitcontentsmask; // ssqc / csqc
-       int drawonlytoclient; // ssqc
-       int exteriormodeltoclient; // ssqc
-       int fatness; // ssqc / csqc
-       int forceshader; // csqc
-       int frame1time; // csqc
-       int frame2; // csqc
-       int frame2time; // csqc
-       int frame3; // csqc
-       int frame3time; // csqc
-       int frame4; // csqc
-       int frame4time; // csqc
-       int frame; // common - used by OP_STATE
-       int fullbright; // ssqc - Nehahra support
-       int glow_color; // ssqc
-       int glow_size; // ssqc
-       int glow_trail; // ssqc
-       int glowmod; // ssqc / csqc
-       int gravity; // ssqc
-       int groundentity; // ssqc / csqc
-       int hull; // ssqc / csqc
-       int ideal_yaw; // ssqc / csqc
-       int idealpitch; // ssqc / csqc
-       int items2; // ssqc
-       int lerpfrac3; // csqc
-       int lerpfrac4; // csqc
-       int lerpfrac; // csqc
-       int light_lev; // ssqc
-       int message; // csqc
-       int modelflags; // ssqc
-       int movement; // ssqc
-       int movetypesteplandevent; // ssqc
-       int netaddress; // ssqc
-       int nextthink; // common - used by OP_STATE
-       int nodrawtoclient; // ssqc
-       int pflags; // ssqc
-       int ping; // ssqc
-       int packetloss; // ssqc
-       int movementloss; // ssqc
-       int pitch_speed; // ssqc / csqc
-       int playermodel; // ssqc
-       int playerskin; // ssqc
-       int pmodel; // ssqc
-       int punchvector; // ssqc
-       int renderamt; // ssqc - HalfLife support
-       int renderflags; // csqc
-       int rendermode; // ssqc - HalfLife support
-       int scale; // ssqc / csqc
-       int shadertime; // csqc
-       int skeletonindex; // csqc / ssqc FTE_CSQC_SKELETONOBJECTS / DP_SKELETONOBJECTS
-       int style; // ssqc
-       int tag_entity; // ssqc / csqc
-       int tag_index; // ssqc / csqc
-       int think; // common - used by OP_STATE
-       int viewmodelforclient; // ssqc
-       int viewzoom; // ssqc
-       int yaw_speed; // ssqc / csqc
-       int bouncefactor; // ssqc
-       int bouncestop; // ssqc
-
-       int solid; // ssqc / csqc (physics)
-       int movetype; // ssqc / csqc (physics)
-       int modelindex; // ssqc / csqc (physics)
-       int mins; // ssqc / csqc (physics)
-       int maxs; // ssqc / csqc (physics)
-       int mass; // ssqc / csqc (physics)
-       int origin; // ssqc / csqc (physics)
-       int velocity; // ssqc / csqc (physics)
-       //int axis_forward; // ssqc / csqc (physics)
-       //int axis_left; // ssqc / csqc (physics)
-       //int axis_up; // ssqc / csqc (physics)
-       //int spinvelocity; // ssqc / csqc (physics)
-       //int angles; // ssqc / csqc (physics)
-       int avelocity; // ssqc / csqc (physics)
-       int jointtype; // ssqc / csqc (physics)
-       int enemy; // ssqc / csqc (physics)
-       int aiment; // ssqc / csqc (physics)
-       int movedir; // ssqc / csqc (physics)
-
-       int camera_transform; // csqc (warpzones)
-
-       int userwavefunc_param0; // csqc (userwavefunc)
-       int userwavefunc_param1; // csqc (userwavefunc)
-       int userwavefunc_param2; // csqc (userwavefunc)
-       int userwavefunc_param3; // csqc (userwavefunc)
-
-       int crypto_keyfp; // svqc (crypto)
-       int crypto_mykeyfp; // svqc (crypto)
-       int crypto_idfp; // svqc (crypto)
-       int crypto_encryptmethod; // svqc (crypto)
-       int crypto_signmethod; // svqc (crypto)
+#define PRVM_DECLARE_serverglobalfloat(x)
+#define PRVM_DECLARE_serverglobalvector(x)
+#define PRVM_DECLARE_serverglobalstring(x)
+#define PRVM_DECLARE_serverglobaledict(x)
+#define PRVM_DECLARE_serverglobalfunction(x)
+#define PRVM_DECLARE_clientglobalfloat(x)
+#define PRVM_DECLARE_clientglobalvector(x)
+#define PRVM_DECLARE_clientglobalstring(x)
+#define PRVM_DECLARE_clientglobaledict(x)
+#define PRVM_DECLARE_clientglobalfunction(x)
+#define PRVM_DECLARE_menuglobalfloat(x)
+#define PRVM_DECLARE_menuglobalvector(x)
+#define PRVM_DECLARE_menuglobalstring(x)
+#define PRVM_DECLARE_menuglobaledict(x)
+#define PRVM_DECLARE_menuglobalfunction(x)
+#define PRVM_DECLARE_serverfieldfloat(x)
+#define PRVM_DECLARE_serverfieldvector(x)
+#define PRVM_DECLARE_serverfieldstring(x)
+#define PRVM_DECLARE_serverfieldedict(x)
+#define PRVM_DECLARE_serverfieldfunction(x)
+#define PRVM_DECLARE_clientfieldfloat(x)
+#define PRVM_DECLARE_clientfieldvector(x)
+#define PRVM_DECLARE_clientfieldstring(x)
+#define PRVM_DECLARE_clientfieldedict(x)
+#define PRVM_DECLARE_clientfieldfunction(x)
+#define PRVM_DECLARE_menufieldfloat(x)
+#define PRVM_DECLARE_menufieldvector(x)
+#define PRVM_DECLARE_menufieldstring(x)
+#define PRVM_DECLARE_menufieldedict(x)
+#define PRVM_DECLARE_menufieldfunction(x)
+#define PRVM_DECLARE_serverfunction(x)
+#define PRVM_DECLARE_clientfunction(x)
+#define PRVM_DECLARE_menufunction(x)
+#define PRVM_DECLARE_field(x) int x;
+#define PRVM_DECLARE_global(x)
+#define PRVM_DECLARE_function(x)
+#include "prvm_offsets.h"
+#undef PRVM_DECLARE_serverglobalfloat
+#undef PRVM_DECLARE_serverglobalvector
+#undef PRVM_DECLARE_serverglobalstring
+#undef PRVM_DECLARE_serverglobaledict
+#undef PRVM_DECLARE_serverglobalfunction
+#undef PRVM_DECLARE_clientglobalfloat
+#undef PRVM_DECLARE_clientglobalvector
+#undef PRVM_DECLARE_clientglobalstring
+#undef PRVM_DECLARE_clientglobaledict
+#undef PRVM_DECLARE_clientglobalfunction
+#undef PRVM_DECLARE_menuglobalfloat
+#undef PRVM_DECLARE_menuglobalvector
+#undef PRVM_DECLARE_menuglobalstring
+#undef PRVM_DECLARE_menuglobaledict
+#undef PRVM_DECLARE_menuglobalfunction
+#undef PRVM_DECLARE_serverfieldfloat
+#undef PRVM_DECLARE_serverfieldvector
+#undef PRVM_DECLARE_serverfieldstring
+#undef PRVM_DECLARE_serverfieldedict
+#undef PRVM_DECLARE_serverfieldfunction
+#undef PRVM_DECLARE_clientfieldfloat
+#undef PRVM_DECLARE_clientfieldvector
+#undef PRVM_DECLARE_clientfieldstring
+#undef PRVM_DECLARE_clientfieldedict
+#undef PRVM_DECLARE_clientfieldfunction
+#undef PRVM_DECLARE_menufieldfloat
+#undef PRVM_DECLARE_menufieldvector
+#undef PRVM_DECLARE_menufieldstring
+#undef PRVM_DECLARE_menufieldedict
+#undef PRVM_DECLARE_menufieldfunction
+#undef PRVM_DECLARE_serverfunction
+#undef PRVM_DECLARE_clientfunction
+#undef PRVM_DECLARE_menufunction
+#undef PRVM_DECLARE_field
+#undef PRVM_DECLARE_global
+#undef PRVM_DECLARE_function
 }
 prvm_prog_fieldoffsets_t;
 
 // NOTE: global offsets use -1 for NULL
 typedef struct prvm_prog_globaloffsets_s
 {
-       // server and client use a lot of similar globals, so this is combined
-       int SV_InitCmd; // ssqc
-       int self; // common
-       int time; // ssqc / csqc
-       int v_forward; // ssqc / csqc
-       int v_right; // ssqc / csqc
-       int v_up; // ssqc / csqc
-       int view_angles; // csqc
-       int view_punchangle; // csqc
-       int view_punchvector; // csqc
-       int trace_allsolid; // ssqc / csqc
-       int trace_startsolid; // ssqc / csqc
-       int trace_fraction; // ssqc / csqc
-       int trace_inwater; // ssqc / csqc
-       int trace_inopen; // ssqc / csqc
-       int trace_endpos; // ssqc / csqc
-       int trace_plane_normal; // ssqc / csqc
-       int trace_plane_dist; // ssqc / csqc
-       int trace_ent; // ssqc / csqc
-       int trace_networkentity; // csqc
-       int trace_dphitcontents; // ssqc / csqc
-       int trace_dphitq3surfaceflags; // ssqc / csqc
-       int trace_dphittexturename; // ssqc / csqc
-       int trace_dpstartcontents; // ssqc / csqc
-       int intermission; // csqc
-       int coop; // csqc
-       int deathmatch; // csqc
-       int dmg_take; // csqc
-       int dmg_save; // csqc
-       int dmg_origin; // csqc
-       int sb_showscores; // csqc
-       int drawfont; // csqc / menu
-       int drawfontscale; // csqc / menu
-       int require_spawnfunc_prefix; // ssqc
-       int worldstatus; // ssqc
-       int servertime; // csqc
-       int serverprevtime; // csqc
-       int serverdeltatime; // csqc
-       int gettaginfo_name; // ssqc / csqc
-       int gettaginfo_parent; // ssqc / csqc
-       int gettaginfo_offset; // ssqc / csqc
-       int gettaginfo_forward; // ssqc / csqc
-       int gettaginfo_right; // ssqc / csqc
-       int gettaginfo_up; // ssqc / csqc
-       int transparent_offset; // csqc
-
-       int particles_alphamin; // csqc
-       int particles_alphamax; // csqc
-       int particles_colormin; // csqc
-       int particles_colormax; // csqc
+#define PRVM_DECLARE_serverglobalfloat(x)
+#define PRVM_DECLARE_serverglobalvector(x)
+#define PRVM_DECLARE_serverglobalstring(x)
+#define PRVM_DECLARE_serverglobaledict(x)
+#define PRVM_DECLARE_serverglobalfunction(x)
+#define PRVM_DECLARE_clientglobalfloat(x)
+#define PRVM_DECLARE_clientglobalvector(x)
+#define PRVM_DECLARE_clientglobalstring(x)
+#define PRVM_DECLARE_clientglobaledict(x)
+#define PRVM_DECLARE_clientglobalfunction(x)
+#define PRVM_DECLARE_menuglobalfloat(x)
+#define PRVM_DECLARE_menuglobalvector(x)
+#define PRVM_DECLARE_menuglobalstring(x)
+#define PRVM_DECLARE_menuglobaledict(x)
+#define PRVM_DECLARE_menuglobalfunction(x)
+#define PRVM_DECLARE_serverfieldfloat(x)
+#define PRVM_DECLARE_serverfieldvector(x)
+#define PRVM_DECLARE_serverfieldstring(x)
+#define PRVM_DECLARE_serverfieldedict(x)
+#define PRVM_DECLARE_serverfieldfunction(x)
+#define PRVM_DECLARE_clientfieldfloat(x)
+#define PRVM_DECLARE_clientfieldvector(x)
+#define PRVM_DECLARE_clientfieldstring(x)
+#define PRVM_DECLARE_clientfieldedict(x)
+#define PRVM_DECLARE_clientfieldfunction(x)
+#define PRVM_DECLARE_menufieldfloat(x)
+#define PRVM_DECLARE_menufieldvector(x)
+#define PRVM_DECLARE_menufieldstring(x)
+#define PRVM_DECLARE_menufieldedict(x)
+#define PRVM_DECLARE_menufieldfunction(x)
+#define PRVM_DECLARE_serverfunction(x)
+#define PRVM_DECLARE_clientfunction(x)
+#define PRVM_DECLARE_menufunction(x)
+#define PRVM_DECLARE_field(x)
+#define PRVM_DECLARE_global(x) int x;
+#define PRVM_DECLARE_function(x)
+#include "prvm_offsets.h"
+#undef PRVM_DECLARE_serverglobalfloat
+#undef PRVM_DECLARE_serverglobalvector
+#undef PRVM_DECLARE_serverglobalstring
+#undef PRVM_DECLARE_serverglobaledict
+#undef PRVM_DECLARE_serverglobalfunction
+#undef PRVM_DECLARE_clientglobalfloat
+#undef PRVM_DECLARE_clientglobalvector
+#undef PRVM_DECLARE_clientglobalstring
+#undef PRVM_DECLARE_clientglobaledict
+#undef PRVM_DECLARE_clientglobalfunction
+#undef PRVM_DECLARE_menuglobalfloat
+#undef PRVM_DECLARE_menuglobalvector
+#undef PRVM_DECLARE_menuglobalstring
+#undef PRVM_DECLARE_menuglobaledict
+#undef PRVM_DECLARE_menuglobalfunction
+#undef PRVM_DECLARE_serverfieldfloat
+#undef PRVM_DECLARE_serverfieldvector
+#undef PRVM_DECLARE_serverfieldstring
+#undef PRVM_DECLARE_serverfieldedict
+#undef PRVM_DECLARE_serverfieldfunction
+#undef PRVM_DECLARE_clientfieldfloat
+#undef PRVM_DECLARE_clientfieldvector
+#undef PRVM_DECLARE_clientfieldstring
+#undef PRVM_DECLARE_clientfieldedict
+#undef PRVM_DECLARE_clientfieldfunction
+#undef PRVM_DECLARE_menufieldfloat
+#undef PRVM_DECLARE_menufieldvector
+#undef PRVM_DECLARE_menufieldstring
+#undef PRVM_DECLARE_menufieldedict
+#undef PRVM_DECLARE_menufieldfunction
+#undef PRVM_DECLARE_serverfunction
+#undef PRVM_DECLARE_clientfunction
+#undef PRVM_DECLARE_menufunction
+#undef PRVM_DECLARE_field
+#undef PRVM_DECLARE_global
+#undef PRVM_DECLARE_function
 }
 prvm_prog_globaloffsets_t;
 
-// these are initialized using PRVM_ED_FindFunction
 // NOTE: function offsets use 0 for NULL
 typedef struct prvm_prog_funcoffsets_s
 {
-       func_t CSQC_ConsoleCommand; // csqc
-       func_t CSQC_Ent_Remove; // csqc
-       func_t CSQC_Ent_Spawn; // csqc DP_CSQC_ENT_SPAWN extension (BlackHC - TODO: needs to be added to dpextensions.qc)
-       func_t CSQC_Ent_Update; // csqc
-       func_t CSQC_Event; // csqc [515]: engine call this for its own needs so csqc can do some things according to what engine it's running on.  example: to say about edicts increase, whatever...
-       func_t CSQC_Event_Sound; // csqc : called by engine when an incoming sound packet arrives so CSQC can act on it
-       func_t CSQC_Init; // csqc
-       func_t CSQC_InputEvent; // csqc
-       func_t CSQC_Parse_CenterPrint; // csqc
-       func_t CSQC_Parse_Print; // csqc
-       func_t CSQC_Parse_StuffCmd; // csqc
-       func_t CSQC_Parse_TempEntity; // csqc [515]: very helpfull when you want to create your own particles/decals/etc for effects that already exist
-       func_t CSQC_Shutdown; // csqc
-       func_t CSQC_UpdateView; // csqc
-       func_t Gecko_Query; // csqc, mqc
-       func_t EndFrame; // ssqc
-       func_t RestoreGame; // ssqc
-       func_t SV_ChangeTeam; // ssqc
-       func_t SV_ParseClientCommand; // ssqc
-       func_t SV_PlayerPhysics; // ssqc
-       func_t SV_OnEntityPreSpawnFunction; // ssqc
-       func_t SV_OnEntityNoSpawnFunction; // ssqc
-       func_t SV_OnEntityPostSpawnFunction; // ssqc
-       func_t GameCommand; // any
-       func_t SV_Shutdown; // ssqc
-       func_t URI_Get_Callback; // any
-       func_t SV_PausedTic; //ssqc
-
-       // menu qc only uses some functions, nothing else
-       func_t m_draw; // mqc
-       func_t m_init; // mqc
-       func_t m_keydown; // mqc
-       func_t m_keyup; // mqc
-       func_t m_shutdown; // mqc
-       func_t m_toggle; // mqc
-       func_t m_newmap; // mqc
+#define PRVM_DECLARE_serverglobalfloat(x)
+#define PRVM_DECLARE_serverglobalvector(x)
+#define PRVM_DECLARE_serverglobalstring(x)
+#define PRVM_DECLARE_serverglobaledict(x)
+#define PRVM_DECLARE_serverglobalfunction(x)
+#define PRVM_DECLARE_clientglobalfloat(x)
+#define PRVM_DECLARE_clientglobalvector(x)
+#define PRVM_DECLARE_clientglobalstring(x)
+#define PRVM_DECLARE_clientglobaledict(x)
+#define PRVM_DECLARE_clientglobalfunction(x)
+#define PRVM_DECLARE_menuglobalfloat(x)
+#define PRVM_DECLARE_menuglobalvector(x)
+#define PRVM_DECLARE_menuglobalstring(x)
+#define PRVM_DECLARE_menuglobaledict(x)
+#define PRVM_DECLARE_menuglobalfunction(x)
+#define PRVM_DECLARE_serverfieldfloat(x)
+#define PRVM_DECLARE_serverfieldvector(x)
+#define PRVM_DECLARE_serverfieldstring(x)
+#define PRVM_DECLARE_serverfieldedict(x)
+#define PRVM_DECLARE_serverfieldfunction(x)
+#define PRVM_DECLARE_clientfieldfloat(x)
+#define PRVM_DECLARE_clientfieldvector(x)
+#define PRVM_DECLARE_clientfieldstring(x)
+#define PRVM_DECLARE_clientfieldedict(x)
+#define PRVM_DECLARE_clientfieldfunction(x)
+#define PRVM_DECLARE_menufieldfloat(x)
+#define PRVM_DECLARE_menufieldvector(x)
+#define PRVM_DECLARE_menufieldstring(x)
+#define PRVM_DECLARE_menufieldedict(x)
+#define PRVM_DECLARE_menufieldfunction(x)
+#define PRVM_DECLARE_serverfunction(x)
+#define PRVM_DECLARE_clientfunction(x)
+#define PRVM_DECLARE_menufunction(x)
+#define PRVM_DECLARE_field(x)
+#define PRVM_DECLARE_global(x)
+#define PRVM_DECLARE_function(x) int x;
+#include "prvm_offsets.h"
+#undef PRVM_DECLARE_serverglobalfloat
+#undef PRVM_DECLARE_serverglobalvector
+#undef PRVM_DECLARE_serverglobalstring
+#undef PRVM_DECLARE_serverglobaledict
+#undef PRVM_DECLARE_serverglobalfunction
+#undef PRVM_DECLARE_clientglobalfloat
+#undef PRVM_DECLARE_clientglobalvector
+#undef PRVM_DECLARE_clientglobalstring
+#undef PRVM_DECLARE_clientglobaledict
+#undef PRVM_DECLARE_clientglobalfunction
+#undef PRVM_DECLARE_menuglobalfloat
+#undef PRVM_DECLARE_menuglobalvector
+#undef PRVM_DECLARE_menuglobalstring
+#undef PRVM_DECLARE_menuglobaledict
+#undef PRVM_DECLARE_menuglobalfunction
+#undef PRVM_DECLARE_serverfieldfloat
+#undef PRVM_DECLARE_serverfieldvector
+#undef PRVM_DECLARE_serverfieldstring
+#undef PRVM_DECLARE_serverfieldedict
+#undef PRVM_DECLARE_serverfieldfunction
+#undef PRVM_DECLARE_clientfieldfloat
+#undef PRVM_DECLARE_clientfieldvector
+#undef PRVM_DECLARE_clientfieldstring
+#undef PRVM_DECLARE_clientfieldedict
+#undef PRVM_DECLARE_clientfieldfunction
+#undef PRVM_DECLARE_menufieldfloat
+#undef PRVM_DECLARE_menufieldvector
+#undef PRVM_DECLARE_menufieldstring
+#undef PRVM_DECLARE_menufieldedict
+#undef PRVM_DECLARE_menufieldfunction
+#undef PRVM_DECLARE_serverfunction
+#undef PRVM_DECLARE_clientfunction
+#undef PRVM_DECLARE_menufunction
+#undef PRVM_DECLARE_field
+#undef PRVM_DECLARE_global
+#undef PRVM_DECLARE_function
 }
 prvm_prog_funcoffsets_t;
 
@@ -401,24 +494,42 @@ typedef struct prvm_prog_s
 {
        double              starttime;
        unsigned int            id; // increasing unique id of progs instance
-       dprograms_t                     *progs;
        mfunction_t                     *functions;
        char                            *strings;
        int                                     stringssize;
        ddef_t                          *fielddefs;
        ddef_t                          *globaldefs;
-       dstatement_t            *statements;
+       mstatement_t            *statements;
        int                                     entityfields;                   // number of vec_t fields in progs (some variables are 3)
        int                                     entityfieldsarea;               // LordHavoc: equal to max_edicts * entityfields (for bounds checking)
 
+       // loaded values from the disk format
+       int                                     progs_version;
+       int                                     progs_crc;
+       int                                     progs_numstatements;
+       int                                     progs_numglobaldefs;
+       int                                     progs_numfielddefs;
+       int                                     progs_numfunctions;
+       int                                     progs_numstrings;
+       int                                     progs_numglobals;
+       int                                     progs_entityfields;
+
+       // real values in memory (some modified by loader)
+       int                                     numstatements;
+       int                                     numglobaldefs;
+       int                                     numfielddefs;
+       int                                     numfunctions;
+       int                                     numstrings;
+       int                                     numglobals;
+
        int                                     *statement_linenums; // NULL if not available
 
        double                          *statement_profile; // only incremented if prvm_statementprofiling is on
 
        union {
                vec_t *generic;
-               globalvars_t *server;
-               cl_globalvars_t *client;
+//             globalvars_t *server;
+//             cl_globalvars_t *client;
        } globals;
 
        int                                     maxknownstrings;
@@ -453,9 +564,6 @@ typedef struct prvm_prog_s
        int                                     localstack[PRVM_LOCALSTACK_SIZE];
        int                                     localstack_used;
 
-       unsigned short          headercrc; // [INIT]
-       unsigned short          headercrc2; // [INIT] alternate CRC for tenebrae progs.dat
-
        unsigned short          filecrc;
 
        //============================================================================
@@ -487,7 +595,7 @@ typedef struct prvm_prog_s
 
        prvm_prog_fieldoffsets_t        fieldoffsets;
        prvm_prog_globaloffsets_t       globaloffsets;
-       prvm_prog_funcoffsets_t         funcoffsets;
+       prvm_prog_funcoffsets_t funcoffsets;
 
        // allow writing to world entity fields, this is set by server init and
        // cleared before first server frame
@@ -722,7 +830,7 @@ 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, char **required_global);
+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);
index f2c7b29d0dd43a00b93c1d5d034fb3f48e471804..3e384e16fccb0face48c7b49f3087702575e1439 100644 (file)
@@ -7,14 +7,7 @@
        if(developer_networkentities.integer >= 2) \
        { \
                prvm_edict_t *ed = prog->edicts + num; \
-               const char *cname = "(no classname)"; \
-               if(prog->fieldoffsets.classname >= 0) \
-               { \
-                       string_t handle =  PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.classname)->string; \
-                       if (handle) \
-                               cname = PRVM_GetString(handle); \
-               } \
-               Con_Printf("sent entity update of size %d for a %s\n", (msg->cursize - entityprofiling_startsize), cname); \
+               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)"); \
        }
 
 // this is 88 bytes (must match entity_state_t in protocol.h)
@@ -36,6 +29,7 @@ entity_state_t defaultstate =
        0,//unsigned short exteriormodelforclient; // ! not shown if first person viewing from this entity, shown in all other cases
        0,//unsigned short nodrawtoclient; // !
        0,//unsigned short drawonlytoclient; // !
+       0,//unsigned short traileffectnum;
        {0,0,0,0},//unsigned short light[4]; // color*256 (0.00 to 255.996), and radius*1
        ACTIVE_NOT,//unsigned char active; // true if a valid state
        0,//unsigned char lightstyle;
@@ -279,20 +273,15 @@ static void EntityFrameCSQC_LostAllFrames(client_t *client)
        // mark ALL csqc entities as requiring a FULL resend!
        // I know this is a bad workaround, but better than nothing.
        int i, n;
-       prvm_eval_t *val;
        prvm_edict_t *ed;
 
-       if(prog->fieldoffsets.SendEntity < 0 || prog->fieldoffsets.Version < 0)
-               return;
-
        n = client->csqcnumedicts;
        for(i = 0; i < n; ++i)
        {
                if(client->csqcentityglobalhistory[i])
                {
                        ed = prog->edicts + i;
-                       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.SendEntity);
-                       if (val->function)
+                       if (PRVM_serveredictfunction(ed, SendEntity))
                                client->csqcentitysendflags[i] |= 0xFFFFFF; // FULL RESEND
                        else // if it was ever sent to that client as a CSQC entity
                        {
@@ -447,7 +436,6 @@ qboolean EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int maxsize, int numnumbers
        qboolean sectionstarted = false;
        const unsigned short *n;
        prvm_edict_t *ed;
-       prvm_eval_t *val;
        client_t *client = svs.clients + sv.writeentitiestoclient_clientnumber;
        int dbframe = EntityFrameCSQC_AllocFrame(client, framenum);
        csqcentityframedb_t *db = &client->csqcentityframehistory[dbframe];
@@ -457,10 +445,6 @@ qboolean EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int maxsize, int numnumbers
 
        maxsize -= 24; // always fit in an empty svc_entities message (for packet loss detection!)
 
-       // if this server progs is not CSQC-aware, return early
-       if(prog->fieldoffsets.SendEntity < 0 || prog->fieldoffsets.Version < 0)
-               return false;
-
        // make sure there is enough room to store the svc_csqcentities byte,
        // the terminator (0x0000) and at least one entity update
        if (msg->cursize + 32 >= maxsize)
@@ -482,8 +466,7 @@ qboolean EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int maxsize, int numnumbers
                        }
                }
                ed = prog->edicts + number;
-               val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.SendEntity);
-               if (val->function)
+               if (PRVM_serveredictfunction(ed, SendEntity))
                        client->csqcentityscope[number] = 2;
                else if (client->csqcentityscope[number])
                {
@@ -512,8 +495,7 @@ qboolean EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int maxsize, int numnumbers
        {
                number = *n;
                ed = prog->edicts + number;
-               val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.SendEntity);
-               if (val->function)
+               if (PRVM_serveredictfunction(ed, SendEntity))
                        client->csqcentityscope[number] = 2;
        }
        */
@@ -562,8 +544,7 @@ qboolean EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int maxsize, int numnumbers
                        // save the cursize value in case we overflow and have to rollback
                        int oldcursize = msg->cursize;
                        client->csqcentityscope[number] = 1;
-                       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.SendEntity);
-                       if (val->function)
+                       if (PRVM_serveredictfunction(ed, SendEntity))
                        {
                                if(!sectionstarted)
                                        MSG_WriteByte(msg, svc_csqcentities);
@@ -573,8 +554,8 @@ qboolean EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int maxsize, int numnumbers
                                        msg->allowoverflow = true;
                                        PRVM_G_INT(OFS_PARM0) = sv.writeentitiestoclient_cliententitynumber;
                                        PRVM_G_FLOAT(OFS_PARM1) = sendflags;
-                                       prog->globals.server->self = number;
-                                       PRVM_ExecuteProgram(val->function, "Null SendEntity\n");
+                                       PRVM_serverglobaledict(self) = number;
+                                       PRVM_ExecuteProgram(PRVM_serveredictfunction(ed, SendEntity), "Null SendEntity\n");
                                        msg->allowoverflow = false;
                                        if(PRVM_G_FLOAT(OFS_RETURN) && msg->cursize + 2 <= maxsize)
                                        {
@@ -701,7 +682,6 @@ qboolean EntityFrameQuake_WriteFrame(sizebuf_t *msg, int maxsize, int numstates,
        int i, bits;
        sizebuf_t buf;
        unsigned char data[128];
-       prvm_eval_t *val;
        qboolean success = false;
 
        // prepare the buffer
@@ -713,8 +693,7 @@ qboolean EntityFrameQuake_WriteFrame(sizebuf_t *msg, int maxsize, int numstates,
        {
                ENTITYSIZEPROFILING_START(msg, states[i]->number);
                s = states[i];
-               val = PRVM_EDICTFIELDVALUE((&prog->edicts[s->number]), prog->fieldoffsets.SendEntity);
-               if(val && val->function)
+               if(PRVM_serveredictfunction((&prog->edicts[s->number]), SendEntity))
                        continue;
 
                // prepare the buffer
@@ -1409,7 +1388,6 @@ qboolean EntityFrame_WriteFrame(sizebuf_t *msg, int maxsize, entityframe_databas
        entity_frame_t *o = &d->deltaframe;
        const entity_state_t *ent, *delta;
        vec3_t eye;
-       prvm_eval_t *val;
 
        d->latestframenum++;
 
@@ -1441,8 +1419,7 @@ qboolean EntityFrame_WriteFrame(sizebuf_t *msg, int maxsize, entityframe_databas
                ent = states[i];
                number = ent->number;
 
-               val = PRVM_EDICTFIELDVALUE((&prog->edicts[number]), prog->fieldoffsets.SendEntity);
-               if(val && val->function)
+               if (PRVM_serveredictfunction((&prog->edicts[number]), SendEntity))
                        continue;
                for (;onum < o->numentities && o->entitydata[onum].number < number;onum++)
                {
@@ -1887,7 +1864,6 @@ qboolean EntityFrame4_WriteFrame(sizebuf_t *msg, int maxsize, entityframe4_datab
        int i, n, startnumber;
        sizebuf_t buf;
        unsigned char data[128];
-       prvm_eval_t *val;
 
        // if there isn't enough space to accomplish anything, skip it
        if (msg->cursize + 24 > maxsize)
@@ -1932,8 +1908,7 @@ qboolean EntityFrame4_WriteFrame(sizebuf_t *msg, int maxsize, entityframe4_datab
        d->currententitynumber = 1;
        for (i = 0, n = startnumber;n < prog->max_edicts;n++)
        {
-               val = PRVM_EDICTFIELDVALUE((&prog->edicts[n]), prog->fieldoffsets.SendEntity);
-               if(val && val->function)
+               if (PRVM_serveredictfunction((&prog->edicts[n]), SendEntity))
                        continue;
                // find the old state to delta from
                e = EntityFrame4_GetReferenceEntity(d, n);
@@ -2089,15 +2064,13 @@ void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbi
        //dp_model_t *model;
        ENTITYSIZEPROFILING_START(msg, s->number);
 
-       prvm_eval_t *val;
-       val = PRVM_EDICTFIELDVALUE((&prog->edicts[s->number]), prog->fieldoffsets.SendEntity);
-       if(val && val->function)
-               return;
-
        if (s->active != ACTIVE_NETWORK)
                MSG_WriteShort(msg, number | 0x8000);
        else
        {
+               if (PRVM_serveredictfunction((&prog->edicts[s->number]), SendEntity))
+                       return;
+
                bits = changedbits;
                if ((bits & E5_ORIGIN) && (!(s->flags & RENDER_LOWPRECISION) || s->exteriormodelforclient || s->tagentity || s->viewmodelforclient || (s->number >= 1 && s->number <= svs.maxclients) || s->origin[0] <= -4096.0625 || s->origin[0] >= 4095.9375 || s->origin[1] <= -4096.0625 || s->origin[1] >= 4095.9375 || s->origin[2] <= -4096.0625 || s->origin[2] >= 4095.9375))
                // maybe also add: ((model = SV_GetModelByIndex(s->modelindex)) != NULL && model->name[0] == '*')
@@ -2232,11 +2205,82 @@ void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbi
                        MSG_WriteByte(msg, s->glowmod[1]);
                        MSG_WriteByte(msg, s->glowmod[2]);
                }
+               if (bits & E5_COMPLEXANIMATION)
+               {
+                       if (s->skeletonobject.model && s->skeletonobject.relativetransforms)
+                       {
+                               int numbones = s->skeletonobject.model->num_bones;
+                               int bonenum;
+                               short pose6s[6];
+                               MSG_WriteByte(msg, 4);
+                               MSG_WriteShort(msg, s->modelindex);
+                               MSG_WriteByte(msg, numbones);
+                               for (bonenum = 0;bonenum < numbones;bonenum++)
+                               {
+                                       Matrix4x4_ToBonePose6s(s->skeletonobject.relativetransforms + bonenum, 64, pose6s);
+                                       MSG_WriteShort(msg, pose6s[0]);
+                                       MSG_WriteShort(msg, pose6s[1]);
+                                       MSG_WriteShort(msg, pose6s[2]);
+                                       MSG_WriteShort(msg, pose6s[3]);
+                                       MSG_WriteShort(msg, pose6s[4]);
+                                       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));
+                       }
+               }
+               if (bits & E5_TRAILEFFECTNUM)
+                       MSG_WriteShort(msg, s->traileffectnum);
        }
 
        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;
@@ -2350,6 +2394,109 @@ static void EntityState5_ReadUpdate(entity_state_t *s, int number)
                s->glowmod[1] = MSG_ReadByte();
                s->glowmod[2] = MSG_ReadByte();
        }
+       if (bits & E5_COMPLEXANIMATION)
+       {
+               skeleton_t *skeleton;
+               const dp_model_t *model;
+               int modelindex;
+               int type;
+               int bonenum;
+               int numbones;
+               short pose6s[6];
+               type = MSG_ReadByte();
+               switch(type)
+               {
+               case 0:
+                       s->framegroupblend[0].frame = MSG_ReadShort();
+                       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[1].start = 0;
+                       s->framegroupblend[2].start = 0;
+                       s->framegroupblend[3].start = 0;
+                       s->framegroupblend[0].lerp = 1;
+                       s->framegroupblend[1].lerp = 0;
+                       s->framegroupblend[2].lerp = 0;
+                       s->framegroupblend[3].lerp = 0;
+                       break;
+               case 1:
+                       s->framegroupblend[0].frame = MSG_ReadShort();
+                       s->framegroupblend[1].frame = MSG_ReadShort();
+                       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[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[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[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[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[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);
+                       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();
+                       model = CL_GetModelByIndex(modelindex);
+                       numbones = MSG_ReadByte();
+                       if (model && numbones != model->num_bones)
+                               Host_Error("E5_COMPLEXANIMATION: model has different number of bones than network packet describes\n");
+                       if (!skeleton->relativetransforms || skeleton->model != model)
+                       {
+                               skeleton->model = model;
+                               skeleton->relativetransforms = (matrix4x4_t *) Mem_Realloc(cls.levelmempool, skeleton->relativetransforms, sizeof(*skeleton->relativetransforms) * skeleton->model->num_bones);
+                               for (bonenum = 0;bonenum < model->num_bones;bonenum++)
+                                       skeleton->relativetransforms[bonenum] = identitymatrix;
+                       }
+                       for (bonenum = 0;bonenum < numbones;bonenum++)
+                       {
+                               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();
+                               Matrix4x4_FromBonePose6s(skeleton->relativetransforms + bonenum, 1.0f / 64.0f, pose6s);
+                       }
+                       s->skeletonobject = *skeleton;
+                       break;
+               default:
+                       Host_Error("E5_COMPLEXANIMATION: Parse error - unknown type %i\n", type);
+                       break;
+               }
+       }
+       if (bits & E5_TRAILEFFECTNUM)
+               s->traileffectnum = (unsigned short) MSG_ReadShort();
 
 
        if (developer_networkentities.integer >= 2)
@@ -2448,6 +2595,10 @@ static int EntityState5_DeltaBits(const entity_state_t *o, const entity_state_t
                        bits |= E5_COLORMOD;
                if (o->glowmod[0] != n->glowmod[0] || o->glowmod[1] != n->glowmod[1] || o->glowmod[2] != n->glowmod[2])
                        bits |= E5_GLOWMOD;
+               if (n->flags & RENDER_COMPLEXANIMATION)
+                       bits |= E5_COMPLEXANIMATION;
+               if (o->traileffectnum != n->traileffectnum)
+                       bits |= E5_TRAILEFFECTNUM;
        }
        else
                if (o->active == ACTIVE_NETWORK)
@@ -2712,6 +2863,7 @@ qboolean EntityFrame5_WriteFrame(sizebuf_t *msg, int maxsize, entityframe5_datab
                                        packetlog = d->packetlog + packetlognumber;
                                        packetlog->packetnumber = framenum;
                                        packetlog->numstates = 0;
+                                       memset(packetlog->statsdeltabits, 0, sizeof(packetlog->statsdeltabits));
                                }
                                packetlog->statsdeltabits[i>>3] |= (1<<(i&7));
                                if (host_client->stats[i] >= 0 && host_client->stats[i] < 256)
@@ -2742,6 +2894,7 @@ qboolean EntityFrame5_WriteFrame(sizebuf_t *msg, int maxsize, entityframe5_datab
                packetlog = d->packetlog + packetlognumber;
                packetlog->packetnumber = framenum;
                packetlog->numstates = 0;
+               memset(packetlog->statsdeltabits, 0, sizeof(packetlog->statsdeltabits));
        }
 
        // write state updates
index e9d5874aa9cfcb8e5795530e6db5a454ddd4122b..c101665d53f93ffb0538ed8a3ac58f0724e36408 100644 (file)
@@ -333,6 +333,7 @@ void Protocol_Names(char *buffer, size_t buffersize);
 #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_COMPLEXANIMATION 128
 
 #define RENDER_SHADOW 65536 // cast shadow
 #define RENDER_LIGHT 131072 // receive light
@@ -343,6 +344,28 @@ void Protocol_Names(char *buffer, size_t buffersize);
 #define RENDER_ADDITIVE 2097152
 #define RENDER_DOUBLESIDED 4194304
 
+#define MAX_FRAMEGROUPBLENDS 4
+typedef struct framegroupblend_s
+{
+       // animation number and blend factor
+       // (for most models this is the frame number)
+       int frame;
+       float lerp;
+       // time frame began playing (for framegroup animations)
+       double start;
+}
+framegroupblend_t;
+
+struct matrix4x4_s;
+struct model_s;
+
+typedef struct skeleton_s
+{
+       const struct model_s *model;
+       struct matrix4x4_s *relativetransforms;
+}
+skeleton_t;
+
 typedef enum entity_state_active_e
 {
        ACTIVE_NOT = 0,
@@ -351,7 +374,7 @@ typedef enum entity_state_active_e
 }
 entity_state_active_t;
 
-// this is 96 bytes
+// this was 96 bytes, now 168 bytes (32bit) or 176 bytes (64bit)
 typedef struct entity_state_s
 {
        // ! means this is not sent to client
@@ -370,6 +393,7 @@ typedef struct entity_state_s
        unsigned short exteriormodelforclient; // ! not shown if first person viewing from this entity, shown in all other cases
        unsigned short nodrawtoclient; // !
        unsigned short drawonlytoclient; // !
+       unsigned short traileffectnum;
        unsigned short light[4]; // color*256 (0.00 to 255.996), and radius*1
        unsigned char active; // true if a valid state
        unsigned char lightstyle;
@@ -385,6 +409,9 @@ typedef struct entity_state_s
        unsigned char tagindex;
        unsigned char colormod[3];
        unsigned char glowmod[3];
+       // LordHavoc: very big data here :(
+       framegroupblend_t framegroupblend[4];
+       skeleton_t skeletonobject;
 }
 entity_state_t;
 
@@ -713,10 +740,15 @@ void EntityFrame4_CL_ReadFrame(void);
 
 // byte[3] = s->glowmod[0], s->glowmod[1], s->glowmod[2]
 #define E5_GLOWMOD (1<<24)
-// unused
-#define E5_UNUSED25 (1<<25)
-// unused
-#define E5_UNUSED26 (1<<26)
+// byte type=0 short frames[1] short times[1]
+// byte type=1 short frames[2] short times[2] byte lerps[2]
+// byte type=2 short frames[3] short times[3] byte lerps[3]
+// byte type=3 short frames[4] short times[4] byte lerps[4]
+// byte type=4 short modelindex byte numbones {short pose6s[6]}
+// see also RENDER_COMPLEXANIMATION
+#define E5_COMPLEXANIMATION (1<<25)
+// ushort traileffectnum
+#define E5_TRAILEFFECTNUM (1<<26)
 // unused
 #define E5_UNUSED27 (1<<27)
 // unused
index f604516e9b04e5419381d92422a5e641c0ca0fae..716762eddc42ef56b32069a258b272bff396475d 100644 (file)
@@ -55,7 +55,6 @@ void VM_CheckEmptyString (const char *s)
 
 void VM_GenerateFrameGroupBlend(framegroupblend_t *framegroupblend, const prvm_edict_t *ed)
 {
-       prvm_eval_t *val;
        // self.frame is the interpolation target (new frame)
        // self.frame1time is the animation base time for the interpolation target
        // self.frame2 is the interpolation start (previous frame)
@@ -65,17 +64,17 @@ void VM_GenerateFrameGroupBlend(framegroupblend_t *framegroupblend, const prvm_e
        // self.lerpfrac4 is the interpolation strength for self.frame4
        // pitch angle on a player model where the animator set up 5 sets of
        // animations and the csqc simply lerps between sets)
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame))) framegroupblend[0].frame = (int) val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2))) framegroupblend[1].frame = (int) val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame3))) framegroupblend[2].frame = (int) val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame4))) framegroupblend[3].frame = (int) val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame1time))) framegroupblend[0].start = val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2time))) framegroupblend[1].start = val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame3time))) framegroupblend[2].start = val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame4time))) framegroupblend[3].start = val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac))) framegroupblend[1].lerp = val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac3))) framegroupblend[2].lerp = val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac4))) framegroupblend[3].lerp = val->_float;
+       framegroupblend[0].frame = (int) PRVM_gameedictfloat(ed, frame     );
+       framegroupblend[1].frame = (int) PRVM_gameedictfloat(ed, frame2    );
+       framegroupblend[2].frame = (int) PRVM_gameedictfloat(ed, frame3    );
+       framegroupblend[3].frame = (int) PRVM_gameedictfloat(ed, frame4    );
+       framegroupblend[0].start =       PRVM_gameedictfloat(ed, frame1time);
+       framegroupblend[1].start =       PRVM_gameedictfloat(ed, frame2time);
+       framegroupblend[2].start =       PRVM_gameedictfloat(ed, frame3time);
+       framegroupblend[3].start =       PRVM_gameedictfloat(ed, frame4time);
+       framegroupblend[1].lerp  =       PRVM_gameedictfloat(ed, lerpfrac  );
+       framegroupblend[2].lerp  =       PRVM_gameedictfloat(ed, lerpfrac3 );
+       framegroupblend[3].lerp  =       PRVM_gameedictfloat(ed, lerpfrac4 );
        // assume that the (missing) lerpfrac1 is whatever remains after lerpfrac2+lerpfrac3+lerpfrac4 are summed
        framegroupblend[0].lerp = 1 - framegroupblend[1].lerp - framegroupblend[2].lerp - framegroupblend[3].lerp;
 }
@@ -198,8 +197,7 @@ void VM_UpdateEdictSkeleton(prvm_edict_t *ed, const dp_model_t *edmodel, const f
        {
                int skeletonindex = -1;
                skeleton_t *skeleton;
-               prvm_eval_t *val;
-               if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.skeletonindex))) skeletonindex = (int)val->_float - 1;
+               skeletonindex = (int)PRVM_gameedictfloat(ed, skeletonindex) - 1;
                if (skeletonindex >= 0 && skeletonindex < MAX_EDICTS && (skeleton = prog->skeletons[skeletonindex]) && skeleton->model->num_bones == ed->priv.server->skeleton.model->num_bones)
                {
                        // custom skeleton controlled by the game (FTE_CSQC_SKELETONOBJECTS)
@@ -312,11 +310,8 @@ void VM_error (void)
 
        VM_VarString(0, string, sizeof(string));
        Con_Printf("======%s ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
-       if (prog->globaloffsets.self >= 0)
-       {
-               ed = PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict);
-               PRVM_ED_Print(ed, NULL);
-       }
+       ed = PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self));
+       PRVM_ED_Print(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);
 }
@@ -338,16 +333,9 @@ void VM_objerror (void)
 
        VM_VarString(0, string, sizeof(string));
        Con_Printf("======OBJECT ERROR======\n"); // , PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string); // or include them? FIXME
-       if (prog->globaloffsets.self >= 0)
-       {
-               ed = PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict);
-               PRVM_ED_Print(ed, NULL);
-
-               PRVM_ED_Free (ed);
-       }
-       else
-               // objerror has to display the object fields -> else call
-               PRVM_ERROR ("VM_objecterror: self not defined !");
+       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);
 }
 
@@ -1115,7 +1103,7 @@ void VM_findchain (void)
                if (strcmp(t,s))
                        continue;
 
-               PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_NUM_FOR_EDICT(chain);
+               PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_NUM_FOR_EDICT(chain);
                chain = ent;
        }
 
@@ -1163,7 +1151,7 @@ void VM_findchainfloat (void)
                if (PRVM_E_FLOAT(ent,f) != s)
                        continue;
 
-               PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_EDICT_TO_PROG(chain);
+               PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain);
                chain = ent;
        }
 
@@ -1251,7 +1239,7 @@ void VM_findchainflags (void)
                if (!((int)PRVM_E_FLOAT(ent,f) & s))
                        continue;
 
-               PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_EDICT_TO_PROG(chain);
+               PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain);
                chain = ent;
        }
 
@@ -2019,7 +2007,7 @@ Return the number of entity fields - NOT offsets
 */
 void VM_numentityfields(void)
 {
-       PRVM_G_FLOAT(OFS_RETURN) = prog->progs->numfielddefs;
+       PRVM_G_FLOAT(OFS_RETURN) = prog->numfielddefs;
 }
 
 // KrimZon - DP_QC_ENTITYDATA
@@ -2036,7 +2024,7 @@ void VM_entityfieldname(void)
        ddef_t *d;
        int i = (int)PRVM_G_FLOAT(OFS_PARM0);
        
-       if (i < 0 || i >= prog->progs->numfielddefs)
+       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("");
@@ -2060,7 +2048,7 @@ void VM_entityfieldtype(void)
        ddef_t *d;
        int i = (int)PRVM_G_FLOAT(OFS_PARM0);
        
-       if (i < 0 || i >= prog->progs->numfielddefs)
+       if (i < 0 || i >= prog->numfielddefs)
        {
                VM_Warning("VM_entityfieldtype: %s: field index out of bounds\n", PRVM_NAME);
                PRVM_G_FLOAT(OFS_RETURN) = -1.0;
@@ -2088,7 +2076,7 @@ void VM_getentityfieldstring(void)
        prvm_edict_t * ent;
        int i = (int)PRVM_G_FLOAT(OFS_PARM0);
        
-       if (i < 0 || i >= prog->progs->numfielddefs)
+       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("");
@@ -2135,7 +2123,7 @@ void VM_putentityfieldstring(void)
        prvm_edict_t * ent;
        int i = (int)PRVM_G_FLOAT(OFS_PARM0);
 
-       if (i < 0 || i >= prog->progs->numfielddefs)
+       if (i < 0 || i >= prog->numfielddefs)
        {
         VM_Warning("VM_entityfielddata: %s: field index out of bounds\n", PRVM_NAME);
                PRVM_G_FLOAT(OFS_RETURN) = 0.0f;
@@ -2935,7 +2923,8 @@ void VM_getsoundtime (void)
        }
        entnum = ((pnum == PRVM_CLIENTPROG) ? MAX_EDICTS : 0) + PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0));
        entchannel = (int)PRVM_G_FLOAT(OFS_PARM1);
-       if (entchannel <= 0 || entchannel > 8)
+       entchannel = CHAN_USER2ENGINE(entchannel);
+       if (!IS_CHAN(entchannel))
                VM_Warning("VM_getsoundtime: %s: bad channel %i\n", PRVM_NAME, entchannel);
        PRVM_G_FLOAT(OFS_RETURN) = (float)S_GetEntChannelPosition(entnum, entchannel);
 }
@@ -3296,28 +3285,20 @@ void getdrawfontscale(float *sx, float *sy)
 {
        vec3_t v;
        *sx = *sy = 1;
-       if(prog->globaloffsets.drawfontscale >= 0)
+       VectorCopy(PRVM_drawglobalvector(drawfontscale), v);
+       if(VectorLength2(v) > 0)
        {
-               VectorCopy(PRVM_G_VECTOR(prog->globaloffsets.drawfontscale), v);
-               if(VectorLength2(v) > 0)
-               {
-                       *sx = v[0];
-                       *sy = v[1];
-               }
+               *sx = v[0];
+               *sy = v[1];
        }
 }
 
 dp_font_t *getdrawfont(void)
 {
-       if(prog->globaloffsets.drawfont >= 0)
-       {
-               int f = (int) PRVM_G_FLOAT(prog->globaloffsets.drawfont);
-               if(f < 0 || f >= dp_fonts.maxsize)
-                       return FONT_DEFAULT;
-               return &dp_fonts.f[f];
-       }
-       else
+       int f = (int) PRVM_drawglobalfloat(drawfont);
+       if(f < 0 || f >= dp_fonts.maxsize)
                return FONT_DEFAULT;
+       return &dp_fonts.f[f];
 }
 
 /*
@@ -3374,22 +3355,23 @@ 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)
 {
        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)
        {
@@ -3717,9 +3699,9 @@ void VM_drawpic(void)
 {
        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);
@@ -3735,7 +3717,8 @@ void VM_drawpic(void)
        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)
        {
@@ -4449,17 +4432,8 @@ void makevectors(vector angle)
 */
 void VM_makevectors (void)
 {
-       prvm_eval_t *valforward, *valright, *valup;
-       valforward = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_forward);
-       valright = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_right);
-       valup = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_up);
-       if (!valforward || !valright || !valup)
-       {
-               VM_Warning("makevectors: could not find v_forward, v_right, or v_up global variables\n");
-               return;
-       }
        VM_SAFEPARMCOUNT(1, VM_makevectors);
-       AngleVectors (PRVM_G_VECTOR(OFS_PARM0), valforward->vector, valright->vector, valup->vector);
+       AngleVectors(PRVM_G_VECTOR(OFS_PARM0), PRVM_gameglobalvector(v_forward), PRVM_gameglobalvector(v_right), PRVM_gameglobalvector(v_up));
 }
 
 /*
@@ -4472,18 +4446,9 @@ vectorvectors(vector)
 */
 void VM_vectorvectors (void)
 {
-       prvm_eval_t *valforward, *valright, *valup;
-       valforward = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_forward);
-       valright = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_right);
-       valup = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_up);
-       if (!valforward || !valright || !valup)
-       {
-               VM_Warning("vectorvectors: could not find v_forward, v_right, or v_up global variables\n");
-               return;
-       }
        VM_SAFEPARMCOUNT(1, VM_vectorvectors);
-       VectorNormalize2(PRVM_G_VECTOR(OFS_PARM0), valforward->vector);
-       VectorVectors(valforward->vector, valright->vector, valup->vector);
+       VectorNormalize2(PRVM_G_VECTOR(OFS_PARM0), PRVM_gameglobalvector(v_forward));
+       VectorVectors(PRVM_gameglobalvector(v_forward), PRVM_gameglobalvector(v_right), PRVM_gameglobalvector(v_up));
 }
 
 /*
@@ -5263,7 +5228,7 @@ void VM_changeyaw (void)
        // parameters because they are the parameters to SV_MoveToGoal, not this
        //VM_SAFEPARMCOUNT(0, VM_changeyaw);
 
-       ent = PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict);
+       ent = PRVM_PROG_TO_EDICT(PRVM_gameglobaledict(self));
        if (ent == prog->edicts)
        {
                VM_Warning("changeyaw: can not modify world entity\n");
@@ -5274,14 +5239,10 @@ void VM_changeyaw (void)
                VM_Warning("changeyaw: can not modify free entity\n");
                return;
        }
-       if (prog->fieldoffsets.angles < 0 || prog->fieldoffsets.ideal_yaw < 0 || prog->fieldoffsets.yaw_speed < 0)
-       {
-               VM_Warning("changeyaw: angles, ideal_yaw, or yaw_speed field(s) not found\n");
-               return;
-       }
-       current = ANGLEMOD(PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[1]);
-       ideal = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.ideal_yaw)->_float;
-       speed = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.yaw_speed)->_float;
+       current = PRVM_gameedictvector(ent, angles)[1];
+       current = ANGLEMOD(current);
+       ideal = PRVM_gameedictfloat(ent, ideal_yaw);
+       speed = PRVM_gameedictfloat(ent, yaw_speed);
 
        if (current == ideal)
                return;
@@ -5307,7 +5268,8 @@ void VM_changeyaw (void)
                        move = -speed;
        }
 
-       PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[1] = ANGLEMOD (current + move);
+       current += move;
+       PRVM_gameedictvector(ent, angles)[1] = ANGLEMOD(current);
 }
 
 /*
@@ -5333,14 +5295,10 @@ void VM_changepitch (void)
                VM_Warning("changepitch: can not modify free entity\n");
                return;
        }
-       if (prog->fieldoffsets.angles < 0 || prog->fieldoffsets.idealpitch < 0 || prog->fieldoffsets.pitch_speed < 0)
-       {
-               VM_Warning("changepitch: angles, idealpitch, or pitch_speed field(s) not found\n");
-               return;
-       }
-       current = ANGLEMOD(PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[0]);
-       ideal = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.idealpitch)->_float;
-       speed = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.pitch_speed)->_float;
+       current = PRVM_gameedictvector(ent, angles)[0];
+       current = ANGLEMOD(current);
+       ideal = PRVM_gameedictfloat(ent, idealpitch);
+       speed = PRVM_gameedictfloat(ent, pitch_speed);
 
        if (current == ideal)
                return;
@@ -5366,7 +5324,8 @@ void VM_changepitch (void)
                        move = -speed;
        }
 
-       PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[0] = ANGLEMOD (current + move);
+       current += move;
+       PRVM_gameedictvector(ent, angles)[0] = ANGLEMOD(current);
 }
 
 
@@ -5689,65 +5648,37 @@ void VM_wasfreed (void)
 
 void VM_SetTraceGlobals(const trace_t *trace)
 {
-       prvm_eval_t *val;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_allsolid)))
-               val->_float = trace->allsolid;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_startsolid)))
-               val->_float = trace->startsolid;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_fraction)))
-               val->_float = trace->fraction;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_inwater)))
-               val->_float = trace->inwater;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_inopen)))
-               val->_float = trace->inopen;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_endpos)))
-               VectorCopy(trace->endpos, val->vector);
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_plane_normal)))
-               VectorCopy(trace->plane.normal, val->vector);
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_plane_dist)))
-               val->_float = trace->plane.dist;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_ent)))
-               val->edict = PRVM_EDICT_TO_PROG(trace->ent ? trace->ent : prog->edicts);
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dpstartcontents)))
-               val->_float = trace->startsupercontents;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphitcontents)))
-               val->_float = trace->hitsupercontents;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphitq3surfaceflags)))
-               val->_float = trace->hitq3surfaceflags;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphittexturename)))
-               val->string = trace->hittexture ? PRVM_SetTempString(trace->hittexture->name) : 0;
+       PRVM_gameglobalfloat(trace_allsolid) = trace->allsolid;
+       PRVM_gameglobalfloat(trace_startsolid) = trace->startsolid;
+       PRVM_gameglobalfloat(trace_fraction) = trace->fraction;
+       PRVM_gameglobalfloat(trace_inwater) = trace->inwater;
+       PRVM_gameglobalfloat(trace_inopen) = trace->inopen;
+       VectorCopy(trace->endpos, PRVM_gameglobalvector(trace_endpos));
+       VectorCopy(trace->plane.normal, PRVM_gameglobalvector(trace_plane_normal));
+       PRVM_gameglobalfloat(trace_plane_dist) = trace->plane.dist;
+       PRVM_gameglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(trace->ent ? trace->ent : prog->edicts);
+       PRVM_gameglobalfloat(trace_dpstartcontents) = trace->startsupercontents;
+       PRVM_gameglobalfloat(trace_dphitcontents) = trace->hitsupercontents;
+       PRVM_gameglobalfloat(trace_dphitq3surfaceflags) = trace->hitq3surfaceflags;
+       PRVM_gameglobalstring(trace_dphittexturename) = trace->hittexture ? PRVM_SetTempString(trace->hittexture->name) : 0;
 }
 
 void VM_ClearTraceGlobals(void)
 {
        // clean up all trace globals when leaving the VM (anti-triggerbot safeguard)
-       prvm_eval_t *val;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_allsolid)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_startsolid)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_fraction)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_inwater)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_inopen)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_endpos)))
-               VectorClear(val->vector);
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_plane_normal)))
-               VectorClear(val->vector);
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_plane_dist)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_ent)))
-               val->edict = PRVM_EDICT_TO_PROG(prog->edicts);
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dpstartcontents)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphitcontents)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphitq3surfaceflags)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphittexturename)))
-               val->string = 0;
+       PRVM_gameglobalfloat(trace_allsolid) = 0;
+       PRVM_gameglobalfloat(trace_startsolid) = 0;
+       PRVM_gameglobalfloat(trace_fraction) = 0;
+       PRVM_gameglobalfloat(trace_inwater) = 0;
+       PRVM_gameglobalfloat(trace_inopen) = 0;
+       VectorClear(PRVM_gameglobalvector(trace_endpos));
+       VectorClear(PRVM_gameglobalvector(trace_plane_normal));
+       PRVM_gameglobalfloat(trace_plane_dist) = 0;
+       PRVM_gameglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(prog->edicts);
+       PRVM_gameglobalfloat(trace_dpstartcontents) = 0;
+       PRVM_gameglobalfloat(trace_dphitcontents) = 0;
+       PRVM_gameglobalfloat(trace_dphitq3surfaceflags) = 0;
+       PRVM_gameglobalstring(trace_dphittexturename) = 0;
 }
 
 //=============
@@ -5893,7 +5824,7 @@ static void uri_to_string_callback(int status, size_t length_received, unsigned
                
        PRVM_SetProg(handle->prognr);
        PRVM_Begin;
-               if((prog->starttime == handle->starttime) && (prog->funcoffsets.URI_Get_Callback))
+               if((prog->starttime == handle->starttime) && (PRVM_allfunction(URI_Get_Callback)))
                {
                        if(length_received >= sizeof(handle->buffer))
                                length_received = sizeof(handle->buffer) - 1;
@@ -5902,7 +5833,7 @@ static void uri_to_string_callback(int status, size_t length_received, unsigned
                        PRVM_G_FLOAT(OFS_PARM0) = handle->id;
                        PRVM_G_FLOAT(OFS_PARM1) = status;
                        PRVM_G_INT(OFS_PARM2) = PRVM_SetTempString(handle->buffer);
-                       PRVM_ExecuteProgram(prog->funcoffsets.URI_Get_Callback, "QC function URI_Get_Callback is missing");
+                       PRVM_ExecuteProgram(PRVM_allfunction(URI_Get_Callback), "QC function URI_Get_Callback is missing");
                }
        PRVM_End;
        
@@ -5928,7 +5859,7 @@ void VM_uri_get (void)
        const char *query_string = NULL;
        size_t lq;
 
-       if(!prog->funcoffsets.URI_Get_Callback)
+       if(!PRVM_allfunction(URI_Get_Callback))
                PRVM_ERROR("uri_get called by %s without URI_Get_Callback defined", PRVM_NAME);
 
        VM_SAFEPARMCOUNTRANGE(2, 6, VM_uri_get);
@@ -5953,7 +5884,7 @@ void VM_uri_get (void)
        handle->prognr = PRVM_GetProgNr();
        handle->starttime = prog->starttime;
        handle->id = id;
-       if(postseparator)
+       if(postseparator && posttype && *posttype)
        {
                size_t l = strlen(postseparator);
                if(poststringbuffer >= 0)
@@ -6573,7 +6504,6 @@ static animatemodel_cache_t animatemodel_cache;
 
 void animatemodel(dp_model_t *model, prvm_edict_t *ed)
 {
-       prvm_eval_t *val;
        skeleton_t *skeleton;
        int skeletonindex = -1;
        qboolean need = false;
@@ -6591,7 +6521,7 @@ void animatemodel(dp_model_t *model, prvm_edict_t *ed)
        VM_GenerateFrameGroupBlend(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;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.skeletonindex))) skeletonindex = (int)val->_float - 1;
+       skeletonindex = (int)PRVM_gameedictfloat(ed, skeletonindex) - 1;
        if (!(skeletonindex >= 0 && skeletonindex < MAX_EDICTS && (skeleton = prog->skeletons[skeletonindex]) && skeleton->model->num_bones == ed->priv.server->skeleton.model->num_bones))
                skeleton = NULL;
        need |= (animatemodel_cache.skeleton_p != skeleton);
@@ -6918,7 +6848,7 @@ void VM_getsurfaceclippedpoint(void)
        animatemodel(model, ed);
        applytransform_inverted(PRVM_G_VECTOR(OFS_PARM2), ed, p);
        clippointtosurface(ed, model, surface, p, out);
-       VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
+       VectorAdd(out, PRVM_serveredictvector(ed, origin), PRVM_G_VECTOR(OFS_RETURN));
 }
 
 //PF_getsurfacenumtriangles, // #??? float(entity e, float s) getsurfacenumtriangles = #???;
@@ -6997,7 +6927,7 @@ void VM_physics_enable(void)
                return;
        }
        // entity should have MOVETYPE_PHYSICS already set, this can damage memory (making leaked allocation) so warn about this even if non-developer
-       if (ed->fields.server->movetype != MOVETYPE_PHYSICS)
+       if (PRVM_serveredictfloat(ed, movetype) != MOVETYPE_PHYSICS)
        {
                VM_Warning("VM_physics_enable: entity is not MOVETYPE_PHYSICS!\n");
                return;
@@ -7021,14 +6951,14 @@ void VM_physics_addforce(void)
                return;
        }
        // entity should have MOVETYPE_PHYSICS already set, this can damage memory (making leaked allocation) so warn about this even if non-developer
-       if (ed->fields.server->movetype != MOVETYPE_PHYSICS)
+       if (PRVM_serveredictfloat(ed, movetype) != MOVETYPE_PHYSICS)
        {
                VM_Warning("VM_physics_addforce: entity is not MOVETYPE_PHYSICS!\n");
                return;
        }
        f.type = ODEFUNC_RELFORCEATPOS;
        VectorCopy(PRVM_G_VECTOR(OFS_PARM1), f.v1);
-       VectorSubtract(ed->fields.server->origin, PRVM_G_VECTOR(OFS_PARM2), f.v2);
+       VectorSubtract(PRVM_serveredictvector(ed, origin), PRVM_G_VECTOR(OFS_PARM2), f.v2);
        VM_physics_ApplyCmd(ed, &f);
 }
 
@@ -7047,7 +6977,7 @@ void VM_physics_addtorque(void)
                return;
        }
        // entity should have MOVETYPE_PHYSICS already set, this can damage memory (making leaked allocation) so warn about this even if non-developer
-       if (ed->fields.server->movetype != MOVETYPE_PHYSICS)
+       if (PRVM_serveredictfloat(ed, movetype) != MOVETYPE_PHYSICS)
        {
                VM_Warning("VM_physics_addtorque: entity is not MOVETYPE_PHYSICS!\n");
                return;
index e874eaae6602a9377fac137ddcfe98fc7aaa6e4d..ffe917a8060034737664e089d8cb042321b4740a 100644 (file)
@@ -29,6 +29,8 @@ static prvm_prog_t prog_list[PRVM_MAXPROGS];
 
 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);
 
@@ -212,7 +214,7 @@ Sets everything to NULL
 */
 void PRVM_ED_ClearEdict (prvm_edict_t *e)
 {
-       memset (e->fields.vp, 0, prog->progs->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
@@ -337,7 +339,7 @@ ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
        ddef_t          *def;
        int                     i;
 
-       for (i=0 ; i<prog->progs->numglobaldefs ; i++)
+       for (i = 0;i < prog->numglobaldefs;i++)
        {
                def = &prog->globaldefs[i];
                if (def->ofs == ofs)
@@ -356,7 +358,7 @@ ddef_t *PRVM_ED_FieldAtOfs (int ofs)
        ddef_t          *def;
        int                     i;
 
-       for (i=0 ; i<prog->progs->numfielddefs ; i++)
+       for (i = 0;i < prog->numfielddefs;i++)
        {
                def = &prog->fielddefs[i];
                if (def->ofs == ofs)
@@ -375,7 +377,7 @@ ddef_t *PRVM_ED_FindField (const char *name)
        ddef_t *def;
        int i;
 
-       for (i=0 ; i<prog->progs->numfielddefs ; i++)
+       for (i = 0;i < prog->numfielddefs;i++)
        {
                def = &prog->fielddefs[i];
                if (!strcmp(PRVM_GetString(def->s_name), name))
@@ -394,7 +396,7 @@ ddef_t *PRVM_ED_FindGlobal (const char *name)
        ddef_t *def;
        int i;
 
-       for (i=0 ; i<prog->progs->numglobaldefs ; i++)
+       for (i = 0;i < prog->numglobaldefs;i++)
        {
                def = &prog->globaldefs[i];
                if (!strcmp(PRVM_GetString(def->s_name), name))
@@ -414,7 +416,7 @@ mfunction_t *PRVM_ED_FindFunction (const char *name)
        mfunction_t             *func;
        int                             i;
 
-       for (i=0 ; i<prog->progs->numfunctions ; i++)
+       for (i = 0;i < prog->numfunctions;i++)
        {
                func = &prog->functions[i];
                if (!strcmp(PRVM_GetString(func->s_name), name))
@@ -645,7 +647,7 @@ void PRVM_ED_Print(prvm_edict_t *ed, const char *wildcard_fieldname)
 
        tempstring[0] = 0;
        dpsnprintf(tempstring, sizeof(tempstring), "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
-       for (i=1 ; i<prog->progs->numfielddefs ; i++)
+       for (i = 1;i < prog->numfielddefs;i++)
        {
                d = &prog->fielddefs[i];
                name = PRVM_GetString(d->s_name);
@@ -725,7 +727,7 @@ void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
                return;
        }
 
-       for (i=1 ; i<prog->progs->numfielddefs ; i++)
+       for (i = 1;i < prog->numfielddefs;i++)
        {
                d = &prog->fielddefs[i];
                name = PRVM_GetString(d->s_name);
@@ -902,7 +904,7 @@ void PRVM_ED_WriteGlobals (qfile_t *f)
        int                     type;
 
        FS_Print(f,"{\n");
-       for (i=0 ; i<prog->progs->numglobaldefs ; i++)
+       for (i = 0;i < prog->numglobaldefs;i++)
        {
                def = &prog->globaldefs[i];
                type = def->type;
@@ -1116,7 +1118,7 @@ void PRVM_GameCommand(const char *whichprogs, const char *whichcmd)
                return;
        }
 
-       if(!prog->funcoffsets.GameCommand)
+       if(!PRVM_allfunction(GameCommand))
        {
                Con_Printf("%s program do not support GameCommand!\n", whichprogs);
        }
@@ -1129,7 +1131,7 @@ void PRVM_GameCommand(const char *whichprogs, const char *whichcmd)
 
                restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
                PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(s ? s : "");
-               PRVM_ExecuteProgram (prog->funcoffsets.GameCommand, "QC function GameCommand is missing");
+               PRVM_ExecuteProgram (PRVM_allfunction(GameCommand), "QC function GameCommand is missing");
                vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
        }
 
@@ -1430,7 +1432,7 @@ void PRVM_ED_LoadFromFile (const char *data)
 
                // clear it
                if (ent != prog->edicts)        // hack
-                       memset (ent->fields.vp, 0, prog->progs->entityfields * 4);
+                       memset (ent->fields.vp, 0, prog->entityfields * 4);
 
                data = PRVM_ED_ParseEdict (data, ent);
                parsed++;
@@ -1443,11 +1445,11 @@ void PRVM_ED_LoadFromFile (const char *data)
                        continue;
                }
 
-               if (prog->funcoffsets.SV_OnEntityPreSpawnFunction)
+               if (PRVM_serverfunction(SV_OnEntityPreSpawnFunction))
                {
                        // self = ent
-                       PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
-                       PRVM_ExecuteProgram (prog->funcoffsets.SV_OnEntityPreSpawnFunction, "QC function SV_OnEntityPreSpawnFunction is missing");
+                       PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
+                       PRVM_ExecuteProgram (PRVM_serverfunction(SV_OnEntityPreSpawnFunction), "QC function SV_OnEntityPreSpawnFunction is missing");
                }
 
                if(ent->priv.required->free)
@@ -1460,10 +1462,8 @@ void PRVM_ED_LoadFromFile (const char *data)
 // immediately call spawn function, but only if there is a self global and a classname
 //
                if(!ent->priv.required->free)
-               if(prog->globaloffsets.self >= 0 && prog->fieldoffsets.classname >= 0)
                {
-                       string_t handle =  PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.classname)->string;
-                       if (!handle)
+                       if (!PRVM_alledictstring(ent, classname))
                        {
                                Con_Print("No classname for:\n");
                                PRVM_ED_Print(ent, NULL);
@@ -1472,20 +1472,20 @@ void PRVM_ED_LoadFromFile (const char *data)
                        }
 
                        // look for the spawn function
-                       funcname = PRVM_GetString(handle);
+                       funcname = PRVM_GetString(PRVM_alledictstring(ent, classname));
                        func = PRVM_ED_FindFunction (va("spawnfunc_%s", funcname));
                        if(!func)
-                               if(prog->globaloffsets.require_spawnfunc_prefix < 0)
+                               if(!PRVM_allglobalfloat(require_spawnfunc_prefix))
                                        func = PRVM_ED_FindFunction (funcname);
 
                        if (!func)
                        {
                                // check for OnEntityNoSpawnFunction
-                               if (prog->funcoffsets.SV_OnEntityNoSpawnFunction)
+                               if (PRVM_serverfunction(SV_OnEntityNoSpawnFunction))
                                {
                                        // self = ent
-                                       PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
-                                       PRVM_ExecuteProgram (prog->funcoffsets.SV_OnEntityNoSpawnFunction, "QC function SV_OnEntityNoSpawnFunction is missing");
+                                       PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
+                                       PRVM_ExecuteProgram (PRVM_serverfunction(SV_OnEntityNoSpawnFunction), "QC function SV_OnEntityNoSpawnFunction is missing");
                                }
                                else
                                {
@@ -1501,17 +1501,17 @@ void PRVM_ED_LoadFromFile (const char *data)
                        else
                        {
                                // self = ent
-                               PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
+                               PRVM_allglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
                                PRVM_ExecuteProgram (func - prog->functions, "");
                        }
                }
 
                if(!ent->priv.required->free)
-               if (prog->funcoffsets.SV_OnEntityPostSpawnFunction)
+               if (PRVM_serverfunction(SV_OnEntityPostSpawnFunction))
                {
                        // self = ent
-                       PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
-                       PRVM_ExecuteProgram (prog->funcoffsets.SV_OnEntityPostSpawnFunction, "QC function SV_OnEntityPostSpawnFunction is missing");
+                       PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
+                       PRVM_ExecuteProgram (PRVM_serverfunction(SV_OnEntityPostSpawnFunction), "QC function SV_OnEntityPostSpawnFunction is missing");
                }
 
                spawned++;
@@ -1529,231 +1529,81 @@ void PRVM_FindOffsets(void)
        // field and global searches use -1 for NULL
        memset(&prog->fieldoffsets, -1, sizeof(prog->fieldoffsets));
        memset(&prog->globaloffsets, -1, sizeof(prog->globaloffsets));
-       // functions use 0 for NULL
+       // function searches use 0 for NULL
        memset(&prog->funcoffsets, 0, sizeof(prog->funcoffsets));
-
-       // server and client qc use a lot of similar fields, so this is combined
-       prog->fieldoffsets.SendEntity                     = PRVM_ED_FindFieldOffset("SendEntity");
-       prog->fieldoffsets.SendFlags                      = PRVM_ED_FindFieldOffset("SendFlags");
-       prog->fieldoffsets.Version                        = PRVM_ED_FindFieldOffset("Version");
-       prog->fieldoffsets.alpha                          = PRVM_ED_FindFieldOffset("alpha");
-       prog->fieldoffsets.ammo_cells1                    = PRVM_ED_FindFieldOffset("ammo_cells1");
-       prog->fieldoffsets.ammo_lava_nails                = PRVM_ED_FindFieldOffset("ammo_lava_nails");
-       prog->fieldoffsets.ammo_multi_rockets             = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
-       prog->fieldoffsets.ammo_nails1                    = PRVM_ED_FindFieldOffset("ammo_nails1");
-       prog->fieldoffsets.ammo_plasma                    = PRVM_ED_FindFieldOffset("ammo_plasma");
-       prog->fieldoffsets.ammo_rockets1                  = PRVM_ED_FindFieldOffset("ammo_rockets1");
-       prog->fieldoffsets.ammo_shells1                   = PRVM_ED_FindFieldOffset("ammo_shells1");
-       prog->fieldoffsets.angles                         = PRVM_ED_FindFieldOffset("angles");
-       prog->fieldoffsets.button3                        = PRVM_ED_FindFieldOffset("button3");
-       prog->fieldoffsets.button4                        = PRVM_ED_FindFieldOffset("button4");
-       prog->fieldoffsets.button5                        = PRVM_ED_FindFieldOffset("button5");
-       prog->fieldoffsets.button6                        = PRVM_ED_FindFieldOffset("button6");
-       prog->fieldoffsets.button7                        = PRVM_ED_FindFieldOffset("button7");
-       prog->fieldoffsets.button8                        = PRVM_ED_FindFieldOffset("button8");
-       prog->fieldoffsets.button9                        = PRVM_ED_FindFieldOffset("button9");
-       prog->fieldoffsets.button10                       = PRVM_ED_FindFieldOffset("button10");
-       prog->fieldoffsets.button11                       = PRVM_ED_FindFieldOffset("button11");
-       prog->fieldoffsets.button12                       = PRVM_ED_FindFieldOffset("button12");
-       prog->fieldoffsets.button13                       = PRVM_ED_FindFieldOffset("button13");
-       prog->fieldoffsets.button14                       = PRVM_ED_FindFieldOffset("button14");
-       prog->fieldoffsets.button15                       = PRVM_ED_FindFieldOffset("button15");
-       prog->fieldoffsets.button16                       = PRVM_ED_FindFieldOffset("button16");
-       prog->fieldoffsets.buttonchat                     = PRVM_ED_FindFieldOffset("buttonchat");
-       prog->fieldoffsets.buttonuse                      = PRVM_ED_FindFieldOffset("buttonuse");
-       prog->fieldoffsets.chain                          = PRVM_ED_FindFieldOffset("chain");
-       prog->fieldoffsets.classname                      = PRVM_ED_FindFieldOffset("classname");
-       prog->fieldoffsets.clientcamera                   = PRVM_ED_FindFieldOffset("clientcamera");
-       prog->fieldoffsets.clientcolors                   = PRVM_ED_FindFieldOffset("clientcolors");
-       prog->fieldoffsets.clientstatus                   = PRVM_ED_FindFieldOffset("clientstatus");
-       prog->fieldoffsets.color                          = PRVM_ED_FindFieldOffset("color");
-       prog->fieldoffsets.colormod                       = PRVM_ED_FindFieldOffset("colormod");
-       prog->fieldoffsets.contentstransition             = PRVM_ED_FindFieldOffset("contentstransition");
-       prog->fieldoffsets.cursor_active                  = PRVM_ED_FindFieldOffset("cursor_active");
-       prog->fieldoffsets.cursor_screen                  = PRVM_ED_FindFieldOffset("cursor_screen");
-       prog->fieldoffsets.cursor_trace_endpos            = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
-       prog->fieldoffsets.cursor_trace_ent               = PRVM_ED_FindFieldOffset("cursor_trace_ent");
-       prog->fieldoffsets.cursor_trace_start             = PRVM_ED_FindFieldOffset("cursor_trace_start");
-       prog->fieldoffsets.customizeentityforclient       = PRVM_ED_FindFieldOffset("customizeentityforclient");
-       prog->fieldoffsets.dimension_hit                  = PRVM_ED_FindFieldOffset("dimension_hit");
-       prog->fieldoffsets.dimension_solid                = PRVM_ED_FindFieldOffset("dimension_solid");
-       prog->fieldoffsets.disableclientprediction        = PRVM_ED_FindFieldOffset("disableclientprediction");
-       prog->fieldoffsets.discardabledemo                = PRVM_ED_FindFieldOffset("discardabledemo");
-       prog->fieldoffsets.dphitcontentsmask              = PRVM_ED_FindFieldOffset("dphitcontentsmask");
-       prog->fieldoffsets.drawonlytoclient               = PRVM_ED_FindFieldOffset("drawonlytoclient");
-       prog->fieldoffsets.exteriormodeltoclient          = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
-       prog->fieldoffsets.fatness                        = PRVM_ED_FindFieldOffset("fatness");
-       prog->fieldoffsets.forceshader                    = PRVM_ED_FindFieldOffset("forceshader");
-       prog->fieldoffsets.frame                          = PRVM_ED_FindFieldOffset("frame");
-       prog->fieldoffsets.frame1time                     = PRVM_ED_FindFieldOffset("frame1time");
-       prog->fieldoffsets.frame2                         = PRVM_ED_FindFieldOffset("frame2");
-       prog->fieldoffsets.frame2time                     = PRVM_ED_FindFieldOffset("frame2time");
-       prog->fieldoffsets.frame3                         = PRVM_ED_FindFieldOffset("frame3");
-       prog->fieldoffsets.frame3time                     = PRVM_ED_FindFieldOffset("frame3time");
-       prog->fieldoffsets.frame4                         = PRVM_ED_FindFieldOffset("frame4");
-       prog->fieldoffsets.frame4time                     = PRVM_ED_FindFieldOffset("frame4time");
-       prog->fieldoffsets.fullbright                     = PRVM_ED_FindFieldOffset("fullbright");
-       prog->fieldoffsets.glow_color                     = PRVM_ED_FindFieldOffset("glow_color");
-       prog->fieldoffsets.glow_size                      = PRVM_ED_FindFieldOffset("glow_size");
-       prog->fieldoffsets.glow_trail                     = PRVM_ED_FindFieldOffset("glow_trail");
-       prog->fieldoffsets.glowmod                        = PRVM_ED_FindFieldOffset("glowmod");
-       prog->fieldoffsets.gravity                        = PRVM_ED_FindFieldOffset("gravity");
-       prog->fieldoffsets.groundentity                   = PRVM_ED_FindFieldOffset("groundentity");
-       prog->fieldoffsets.hull                           = PRVM_ED_FindFieldOffset("hull");
-       prog->fieldoffsets.ideal_yaw                      = PRVM_ED_FindFieldOffset("ideal_yaw");
-       prog->fieldoffsets.idealpitch                     = PRVM_ED_FindFieldOffset("idealpitch");
-       prog->fieldoffsets.items2                         = PRVM_ED_FindFieldOffset("items2");
-       prog->fieldoffsets.lerpfrac                       = PRVM_ED_FindFieldOffset("lerpfrac");
-       prog->fieldoffsets.lerpfrac3                      = PRVM_ED_FindFieldOffset("lerpfrac3");
-       prog->fieldoffsets.lerpfrac4                      = PRVM_ED_FindFieldOffset("lerpfrac4");
-       prog->fieldoffsets.light_lev                      = PRVM_ED_FindFieldOffset("light_lev");
-       prog->fieldoffsets.message                        = PRVM_ED_FindFieldOffset("message");
-       prog->fieldoffsets.modelflags                     = PRVM_ED_FindFieldOffset("modelflags");
-       prog->fieldoffsets.movement                       = PRVM_ED_FindFieldOffset("movement");
-       prog->fieldoffsets.movetypesteplandevent          = PRVM_ED_FindFieldOffset("movetypesteplandevent");
-       prog->fieldoffsets.netaddress                     = PRVM_ED_FindFieldOffset("netaddress");
-       prog->fieldoffsets.nextthink                      = PRVM_ED_FindFieldOffset("nextthink");
-       prog->fieldoffsets.nodrawtoclient                 = PRVM_ED_FindFieldOffset("nodrawtoclient");
-       prog->fieldoffsets.pflags                         = PRVM_ED_FindFieldOffset("pflags");
-       prog->fieldoffsets.ping                           = PRVM_ED_FindFieldOffset("ping");
-       prog->fieldoffsets.packetloss                     = PRVM_ED_FindFieldOffset("ping_packetloss");
-       prog->fieldoffsets.movementloss                   = PRVM_ED_FindFieldOffset("ping_movementloss");
-       prog->fieldoffsets.pitch_speed                    = PRVM_ED_FindFieldOffset("pitch_speed");
-       prog->fieldoffsets.playermodel                    = PRVM_ED_FindFieldOffset("playermodel");
-       prog->fieldoffsets.playerskin                     = PRVM_ED_FindFieldOffset("playerskin");
-       prog->fieldoffsets.pmodel                         = PRVM_ED_FindFieldOffset("pmodel");
-       prog->fieldoffsets.punchvector                    = PRVM_ED_FindFieldOffset("punchvector");
-       prog->fieldoffsets.renderamt                      = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
-       prog->fieldoffsets.renderflags                    = PRVM_ED_FindFieldOffset("renderflags");
-       prog->fieldoffsets.rendermode                     = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
-       prog->fieldoffsets.scale                          = PRVM_ED_FindFieldOffset("scale");
-       prog->fieldoffsets.shadertime                     = PRVM_ED_FindFieldOffset("shadertime");
-       prog->fieldoffsets.skeletonindex                  = PRVM_ED_FindFieldOffset("skeletonindex");
-       prog->fieldoffsets.style                          = PRVM_ED_FindFieldOffset("style");
-       prog->fieldoffsets.tag_entity                     = PRVM_ED_FindFieldOffset("tag_entity");
-       prog->fieldoffsets.tag_index                      = PRVM_ED_FindFieldOffset("tag_index");
-       prog->fieldoffsets.think                          = PRVM_ED_FindFieldOffset("think");
-       prog->fieldoffsets.viewmodelforclient             = PRVM_ED_FindFieldOffset("viewmodelforclient");
-       prog->fieldoffsets.viewzoom                       = PRVM_ED_FindFieldOffset("viewzoom");
-       prog->fieldoffsets.yaw_speed                      = PRVM_ED_FindFieldOffset("yaw_speed");
-       prog->fieldoffsets.bouncefactor                   = PRVM_ED_FindFieldOffset("bouncefactor");
-       prog->fieldoffsets.bouncestop                     = PRVM_ED_FindFieldOffset("bouncestop");
-
-       prog->fieldoffsets.solid                          = PRVM_ED_FindFieldOffset("solid");
-       prog->fieldoffsets.movetype                       = PRVM_ED_FindFieldOffset("movetype");
-       prog->fieldoffsets.modelindex                     = PRVM_ED_FindFieldOffset("modelindex");
-       prog->fieldoffsets.mins                           = PRVM_ED_FindFieldOffset("mins");
-       prog->fieldoffsets.maxs                           = PRVM_ED_FindFieldOffset("maxs");
-       prog->fieldoffsets.mass                           = PRVM_ED_FindFieldOffset("mass");
-       prog->fieldoffsets.origin                         = PRVM_ED_FindFieldOffset("origin");
-       prog->fieldoffsets.velocity                       = PRVM_ED_FindFieldOffset("velocity");
-       //prog->fieldoffsets.axis_forward                   = PRVM_ED_FindFieldOffset("axis_forward");
-       //prog->fieldoffsets.axis_left                      = PRVM_ED_FindFieldOffset("axis_left");
-       //prog->fieldoffsets.axis_up                        = PRVM_ED_FindFieldOffset("axis_up");
-       //prog->fieldoffsets.spinvelocity                   = PRVM_ED_FindFieldOffset("spinvelocity");
-       prog->fieldoffsets.angles                         = PRVM_ED_FindFieldOffset("angles");
-       prog->fieldoffsets.avelocity                      = PRVM_ED_FindFieldOffset("avelocity");
-       prog->fieldoffsets.aiment                         = PRVM_ED_FindFieldOffset("aiment");
-       prog->fieldoffsets.enemy                          = PRVM_ED_FindFieldOffset("enemy");
-       prog->fieldoffsets.jointtype                      = PRVM_ED_FindFieldOffset("jointtype");
-       prog->fieldoffsets.movedir                        = PRVM_ED_FindFieldOffset("movedir");
-
-       prog->fieldoffsets.camera_transform               = PRVM_ED_FindFieldOffset("camera_transform");
-       prog->fieldoffsets.userwavefunc_param0            = PRVM_ED_FindFieldOffset("userwavefunc_param0");
-       prog->fieldoffsets.userwavefunc_param1            = PRVM_ED_FindFieldOffset("userwavefunc_param1");
-       prog->fieldoffsets.userwavefunc_param2            = PRVM_ED_FindFieldOffset("userwavefunc_param2");
-       prog->fieldoffsets.userwavefunc_param3            = PRVM_ED_FindFieldOffset("userwavefunc_param3");
-
-       prog->fieldoffsets.crypto_keyfp                   = PRVM_ED_FindFieldOffset("crypto_keyfp");
-       prog->fieldoffsets.crypto_mykeyfp                 = PRVM_ED_FindFieldOffset("crypto_mykeyfp");
-       prog->fieldoffsets.crypto_idfp                    = PRVM_ED_FindFieldOffset("crypto_idfp");
-       prog->fieldoffsets.crypto_encryptmethod           = PRVM_ED_FindFieldOffset("crypto_encryptmethod");
-       prog->fieldoffsets.crypto_signmethod              = PRVM_ED_FindFieldOffset("crypto_signmethod");
-
-       prog->funcoffsets.CSQC_ConsoleCommand             = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand");
-       prog->funcoffsets.CSQC_Ent_Remove                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove");
-       prog->funcoffsets.CSQC_Ent_Spawn                  = PRVM_ED_FindFunctionOffset("CSQC_Ent_Spawn");
-       prog->funcoffsets.CSQC_Ent_Update                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Update");
-       prog->funcoffsets.CSQC_Event                      = PRVM_ED_FindFunctionOffset("CSQC_Event");
-       prog->funcoffsets.CSQC_Event_Sound                = PRVM_ED_FindFunctionOffset("CSQC_Event_Sound");
-       prog->funcoffsets.CSQC_Init                       = PRVM_ED_FindFunctionOffset("CSQC_Init");
-       prog->funcoffsets.CSQC_InputEvent                 = PRVM_ED_FindFunctionOffset("CSQC_InputEvent");
-       prog->funcoffsets.CSQC_Parse_CenterPrint          = PRVM_ED_FindFunctionOffset("CSQC_Parse_CenterPrint");
-       prog->funcoffsets.CSQC_Parse_Print                = PRVM_ED_FindFunctionOffset("CSQC_Parse_Print");
-       prog->funcoffsets.CSQC_Parse_StuffCmd             = PRVM_ED_FindFunctionOffset("CSQC_Parse_StuffCmd");
-       prog->funcoffsets.CSQC_Parse_TempEntity           = PRVM_ED_FindFunctionOffset("CSQC_Parse_TempEntity");
-       prog->funcoffsets.CSQC_Shutdown                   = PRVM_ED_FindFunctionOffset("CSQC_Shutdown");
-       prog->funcoffsets.CSQC_UpdateView                 = PRVM_ED_FindFunctionOffset("CSQC_UpdateView");
-       prog->funcoffsets.EndFrame                        = PRVM_ED_FindFunctionOffset("EndFrame");
-       prog->funcoffsets.GameCommand                     = PRVM_ED_FindFunctionOffset("GameCommand");
-       prog->funcoffsets.Gecko_Query                     = PRVM_ED_FindFunctionOffset("Gecko_Query");
-       prog->funcoffsets.RestoreGame                     = PRVM_ED_FindFunctionOffset("RestoreGame");
-       prog->funcoffsets.SV_ChangeTeam                   = PRVM_ED_FindFunctionOffset("SV_ChangeTeam");
-       prog->funcoffsets.SV_OnEntityNoSpawnFunction      = PRVM_ED_FindFunctionOffset("SV_OnEntityNoSpawnFunction");
-       prog->funcoffsets.SV_OnEntityPostSpawnFunction    = PRVM_ED_FindFunctionOffset("SV_OnEntityPostSpawnFunction");
-       prog->funcoffsets.SV_OnEntityPreSpawnFunction     = PRVM_ED_FindFunctionOffset("SV_OnEntityPreSpawnFunction");
-       prog->funcoffsets.SV_ParseClientCommand           = PRVM_ED_FindFunctionOffset("SV_ParseClientCommand");
-       prog->funcoffsets.SV_PausedTic                    = PRVM_ED_FindFunctionOffset("SV_PausedTic");
-       prog->funcoffsets.SV_PlayerPhysics                = PRVM_ED_FindFunctionOffset("SV_PlayerPhysics");
-       prog->funcoffsets.SV_Shutdown                     = PRVM_ED_FindFunctionOffset("SV_Shutdown");
-       prog->funcoffsets.URI_Get_Callback                = PRVM_ED_FindFunctionOffset("URI_Get_Callback");
-       prog->globaloffsets.SV_InitCmd                    = PRVM_ED_FindGlobalOffset("SV_InitCmd");
-       prog->globaloffsets.coop                          = PRVM_ED_FindGlobalOffset("coop");
-       prog->globaloffsets.deathmatch                    = PRVM_ED_FindGlobalOffset("deathmatch");
-       prog->globaloffsets.dmg_origin                    = PRVM_ED_FindGlobalOffset("dmg_origin");
-       prog->globaloffsets.dmg_save                      = PRVM_ED_FindGlobalOffset("dmg_save");
-       prog->globaloffsets.dmg_take                      = PRVM_ED_FindGlobalOffset("dmg_take");
-       prog->globaloffsets.drawfont                      = PRVM_ED_FindGlobalOffset("drawfont");
-       prog->globaloffsets.drawfontscale                 = PRVM_ED_FindGlobalOffset("drawfontscale");
-       prog->globaloffsets.gettaginfo_forward            = PRVM_ED_FindGlobalOffset("gettaginfo_forward");
-       prog->globaloffsets.gettaginfo_name               = PRVM_ED_FindGlobalOffset("gettaginfo_name");
-       prog->globaloffsets.gettaginfo_offset             = PRVM_ED_FindGlobalOffset("gettaginfo_offset");
-       prog->globaloffsets.gettaginfo_parent             = PRVM_ED_FindGlobalOffset("gettaginfo_parent");
-       prog->globaloffsets.gettaginfo_right              = PRVM_ED_FindGlobalOffset("gettaginfo_right");
-       prog->globaloffsets.gettaginfo_up                 = PRVM_ED_FindGlobalOffset("gettaginfo_up");
-       prog->globaloffsets.transparent_offset            = PRVM_ED_FindGlobalOffset("transparent_offset");
-       prog->globaloffsets.intermission                  = PRVM_ED_FindGlobalOffset("intermission");
-       prog->globaloffsets.require_spawnfunc_prefix      = PRVM_ED_FindGlobalOffset("require_spawnfunc_prefix");
-       prog->globaloffsets.sb_showscores                 = PRVM_ED_FindGlobalOffset("sb_showscores");
-       prog->globaloffsets.self                          = PRVM_ED_FindGlobalOffset("self");
-       prog->globaloffsets.serverdeltatime               = PRVM_ED_FindGlobalOffset("serverdeltatime");
-       prog->globaloffsets.serverprevtime                = PRVM_ED_FindGlobalOffset("serverprevtime");
-       prog->globaloffsets.servertime                    = PRVM_ED_FindGlobalOffset("servertime");
-       prog->globaloffsets.time                          = PRVM_ED_FindGlobalOffset("time");
-       prog->globaloffsets.trace_allsolid                = PRVM_ED_FindGlobalOffset("trace_allsolid");
-       prog->globaloffsets.trace_dphitcontents           = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
-       prog->globaloffsets.trace_dphitq3surfaceflags     = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
-       prog->globaloffsets.trace_dphittexturename        = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
-       prog->globaloffsets.trace_dpstartcontents         = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
-       prog->globaloffsets.trace_endpos                  = PRVM_ED_FindGlobalOffset("trace_endpos");
-       prog->globaloffsets.trace_ent                     = PRVM_ED_FindGlobalOffset("trace_ent");
-       prog->globaloffsets.trace_fraction                = PRVM_ED_FindGlobalOffset("trace_fraction");
-       prog->globaloffsets.trace_inopen                  = PRVM_ED_FindGlobalOffset("trace_inopen");
-       prog->globaloffsets.trace_inwater                 = PRVM_ED_FindGlobalOffset("trace_inwater");
-       prog->globaloffsets.trace_networkentity           = PRVM_ED_FindGlobalOffset("trace_networkentity");
-       prog->globaloffsets.trace_plane_dist              = PRVM_ED_FindGlobalOffset("trace_plane_dist");
-       prog->globaloffsets.trace_plane_normal            = PRVM_ED_FindGlobalOffset("trace_plane_normal");
-       prog->globaloffsets.trace_startsolid              = PRVM_ED_FindGlobalOffset("trace_startsolid");
-       prog->globaloffsets.v_forward                     = PRVM_ED_FindGlobalOffset("v_forward");
-       prog->globaloffsets.v_right                       = PRVM_ED_FindGlobalOffset("v_right");
-       prog->globaloffsets.v_up                          = PRVM_ED_FindGlobalOffset("v_up");
-       prog->globaloffsets.view_angles                   = PRVM_ED_FindGlobalOffset("view_angles");
-       prog->globaloffsets.view_punchangle               = PRVM_ED_FindGlobalOffset("view_punchangle");
-       prog->globaloffsets.view_punchvector              = PRVM_ED_FindGlobalOffset("view_punchvector");
-       prog->globaloffsets.worldstatus                   = PRVM_ED_FindGlobalOffset("worldstatus");
-       prog->globaloffsets.particles_alphamin            = PRVM_ED_FindGlobalOffset("particles_alphamin");
-       prog->globaloffsets.particles_alphamax            = PRVM_ED_FindGlobalOffset("particles_alphamax");
-       prog->globaloffsets.particles_colormin            = PRVM_ED_FindGlobalOffset("particles_colormin");
-       prog->globaloffsets.particles_colormax            = PRVM_ED_FindGlobalOffset("particles_colormax");
-
-       // menu qc only uses some functions, nothing else
-       prog->funcoffsets.m_draw                          = PRVM_ED_FindFunctionOffset("m_draw");
-       prog->funcoffsets.m_init                          = PRVM_ED_FindFunctionOffset("m_init");
-       prog->funcoffsets.m_keydown                       = PRVM_ED_FindFunctionOffset("m_keydown");
-       prog->funcoffsets.m_keyup                         = PRVM_ED_FindFunctionOffset("m_keyup");
-       prog->funcoffsets.m_shutdown                      = PRVM_ED_FindFunctionOffset("m_shutdown");
-       prog->funcoffsets.m_toggle                        = PRVM_ED_FindFunctionOffset("m_toggle");
-       prog->funcoffsets.m_newmap                        = PRVM_ED_FindFunctionOffset("m_newmap");
+#define PRVM_DECLARE_serverglobalfloat(x)
+#define PRVM_DECLARE_serverglobalvector(x)
+#define PRVM_DECLARE_serverglobalstring(x)
+#define PRVM_DECLARE_serverglobaledict(x)
+#define PRVM_DECLARE_serverglobalfunction(x)
+#define PRVM_DECLARE_clientglobalfloat(x)
+#define PRVM_DECLARE_clientglobalvector(x)
+#define PRVM_DECLARE_clientglobalstring(x)
+#define PRVM_DECLARE_clientglobaledict(x)
+#define PRVM_DECLARE_clientglobalfunction(x)
+#define PRVM_DECLARE_menuglobalfloat(x)
+#define PRVM_DECLARE_menuglobalvector(x)
+#define PRVM_DECLARE_menuglobalstring(x)
+#define PRVM_DECLARE_menuglobaledict(x)
+#define PRVM_DECLARE_menuglobalfunction(x)
+#define PRVM_DECLARE_serverfieldfloat(x)
+#define PRVM_DECLARE_serverfieldvector(x)
+#define PRVM_DECLARE_serverfieldstring(x)
+#define PRVM_DECLARE_serverfieldedict(x)
+#define PRVM_DECLARE_serverfieldfunction(x)
+#define PRVM_DECLARE_clientfieldfloat(x)
+#define PRVM_DECLARE_clientfieldvector(x)
+#define PRVM_DECLARE_clientfieldstring(x)
+#define PRVM_DECLARE_clientfieldedict(x)
+#define PRVM_DECLARE_clientfieldfunction(x)
+#define PRVM_DECLARE_menufieldfloat(x)
+#define PRVM_DECLARE_menufieldvector(x)
+#define PRVM_DECLARE_menufieldstring(x)
+#define PRVM_DECLARE_menufieldedict(x)
+#define PRVM_DECLARE_menufieldfunction(x)
+#define PRVM_DECLARE_serverfunction(x)
+#define PRVM_DECLARE_clientfunction(x)
+#define PRVM_DECLARE_menufunction(x)
+#define PRVM_DECLARE_field(x) prog->fieldoffsets.x = PRVM_ED_FindFieldOffset(#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);
+#include "prvm_offsets.h"
+#undef PRVM_DECLARE_serverglobalfloat
+#undef PRVM_DECLARE_serverglobalvector
+#undef PRVM_DECLARE_serverglobalstring
+#undef PRVM_DECLARE_serverglobaledict
+#undef PRVM_DECLARE_serverglobalfunction
+#undef PRVM_DECLARE_clientglobalfloat
+#undef PRVM_DECLARE_clientglobalvector
+#undef PRVM_DECLARE_clientglobalstring
+#undef PRVM_DECLARE_clientglobaledict
+#undef PRVM_DECLARE_clientglobalfunction
+#undef PRVM_DECLARE_menuglobalfloat
+#undef PRVM_DECLARE_menuglobalvector
+#undef PRVM_DECLARE_menuglobalstring
+#undef PRVM_DECLARE_menuglobaledict
+#undef PRVM_DECLARE_menuglobalfunction
+#undef PRVM_DECLARE_serverfieldfloat
+#undef PRVM_DECLARE_serverfieldvector
+#undef PRVM_DECLARE_serverfieldstring
+#undef PRVM_DECLARE_serverfieldedict
+#undef PRVM_DECLARE_serverfieldfunction
+#undef PRVM_DECLARE_clientfieldfloat
+#undef PRVM_DECLARE_clientfieldvector
+#undef PRVM_DECLARE_clientfieldstring
+#undef PRVM_DECLARE_clientfieldedict
+#undef PRVM_DECLARE_clientfieldfunction
+#undef PRVM_DECLARE_menufieldfloat
+#undef PRVM_DECLARE_menufieldvector
+#undef PRVM_DECLARE_menufieldstring
+#undef PRVM_DECLARE_menufieldedict
+#undef PRVM_DECLARE_menufieldfunction
+#undef PRVM_DECLARE_serverfunction
+#undef PRVM_DECLARE_clientfunction
+#undef PRVM_DECLARE_menufunction
+#undef PRVM_DECLARE_field
+#undef PRVM_DECLARE_global
+#undef PRVM_DECLARE_function
 }
 
 // not used
@@ -2059,7 +1909,8 @@ void PRVM_LoadLNO( const char *progname ) {
 <Spike>    SafeWrite (h, &numstatements, sizeof(int));
 <Spike>    SafeWrite (h, statement_linenums, numstatements*sizeof(int));
 */
-       if( (unsigned) filesize < (6 + prog->progs->numstatements) * sizeof( int ) ) {
+       if ((unsigned int)filesize < (6 + prog->progs_numstatements) * sizeof(int))
+       {
                Mem_Free(lno);
                return;
        }
@@ -2067,13 +1918,13 @@ void PRVM_LoadLNO( const char *progname ) {
        header = (unsigned int *) lno;
        if( header[ 0 ] == *(unsigned int *) "LNOF" &&
                LittleLong( header[ 1 ] ) == 1 &&
-               (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs->numglobaldefs &&
-               (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs->numglobals &&
-               (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs->numfielddefs &&
-               (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs->numstatements )
+               (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs_numglobaldefs &&
+               (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs_numglobals &&
+               (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs_numfielddefs &&
+               (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs_numstatements )
        {
-               prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof( int ) );
-               memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs->numstatements * sizeof( int ) );
+               prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof( int ) );
+               memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs_numstatements * sizeof( int ) );
        }
        Mem_Free( lno );
 }
@@ -2083,43 +1934,71 @@ 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, char **required_global)
+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)
 {
        int i;
-       dstatement_t *st;
+       dprograms_t *dprograms;
+       dstatement_t *instatements;
        ddef_t *infielddefs;
-       dfunction_t *dfunctions;
+       ddef_t *inglobaldefs;
+       float *inglobals;
+       dfunction_t *infunctions;
+       char *instrings;
        fs_offset_t filesize;
+       int requiredglobalspace;
+       opcode_t op;
+       int a;
+       int b;
+       int c;
 
-       if( prog->loaded ) {
+       if (prog->loaded)
                PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!", PRVM_NAME );
-       }
 
-       prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
-       if (prog->progs == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
+       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);
        // 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->filecrc = CRC_Block((unsigned char *)prog->progs, filesize);
-
-// byte swap the header
-       for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
-               ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
-
-       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);
-       if (prog->progs->crc != prog->headercrc && prog->progs->crc != prog->headercrc2)
-               PRVM_ERROR ("%s: %s system vars have been modified (CRC of progs.dat systemvars %i != engine %i), progdefs.h is out of date", PRVM_NAME, filename, prog->progs->crc, prog->headercrc);
+       requiredglobalspace = 0;
+       for (i = 0;i < numrequiredglobals;i++)
+               requiredglobalspace += required_global[i].type == ev_vector ? 3 : 1;
 
-       //prog->functions = (dfunction_t *)((unsigned char *)progs + progs->ofs_functions);
-       dfunctions = (dfunction_t *)((unsigned char *)prog->progs + prog->progs->ofs_functions);
+       prog->filecrc = CRC_Block((unsigned char *)dprograms, filesize);
 
-       if (prog->progs->ofs_strings + prog->progs->numstrings >= (int)filesize)
+// byte swap the header
+       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);
+       instatements = (dstatement_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_statements));
+       prog->progs_numstatements = LittleLong(dprograms->numstatements);
+       inglobaldefs = (ddef_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_globaldefs));
+       prog->progs_numglobaldefs = LittleLong(dprograms->numglobaldefs);
+       infielddefs = (ddef_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_fielddefs));
+       prog->progs_numfielddefs = LittleLong(dprograms->numfielddefs);
+       infunctions = (dfunction_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_functions));
+       prog->progs_numfunctions = LittleLong(dprograms->numfunctions);
+       instrings = (char *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_strings));
+       prog->progs_numstrings = LittleLong(dprograms->numstrings);
+       inglobals = (float *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_globals));
+       prog->progs_numglobals = LittleLong(dprograms->numglobals);
+       prog->progs_entityfields = LittleLong(dprograms->entityfields);
+
+       prog->numstatements = prog->progs_numstatements;
+       prog->numglobaldefs = prog->progs_numglobaldefs;
+       prog->numfielddefs = prog->progs_numfielddefs;
+       prog->numfunctions = prog->progs_numfunctions;
+       prog->numstrings = prog->progs_numstrings;
+       prog->numglobals = prog->progs_numglobals;
+       prog->entityfields = prog->progs_entityfields;
+
+       if (LittleLong(dprograms->ofs_strings) + prog->progs_numstrings >= (int)filesize)
                PRVM_ERROR ("%s: %s strings go past end of file", PRVM_NAME, filename);
-       prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
-       prog->stringssize = prog->progs->numstrings;
+       prog->strings = (char *)Mem_Alloc(prog->progs_mempool, prog->progs_numstrings);
+       memcpy(prog->strings, instrings, prog->progs_numstrings);
+       prog->stringssize = prog->progs_numstrings;
 
        prog->numknownstrings = 0;
        prog->maxknownstrings = 0;
@@ -2128,106 +2007,119 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
 
        Mem_ExpandableArray_NewArray(&prog->stringbuffersarray, prog->progs_mempool, sizeof(prvm_stringbuffer_t), 64);
 
-       prog->globaldefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_globaldefs);
-
-       // we need to expand the fielddefs list to include all the engine fields,
-       // so allocate a new place for it
-       infielddefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_fielddefs);
-       //                                                                                              ( + DPFIELDS                       )
-       prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs->numfielddefs + numrequiredfields) * sizeof(ddef_t));
-
-       prog->statements = (dstatement_t *)((unsigned char *)prog->progs + prog->progs->ofs_statements);
-
-       prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof(*prog->statement_profile));
-
-       //pr_global_struct = (globalvars_t *)((unsigned char *)progs + progs->ofs_globals);
-       prog->globals.generic = (float *)((unsigned char *)prog->progs + prog->progs->ofs_globals);
-
-// byte swap the lumps
-       for (i=0 ; i<prog->progs->numstatements ; i++)
-       {
-               prog->statements[i].op = LittleShort(prog->statements[i].op);
-               prog->statements[i].a = LittleShort(prog->statements[i].a);
-               prog->statements[i].b = LittleShort(prog->statements[i].b);
-               prog->statements[i].c = LittleShort(prog->statements[i].c);
-       }
-
-       prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
-       for (i = 0;i < prog->progs->numfunctions;i++)
-       {
-               prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
-               prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
-               prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
-               prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
-               prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
-               prog->functions[i].locals = LittleLong (dfunctions[i].locals);
-               memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
-               if(prog->functions[i].first_statement >= prog->progs->numstatements)
+       // we need to expand the globaldefs and fielddefs to include engine defs
+       prog->globaldefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numglobaldefs + numrequiredglobals) * sizeof(ddef_t));
+       prog->globals.generic = (float *)Mem_Alloc(prog->progs_mempool, (prog->progs_numglobals + requiredglobalspace) * sizeof(float));
+       prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numfielddefs + numrequiredfields) * sizeof(ddef_t));
+       // we need to convert the statements to our memory format
+       prog->statements = (mstatement_t *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof(mstatement_t));
+       // allocate space for profiling statement usage
+       prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof(*prog->statement_profile));
+       // functions need to be converted to the memory format
+       prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs_numfunctions);
+
+       for (i = 0;i < prog->progs_numfunctions;i++)
+       {
+               prog->functions[i].first_statement = LittleLong(infunctions[i].first_statement);
+               prog->functions[i].parm_start = LittleLong(infunctions[i].parm_start);
+               prog->functions[i].s_name = LittleLong(infunctions[i].s_name);
+               prog->functions[i].s_file = LittleLong(infunctions[i].s_file);
+               prog->functions[i].numparms = LittleLong(infunctions[i].numparms);
+               prog->functions[i].locals = LittleLong(infunctions[i].locals);
+               memcpy(prog->functions[i].parm_size, infunctions[i].parm_size, sizeof(infunctions[i].parm_size));
+               if(prog->functions[i].first_statement >= prog->numstatements)
                        PRVM_ERROR("PRVM_LoadProgs: out of bounds function statement (function %d) in %s", i, PRVM_NAME);
                // TODO bounds check parm_start, s_name, s_file, numparms, locals, parm_size
        }
 
-       for (i=0 ; i<prog->progs->numglobaldefs ; i++)
+       // copy the globaldefs to the new globaldefs list
+       for (i=0 ; i<prog->numglobaldefs ; i++)
        {
-               prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
-               prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
-               prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
+               prog->globaldefs[i].type = LittleShort(inglobaldefs[i].type);
+               prog->globaldefs[i].ofs = LittleShort(inglobaldefs[i].ofs);
+               prog->globaldefs[i].s_name = LittleLong(inglobaldefs[i].s_name);
                // TODO bounds check ofs, s_name
        }
 
+       // append the required globals
+       for (i = 0;i < numrequiredglobals;i++)
+       {
+               prog->globaldefs[prog->numglobaldefs].type = required_global[i].type;
+               prog->globaldefs[prog->numglobaldefs].ofs = prog->numglobals;
+               prog->globaldefs[prog->numglobaldefs].s_name = PRVM_SetEngineString(required_global[i].name);
+               if (prog->globaldefs[prog->numglobaldefs].type == ev_vector)
+                       prog->numglobals += 3;
+               else
+                       prog->numglobals++;
+               prog->numglobaldefs++;
+       }
+
        // copy the progs fields to the new fields list
-       for (i = 0;i < prog->progs->numfielddefs;i++)
+       for (i = 0;i < prog->numfielddefs;i++)
        {
-               prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
+               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->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
-               prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
+               prog->fielddefs[i].ofs = LittleShort(infielddefs[i].ofs);
+               prog->fielddefs[i].s_name = LittleLong(infielddefs[i].s_name);
                // TODO bounds check ofs, s_name
        }
 
        // append the required fields
-       for (i = 0;i < (int) numrequiredfields;i++)
+       for (i = 0;i < numrequiredfields;i++)
        {
-               prog->fielddefs[prog->progs->numfielddefs].type = required_field[i].type;
-               prog->fielddefs[prog->progs->numfielddefs].ofs = prog->progs->entityfields;
-               prog->fielddefs[prog->progs->numfielddefs].s_name = PRVM_SetEngineString(required_field[i].name);
-               // TODO bounds check ofs, s_name
-               if (prog->fielddefs[prog->progs->numfielddefs].type == ev_vector)
-                       prog->progs->entityfields += 3;
+               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);
+               if (prog->fielddefs[prog->numfielddefs].type == ev_vector)
+                       prog->entityfields += 3;
                else
-                       prog->progs->entityfields++;
-               prog->progs->numfielddefs++;
+                       prog->entityfields++;
+               prog->numfielddefs++;
        }
-       prog->entityfields = prog->progs->entityfields;
-
-       // 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);
 
-       // check required globals
-       for(i=0 ; i < numrequiredglobals ; i++)
-               if(PRVM_ED_FindGlobal(required_global[i]) == 0)
-                       PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_global[i], filename);
+       // LordHavoc: TODO: reorder globals to match engine struct
+       // LordHavoc: TODO: reorder fields to match engine struct
+#define remapglobal(index) (index)
+#define remapfield(index) (index)
 
-       for (i=0 ; i<prog->progs->numglobals ; i++)
-               ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]);
+       // copy globals
+       for (i = 0;i < prog->progs_numglobals;i++)
+               ((int *)prog->globals.generic)[remapglobal(i)] = LittleLong(((int *)inglobals)[i]);
 
-       // LordHavoc: bounds check anything static
-       for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
+       // LordHavoc: TODO: support 32bit progs statement formats
+       // copy, remap globals in statements, bounds check
+       for (i = 0;i < prog->progs_numstatements;i++)
        {
-               switch (st->op)
+               op = (opcode_t)LittleShort(instatements[i].op);
+               a = (unsigned short)LittleShort(instatements[i].a);
+               b = (unsigned short)LittleShort(instatements[i].b);
+               c = (unsigned short)LittleShort(instatements[i].c);
+               switch (op)
                {
                case OP_IF:
                case OP_IFNOT:
-                       if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
+                       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->statements[i].op = op;
+                       prog->statements[i].operand[0] = remapglobal(a);
+                       prog->statements[i].operand[1] = -1;
+                       prog->statements[i].operand[2] = -1;
+                       prog->statements[i].jumpabsolute = i + b;
                        break;
                case OP_GOTO:
-                       if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
+                       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->statements[i].op = op;
+                       prog->statements[i].operand[0] = -1;
+                       prog->statements[i].operand[1] = -1;
+                       prog->statements[i].operand[2] = -1;
+                       prog->statements[i].jumpabsolute = i + a;
                        break;
+               default:
+                       Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", (int)op, i, PRVM_NAME);
                // global global global
                case OP_ADD_F:
                case OP_ADD_V:
@@ -2263,8 +2155,13 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                case OP_LOAD_S:
                case OP_LOAD_FNC:
                case OP_LOAD_V:
-                       if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
+                       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->statements[i].op = op;
+                       prog->statements[i].operand[0] = remapglobal(a);
+                       prog->statements[i].operand[1] = remapglobal(b);
+                       prog->statements[i].operand[2] = remapglobal(c);
+                       prog->statements[i].jumpabsolute = -1;
                        break;
                // global none global
                case OP_NOT_F:
@@ -2272,8 +2169,13 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                case OP_NOT_S:
                case OP_NOT_FNC:
                case OP_NOT_ENT:
-                       if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
+                       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->statements[i].op = op;
+                       prog->statements[i].operand[0] = remapglobal(a);
+                       prog->statements[i].operand[1] = -1;
+                       prog->statements[i].operand[2] = remapglobal(c);
+                       prog->statements[i].jumpabsolute = -1;
                        break;
                // 2 globals
                case OP_STOREP_F:
@@ -2289,8 +2191,13 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                case OP_STATE:
                case OP_STOREP_V:
                case OP_STORE_V:
-                       if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
+                       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->statements[i].op = op;
+                       prog->statements[i].operand[0] = remapglobal(a);
+                       prog->statements[i].operand[1] = remapglobal(b);
+                       prog->statements[i].operand[2] = -1;
+                       prog->statements[i].jumpabsolute = -1;
                        break;
                // 1 global
                case OP_CALL0:
@@ -2304,19 +2211,21 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                case OP_CALL8:
                case OP_DONE:
                case OP_RETURN:
-                       if ((unsigned short) st->a >= prog->progs->numglobals)
+                       if ( a >= prog->progs_numglobals)
                                PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
-                       break;
-               default:
-                       Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
+                       prog->statements[i].op = op;
+                       prog->statements[i].operand[0] = remapglobal(a);
+                       prog->statements[i].operand[1] = -1;
+                       prog->statements[i].operand[2] = -1;
+                       prog->statements[i].jumpabsolute = -1;
                        break;
                }
        }
-       if(prog->progs->numstatements < 1)
+       if(prog->numstatements < 1)
        {
                PRVM_ERROR("PRVM_LoadProgs: empty program in %s", PRVM_NAME);
        }
-       else switch(prog->statements[prog->progs->numstatements - 1].op)
+       else switch(prog->statements[prog->numstatements - 1].op)
        {
                case OP_RETURN:
                case OP_GOTO:
@@ -2327,6 +2236,15 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                        break;
        }
 
+       // we're done with the file now
+       Mem_Free(dprograms);
+       dprograms = NULL;
+
+       // 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);
+
        PRVM_LoadLNO(filename);
 
        PRVM_Init_Exec();
@@ -2339,7 +2257,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                const char *realfilename = (strcmp(PRVM_NAME, "client") ? filename : csqc_progname.string);
                if(deftrans) // once we have dotranslate_ strings, ALWAYS use the opt-in method!
                {
-                       for (i=0 ; i<prog->progs->numglobaldefs ; i++)
+                       for (i=0 ; i<prog->numglobaldefs ; i++)
                        {
                                const char *name;
                                name = PRVM_GetString(prog->globaldefs[i].s_name);
@@ -2357,14 +2275,14 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                        Con_Printf("Dumping to %s.pot\n", realfilename);
                        if(f)
                        {
-                               for (i=0 ; i<prog->progs->numglobaldefs ; i++)
+                               for (i=0 ; i<prog->numglobaldefs ; i++)
                                {
                                        const char *name;
                                        name = PRVM_GetString(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_eval_t *)(prog->globals.generic + prog->globaldefs[i].ofs);
+                                               prvm_eval_t *val = PRVM_GLOBALFIELDVALUE(prog->globaldefs[i].ofs);
                                                const char *value = PRVM_GetString(val->string);
                                                if(*value)
                                                {
@@ -2382,14 +2300,14 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                        po_t *po = PRVM_PO_Load(va("%s.%s.po", realfilename, prvm_language.string), prog->progs_mempool);
                        if(po)
                        {
-                               for (i=0 ; i<prog->progs->numglobaldefs ; i++)
+                               for (i=0 ; i<prog->numglobaldefs ; i++)
                                {
                                        const char *name;
                                        name = PRVM_GetString(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_eval_t *)(prog->globals.generic + prog->globaldefs[i].ofs);
+                                               prvm_eval_t *val = PRVM_GLOBALFIELDVALUE(prog->globaldefs[i].ofs);
                                                const char *value = PRVM_GetString(val->string);
                                                if(*value)
                                                {
@@ -2403,7 +2321,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                }
        }
 
-       for (i=0 ; i<prog->progs->numglobaldefs ; i++)
+       for (i=0 ; i<prog->numglobaldefs ; i++)
        {
                const char *name;
                name = PRVM_GetString(prog->globaldefs[i].s_name);
@@ -2413,7 +2331,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
                        && !(strlen(name) > 1 && name[strlen(name)-2] == '_' && (name[strlen(name)-1] == 'x' || name[strlen(name)-1] == 'y' || name[strlen(name)-1] == 'z'))
                )
                {
-                       prvm_eval_t *val = (prvm_eval_t *)(prog->globals.generic + prog->globaldefs[i].ofs);
+                       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);
                        if(!cvar)
@@ -2539,13 +2457,13 @@ void PRVM_Fields_f (void)
        if(!PRVM_SetProgFromString(Cmd_Argv(1)))
                return;
 
-       counts = (int *)Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
+       counts = (int *)Mem_Alloc(tempmempool, prog->numfielddefs * sizeof(int));
        for (ednum = 0;ednum < prog->max_edicts;ednum++)
        {
                ed = PRVM_EDICT_NUM(ednum);
                if (ed->priv.required->free)
                        continue;
-               for (i = 1;i < prog->progs->numfielddefs;i++)
+               for (i = 1;i < prog->numfielddefs;i++)
                {
                        d = &prog->fielddefs[i];
                        name = PRVM_GetString(d->s_name);
@@ -2566,7 +2484,7 @@ void PRVM_Fields_f (void)
        used = 0;
        usedamount = 0;
        tempstring[0] = 0;
-       for (i = 0;i < prog->progs->numfielddefs;i++)
+       for (i = 0;i < prog->numfielddefs;i++)
        {
                d = &prog->fielddefs[i];
                name = PRVM_GetString(d->s_name);
@@ -2628,7 +2546,7 @@ 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->progs->entityfields, used, prog->progs->entityfields * 4, usedamount * 4, prog->max_edicts, prog->progs->entityfields * 4 * prog->max_edicts, usedamount * 4 * prog->max_edicts);
+       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;
 }
@@ -2662,7 +2580,7 @@ void PRVM_Globals_f (void)
 
        Con_Printf("%s :", PRVM_NAME);
 
-       for (i = 0;i < prog->progs->numglobaldefs;i++)
+       for (i = 0;i < prog->numglobaldefs;i++)
        {
                if(wildcard)
                        if( !matchpattern( PRVM_GetString(prog->globaldefs[i].s_name), wildcard, 1) )
@@ -2672,7 +2590,7 @@ void PRVM_Globals_f (void)
                        }
                Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
        }
-       Con_Printf("%i global variables, %i culled, totalling %i bytes\n", prog->progs->numglobals, numculled, prog->progs->numglobals * 4);
+       Con_Printf("%i global variables, %i culled, totalling %i bytes\n", prog->numglobals, numculled, prog->numglobals * 4);
 
        PRVM_End;
 }
@@ -2698,7 +2616,7 @@ void PRVM_Global_f(void)
        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_eval_t *) &prog->globals.generic[ global->ofs ] ) );
+               Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( (etype_t)global->type, PRVM_GLOBALFIELDVALUE(global->ofs) ) );
        PRVM_End;
 }
 
@@ -2811,9 +2729,12 @@ void _PRVM_Free(void *buffer, const char *filename, int fileline)
 
 void _PRVM_FreeAll(const char *filename, int fileline)
 {
-       prog->progs = NULL;
-       prog->fielddefs = NULL;
        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);
 }
 
@@ -3060,12 +2981,12 @@ static qboolean PRVM_IsStringReferenced(string_t string)
 {
        int i, j;
 
-       for (i = 0;i < prog->progs->numglobaldefs;i++)
+       for (i = 0;i < prog->numglobaldefs;i++)
        {
                ddef_t *d = &prog->globaldefs[i];
                if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string)
                        continue;
-               if(string == ((prvm_eval_t *) &prog->globals.generic[d->ofs])->string)
+               if(string == PRVM_GLOBALFIELDSTRING(d->ofs))
                        return true;
        }
 
@@ -3074,12 +2995,12 @@ static qboolean PRVM_IsStringReferenced(string_t string)
                prvm_edict_t *ed = PRVM_EDICT_NUM(j);
                if (ed->priv.required->free)
                        continue;
-               for (i=0; i<prog->progs->numfielddefs; ++i)
+               for (i=0; i<prog->numfielddefs; ++i)
                {
                        ddef_t *d = &prog->fielddefs[i];
                        if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string)
                                continue;
-                       if(string == ((prvm_eval_t *) &ed->fields.vp[d->ofs])->string)
+                       if(string == PRVM_EDICTFIELDSTRING(ed, d->ofs))
                                return true;
                }
        }
@@ -3095,21 +3016,20 @@ static qboolean PRVM_IsEdictRelevant(prvm_edict_t *edict)
        {
                case PRVM_SERVERPROG:
                        {
-                               entvars_t *ev = edict->fields.server;
-                               if(ev->solid) // can block other stuff, or is a trigger?
+                               if(PRVM_serveredictfloat(edict, solid)) // can block other stuff, or is a trigger?
                                        return true;
-                               if(ev->modelindex) // visible ent?
+                               if(PRVM_serveredictfloat(edict, modelindex)) // visible ent?
                                        return true;
-                               if(ev->effects) // particle effect?
+                               if(PRVM_serveredictfloat(edict, effects)) // particle effect?
                                        return true;
-                               if(ev->think) // has a think function?
-                                       if(ev->nextthink > 0) // that actually will eventually run?
+                               if(PRVM_serveredictfunction(edict, think)) // has a think function?
+                                       if(PRVM_serveredictfloat(edict, nextthink) > 0) // that actually will eventually run?
                                                return true;
-                               if(ev->takedamage)
+                               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(ev->classname))))
+                                       if(strstr(va(" %s ", prvm_leaktest_ignore_classnames.string), va(" %s ", PRVM_GetString(PRVM_serveredictstring(edict, classname)))))
                                                return true;
                                }
                        }
@@ -3117,19 +3037,18 @@ static qboolean PRVM_IsEdictRelevant(prvm_edict_t *edict)
                case PRVM_CLIENTPROG:
                        {
                                // TODO someone add more stuff here
-                               cl_entvars_t *ev = edict->fields.client;
-                               if(ev->entnum) // csqc networked
+                               if(PRVM_clientedictfloat(edict, entnum)) // csqc networked
                                        return true;
-                               if(ev->modelindex) // visible ent?
+                               if(PRVM_clientedictfloat(edict, modelindex)) // visible ent?
                                        return true;
-                               if(ev->effects) // particle effect?
+                               if(PRVM_clientedictfloat(edict, effects)) // particle effect?
                                        return true;
-                               if(ev->think) // has a think function?
-                                       if(ev->nextthink > 0) // that actually will eventually run?
+                               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(ev->classname))))
+                                       if(strstr(va(" %s ", prvm_leaktest_ignore_classnames.string), va(" %s ", PRVM_GetString(PRVM_clientedictstring(edict, classname)))))
                                                return true;
                                }
                        }
@@ -3150,7 +3069,7 @@ static qboolean PRVM_IsEdictReferenced(prvm_edict_t *edict, int mark)
        switch(prog - prog_list)
        {
                case PRVM_SERVERPROG:
-                       targetname = PRVM_GetString(edict->fields.server->targetname);
+                       targetname = PRVM_GetString(PRVM_serveredictstring(edict, targetname));
                        break;
        }
 
@@ -3158,12 +3077,12 @@ static qboolean PRVM_IsEdictReferenced(prvm_edict_t *edict, int mark)
                if(!*targetname) // ""
                        targetname = NULL;
 
-       for (i = 0;i < prog->progs->numglobaldefs;i++)
+       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_eval_t *) &prog->globals.generic[d->ofs])->edict)
+               if(edictnum == PRVM_GLOBALFIELDEDICT(d->ofs))
                        return true;
        }
 
@@ -3176,17 +3095,17 @@ static qboolean PRVM_IsEdictReferenced(prvm_edict_t *edict, int mark)
                        continue;
                if(targetname)
                {
-                       const char *target = PRVM_GetString(ed->fields.server->target);
+                       const char *target = PRVM_GetString(PRVM_serveredictstring(ed, target));
                        if(target)
                                if(!strcmp(target, targetname))
                                        return true;
                }
-               for (i=0; i<prog->progs->numfielddefs; ++i)
+               for (i=0; i<prog->numfielddefs; ++i)
                {
                        ddef_t *d = &prog->fielddefs[i];
                        if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity)
                                continue;
-                       if(edictnum == ((prvm_eval_t *) &ed->fields.vp[d->ofs])->edict)
+                       if(edictnum == PRVM_EDICTFIELDEDICT(ed, d->ofs))
                                return true;
                }
        }
index ca1c191cb04c6835578a2ce421aec3fe60d1e385..8fb0d69254722617045db75231ebb23c047bbf99 100644 (file)
@@ -124,7 +124,7 @@ PRVM_PrintStatement
 */
 extern cvar_t prvm_statementprofiling;
 extern cvar_t prvm_timeprofiling;
-void PRVM_PrintStatement (dstatement_t *s)
+void PRVM_PrintStatement(mstatement_t *s)
 {
        size_t i;
        int opnum = (int)(s - prog->statements);
@@ -146,46 +146,10 @@ void PRVM_PrintStatement (dstatement_t *s)
                for ( ; i<10 ; i++)
                        Con_Print(" ");
        }
-       if (s->op == OP_IF || s->op == OP_IFNOT)
-               Con_Printf("%s, s%i",PRVM_GlobalString((unsigned short) s->a),(signed short)s->b + opnum);
-       else if (s->op == OP_GOTO)
-               Con_Printf("s%i",(signed short)s->a + opnum);
-       else if ( (unsigned)(s->op - OP_STORE_F) < 6)
-       {
-               Con_Print(PRVM_GlobalString((unsigned short) s->a));
-               Con_Print(", ");
-               Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->b));
-       }
-       else if (s->op == OP_ADDRESS || (unsigned)(s->op - OP_LOAD_F) < 6)
-       {
-               if (s->a)
-                       Con_Print(PRVM_GlobalString((unsigned short) s->a));
-               if (s->b)
-               {
-                       Con_Print(", ");
-                       Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->b));
-               }
-               if (s->c)
-               {
-                       Con_Print(", ");
-                       Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->c));
-               }
-       }
-       else
-       {
-               if (s->a)
-                       Con_Print(PRVM_GlobalString((unsigned short) s->a));
-               if (s->b)
-               {
-                       Con_Print(", ");
-                       Con_Print(PRVM_GlobalString((unsigned short) s->b));
-               }
-               if (s->c)
-               {
-                       Con_Print(", ");
-                       Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->c));
-               }
-       }
+       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->jumpabsolute >= 0) Con_Printf(", statement %i", s->jumpabsolute);
        Con_Print("\n");
 }
 
@@ -207,8 +171,8 @@ void PRVM_PrintFunctionStatements (const char *name)
        }
 
        // find the end statement
-       endstatement = prog->progs->numstatements;
-       for (i = 0;i < prog->progs->numfunctions;i++)
+       endstatement = prog->numstatements;
+       for (i = 0;i < prog->numfunctions;i++)
                if (endstatement > prog->functions[i].first_statement && firststatement < prog->functions[i].first_statement)
                        endstatement = prog->functions[i].first_statement;
 
@@ -313,7 +277,7 @@ void PRVM_CallProfile (void)
        {
                max = 0;
                best = NULL;
-               for (i=0 ; i<prog->progs->numfunctions ; i++)
+               for (i=0 ; i<prog->numfunctions ; i++)
                {
                        f = &prog->functions[i];
                        if (max < f->totaltime)
@@ -357,7 +321,7 @@ void PRVM_Profile (int maxfunctions, double mintime, int sortby)
        {
                max = 0;
                best = NULL;
-               for (i=0 ; i<prog->progs->numfunctions ; i++)
+               for (i=0 ; i<prog->numfunctions ; i++)
                {
                        f = &prog->functions[i];
                        if(prvm_timeprofiling.integer)
@@ -559,7 +523,7 @@ void PRVM_Crash(void)
        if (prog == NULL)
                return;
 
-       prog->funcoffsets.SV_Shutdown = 0; // don't call SV_Shutdown on crash
+       PRVM_serverfunction(SV_Shutdown) = 0; // don't call SV_Shutdown on crash
 
        if( prog->depth > 0 )
        {
@@ -701,9 +665,9 @@ void PRVM_Init_Exec(void)
        // nothing here yet
 }
 
-#define OPA ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->a])
-#define OPB ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->b])
-#define OPC ((prvm_eval_t *)&prog->globals.generic[(unsigned short) st->c])
+#define OPA ((prvm_eval_t *)&prog->globals.generic[st->operand[0]])
+#define OPB ((prvm_eval_t *)&prog->globals.generic[st->operand[1]])
+#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;
@@ -717,7 +681,7 @@ MVM_ExecuteProgram
 */
 void MVM_ExecuteProgram (func_t fnum, const char *errormessage)
 {
-       dstatement_t    *st, *startst;
+       mstatement_t    *st, *startst;
        mfunction_t     *f, *newf;
        prvm_edict_t    *ed;
        prvm_eval_t     *ptr;
@@ -728,10 +692,10 @@ void MVM_ExecuteProgram (func_t fnum, const char *errormessage)
 
        calltime = Sys_DoubleTime();
 
-       if (!fnum || fnum >= (unsigned int)prog->progs->numfunctions)
+       if (!fnum || fnum >= (unsigned int)prog->numfunctions)
        {
-               if (prog->globaloffsets.self >= 0 && PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict)
-                       PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict), NULL);
+               if (PRVM_allglobaledict(self))
+                       PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
                PRVM_ERROR ("MVM_ExecuteProgram: %s", errormessage);
        }
 
@@ -806,7 +770,7 @@ CLVM_ExecuteProgram
 */
 void CLVM_ExecuteProgram (func_t fnum, const char *errormessage)
 {
-       dstatement_t    *st, *startst;
+       mstatement_t    *st, *startst;
        mfunction_t     *f, *newf;
        prvm_edict_t    *ed;
        prvm_eval_t     *ptr;
@@ -817,10 +781,10 @@ void CLVM_ExecuteProgram (func_t fnum, const char *errormessage)
 
        calltime = Sys_DoubleTime();
 
-       if (!fnum || fnum >= (unsigned int)prog->progs->numfunctions)
+       if (!fnum || fnum >= (unsigned int)prog->numfunctions)
        {
-               if (prog->globaloffsets.self >= 0 && PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict)
-                       PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict), NULL);
+               if (PRVM_allglobaledict(self))
+                       PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
                PRVM_ERROR ("CLVM_ExecuteProgram: %s", errormessage);
        }
 
@@ -896,7 +860,7 @@ SVVM_ExecuteProgram
 */
 void SVVM_ExecuteProgram (func_t fnum, const char *errormessage)
 {
-       dstatement_t    *st, *startst;
+       mstatement_t    *st, *startst;
        mfunction_t     *f, *newf;
        prvm_edict_t    *ed;
        prvm_eval_t     *ptr;
@@ -907,10 +871,10 @@ void SVVM_ExecuteProgram (func_t fnum, const char *errormessage)
 
        calltime = Sys_DoubleTime();
 
-       if (!fnum || fnum >= (unsigned int)prog->progs->numfunctions)
+       if (!fnum || fnum >= (unsigned int)prog->numfunctions)
        {
-               if (prog->globaloffsets.self >= 0 && PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict)
-                       PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict), NULL);
+               if (PRVM_allglobaledict(self))
+                       PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL);
                PRVM_ERROR ("SVVM_ExecuteProgram: %s", errormessage);
        }
 
index 719224d0246d1e523384a1850504cfaa20814a15..4d872f64bf4e72c09d0afba93c0910e6b24aa488 100644 (file)
                                        PRVM_ERROR("%s attempted to write to an out of bounds edict (%i)", PRVM_NAME, OPB->_int);
                                        goto cleanup;
                                }
-                               if (OPB->_int < prog->progs->entityfields && !prog->allowworldwrites)
+                               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);
                                        PRVM_ERROR("%s attempted to write to an out of bounds edict (%i)", PRVM_NAME, OPB->_int);
                                        goto cleanup;
                                }
-                               if (OPB->_int < prog->progs->entityfields && !prog->allowworldwrites)
+                               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);
                                        PRVM_ERROR ("%s Progs attempted to address an out of bounds edict number", PRVM_NAME);
                                        goto cleanup;
                                }
-                               if ((unsigned int)(OPB->_int) >= (unsigned int)(prog->progs->entityfields))
+                               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);
                                        PRVM_ERROR ("%s Progs attempted to read an out of bounds edict number", PRVM_NAME);
                                        goto cleanup;
                                }
-                               if ((unsigned int)(OPB->_int) >= (unsigned int)(prog->progs->entityfields))
+                               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);
                                        PRVM_ERROR ("%s Progs attempted to read an out of bounds edict number", PRVM_NAME);
                                        goto cleanup;
                                }
-                               if (OPB->_int < 0 || OPB->_int + 2 >= prog->progs->entityfields)
+                               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);
                                // and entity, string, field values can never have that value
                                {
                                        prog->xfunction->profile += (st - startst);
-                                       st += st->b - 1;        // offset the s++
+                                       st = prog->statements + st->jumpabsolute - 1;   // offset the st++
                                        startst = st;
                                        // no bounds check needed, it is done when loading progs
                                        if (++jumpcount == 10000000 && prvm_runawaycheck)
                                // and entity, string, field values can never have that value
                                {
                                        prog->xfunction->profile += (st - startst);
-                                       st += st->b - 1;        // offset the s++
+                                       st = prog->statements + st->jumpabsolute - 1;   // offset the st++
                                        startst = st;
                                        // no bounds check needed, it is done when loading progs
                                        if (++jumpcount == 10000000 && prvm_runawaycheck)
 
                        case OP_GOTO:
                                prog->xfunction->profile += (st - startst);
-                               st += st->a - 1;        // offset the s++
+                               st = prog->statements + st->jumpabsolute - 1;   // offset the st++
                                startst = st;
                                // no bounds check needed, it is done when loading progs
                                if (++jumpcount == 10000000 && prvm_runawaycheck)
                                if (!OPA->function)
                                        PRVM_ERROR("NULL function in %s", PRVM_NAME);
 
-                               if(!OPA->function || OPA->function >= (unsigned int)prog->progs->numfunctions)
+                               if(!OPA->function || OPA->function >= (unsigned int)prog->numfunctions)
                                {
                                        PreError();
                                        PRVM_ERROR("%s CALL outside the program", PRVM_NAME);
                                prog->xfunction->profile += (st - startst);
                                prog->xstatement = st - prog->statements;
 
-                               prog->globals.generic[OFS_RETURN] = prog->globals.generic[(unsigned short) st->a];
-                               prog->globals.generic[OFS_RETURN+1] = prog->globals.generic[(unsigned short) st->a+1];
-                               prog->globals.generic[OFS_RETURN+2] = prog->globals.generic[(unsigned short) st->a+2];
+                               prog->globals.generic[OFS_RETURN] = prog->globals.generic[st->operand[0]];
+                               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();
                                startst = st;
                        case OP_STATE:
                                if(prog->flag & PRVM_OP_STATE)
                                {
-                                       ed = PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict);
-                                       PRVM_EDICTFIELDVALUE(ed,prog->fieldoffsets.nextthink)->_float = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.time)->_float + 0.1;
-                                       PRVM_EDICTFIELDVALUE(ed,prog->fieldoffsets.frame)->_float = OPA->_float;
-                                       PRVM_EDICTFIELDVALUE(ed,prog->fieldoffsets.think)->function = OPB->function;
+                                       ed = PRVM_PROG_TO_EDICT(PRVM_gameglobaledict(self));
+                                       PRVM_gameedictfloat(ed,nextthink) = PRVM_gameglobalfloat(time) + 0.1;
+                                       PRVM_gameedictfloat(ed,frame) = OPA->_float;
+                                       PRVM_gameedictfunction(ed,think) = OPB->function;
                                }
                                else
                                {
diff --git a/prvm_offsets.h b/prvm_offsets.h
new file mode 100644 (file)
index 0000000..1bd6c5e
--- /dev/null
@@ -0,0 +1,812 @@
+PRVM_DECLARE_clientfieldedict(aiment)
+PRVM_DECLARE_clientfieldedict(chain)
+PRVM_DECLARE_clientfieldedict(enemy)
+PRVM_DECLARE_clientfieldedict(groundentity)
+PRVM_DECLARE_clientfieldedict(owner)
+PRVM_DECLARE_clientfieldedict(tag_entity)
+PRVM_DECLARE_clientfieldfloat(alpha)
+PRVM_DECLARE_clientfieldfloat(bouncefactor)
+PRVM_DECLARE_clientfieldfloat(bouncestop)
+PRVM_DECLARE_clientfieldfloat(colormap)
+PRVM_DECLARE_clientfieldfloat(dphitcontentsmask)
+PRVM_DECLARE_clientfieldfloat(drawmask)
+PRVM_DECLARE_clientfieldfloat(effects)
+PRVM_DECLARE_clientfieldfloat(entnum)
+PRVM_DECLARE_clientfieldfloat(flags)
+PRVM_DECLARE_clientfieldfloat(frame)
+PRVM_DECLARE_clientfieldfloat(frame1time)
+PRVM_DECLARE_clientfieldfloat(frame2)
+PRVM_DECLARE_clientfieldfloat(frame2time)
+PRVM_DECLARE_clientfieldfloat(frame3)
+PRVM_DECLARE_clientfieldfloat(frame3time)
+PRVM_DECLARE_clientfieldfloat(frame4)
+PRVM_DECLARE_clientfieldfloat(frame4time)
+PRVM_DECLARE_clientfieldfloat(gravity)
+PRVM_DECLARE_clientfieldfloat(ideal_yaw)
+PRVM_DECLARE_clientfieldfloat(idealpitch)
+PRVM_DECLARE_clientfieldfloat(jointtype)
+PRVM_DECLARE_clientfieldfloat(lerpfrac)
+PRVM_DECLARE_clientfieldfloat(lerpfrac3)
+PRVM_DECLARE_clientfieldfloat(lerpfrac4)
+PRVM_DECLARE_clientfieldfloat(mass)
+PRVM_DECLARE_clientfieldfloat(modelindex)
+PRVM_DECLARE_clientfieldfloat(movetype)
+PRVM_DECLARE_clientfieldfloat(nextthink)
+PRVM_DECLARE_clientfieldfloat(pitch_speed)
+PRVM_DECLARE_clientfieldfloat(renderflags)
+PRVM_DECLARE_clientfieldfloat(scale)
+PRVM_DECLARE_clientfieldfloat(shadertime)
+PRVM_DECLARE_clientfieldfloat(skeletonindex)
+PRVM_DECLARE_clientfieldfloat(skin)
+PRVM_DECLARE_clientfieldfloat(solid)
+PRVM_DECLARE_clientfieldfloat(tag_index)
+PRVM_DECLARE_clientfieldfloat(userwavefunc_param0)
+PRVM_DECLARE_clientfieldfloat(userwavefunc_param1)
+PRVM_DECLARE_clientfieldfloat(userwavefunc_param2)
+PRVM_DECLARE_clientfieldfloat(userwavefunc_param3)
+PRVM_DECLARE_clientfieldfloat(yaw_speed)
+PRVM_DECLARE_clientfieldfunction(blocked)
+PRVM_DECLARE_clientfieldfunction(camera_transform)
+PRVM_DECLARE_clientfieldfunction(predraw)
+PRVM_DECLARE_clientfieldfunction(think)
+PRVM_DECLARE_clientfieldfunction(touch)
+PRVM_DECLARE_clientfieldfunction(use)
+PRVM_DECLARE_clientfieldstring(classname)
+PRVM_DECLARE_clientfieldstring(message)
+PRVM_DECLARE_clientfieldstring(model)
+PRVM_DECLARE_clientfieldstring(netname)
+PRVM_DECLARE_clientfieldvector(absmax)
+PRVM_DECLARE_clientfieldvector(absmin)
+PRVM_DECLARE_clientfieldvector(angles)
+PRVM_DECLARE_clientfieldvector(avelocity)
+PRVM_DECLARE_clientfieldvector(colormod)
+PRVM_DECLARE_clientfieldvector(glowmod)
+PRVM_DECLARE_clientfieldvector(maxs)
+PRVM_DECLARE_clientfieldvector(mins)
+PRVM_DECLARE_clientfieldvector(movedir)
+PRVM_DECLARE_clientfieldvector(oldorigin)
+PRVM_DECLARE_clientfieldvector(origin)
+PRVM_DECLARE_clientfieldvector(size)
+PRVM_DECLARE_clientfieldvector(velocity)
+PRVM_DECLARE_clientfunction(CSQC_ConsoleCommand)
+PRVM_DECLARE_clientfunction(CSQC_Ent_Remove)
+PRVM_DECLARE_clientfunction(CSQC_Ent_Spawn)
+PRVM_DECLARE_clientfunction(CSQC_Ent_Update)
+PRVM_DECLARE_clientfunction(CSQC_Event)
+PRVM_DECLARE_clientfunction(CSQC_Event_Sound)
+PRVM_DECLARE_clientfunction(CSQC_Init)
+PRVM_DECLARE_clientfunction(CSQC_InputEvent)
+PRVM_DECLARE_clientfunction(CSQC_Parse_CenterPrint)
+PRVM_DECLARE_clientfunction(CSQC_Parse_Print)
+PRVM_DECLARE_clientfunction(CSQC_Parse_StuffCmd)
+PRVM_DECLARE_clientfunction(CSQC_Parse_TempEntity)
+PRVM_DECLARE_clientfunction(CSQC_Shutdown)
+PRVM_DECLARE_clientfunction(CSQC_UpdateView)
+PRVM_DECLARE_clientfunction(GameCommand)
+PRVM_DECLARE_clientfunction(Gecko_Query)
+PRVM_DECLARE_clientfunction(URI_Get_Callback)
+PRVM_DECLARE_clientglobaledict(other)
+PRVM_DECLARE_clientglobaledict(self)
+PRVM_DECLARE_clientglobaledict(trace_ent)
+PRVM_DECLARE_clientglobaledict(world)
+PRVM_DECLARE_clientglobalfloat(clientcommandframe)
+PRVM_DECLARE_clientglobalfloat(coop)
+PRVM_DECLARE_clientglobalfloat(deathmatch)
+PRVM_DECLARE_clientglobalfloat(dmg_save)
+PRVM_DECLARE_clientglobalfloat(dmg_take)
+PRVM_DECLARE_clientglobalfloat(drawfont)
+PRVM_DECLARE_clientglobalfloat(frametime)
+PRVM_DECLARE_clientglobalfloat(gettaginfo_parent)
+PRVM_DECLARE_clientglobalfloat(input_buttons)
+PRVM_DECLARE_clientglobalfloat(input_timelength)
+PRVM_DECLARE_clientglobalfloat(intermission)
+PRVM_DECLARE_clientglobalfloat(maxclients)
+PRVM_DECLARE_clientglobalfloat(movevar_accelerate)
+PRVM_DECLARE_clientglobalfloat(movevar_airaccelerate)
+PRVM_DECLARE_clientglobalfloat(movevar_entgravity)
+PRVM_DECLARE_clientglobalfloat(movevar_friction)
+PRVM_DECLARE_clientglobalfloat(movevar_gravity)
+PRVM_DECLARE_clientglobalfloat(movevar_maxspeed)
+PRVM_DECLARE_clientglobalfloat(movevar_spectatormaxspeed)
+PRVM_DECLARE_clientglobalfloat(movevar_stopspeed)
+PRVM_DECLARE_clientglobalfloat(movevar_wateraccelerate)
+PRVM_DECLARE_clientglobalfloat(movevar_waterfriction)
+PRVM_DECLARE_clientglobalfloat(particle_airfriction)
+PRVM_DECLARE_clientglobalfloat(particle_alpha)
+PRVM_DECLARE_clientglobalfloat(particle_alphafade)
+PRVM_DECLARE_clientglobalfloat(particle_angle)
+PRVM_DECLARE_clientglobalfloat(particle_blendmode)
+PRVM_DECLARE_clientglobalfloat(particle_bounce)
+PRVM_DECLARE_clientglobalfloat(particle_delaycollision)
+PRVM_DECLARE_clientglobalfloat(particle_delayspawn)
+PRVM_DECLARE_clientglobalfloat(particle_gravity)
+PRVM_DECLARE_clientglobalfloat(particle_liquidfriction)
+PRVM_DECLARE_clientglobalfloat(particle_orientation)
+PRVM_DECLARE_clientglobalfloat(particle_originjitter)
+PRVM_DECLARE_clientglobalfloat(particle_qualityreduction)
+PRVM_DECLARE_clientglobalfloat(particle_size)
+PRVM_DECLARE_clientglobalfloat(particle_sizeincrease)
+PRVM_DECLARE_clientglobalfloat(particle_spin)
+PRVM_DECLARE_clientglobalfloat(particle_stainalpha)
+PRVM_DECLARE_clientglobalfloat(particle_stainsize)
+PRVM_DECLARE_clientglobalfloat(particle_staintex)
+PRVM_DECLARE_clientglobalfloat(particle_stretch)
+PRVM_DECLARE_clientglobalfloat(particle_tex)
+PRVM_DECLARE_clientglobalfloat(particle_time)
+PRVM_DECLARE_clientglobalfloat(particle_type)
+PRVM_DECLARE_clientglobalfloat(particle_velocityjitter)
+PRVM_DECLARE_clientglobalfloat(particles_alphamax)
+PRVM_DECLARE_clientglobalfloat(particles_alphamin)
+PRVM_DECLARE_clientglobalfloat(player_localentnum)
+PRVM_DECLARE_clientglobalfloat(player_localnum)
+PRVM_DECLARE_clientglobalfloat(require_spawnfunc_prefix)
+PRVM_DECLARE_clientglobalfloat(sb_showscores)
+PRVM_DECLARE_clientglobalfloat(servercommandframe)
+PRVM_DECLARE_clientglobalfloat(serverdeltatime)
+PRVM_DECLARE_clientglobalfloat(serverprevtime)
+PRVM_DECLARE_clientglobalfloat(servertime)
+PRVM_DECLARE_clientglobalfloat(time)
+PRVM_DECLARE_clientglobalfloat(trace_allsolid)
+PRVM_DECLARE_clientglobalfloat(trace_dphitcontents)
+PRVM_DECLARE_clientglobalfloat(trace_dphitq3surfaceflags)
+PRVM_DECLARE_clientglobalfloat(trace_dpstartcontents)
+PRVM_DECLARE_clientglobalfloat(trace_fraction)
+PRVM_DECLARE_clientglobalfloat(trace_inopen)
+PRVM_DECLARE_clientglobalfloat(trace_inwater)
+PRVM_DECLARE_clientglobalfloat(trace_networkentity)
+PRVM_DECLARE_clientglobalfloat(trace_plane_dist)
+PRVM_DECLARE_clientglobalfloat(trace_startsolid)
+PRVM_DECLARE_clientglobalfloat(transparent_offset)
+PRVM_DECLARE_clientglobalstring(gettaginfo_name)
+PRVM_DECLARE_clientglobalstring(mapname)
+PRVM_DECLARE_clientglobalstring(trace_dphittexturename)
+PRVM_DECLARE_clientglobalvector(dmg_origin)
+PRVM_DECLARE_clientglobalvector(drawfontscale)
+PRVM_DECLARE_clientglobalvector(gettaginfo_forward)
+PRVM_DECLARE_clientglobalvector(gettaginfo_offset)
+PRVM_DECLARE_clientglobalvector(gettaginfo_right)
+PRVM_DECLARE_clientglobalvector(gettaginfo_up)
+PRVM_DECLARE_clientglobalvector(input_angles)
+PRVM_DECLARE_clientglobalvector(input_movevalues)
+PRVM_DECLARE_clientglobalvector(particle_color1)
+PRVM_DECLARE_clientglobalvector(particle_color2)
+PRVM_DECLARE_clientglobalvector(particle_staincolor1)
+PRVM_DECLARE_clientglobalvector(particle_staincolor2)
+PRVM_DECLARE_clientglobalvector(particles_colormax)
+PRVM_DECLARE_clientglobalvector(particles_colormin)
+PRVM_DECLARE_clientglobalvector(pmove_inwater)
+PRVM_DECLARE_clientglobalvector(pmove_maxs)
+PRVM_DECLARE_clientglobalvector(pmove_mins)
+PRVM_DECLARE_clientglobalvector(pmove_onground)
+PRVM_DECLARE_clientglobalvector(pmove_org)
+PRVM_DECLARE_clientglobalvector(pmove_vel)
+PRVM_DECLARE_clientglobalvector(trace_endpos)
+PRVM_DECLARE_clientglobalvector(trace_plane_normal)
+PRVM_DECLARE_clientglobalvector(v_forward)
+PRVM_DECLARE_clientglobalvector(v_right)
+PRVM_DECLARE_clientglobalvector(v_up)
+PRVM_DECLARE_clientglobalvector(view_angles)
+PRVM_DECLARE_clientglobalvector(view_punchangle)
+PRVM_DECLARE_clientglobalvector(view_punchvector)
+PRVM_DECLARE_field(SendEntity)
+PRVM_DECLARE_field(SendFlags)
+PRVM_DECLARE_field(Version)
+PRVM_DECLARE_field(absmax)
+PRVM_DECLARE_field(absmin)
+PRVM_DECLARE_field(aiment)
+PRVM_DECLARE_field(alpha)
+PRVM_DECLARE_field(ammo_cells)
+PRVM_DECLARE_field(ammo_cells1)
+PRVM_DECLARE_field(ammo_lava_nails)
+PRVM_DECLARE_field(ammo_multi_rockets)
+PRVM_DECLARE_field(ammo_nails)
+PRVM_DECLARE_field(ammo_nails1)
+PRVM_DECLARE_field(ammo_plasma)
+PRVM_DECLARE_field(ammo_rockets)
+PRVM_DECLARE_field(ammo_rockets1)
+PRVM_DECLARE_field(ammo_shells)
+PRVM_DECLARE_field(ammo_shells1)
+PRVM_DECLARE_field(angles)
+PRVM_DECLARE_field(armortype)
+PRVM_DECLARE_field(armorvalue)
+PRVM_DECLARE_field(avelocity)
+PRVM_DECLARE_field(blocked)
+PRVM_DECLARE_field(bouncefactor)
+PRVM_DECLARE_field(bouncestop)
+PRVM_DECLARE_field(button0)
+PRVM_DECLARE_field(button1)
+PRVM_DECLARE_field(button2)
+PRVM_DECLARE_field(button3)
+PRVM_DECLARE_field(button4)
+PRVM_DECLARE_field(button5)
+PRVM_DECLARE_field(button6)
+PRVM_DECLARE_field(button7)
+PRVM_DECLARE_field(button8)
+PRVM_DECLARE_field(button9)
+PRVM_DECLARE_field(button10)
+PRVM_DECLARE_field(button11)
+PRVM_DECLARE_field(button12)
+PRVM_DECLARE_field(button13)
+PRVM_DECLARE_field(button14)
+PRVM_DECLARE_field(button15)
+PRVM_DECLARE_field(button16)
+PRVM_DECLARE_field(buttonchat)
+PRVM_DECLARE_field(buttonuse)
+PRVM_DECLARE_field(camera_transform)
+PRVM_DECLARE_field(chain)
+PRVM_DECLARE_field(classname)
+PRVM_DECLARE_field(clientcamera)
+PRVM_DECLARE_field(clientcolors)
+PRVM_DECLARE_field(clientstatus)
+PRVM_DECLARE_field(color)
+PRVM_DECLARE_field(colormap)
+PRVM_DECLARE_field(colormod)
+PRVM_DECLARE_field(contentstransition)
+PRVM_DECLARE_field(crypto_encryptmethod)
+PRVM_DECLARE_field(crypto_idfp)
+PRVM_DECLARE_field(crypto_keyfp)
+PRVM_DECLARE_field(crypto_mykeyfp)
+PRVM_DECLARE_field(crypto_signmethod)
+PRVM_DECLARE_field(currentammo)
+PRVM_DECLARE_field(cursor_active)
+PRVM_DECLARE_field(cursor_screen)
+PRVM_DECLARE_field(cursor_trace_endpos)
+PRVM_DECLARE_field(cursor_trace_ent)
+PRVM_DECLARE_field(cursor_trace_start)
+PRVM_DECLARE_field(customizeentityforclient)
+PRVM_DECLARE_field(deadflag)
+PRVM_DECLARE_field(disableclientprediction)
+PRVM_DECLARE_field(discardabledemo)
+PRVM_DECLARE_field(dmg_inflictor)
+PRVM_DECLARE_field(dmg_save)
+PRVM_DECLARE_field(dmg_take)
+PRVM_DECLARE_field(dphitcontentsmask)
+PRVM_DECLARE_field(drawmask)
+PRVM_DECLARE_field(drawonlytoclient)
+PRVM_DECLARE_field(effects)
+PRVM_DECLARE_field(enemy)
+PRVM_DECLARE_field(entnum)
+PRVM_DECLARE_field(exteriormodeltoclient)
+PRVM_DECLARE_field(fixangle)
+PRVM_DECLARE_field(flags)
+PRVM_DECLARE_field(frags)
+PRVM_DECLARE_field(frame)
+PRVM_DECLARE_field(frame1time)
+PRVM_DECLARE_field(frame2)
+PRVM_DECLARE_field(frame2time)
+PRVM_DECLARE_field(frame3)
+PRVM_DECLARE_field(frame3time)
+PRVM_DECLARE_field(frame4)
+PRVM_DECLARE_field(frame4time)
+PRVM_DECLARE_field(fullbright)
+PRVM_DECLARE_field(glow_color)
+PRVM_DECLARE_field(glow_size)
+PRVM_DECLARE_field(glow_trail)
+PRVM_DECLARE_field(glowmod)
+PRVM_DECLARE_field(goalentity)
+PRVM_DECLARE_field(gravity)
+PRVM_DECLARE_field(groundentity)
+PRVM_DECLARE_field(health)
+PRVM_DECLARE_field(ideal_yaw)
+PRVM_DECLARE_field(idealpitch)
+PRVM_DECLARE_field(impulse)
+PRVM_DECLARE_field(items)
+PRVM_DECLARE_field(items2)
+PRVM_DECLARE_field(jointtype)
+PRVM_DECLARE_field(lerpfrac)
+PRVM_DECLARE_field(lerpfrac3)
+PRVM_DECLARE_field(lerpfrac4)
+PRVM_DECLARE_field(light_lev)
+PRVM_DECLARE_field(ltime)
+PRVM_DECLARE_field(mass)
+PRVM_DECLARE_field(max_health)
+PRVM_DECLARE_field(maxs)
+PRVM_DECLARE_field(message)
+PRVM_DECLARE_field(mins)
+PRVM_DECLARE_field(model)
+PRVM_DECLARE_field(modelflags)
+PRVM_DECLARE_field(modelindex)
+PRVM_DECLARE_field(movedir)
+PRVM_DECLARE_field(movement)
+PRVM_DECLARE_field(movetype)
+PRVM_DECLARE_field(movetypesteplandevent)
+PRVM_DECLARE_field(netaddress)
+PRVM_DECLARE_field(netname)
+PRVM_DECLARE_field(nextthink)
+PRVM_DECLARE_field(nodrawtoclient)
+PRVM_DECLARE_field(noise)
+PRVM_DECLARE_field(noise1)
+PRVM_DECLARE_field(noise2)
+PRVM_DECLARE_field(noise3)
+PRVM_DECLARE_field(oldorigin)
+PRVM_DECLARE_field(origin)
+PRVM_DECLARE_field(owner)
+PRVM_DECLARE_field(pflags)
+PRVM_DECLARE_field(ping)
+PRVM_DECLARE_field(ping_movementloss)
+PRVM_DECLARE_field(ping_packetloss)
+PRVM_DECLARE_field(pitch_speed)
+PRVM_DECLARE_field(playermodel)
+PRVM_DECLARE_field(playerskin)
+PRVM_DECLARE_field(pmodel)
+PRVM_DECLARE_field(predraw)
+PRVM_DECLARE_field(punchangle)
+PRVM_DECLARE_field(punchvector)
+PRVM_DECLARE_field(renderamt)
+PRVM_DECLARE_field(renderflags)
+PRVM_DECLARE_field(scale)
+PRVM_DECLARE_field(sendcomplexanimation)
+PRVM_DECLARE_field(shadertime)
+PRVM_DECLARE_field(size)
+PRVM_DECLARE_field(skeletonindex)
+PRVM_DECLARE_field(skin)
+PRVM_DECLARE_field(solid)
+PRVM_DECLARE_field(sounds)
+PRVM_DECLARE_field(spawnflags)
+PRVM_DECLARE_field(style)
+PRVM_DECLARE_field(tag_entity)
+PRVM_DECLARE_field(tag_index)
+PRVM_DECLARE_field(takedamage)
+PRVM_DECLARE_field(target)
+PRVM_DECLARE_field(targetname)
+PRVM_DECLARE_field(team)
+PRVM_DECLARE_field(teleport_time)
+PRVM_DECLARE_field(think)
+PRVM_DECLARE_field(touch)
+PRVM_DECLARE_field(traileffectnum)
+PRVM_DECLARE_field(use)
+PRVM_DECLARE_field(userwavefunc_param0)
+PRVM_DECLARE_field(userwavefunc_param1)
+PRVM_DECLARE_field(userwavefunc_param2)
+PRVM_DECLARE_field(userwavefunc_param3)
+PRVM_DECLARE_field(v_angle)
+PRVM_DECLARE_field(velocity)
+PRVM_DECLARE_field(view_ofs)
+PRVM_DECLARE_field(viewmodelforclient)
+PRVM_DECLARE_field(viewzoom)
+PRVM_DECLARE_field(waterlevel)
+PRVM_DECLARE_field(watertype)
+PRVM_DECLARE_field(weapon)
+PRVM_DECLARE_field(weaponframe)
+PRVM_DECLARE_field(weaponmodel)
+PRVM_DECLARE_field(yaw_speed)
+PRVM_DECLARE_function(CSQC_ConsoleCommand)
+PRVM_DECLARE_function(CSQC_Ent_Remove)
+PRVM_DECLARE_function(CSQC_Ent_Spawn)
+PRVM_DECLARE_function(CSQC_Ent_Update)
+PRVM_DECLARE_function(CSQC_Event)
+PRVM_DECLARE_function(CSQC_Event_Sound)
+PRVM_DECLARE_function(CSQC_Init)
+PRVM_DECLARE_function(CSQC_InputEvent)
+PRVM_DECLARE_function(CSQC_Parse_CenterPrint)
+PRVM_DECLARE_function(CSQC_Parse_Print)
+PRVM_DECLARE_function(CSQC_Parse_StuffCmd)
+PRVM_DECLARE_function(CSQC_Parse_TempEntity)
+PRVM_DECLARE_function(CSQC_Shutdown)
+PRVM_DECLARE_function(CSQC_UpdateView)
+PRVM_DECLARE_function(ClientConnect)
+PRVM_DECLARE_function(ClientDisconnect)
+PRVM_DECLARE_function(ClientKill)
+PRVM_DECLARE_function(EndFrame)
+PRVM_DECLARE_function(GameCommand)
+PRVM_DECLARE_function(Gecko_Query)
+PRVM_DECLARE_function(PlayerPostThink)
+PRVM_DECLARE_function(PlayerPreThink)
+PRVM_DECLARE_function(PutClientInServer)
+PRVM_DECLARE_function(RestoreGame)
+PRVM_DECLARE_function(SV_ChangeTeam)
+PRVM_DECLARE_function(SV_OnEntityNoSpawnFunction)
+PRVM_DECLARE_function(SV_OnEntityPostSpawnFunction)
+PRVM_DECLARE_function(SV_OnEntityPreSpawnFunction)
+PRVM_DECLARE_function(SV_ParseClientCommand)
+PRVM_DECLARE_function(SV_PausedTic)
+PRVM_DECLARE_function(SV_PlayerPhysics)
+PRVM_DECLARE_function(SV_Shutdown)
+PRVM_DECLARE_function(SetChangeParms)
+PRVM_DECLARE_function(SetNewParms)
+PRVM_DECLARE_function(StartFrame)
+PRVM_DECLARE_function(URI_Get_Callback)
+PRVM_DECLARE_function(m_draw)
+PRVM_DECLARE_function(m_init)
+PRVM_DECLARE_function(m_keydown)
+PRVM_DECLARE_function(m_keyup)
+PRVM_DECLARE_function(m_newmap)
+PRVM_DECLARE_function(m_shutdown)
+PRVM_DECLARE_function(m_toggle)
+PRVM_DECLARE_function(main)
+PRVM_DECLARE_global(SV_InitCmd)
+PRVM_DECLARE_global(clientcommandframe)
+PRVM_DECLARE_global(coop)
+PRVM_DECLARE_global(deathmatch)
+PRVM_DECLARE_global(dmg_origin)
+PRVM_DECLARE_global(dmg_save)
+PRVM_DECLARE_global(dmg_take)
+PRVM_DECLARE_global(drawfont)
+PRVM_DECLARE_global(drawfontscale)
+PRVM_DECLARE_global(force_retouch)
+PRVM_DECLARE_global(found_secrets)
+PRVM_DECLARE_global(frametime)
+PRVM_DECLARE_global(gettaginfo_forward)
+PRVM_DECLARE_global(gettaginfo_name)
+PRVM_DECLARE_global(gettaginfo_offset)
+PRVM_DECLARE_global(gettaginfo_parent)
+PRVM_DECLARE_global(gettaginfo_right)
+PRVM_DECLARE_global(gettaginfo_up)
+PRVM_DECLARE_global(input_angles)
+PRVM_DECLARE_global(input_buttons)
+PRVM_DECLARE_global(input_movevalues)
+PRVM_DECLARE_global(input_timelength)
+PRVM_DECLARE_global(intermission)
+PRVM_DECLARE_global(killed_monsters)
+PRVM_DECLARE_global(mapname)
+PRVM_DECLARE_global(maxclients)
+PRVM_DECLARE_global(movevar_accelerate)
+PRVM_DECLARE_global(movevar_airaccelerate)
+PRVM_DECLARE_global(movevar_entgravity)
+PRVM_DECLARE_global(movevar_friction)
+PRVM_DECLARE_global(movevar_gravity)
+PRVM_DECLARE_global(movevar_maxspeed)
+PRVM_DECLARE_global(movevar_spectatormaxspeed)
+PRVM_DECLARE_global(movevar_stopspeed)
+PRVM_DECLARE_global(movevar_wateraccelerate)
+PRVM_DECLARE_global(movevar_waterfriction)
+PRVM_DECLARE_global(msg_entity)
+PRVM_DECLARE_global(other)
+PRVM_DECLARE_global(parm1)
+PRVM_DECLARE_global(parm2)
+PRVM_DECLARE_global(parm3)
+PRVM_DECLARE_global(parm4)
+PRVM_DECLARE_global(parm5)
+PRVM_DECLARE_global(parm6)
+PRVM_DECLARE_global(parm7)
+PRVM_DECLARE_global(parm8)
+PRVM_DECLARE_global(parm9)
+PRVM_DECLARE_global(parm10)
+PRVM_DECLARE_global(parm11)
+PRVM_DECLARE_global(parm12)
+PRVM_DECLARE_global(parm13)
+PRVM_DECLARE_global(parm14)
+PRVM_DECLARE_global(parm15)
+PRVM_DECLARE_global(parm16)
+PRVM_DECLARE_global(particle_airfriction)
+PRVM_DECLARE_global(particle_alpha)
+PRVM_DECLARE_global(particle_alphafade)
+PRVM_DECLARE_global(particle_angle)
+PRVM_DECLARE_global(particle_blendmode)
+PRVM_DECLARE_global(particle_bounce)
+PRVM_DECLARE_global(particle_color1)
+PRVM_DECLARE_global(particle_color2)
+PRVM_DECLARE_global(particle_delaycollision)
+PRVM_DECLARE_global(particle_delayspawn)
+PRVM_DECLARE_global(particle_gravity)
+PRVM_DECLARE_global(particle_liquidfriction)
+PRVM_DECLARE_global(particle_orientation)
+PRVM_DECLARE_global(particle_originjitter)
+PRVM_DECLARE_global(particle_qualityreduction)
+PRVM_DECLARE_global(particle_size)
+PRVM_DECLARE_global(particle_sizeincrease)
+PRVM_DECLARE_global(particle_spin)
+PRVM_DECLARE_global(particle_stainalpha)
+PRVM_DECLARE_global(particle_staincolor1)
+PRVM_DECLARE_global(particle_staincolor2)
+PRVM_DECLARE_global(particle_stainsize)
+PRVM_DECLARE_global(particle_staintex)
+PRVM_DECLARE_global(particle_stretch)
+PRVM_DECLARE_global(particle_tex)
+PRVM_DECLARE_global(particle_time)
+PRVM_DECLARE_global(particle_type)
+PRVM_DECLARE_global(particle_velocityjitter)
+PRVM_DECLARE_global(particles_alphamax)
+PRVM_DECLARE_global(particles_alphamin)
+PRVM_DECLARE_global(particles_colormax)
+PRVM_DECLARE_global(particles_colormin)
+PRVM_DECLARE_global(player_localentnum)
+PRVM_DECLARE_global(player_localnum)
+PRVM_DECLARE_global(pmove_inwater)
+PRVM_DECLARE_global(pmove_maxs)
+PRVM_DECLARE_global(pmove_mins)
+PRVM_DECLARE_global(pmove_onground)
+PRVM_DECLARE_global(pmove_org)
+PRVM_DECLARE_global(pmove_vel)
+PRVM_DECLARE_global(require_spawnfunc_prefix)
+PRVM_DECLARE_global(sb_showscores)
+PRVM_DECLARE_global(self)
+PRVM_DECLARE_global(servercommandframe)
+PRVM_DECLARE_global(serverdeltatime)
+PRVM_DECLARE_global(serverflags)
+PRVM_DECLARE_global(serverprevtime)
+PRVM_DECLARE_global(servertime)
+PRVM_DECLARE_global(teamplay)
+PRVM_DECLARE_global(time)
+PRVM_DECLARE_global(total_monsters)
+PRVM_DECLARE_global(total_secrets)
+PRVM_DECLARE_global(trace_allsolid)
+PRVM_DECLARE_global(trace_dphitcontents)
+PRVM_DECLARE_global(trace_dphitq3surfaceflags)
+PRVM_DECLARE_global(trace_dphittexturename)
+PRVM_DECLARE_global(trace_dpstartcontents)
+PRVM_DECLARE_global(trace_endpos)
+PRVM_DECLARE_global(trace_ent)
+PRVM_DECLARE_global(trace_fraction)
+PRVM_DECLARE_global(trace_inopen)
+PRVM_DECLARE_global(trace_inwater)
+PRVM_DECLARE_global(trace_networkentity)
+PRVM_DECLARE_global(trace_plane_dist)
+PRVM_DECLARE_global(trace_plane_normal)
+PRVM_DECLARE_global(trace_startsolid)
+PRVM_DECLARE_global(transparent_offset)
+PRVM_DECLARE_global(v_forward)
+PRVM_DECLARE_global(v_right)
+PRVM_DECLARE_global(v_up)
+PRVM_DECLARE_global(view_angles)
+PRVM_DECLARE_global(view_punchangle)
+PRVM_DECLARE_global(view_punchvector)
+PRVM_DECLARE_global(world)
+PRVM_DECLARE_global(worldstatus)
+PRVM_DECLARE_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)
+PRVM_DECLARE_menufunction(m_keydown)
+PRVM_DECLARE_menufunction(m_keyup)
+PRVM_DECLARE_menufunction(m_newmap)
+PRVM_DECLARE_menufunction(m_shutdown)
+PRVM_DECLARE_menufunction(m_toggle)
+PRVM_DECLARE_menuglobaledict(self)
+PRVM_DECLARE_menuglobalfloat(drawfont)
+PRVM_DECLARE_menuglobalfloat(require_spawnfunc_prefix)
+PRVM_DECLARE_menuglobalvector(drawfontscale)
+PRVM_DECLARE_serverfieldedict(aiment)
+PRVM_DECLARE_serverfieldedict(chain)
+PRVM_DECLARE_serverfieldedict(clientcamera)
+PRVM_DECLARE_serverfieldedict(cursor_trace_ent)
+PRVM_DECLARE_serverfieldedict(dmg_inflictor)
+PRVM_DECLARE_serverfieldedict(drawonlytoclient)
+PRVM_DECLARE_serverfieldedict(enemy)
+PRVM_DECLARE_serverfieldedict(exteriormodeltoclient)
+PRVM_DECLARE_serverfieldedict(goalentity)
+PRVM_DECLARE_serverfieldedict(groundentity)
+PRVM_DECLARE_serverfieldedict(nodrawtoclient)
+PRVM_DECLARE_serverfieldedict(owner)
+PRVM_DECLARE_serverfieldedict(tag_entity)
+PRVM_DECLARE_serverfieldedict(viewmodelforclient)
+PRVM_DECLARE_serverfieldfloat(SendFlags)
+PRVM_DECLARE_serverfieldfloat(Version)
+PRVM_DECLARE_serverfieldfloat(alpha)
+PRVM_DECLARE_serverfieldfloat(ammo_cells)
+PRVM_DECLARE_serverfieldfloat(ammo_cells1)
+PRVM_DECLARE_serverfieldfloat(ammo_lava_nails)
+PRVM_DECLARE_serverfieldfloat(ammo_multi_rockets)
+PRVM_DECLARE_serverfieldfloat(ammo_nails)
+PRVM_DECLARE_serverfieldfloat(ammo_nails1)
+PRVM_DECLARE_serverfieldfloat(ammo_plasma)
+PRVM_DECLARE_serverfieldfloat(ammo_rockets)
+PRVM_DECLARE_serverfieldfloat(ammo_rockets1)
+PRVM_DECLARE_serverfieldfloat(ammo_shells)
+PRVM_DECLARE_serverfieldfloat(ammo_shells1)
+PRVM_DECLARE_serverfieldfloat(armortype)
+PRVM_DECLARE_serverfieldfloat(armorvalue)
+PRVM_DECLARE_serverfieldfloat(bouncefactor)
+PRVM_DECLARE_serverfieldfloat(bouncestop)
+PRVM_DECLARE_serverfieldfloat(button0)
+PRVM_DECLARE_serverfieldfloat(button1)
+PRVM_DECLARE_serverfieldfloat(button2)
+PRVM_DECLARE_serverfieldfloat(button3)
+PRVM_DECLARE_serverfieldfloat(button4)
+PRVM_DECLARE_serverfieldfloat(button5)
+PRVM_DECLARE_serverfieldfloat(button6)
+PRVM_DECLARE_serverfieldfloat(button7)
+PRVM_DECLARE_serverfieldfloat(button8)
+PRVM_DECLARE_serverfieldfloat(button9)
+PRVM_DECLARE_serverfieldfloat(button10)
+PRVM_DECLARE_serverfieldfloat(button11)
+PRVM_DECLARE_serverfieldfloat(button12)
+PRVM_DECLARE_serverfieldfloat(button13)
+PRVM_DECLARE_serverfieldfloat(button14)
+PRVM_DECLARE_serverfieldfloat(button15)
+PRVM_DECLARE_serverfieldfloat(button16)
+PRVM_DECLARE_serverfieldfloat(buttonchat)
+PRVM_DECLARE_serverfieldfloat(buttonuse)
+PRVM_DECLARE_serverfieldfloat(clientcolors)
+PRVM_DECLARE_serverfieldfloat(colormap)
+PRVM_DECLARE_serverfieldfloat(currentammo)
+PRVM_DECLARE_serverfieldfloat(cursor_active)
+PRVM_DECLARE_serverfieldfloat(deadflag)
+PRVM_DECLARE_serverfieldfloat(disableclientprediction)
+PRVM_DECLARE_serverfieldfloat(discardabledemo)
+PRVM_DECLARE_serverfieldfloat(dmg_save)
+PRVM_DECLARE_serverfieldfloat(dmg_take)
+PRVM_DECLARE_serverfieldfloat(dphitcontentsmask)
+PRVM_DECLARE_serverfieldfloat(effects)
+PRVM_DECLARE_serverfieldfloat(fixangle)
+PRVM_DECLARE_serverfieldfloat(flags)
+PRVM_DECLARE_serverfieldfloat(frags)
+PRVM_DECLARE_serverfieldfloat(frame)
+PRVM_DECLARE_serverfieldfloat(frame1time)
+PRVM_DECLARE_serverfieldfloat(frame2)
+PRVM_DECLARE_serverfieldfloat(frame2time)
+PRVM_DECLARE_serverfieldfloat(frame3)
+PRVM_DECLARE_serverfieldfloat(frame3time)
+PRVM_DECLARE_serverfieldfloat(frame4)
+PRVM_DECLARE_serverfieldfloat(frame4time)
+PRVM_DECLARE_serverfieldfloat(fullbright)
+PRVM_DECLARE_serverfieldfloat(glow_color)
+PRVM_DECLARE_serverfieldfloat(glow_size)
+PRVM_DECLARE_serverfieldfloat(glow_trail)
+PRVM_DECLARE_serverfieldfloat(gravity)
+PRVM_DECLARE_serverfieldfloat(health)
+PRVM_DECLARE_serverfieldfloat(ideal_yaw)
+PRVM_DECLARE_serverfieldfloat(idealpitch)
+PRVM_DECLARE_serverfieldfloat(impulse)
+PRVM_DECLARE_serverfieldfloat(items)
+PRVM_DECLARE_serverfieldfloat(items2)
+PRVM_DECLARE_serverfieldfloat(jointtype)
+PRVM_DECLARE_serverfieldfloat(lerpfrac)
+PRVM_DECLARE_serverfieldfloat(lerpfrac3)
+PRVM_DECLARE_serverfieldfloat(lerpfrac4)
+PRVM_DECLARE_serverfieldfloat(light_lev)
+PRVM_DECLARE_serverfieldfloat(ltime)
+PRVM_DECLARE_serverfieldfloat(mass)
+PRVM_DECLARE_serverfieldfloat(max_health)
+PRVM_DECLARE_serverfieldfloat(modelflags)
+PRVM_DECLARE_serverfieldfloat(modelindex)
+PRVM_DECLARE_serverfieldfloat(movetype)
+PRVM_DECLARE_serverfieldfloat(nextthink)
+PRVM_DECLARE_serverfieldfloat(pflags)
+PRVM_DECLARE_serverfieldfloat(ping)
+PRVM_DECLARE_serverfieldfloat(ping_movementloss)
+PRVM_DECLARE_serverfieldfloat(ping_packetloss)
+PRVM_DECLARE_serverfieldfloat(pitch_speed)
+PRVM_DECLARE_serverfieldfloat(pmodel)
+PRVM_DECLARE_serverfieldfloat(renderamt)
+PRVM_DECLARE_serverfieldfloat(scale)
+PRVM_DECLARE_serverfieldfloat(sendcomplexanimation)
+PRVM_DECLARE_serverfieldfloat(skeletonindex)
+PRVM_DECLARE_serverfieldfloat(skin)
+PRVM_DECLARE_serverfieldfloat(solid)
+PRVM_DECLARE_serverfieldfloat(sounds)
+PRVM_DECLARE_serverfieldfloat(spawnflags)
+PRVM_DECLARE_serverfieldfloat(style)
+PRVM_DECLARE_serverfieldfloat(tag_index)
+PRVM_DECLARE_serverfieldfloat(takedamage)
+PRVM_DECLARE_serverfieldfloat(team)
+PRVM_DECLARE_serverfieldfloat(teleport_time)
+PRVM_DECLARE_serverfieldfloat(traileffectnum)
+PRVM_DECLARE_serverfieldfloat(viewzoom)
+PRVM_DECLARE_serverfieldfloat(waterlevel)
+PRVM_DECLARE_serverfieldfloat(watertype)
+PRVM_DECLARE_serverfieldfloat(weapon)
+PRVM_DECLARE_serverfieldfloat(weaponframe)
+PRVM_DECLARE_serverfieldfloat(yaw_speed)
+PRVM_DECLARE_serverfieldfunction(SendEntity)
+PRVM_DECLARE_serverfieldfunction(blocked)
+PRVM_DECLARE_serverfieldfunction(camera_transform)
+PRVM_DECLARE_serverfieldfunction(contentstransition)
+PRVM_DECLARE_serverfieldfunction(customizeentityforclient)
+PRVM_DECLARE_serverfieldfunction(movetypesteplandevent)
+PRVM_DECLARE_serverfieldfunction(think)
+PRVM_DECLARE_serverfieldfunction(touch)
+PRVM_DECLARE_serverfieldfunction(use)
+PRVM_DECLARE_serverfieldstring(classname)
+PRVM_DECLARE_serverfieldstring(clientstatus)
+PRVM_DECLARE_serverfieldstring(crypto_encryptmethod)
+PRVM_DECLARE_serverfieldstring(crypto_idfp)
+PRVM_DECLARE_serverfieldstring(crypto_keyfp)
+PRVM_DECLARE_serverfieldstring(crypto_mykeyfp)
+PRVM_DECLARE_serverfieldstring(crypto_signmethod)
+PRVM_DECLARE_serverfieldstring(message)
+PRVM_DECLARE_serverfieldstring(model)
+PRVM_DECLARE_serverfieldstring(netaddress)
+PRVM_DECLARE_serverfieldstring(netname)
+PRVM_DECLARE_serverfieldstring(noise)
+PRVM_DECLARE_serverfieldstring(noise1)
+PRVM_DECLARE_serverfieldstring(noise2)
+PRVM_DECLARE_serverfieldstring(noise3)
+PRVM_DECLARE_serverfieldstring(playermodel)
+PRVM_DECLARE_serverfieldstring(playerskin)
+PRVM_DECLARE_serverfieldstring(target)
+PRVM_DECLARE_serverfieldstring(targetname)
+PRVM_DECLARE_serverfieldstring(weaponmodel)
+PRVM_DECLARE_serverfieldvector(absmax)
+PRVM_DECLARE_serverfieldvector(absmin)
+PRVM_DECLARE_serverfieldvector(angles)
+PRVM_DECLARE_serverfieldvector(avelocity)
+PRVM_DECLARE_serverfieldvector(color)
+PRVM_DECLARE_serverfieldvector(colormod)
+PRVM_DECLARE_serverfieldvector(cursor_screen)
+PRVM_DECLARE_serverfieldvector(cursor_trace_endpos)
+PRVM_DECLARE_serverfieldvector(cursor_trace_start)
+PRVM_DECLARE_serverfieldvector(glowmod)
+PRVM_DECLARE_serverfieldvector(maxs)
+PRVM_DECLARE_serverfieldvector(mins)
+PRVM_DECLARE_serverfieldvector(movedir)
+PRVM_DECLARE_serverfieldvector(movement)
+PRVM_DECLARE_serverfieldvector(oldorigin)
+PRVM_DECLARE_serverfieldvector(origin)
+PRVM_DECLARE_serverfieldvector(punchangle)
+PRVM_DECLARE_serverfieldvector(punchvector)
+PRVM_DECLARE_serverfieldvector(size)
+PRVM_DECLARE_serverfieldvector(v_angle)
+PRVM_DECLARE_serverfieldvector(velocity)
+PRVM_DECLARE_serverfieldvector(view_ofs)
+PRVM_DECLARE_serverfunction(ClientConnect)
+PRVM_DECLARE_serverfunction(ClientDisconnect)
+PRVM_DECLARE_serverfunction(ClientKill)
+PRVM_DECLARE_serverfunction(EndFrame)
+PRVM_DECLARE_serverfunction(GameCommand)
+PRVM_DECLARE_serverfunction(PlayerPostThink)
+PRVM_DECLARE_serverfunction(PlayerPreThink)
+PRVM_DECLARE_serverfunction(PutClientInServer)
+PRVM_DECLARE_serverfunction(RestoreGame)
+PRVM_DECLARE_serverfunction(SV_ChangeTeam)
+PRVM_DECLARE_serverfunction(SV_OnEntityNoSpawnFunction)
+PRVM_DECLARE_serverfunction(SV_OnEntityPostSpawnFunction)
+PRVM_DECLARE_serverfunction(SV_OnEntityPreSpawnFunction)
+PRVM_DECLARE_serverfunction(SV_ParseClientCommand)
+PRVM_DECLARE_serverfunction(SV_PausedTic)
+PRVM_DECLARE_serverfunction(SV_PlayerPhysics)
+PRVM_DECLARE_serverfunction(SV_Shutdown)
+PRVM_DECLARE_serverfunction(SetChangeParms)
+PRVM_DECLARE_serverfunction(SetNewParms)
+PRVM_DECLARE_serverfunction(StartFrame)
+PRVM_DECLARE_serverfunction(URI_Get_Callback)
+PRVM_DECLARE_serverfunction(main)
+PRVM_DECLARE_serverglobaledict(msg_entity)
+PRVM_DECLARE_serverglobaledict(other)
+PRVM_DECLARE_serverglobaledict(self)
+PRVM_DECLARE_serverglobaledict(trace_ent)
+PRVM_DECLARE_serverglobaledict(world)
+PRVM_DECLARE_serverglobalfloat(coop)
+PRVM_DECLARE_serverglobalfloat(deathmatch)
+PRVM_DECLARE_serverglobalfloat(force_retouch)
+PRVM_DECLARE_serverglobalfloat(found_secrets)
+PRVM_DECLARE_serverglobalfloat(frametime)
+PRVM_DECLARE_serverglobalfloat(gettaginfo_parent)
+PRVM_DECLARE_serverglobalfloat(killed_monsters)
+PRVM_DECLARE_serverglobalfloat(parm1)
+PRVM_DECLARE_serverglobalfloat(parm2)
+PRVM_DECLARE_serverglobalfloat(parm3)
+PRVM_DECLARE_serverglobalfloat(parm4)
+PRVM_DECLARE_serverglobalfloat(parm5)
+PRVM_DECLARE_serverglobalfloat(parm6)
+PRVM_DECLARE_serverglobalfloat(parm7)
+PRVM_DECLARE_serverglobalfloat(parm8)
+PRVM_DECLARE_serverglobalfloat(parm9)
+PRVM_DECLARE_serverglobalfloat(parm10)
+PRVM_DECLARE_serverglobalfloat(parm11)
+PRVM_DECLARE_serverglobalfloat(parm12)
+PRVM_DECLARE_serverglobalfloat(parm13)
+PRVM_DECLARE_serverglobalfloat(parm14)
+PRVM_DECLARE_serverglobalfloat(parm15)
+PRVM_DECLARE_serverglobalfloat(parm16)
+PRVM_DECLARE_serverglobalfloat(require_spawnfunc_prefix)
+PRVM_DECLARE_serverglobalfloat(serverflags)
+PRVM_DECLARE_serverglobalfloat(teamplay)
+PRVM_DECLARE_serverglobalfloat(time)
+PRVM_DECLARE_serverglobalfloat(total_monsters)
+PRVM_DECLARE_serverglobalfloat(total_secrets)
+PRVM_DECLARE_serverglobalfloat(trace_allsolid)
+PRVM_DECLARE_serverglobalfloat(trace_dphitcontents)
+PRVM_DECLARE_serverglobalfloat(trace_dphitq3surfaceflags)
+PRVM_DECLARE_serverglobalfloat(trace_dpstartcontents)
+PRVM_DECLARE_serverglobalfloat(trace_fraction)
+PRVM_DECLARE_serverglobalfloat(trace_inopen)
+PRVM_DECLARE_serverglobalfloat(trace_inwater)
+PRVM_DECLARE_serverglobalfloat(trace_plane_dist)
+PRVM_DECLARE_serverglobalfloat(trace_startsolid)
+PRVM_DECLARE_serverglobalstring(SV_InitCmd)
+PRVM_DECLARE_serverglobalstring(gettaginfo_name)
+PRVM_DECLARE_serverglobalstring(mapname)
+PRVM_DECLARE_serverglobalstring(trace_dphittexturename)
+PRVM_DECLARE_serverglobalstring(worldstatus)
+PRVM_DECLARE_serverglobalvector(gettaginfo_forward)
+PRVM_DECLARE_serverglobalvector(gettaginfo_offset)
+PRVM_DECLARE_serverglobalvector(gettaginfo_right)
+PRVM_DECLARE_serverglobalvector(gettaginfo_up)
+PRVM_DECLARE_serverglobalvector(trace_endpos)
+PRVM_DECLARE_serverglobalvector(trace_plane_normal)
+PRVM_DECLARE_serverglobalvector(v_forward)
+PRVM_DECLARE_serverglobalvector(v_right)
+PRVM_DECLARE_serverglobalvector(v_up)
\ No newline at end of file
index 4cc7527c0beb53af0b79698cca63a896afa7f7ba..7e1de4fedbefd77024da8b622dce0a24ec88ed0e 100644 (file)
@@ -86,7 +86,7 @@ extern char engineversion[128];
 #define MAX_NETWM_ICON 1026 // one 32x32
 
 #define        MAX_WATERPLANES                 2
-#define        MAX_CUBEMAPS                    64
+#define        MAX_CUBEMAPS                    1024
 #define        MAX_EXPLOSIONS                  8
 #define        MAX_DLIGHTS                             16
 #define        MAX_CACHED_PICS                 1024 // this is 144 bytes each (or 152 on 64bit)
@@ -153,7 +153,7 @@ extern char engineversion[128];
 #define MAX_NETWM_ICON 352822 // 16x16, 22x22, 24x24, 32x32, 48x48, 64x64, 128x128, 256x256, 512x512
 
 #define        MAX_WATERPLANES                 16 ///< max number of water planes visible (each one causes additional view renders)
-#define        MAX_CUBEMAPS                    256 ///< max number of cubemap textures loaded for light filters
+#define        MAX_CUBEMAPS                    1024 ///< max number of cubemap textures loaded for light filters
 #define        MAX_EXPLOSIONS                  64 ///< max number of explosion shell effects active at once (not particle related)
 #define        MAX_DLIGHTS                             256 ///< max number of dynamic lights (rocket flashes, etc) in scene at once
 #define        MAX_CACHED_PICS                 1024 ///< max number of 2D pics loaded at once
@@ -229,6 +229,7 @@ extern char engineversion[128];
 //#define STAT_TIME                    17 ///< FTE
 //#define STAT_VIEW2           20 ///< FTE
 #define STAT_VIEWZOOM          21 ///< DP
+#define STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR 220 ///< DP
 #define STAT_MOVEVARS_AIRCONTROL_PENALTY                                       221 ///< DP
 #define STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW 222 ///< DP
 #define STAT_MOVEVARS_AIRSTRAFEACCEL_QW 223 ///< DP
@@ -391,10 +392,6 @@ extern char engineversion[128];
 #include "console.h"
 #include "menu.h"
 
-#include "glquake.h"
-
-#include "palette.h"
-
 extern qboolean noclip_anglehack;
 
 extern cvar_t developer;
@@ -492,6 +489,10 @@ 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
index 727f847f5b57acd51f46ed8100c277a444a51d0f..2a45c215b94f9780a9dfee73156fbc804014a878 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);
+       R_SetupShader_Generic(explosiontexture, NULL, GL_MODULATE, 1, false, false);
        for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
        {
                const explosion_t *e = explosion + surfacelist[surfacelistindex];
index 5b2a8190b38327019a438c751ec629f850caaca0..76dd1fabb0a8eba63bd281b21b5199be14d955db 100644 (file)
@@ -267,7 +267,9 @@ 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};
+#ifndef USE_GLES2
+static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
+#endif
 
 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"};
@@ -320,25 +322,23 @@ cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to
 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
 cvar_t r_shadow_bouncegrid = {CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, only active on levels with realtime lights active (r_shadow_realtime_world is usually required for these)"};
-cvar_t r_shadow_bouncegrid_airstepmax = {CVAR_SAVE, "r_shadow_bouncegrid_airstepmax", "1024", "maximum number of photon accumulation contributions for one photon"};
-cvar_t r_shadow_bouncegrid_airstepsize = {CVAR_SAVE, "r_shadow_bouncegrid_airstepsize", "64", "maximum spacing of photon accumulation through the air"};
 cvar_t r_shadow_bouncegrid_bounceanglediffuse = {CVAR_SAVE, "r_shadow_bouncegrid_bounceanglediffuse", "0", "use random bounce direction rather than true reflection, makes some corner areas dark"};
 cvar_t r_shadow_bouncegrid_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_directionalshading", "0", "use diffuse shading rather than ambient, 3D texture becomes 8x as many pixels to hold the additional data"};
 cvar_t r_shadow_bouncegrid_dlightparticlemultiplier = {CVAR_SAVE, "r_shadow_bouncegrid_dlightparticlemultiplier", "0", "if set to a high value like 16 this can make dlights look great, but 0 is recommended for performance reasons"};
 cvar_t r_shadow_bouncegrid_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
 cvar_t r_shadow_bouncegrid_includedirectlighting = {CVAR_SAVE, "r_shadow_bouncegrid_includedirectlighting", "0", "allows direct lighting to be recorded, not just indirect (gives an effect somewhat like r_shadow_realtime_world_lightmaps)"};
 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
-cvar_t r_shadow_bouncegrid_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_lightradiusscale", "10", "particles stop at this fraction of light radius (can be more than 1)"};
-cvar_t r_shadow_bouncegrid_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_maxbounce", "5", "maximum number of bounces for a particle (minimum is 1)"};
-cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "4", "amount of energy carried over after each bounce, this is a multiplier of texture color and the result is clamped to 1 or less, to prevent adding energy on each bounce"};
+cvar_t r_shadow_bouncegrid_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_lightradiusscale", "4", "particles stop at this fraction of light radius (can be more than 1)"};
+cvar_t r_shadow_bouncegrid_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_maxbounce", "2", "maximum number of bounces for a particle (minimum is 0)"};
+cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "1", "amount of energy carried over after each bounce, this is a multiplier of texture color and the result is clamped to 1 or less, to prevent adding energy on each bounce"};
 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "1", "brightness of particles contributing to bouncegrid texture"};
 cvar_t r_shadow_bouncegrid_photons = {CVAR_SAVE, "r_shadow_bouncegrid_photons", "2000", "total photons to shoot per update, divided proportionately between lights"};
-cvar_t r_shadow_bouncegrid_spacingx = {CVAR_SAVE, "r_shadow_bouncegrid_spacingx", "64", "unit size of bouncegrid pixel on X axis"};
-cvar_t r_shadow_bouncegrid_spacingy = {CVAR_SAVE, "r_shadow_bouncegrid_spacingy", "64", "unit size of bouncegrid pixel on Y axis"};
-cvar_t r_shadow_bouncegrid_spacingz = {CVAR_SAVE, "r_shadow_bouncegrid_spacingz", "64", "unit size of bouncegrid pixel on Z axis"};
+cvar_t r_shadow_bouncegrid_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_spacing", "64", "unit size of bouncegrid pixel"};
 cvar_t r_shadow_bouncegrid_stablerandom = {CVAR_SAVE, "r_shadow_bouncegrid_stablerandom", "1", "make particle distribution consistent from frame to frame"};
 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
+cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "10", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
+cvar_t r_shadow_bouncegrid_static_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0) in static mode"};
 cvar_t r_shadow_bouncegrid_static_photons = {CVAR_SAVE, "r_shadow_bouncegrid_static_photons", "25000", "photons value to use when in static mode"};
 cvar_t r_shadow_bouncegrid_updateinterval = {CVAR_SAVE, "r_shadow_bouncegrid_updateinterval", "0", "update bouncegrid texture once per this many seconds, useful values are 0, 0.05, or 1000000"};
 cvar_t r_shadow_bouncegrid_x = {CVAR_SAVE, "r_shadow_bouncegrid_x", "64", "maximum texture size of bouncegrid on X axis"};
@@ -372,8 +372,6 @@ typedef struct r_shadow_bouncegrid_settings_s
        int photons;
        float spacing[3];
        int stablerandom;
-       float airstepmax;
-       float airstepsize;
 }
 r_shadow_bouncegrid_settings_t;
 
@@ -743,8 +741,6 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_polygonoffset);
        Cvar_RegisterVariable(&r_shadow_texture3d);
        Cvar_RegisterVariable(&r_shadow_bouncegrid);
-       Cvar_RegisterVariable(&r_shadow_bouncegrid_airstepmax);
-       Cvar_RegisterVariable(&r_shadow_bouncegrid_airstepsize);
        Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
        Cvar_RegisterVariable(&r_shadow_bouncegrid_directionalshading);
        Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier);
@@ -756,12 +752,12 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
        Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
        Cvar_RegisterVariable(&r_shadow_bouncegrid_photons);
-       Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingx);
-       Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingy);
-       Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingz);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_spacing);
        Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom);
        Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
        Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
+       Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
        Cvar_RegisterVariable(&r_shadow_bouncegrid_static_photons);
        Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval);
        Cvar_RegisterVariable(&r_shadow_bouncegrid_x);
@@ -1958,7 +1954,7 @@ void R_Shadow_RenderMode_Begin(void)
        GL_DepthMask(false);
        GL_Color(0, 0, 0, 1);
        GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
-
+       
        r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
 
        if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
@@ -2034,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);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
        r_shadow_usingshadowmap2d = false;
        r_shadow_usingshadowmaportho = false;
        R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
@@ -2056,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();
+       R_SetupShader_DepthOrShadow(false);
        r_shadow_rendermode = mode;
        switch(mode)
        {
@@ -2118,6 +2114,7 @@ static void R_Shadow_MakeShadowMap(int side, int size)
                return;
        }
 
+#ifndef USE_GLES2
        // render depth into the fbo, do not render color at all
        // validate the fbo now
        if (qglDrawBuffer)
@@ -2125,14 +2122,15 @@ static void R_Shadow_MakeShadowMap(int side, int size)
                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))
+               status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER);CHECKGLERROR
+               if (status != GL_FRAMEBUFFER_COMPLETE && (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);
                }
        }
+#endif
 }
 
 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
@@ -2168,7 +2166,7 @@ void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
        R_Mesh_ResetTextureState();
        R_Shadow_RenderMode_Reset();
        R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
-       R_SetupShader_DepthOrShadow();
+       R_SetupShader_DepthOrShadow(true);
        GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
        GL_DepthMask(true);
        GL_DepthTest(true);
@@ -2313,7 +2311,7 @@ void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadow
        R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
 }
 
-static void R_Shadow_UpdateBounceGridTexture(void)
+void R_Shadow_UpdateBounceGridTexture(void)
 {
 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
        dlight_t *light;
@@ -2353,6 +2351,7 @@ static void R_Shadow_UpdateBounceGridTexture(void)
        vec3_t lightcolor;
        vec3_t steppos;
        vec3_t stepdelta;
+       vec3_t cullmins, cullmaxs;
        vec_t radius;
        vec_t s;
        vec_t lightintensity;
@@ -2444,21 +2443,19 @@ static void R_Shadow_UpdateBounceGridTexture(void)
        // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
        memset(&settings, 0, sizeof(settings));
        settings.staticmode                    = r_shadow_bouncegrid_static.integer != 0;
-       settings.airstepmax                    = bound(1, r_shadow_bouncegrid_airstepmax.integer, 1048576);
-       settings.airstepsize                   = bound(1.0f, r_shadow_bouncegrid_airstepsize.value, 1024.0f);
        settings.bounceanglediffuse            = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
        settings.directionalshading            = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_directionalshading.integer != 0) && allowdirectionalshading;
        settings.dlightparticlemultiplier      = r_shadow_bouncegrid_dlightparticlemultiplier.value;
        settings.hitmodels                     = r_shadow_bouncegrid_hitmodels.integer != 0;
-       settings.includedirectlighting         = r_shadow_bouncegrid_includedirectlighting.integer != 0;
-       settings.lightradiusscale              = r_shadow_bouncegrid_lightradiusscale.value;
-       settings.maxbounce                     = r_shadow_bouncegrid_maxbounce.integer;
+       settings.includedirectlighting         = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
+       settings.lightradiusscale              = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_lightradiusscale.value);
+       settings.maxbounce                     = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_maxbounce.integer);
        settings.particlebounceintensity       = r_shadow_bouncegrid_particlebounceintensity.value;
-       settings.particleintensity             = r_shadow_bouncegrid_particleintensity.value;
+       settings.particleintensity             = r_shadow_bouncegrid_particleintensity.value * 16384.0f * (settings.directionalshading ? 4.0f : 1.0f) / (r_shadow_bouncegrid_spacing.value * r_shadow_bouncegrid_spacing.value);
        settings.photons                       = r_shadow_bouncegrid_static.integer ? r_shadow_bouncegrid_static_photons.integer : r_shadow_bouncegrid_photons.integer;
-       settings.spacing[0]                    = r_shadow_bouncegrid_spacingx.value;
-       settings.spacing[1]                    = r_shadow_bouncegrid_spacingy.value;
-       settings.spacing[2]                    = r_shadow_bouncegrid_spacingz.value;
+       settings.spacing[0]                    = r_shadow_bouncegrid_spacing.value;
+       settings.spacing[1]                    = r_shadow_bouncegrid_spacing.value;
+       settings.spacing[2]                    = r_shadow_bouncegrid_spacing.value;
        settings.stablerandom                  = r_shadow_bouncegrid_stablerandom.integer;
 
        // bound the values for sanity
@@ -2600,95 +2597,89 @@ static void R_Shadow_UpdateBounceGridTexture(void)
        photoncount = 0;
        for (lightindex = 0;lightindex < range2;lightindex++)
        {
-               if (settings.staticmode)
+               if (lightindex < range)
                {
                        light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
-                       if (!light || !(light->flags & flag))
+                       if (!light)
                                continue;
                        rtlight = &light->rtlight;
-                       // when static, we skip styled lights because they tend to change...
-                       if (rtlight->style > 0)
+                       VectorClear(rtlight->photoncolor);
+                       rtlight->photons = 0;
+                       if (!(light->flags & flag))
                                continue;
-                       VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
+                       if (settings.staticmode)
+                       {
+                               // when static, we skip styled lights because they tend to change...
+                               if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
+                                       continue;
+                       }
                }
                else
                {
-                       if (lightindex < range)
-                       {
-                               light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
-                               rtlight = &light->rtlight;
-                       }
-                       else
-                               rtlight = r_refdef.scene.lights[lightindex - range];
-                       // draw only visible lights (major speedup)
-                       if (!rtlight->draw)
-                               continue;
-                       VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
+                       rtlight = r_refdef.scene.lights[lightindex - range];
+                       VectorClear(rtlight->photoncolor);
+                       rtlight->photons = 0;
                }
-               if (!VectorLength2(lightcolor))
+               // draw only visible lights (major speedup)
+               radius = rtlight->radius * settings.lightradiusscale;
+               cullmins[0] = rtlight->shadoworigin[0] - radius;
+               cullmins[1] = rtlight->shadoworigin[1] - radius;
+               cullmins[2] = rtlight->shadoworigin[2] - radius;
+               cullmaxs[0] = rtlight->shadoworigin[0] + radius;
+               cullmaxs[1] = rtlight->shadoworigin[1] + radius;
+               cullmaxs[2] = rtlight->shadoworigin[2] + radius;
+               if (R_CullBox(cullmins, cullmaxs))
+                       continue;
+               if (r_refdef.scene.worldmodel
+                && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
+                && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
                        continue;
+               w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
+               if (w * VectorLength2(rtlight->color) == 0.0f)
+                       continue;
+               w *= (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
+               VectorScale(rtlight->color, w, rtlight->photoncolor);
+               //if (!VectorLength2(rtlight->photoncolor))
+               //      continue;
                // shoot particles from this light
                // use a calculation for the number of particles that will not
                // vary with lightstyle, otherwise we get randomized particle
                // distribution, the seeded random is only consistent for a
                // consistent number of particles on this light...
-               radius = rtlight->radius * settings.lightradiusscale;
                s = rtlight->radius;
                lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
                if (lightindex >= range)
                        lightintensity *= settings.dlightparticlemultiplier;
-               photoncount += max(0.0f, lightintensity * s * s);
+               rtlight->photons = max(0.0f, lightintensity * s * s);
+               photoncount += rtlight->photons;
        }
        photonscaling = (float)settings.photons / max(1, photoncount);
        photonresidual = 0.0f;
        for (lightindex = 0;lightindex < range2;lightindex++)
        {
-               if (settings.staticmode)
+               if (lightindex < range)
                {
                        light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
-                       if (!light || !(light->flags & flag))
+                       if (!light)
                                continue;
                        rtlight = &light->rtlight;
-                       // when static, we skip styled lights because they tend to change...
-                       if (rtlight->style > 0)
-                               continue;
-                       VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
                }
                else
-               {
-                       if (lightindex < range)
-                       {
-                               light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
-                               rtlight = &light->rtlight;
-                       }
-                       else
-                               rtlight = r_refdef.scene.lights[lightindex - range];
-                       // draw only visible lights (major speedup)
-                       if (!rtlight->draw)
-                               continue;
-                       VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
-               }
-               if (!VectorLength2(lightcolor))
+                       rtlight = r_refdef.scene.lights[lightindex - range];
+               // skip a light with no photons
+               if (rtlight->photons == 0.0f)
                        continue;
-               // shoot particles from this light
-               // use a calculation for the number of particles that will not
-               // vary with lightstyle, otherwise we get randomized particle
-               // distribution, the seeded random is only consistent for a
-               // consistent number of particles on this light...
-               radius = rtlight->radius * settings.lightradiusscale;
-               s = rtlight->radius;
-               lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
-               if (lightindex >= range)
-                       lightintensity *= settings.dlightparticlemultiplier;
-               photonresidual += lightintensity * s * s * photonscaling;
+               // skip a light with no photon color)
+               if (VectorLength2(rtlight->photoncolor) == 0.0f)
+                       continue;
+               photonresidual += rtlight->photons * photonscaling;
                shootparticles = (int)bound(0, photonresidual, MAXBOUNCEGRIDPARTICLESPERLIGHT);
                if (!shootparticles)
                        continue;
                photonresidual -= shootparticles;
+               radius = rtlight->radius * settings.lightradiusscale;
                s = settings.particleintensity / shootparticles;
-               VectorScale(lightcolor, s, baseshotcolor);
-               if (VectorLength2(baseshotcolor) == 0.0f)
-                       break;
+               VectorScale(rtlight->photoncolor, s, baseshotcolor);
                r_refdef.stats.bouncegrid_lights++;
                r_refdef.stats.bouncegrid_particles += shootparticles;
                for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
@@ -2707,10 +2698,10 @@ static 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
-                                       cliptrace = CL_TraceLine(clipstart, clipend, settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true, true);
+                               //if (settings.staticmode)
+                               //      Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask, true);
+                               //else
+                                       cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, true, false, NULL, true, true);
                                if (bouncecount > 0 || settings.includedirectlighting)
                                {
                                        // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
@@ -2757,20 +2748,18 @@ static void R_Shadow_UpdateBounceGridTexture(void)
                                        }
                                        // calculate the number of steps we need to traverse this distance
                                        VectorSubtract(cliptrace.endpos, clipstart, stepdelta);
-                                       numsteps = (int)(VectorLength(stepdelta) / settings.airstepsize);
-                                       numsteps = bound(1, numsteps, settings.airstepmax);
+                                       numsteps = (int)(VectorLength(stepdelta) * ispacing[0]);
+                                       numsteps = bound(1, numsteps, 1024);
                                        w = 1.0f / numsteps;
                                        VectorScale(stepdelta, w, stepdelta);
                                        VectorMA(clipstart, 0.5f, stepdelta, steppos);
-                                       if (settings.airstepmax == 1)
-                                               VectorCopy(cliptrace.endpos, steppos);
                                        for (step = 0;step < numsteps;step++)
                                        {
                                                r_refdef.stats.bouncegrid_splats++;
                                                // figure out which texture pixel this is in
-                                               texlerp[1][0] = ((steppos[0] - mins[0]) * ispacing[0]);
-                                               texlerp[1][1] = ((steppos[1] - mins[1]) * ispacing[1]);
-                                               texlerp[1][2] = ((steppos[2] - mins[2]) * ispacing[2]);
+                                               texlerp[1][0] = ((steppos[0] - mins[0]) * ispacing[0]) - 0.5f;
+                                               texlerp[1][1] = ((steppos[1] - mins[1]) * ispacing[1]) - 0.5f;
+                                               texlerp[1][2] = ((steppos[2] - mins[2]) * ispacing[2]) - 0.5f;
                                                tex[0] = (int)floor(texlerp[1][0]);
                                                tex[1] = (int)floor(texlerp[1][1]);
                                                tex[2] = (int)floor(texlerp[1][2]);
@@ -2968,7 +2957,7 @@ int bboxedges[12][2] =
 
 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
 {
-       if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass)
+       if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
        {
                r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
                r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
@@ -3167,12 +3156,8 @@ static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, cons
 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
 {
        // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
-       R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
-       if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
-               GL_DepthFunc(GL_EQUAL);
+       R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
        RSurf_DrawBatch();
-       if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
-               GL_DepthFunc(GL_LEQUAL);
 }
 
 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
@@ -3340,8 +3325,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)
        {
@@ -3355,30 +3340,7 @@ void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **textures
        if(negated)
        {
                VectorNegate(lightcolor, lightcolor);
-               switch(vid.renderpath)
-               {
-               case RENDERPATH_GL11:
-               case RENDERPATH_GL13:
-               case RENDERPATH_GL20:
-               case RENDERPATH_GLES1:
-               case RENDERPATH_GLES2:
-                       qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
-                       break;
-               case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
-                       IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
-#endif
-                       break;
-               case RENDERPATH_D3D10:
-                       Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-                       break;
-               case RENDERPATH_D3D11:
-                       Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-                       break;
-               case RENDERPATH_SOFT:
-                       DPSOFTRAST_BlendSubtract(true);
-                       break;
-               }
+               GL_BlendEquationSubtract(true);
        }
        RSurf_SetupDepthAndCulling();
        switch (r_shadow_rendermode)
@@ -3401,32 +3363,7 @@ void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **textures
                break;
        }
        if(negated)
-       {
-               switch(vid.renderpath)
-               {
-               case RENDERPATH_GL11:
-               case RENDERPATH_GL13:
-               case RENDERPATH_GL20:
-               case RENDERPATH_GLES1:
-               case RENDERPATH_GLES2:
-                       qglBlendEquationEXT(GL_FUNC_ADD_EXT);
-                       break;
-               case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
-                       IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
-#endif
-                       break;
-               case RENDERPATH_D3D10:
-                       Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-                       break;
-               case RENDERPATH_D3D11:
-                       Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-                       break;
-               case RENDERPATH_SOFT:
-                       DPSOFTRAST_BlendSubtract(false);
-                       break;
-               }
-       }
+               GL_BlendEquationSubtract(false);
 }
 
 void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec3_t color, int style, const char *cubemapname, int shadow, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
@@ -3632,6 +3569,9 @@ void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
        // can hold
        rtlight->cached_numfrustumplanes = 0;
 
+       if (r_trippy.integer)
+               return;
+
        // haven't implemented a culling path for ortho rendering
        if (!r_refdef.view.useperspective)
        {
@@ -4575,7 +4515,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;
@@ -4611,10 +4551,10 @@ void R_Shadow_PrepareLights(void)
                        // render depth into one texture and normalmap into the other
                        if (qglDrawBuffersARB)
                        {
-                               qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
+                               qglDrawBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR
                                qglReadBuffer(GL_NONE);CHECKGLERROR
-                               status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
-                               if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+                               status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER);CHECKGLERROR
+                               if (status != GL_FRAMEBUFFER_COMPLETE)
                                {
                                        Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
                                        Cvar_SetValueQuick(&r_shadow_deferred, 0);
@@ -4632,8 +4572,8 @@ void R_Shadow_PrepareLights(void)
                        {
                                qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
                                qglReadBuffer(GL_NONE);CHECKGLERROR
-                               status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
-                               if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+                               status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER);CHECKGLERROR
+                               if (status != GL_FRAMEBUFFER_COMPLETE)
                                {
                                        Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
                                        Cvar_SetValueQuick(&r_shadow_deferred, 0);
@@ -4649,10 +4589,10 @@ void R_Shadow_PrepareLights(void)
                        // with depth bound as attachment as well
                        if (qglDrawBuffersARB)
                        {
-                               qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
+                               qglDrawBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR
                                qglReadBuffer(GL_NONE);CHECKGLERROR
-                               status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
-                               if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+                               status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER);CHECKGLERROR
+                               if (status != GL_FRAMEBUFFER_COMPLETE)
                                {
                                        Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
                                        Cvar_SetValueQuick(&r_shadow_deferred, 0);
@@ -4660,10 +4600,12 @@ void R_Shadow_PrepareLights(void)
                                }
                        }
                }
+#endif
                break;
        case RENDERPATH_GL11:
        case RENDERPATH_GL13:
        case RENDERPATH_GLES1:
+       case RENDERPATH_GLES2:
                r_shadow_usingdeferredprepass = false;
                break;
        }
@@ -4671,22 +4613,25 @@ void R_Shadow_PrepareLights(void)
        R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles);
 
        flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
-       if (r_shadow_debuglight.integer >= 0)
+       if (r_shadow_bouncegrid.integer != 2)
        {
-               lightindex = r_shadow_debuglight.integer;
-               light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
-               if (light && (light->flags & flag))
-                       R_Shadow_PrepareLight(&light->rtlight);
-       }
-       else
-       {
-               range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
-               for (lightindex = 0;lightindex < range;lightindex++)
+               if (r_shadow_debuglight.integer >= 0)
                {
+                       lightindex = r_shadow_debuglight.integer;
                        light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
-                       if (light && (light->flags & flag))
+                       if (light)
                                R_Shadow_PrepareLight(&light->rtlight);
                }
+               else
+               {
+                       range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
+                       for (lightindex = 0;lightindex < range;lightindex++)
+                       {
+                               light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+                               if (light && (light->flags & flag))
+                                       R_Shadow_PrepareLight(&light->rtlight);
+                       }
+               }
        }
        if (r_refdef.scene.rtdlight)
        {
@@ -4705,8 +4650,6 @@ void R_Shadow_PrepareLights(void)
 
        if (r_editlights.integer)
                R_Shadow_DrawLightSprites();
-
-       R_Shadow_UpdateBounceGridTexture();
 }
 
 void R_Shadow_DrawLights(void)
@@ -4719,23 +4662,26 @@ void R_Shadow_DrawLights(void)
 
        R_Shadow_RenderMode_Begin();
 
-       flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
-       if (r_shadow_debuglight.integer >= 0)
+       if (r_shadow_bouncegrid.integer != 2)
        {
-               lightindex = r_shadow_debuglight.integer;
-               light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
-               if (light && (light->flags & flag))
-                       R_Shadow_DrawLight(&light->rtlight);
-       }
-       else
-       {
-               range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
-               for (lightindex = 0;lightindex < range;lightindex++)
+               flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
+               if (r_shadow_debuglight.integer >= 0)
                {
+                       lightindex = r_shadow_debuglight.integer;
                        light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
-                       if (light && (light->flags & flag))
+                       if (light)
                                R_Shadow_DrawLight(&light->rtlight);
                }
+               else
+               {
+                       range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
+                       for (lightindex = 0;lightindex < range;lightindex++)
+                       {
+                               light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+                               if (light && (light->flags & flag))
+                                       R_Shadow_DrawLight(&light->rtlight);
+                       }
+               }
        }
        if (r_refdef.scene.rtdlight)
                for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
@@ -4912,7 +4858,7 @@ 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();
+       R_SetupShader_DepthOrShadow(true);
        GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
        GL_DepthMask(true);
        GL_DepthTest(true);
@@ -4933,7 +4879,7 @@ void R_DrawModelShadowMaps(void)
 #if 0
        // debugging
        R_Mesh_SetMainRenderTargets();
-       R_SetupShader_ShowDepth();
+       R_SetupShader_ShowDepth(true);
        GL_ColorMask(1,1,1,1);
        GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
 #endif
@@ -5134,7 +5080,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);
+       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, true);
        R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
 
        // restore the viewport
@@ -5169,6 +5115,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);
@@ -5184,6 +5131,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__);
@@ -5218,10 +5166,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__);
@@ -5256,61 +5206,13 @@ void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
                if(negated)
                {
                        VectorNegate(color, color);
-                       switch(vid.renderpath)
-                       {
-                       case RENDERPATH_GL11:
-                       case RENDERPATH_GL13:
-                       case RENDERPATH_GL20:
-                       case RENDERPATH_GLES1:
-                       case RENDERPATH_GLES2:
-                               qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
-                               break;
-                       case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
-                               IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
-#endif
-                               break;
-                       case RENDERPATH_D3D10:
-                               Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-                               break;
-                       case RENDERPATH_D3D11:
-                               Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-                               break;
-                       case RENDERPATH_SOFT:
-                               DPSOFTRAST_BlendSubtract(true);
-                               break;
-                       }
+                       GL_BlendEquationSubtract(true);
                }
                R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
                RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, RENDER_NODEPTHTEST, 0, color[0], color[1], color[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
                R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
                if(negated)
-               {
-                       switch(vid.renderpath)
-                       {
-                       case RENDERPATH_GL11:
-                       case RENDERPATH_GL13:
-                       case RENDERPATH_GL20:
-                       case RENDERPATH_GLES1:
-                       case RENDERPATH_GLES2:
-                               qglBlendEquationEXT(GL_FUNC_ADD_EXT);
-                               break;
-                       case RENDERPATH_D3D9:
-#ifdef SUPPORTD3D
-                               IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
-#endif
-                               break;
-                       case RENDERPATH_D3D10:
-                               Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-                               break;
-                       case RENDERPATH_D3D11:
-                               Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-                               break;
-                       case RENDERPATH_SOFT:
-                               DPSOFTRAST_BlendSubtract(false);
-                               break;
-                       }
-               }
+                       GL_BlendEquationSubtract(false);
        }
 }
 
@@ -5343,6 +5245,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);
@@ -5364,8 +5267,9 @@ void R_Shadow_DrawCoronas(void)
                        GL_PolygonOffset(0, 0);
                        GL_DepthTest(true);
                        R_Mesh_ResetTextureState();
-                       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
+                       R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false, false);
                }
+#endif
                break;
        case RENDERPATH_D3D9:
                usequery = false;
@@ -6936,6 +6840,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)
diff --git a/r_sky.c b/r_sky.c
index eabb9968278fbebf4c20480ef9a943dda86a6d2d..0f019bbb25b5ab2dfd26d40148b44daf84768eb7 100644 (file)
--- a/r_sky.c
+++ b/r_sky.c
@@ -122,7 +122,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, r_texture_sRGB_skybox.integer != 0);
+                       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);
                        Mem_Free(image_buffer);
                        Mem_Free(temp);
                        success++;
index 4265c5eb56293d24a71665a39d14fda54c92da19..8c59f72ff5c276bd3a202ca776b04919c316735d 100644 (file)
@@ -143,6 +143,8 @@ extern cvar_t gl_texturecompression_q3bspdeluxemaps;
 extern cvar_t gl_texturecompression_sky;
 extern cvar_t gl_texturecompression_lightcubemaps;
 extern cvar_t gl_texturecompression_reflectmask;
+extern cvar_t r_texture_dds_load;
+extern cvar_t r_texture_dds_save;
 
 // add a texture to a pool and optionally precache (upload) it
 // (note: data == NULL is perfectly acceptable)
index c979dd9dce9cf1cb523fa0a1df809cbb8f80ee9a..79b1198bbf74dd88769bd1bf12cbd4cd39db4662 100644 (file)
--- a/render.h
+++ b/render.h
@@ -54,6 +54,8 @@ extern cvar_t gl_flashblend;
 // vis stuff
 extern cvar_t r_novis;
 
+extern cvar_t r_trippy;
+
 extern cvar_t r_lerpsprites;
 extern cvar_t r_lerpmodels;
 extern cvar_t r_lerplightstyles;
@@ -200,14 +202,6 @@ extern cvar_t r_smoothnormals_areaweighting;
 
 extern cvar_t r_test;
 
-extern cvar_t r_texture_sRGB_2d;
-extern cvar_t r_texture_sRGB_skin_diffuse;
-extern cvar_t r_texture_sRGB_skin_gloss;
-extern cvar_t r_texture_sRGB_skin_glow;
-extern cvar_t r_texture_sRGB_skin_reflect;
-extern cvar_t r_texture_sRGB_cubemap;
-extern cvar_t r_texture_sRGB_skybox;
-
 #include "gl_backend.h"
 
 extern rtexture_t *r_texture_blanknormalmap;
@@ -335,8 +329,8 @@ typedef struct rsurfacestate_s
        int ent_skinnum;
        int ent_qwskin;
        int ent_flags;
-       float ent_shadertime;
        int ent_alttextures; // used by q1bsp animated textures (pressed buttons)
+       double shadertime; // r_refdef.scene.time - ent->shadertime
        // transform matrices to render this entity and effects on this entity
        matrix4x4_t matrix;
        matrix4x4_t inversematrix;
@@ -447,10 +441,10 @@ typedef enum rsurfacepass_e
 }
 rsurfacepass_t;
 
-void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale);
-void R_SetupShader_DepthOrShadow(void);
-void R_SetupShader_ShowDepth(void);
-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);
+void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale, qboolean usegamma, qboolean notrippy);
+void R_SetupShader_DepthOrShadow(qboolean notrippy);
+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
diff --git a/sbar.c b/sbar.c
index 28d7f604e48b936b2f33eb290e31c78580eeb3a8..80c6330fa3019202a7d89d9fa23b0dcb2a449ebc 100644 (file)
--- a/sbar.c
+++ b/sbar.c
@@ -812,7 +812,7 @@ void Sbar_DrawInventory (void)
                        else
                                flashon = (flashon%5) + 2;
 
-                       Sbar_DrawAlphaPic (i*24, -16, sb_weapons[flashon][i], sbar_alpha_bg.value);
+                       Sbar_DrawPic (i*24, -16, sb_weapons[flashon][i]);
                }
        }
 
index a345d3bea630a7549fcf6f6d881b9f2d274681e5..ed552a1422b187dfa6b1bd7c1187422beff85d83 100644 (file)
--- a/server.h
+++ b/server.h
@@ -317,6 +317,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 +331,7 @@ 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)
 
 // edict->deadflag values
 #define        DEAD_NO                                 0
@@ -431,13 +433,14 @@ extern cvar_t sv_gameplayfix_droptofloorstartsolid_nudgetocorrect;
 extern cvar_t sv_gameplayfix_easierwaterjump;
 extern cvar_t sv_gameplayfix_findradiusdistancetobox;
 extern cvar_t sv_gameplayfix_gravityunaffectedbyticrate;
-extern cvar_t sv_gameplayfix_nogravityonground;
 extern cvar_t sv_gameplayfix_grenadebouncedownslopes;
 extern cvar_t sv_gameplayfix_multiplethinksperframe;
 extern cvar_t sv_gameplayfix_noairborncorpse;
 extern cvar_t sv_gameplayfix_noairborncorpse_allowsuspendeditems;
 extern cvar_t sv_gameplayfix_nudgeoutofsolid;
-extern cvar_t sv_gameplayfix_nudgeoutofsolid_bias;
+extern cvar_t sv_gameplayfix_nudgeoutofsolid_separation;
+extern cvar_t sv_gameplayfix_q2airaccelerate;
+extern cvar_t sv_gameplayfix_nogravityonground;
 extern cvar_t sv_gameplayfix_setmodelrealbox;
 extern cvar_t sv_gameplayfix_slidemoveprojectiles;
 extern cvar_t sv_gameplayfix_stepdown;
@@ -447,6 +450,7 @@ extern cvar_t sv_gameplayfix_nostepmoveonsteepslopes;
 extern cvar_t sv_gameplayfix_swiminbmodels;
 extern cvar_t sv_gameplayfix_upwardvelocityclearsongroundflag;
 extern cvar_t sv_gameplayfix_downtracesupportsongroundflag;
+extern cvar_t sv_gameplayfix_q1bsptracelinereportstexture;
 extern cvar_t sv_gravity;
 extern cvar_t sv_idealpitchscale;
 extern cvar_t sv_jumpstep;
@@ -488,7 +492,7 @@ 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);
+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_ConnectClient (int clientnum, netconn_t *netconnection);
index e924413d44604052812c7ffe4b3fc1a55fbcbdb7..5a00e7a7acd2c791a5ac30e923696f9a2d2603e6 100644 (file)
@@ -57,7 +57,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"
 "uniform highp mat4 ModelViewProjectionMatrix;\n"
 "#endif\n"
 "\n"
+"#ifdef VERTEX_SHADER\n"
+"#ifdef USETRIPPY\n"
+"// LordHavoc: based on shader code linked at: http://www.youtube.com/watch?v=JpksyojwqzE\n"
+"// tweaked scale\n"
+"uniform highp float ClientTime;\n"
+"vec4 TrippyVertex(vec4 position)\n"
+"{\n"
+"      float worldTime = ClientTime;\n"
+"      // tweaked for Quake\n"
+"      worldTime *= 10.0;\n"
+"      position *= 0.125;\n"
+"      //~tweaked for Quake\n"
+"      float distanceSquared = (position.x * position.x + position.z * position.z);\n"
+"      position.y += 5.0*sin(distanceSquared*sin(worldTime/143.0)/1000.0);\n"
+"      float y = position.y;\n"
+"      float x = position.x;\n"
+"      float om = sin(distanceSquared*sin(worldTime/256.0)/5000.0) * sin(worldTime/200.0);\n"
+"      position.y = x*sin(om)+y*cos(om);\n"
+"      position.x = x*cos(om)-y*sin(om);\n"
+"      return position;\n"
+"}\n"
+"#endif\n"
+"#endif\n"
+"\n"
 "#ifdef MODE_DEPTH_OR_SHADOW\n"
 "#ifdef VERTEX_SHADER\n"
 "void main(void)\n"
 "{\n"
 "      gl_Position = ModelViewProjectionMatrix * Attrib_Position;\n"
+"#ifdef USETRIPPY\n"
+"      gl_Position = TrippyVertex(gl_Position);\n"
+"#endif\n"
+"}\n"
+"#endif\n"
+"\n"
+"#ifdef FRAGMENT_SHADER\n"
+"void main(void)\n"
+"{\n"
+"      dp_FragColor = vec4(1.0,1.0,1.0,1.0);\n"
 "}\n"
 "#endif\n"
 "#else // !MODE_DEPTH_ORSHADOW\n"
 "{\n"
 "      gl_Position = ModelViewProjectionMatrix * Attrib_Position;\n"
 "      VertexColor = vec4(gl_Position.z, gl_Position.z, gl_Position.z, 1.0);\n"
+"#ifdef USETRIPPY\n"
+"      gl_Position = TrippyVertex(gl_Position);\n"
+"#endif\n"
 "}\n"
 "#endif\n"
 "\n"
 "      TexCoord2 = Attrib_TexCoord1.xy;\n"
 "#endif\n"
 "      gl_Position = ModelViewProjectionMatrix * Attrib_Position;\n"
+"#ifdef USETRIPPY\n"
+"      gl_Position = TrippyVertex(gl_Position);\n"
+"#endif\n"
 "}\n"
 "#endif\n"
 "\n"
 "#ifdef 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 = 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"
 "      TexCoord = vec2(TexMatrix * Attrib_TexCoord0);\n"
 "      gl_Position = ModelViewProjectionMatrix * Attrib_Position;\n"
 "      ModelViewProjectionPosition = gl_Position;\n"
+"#ifdef USETRIPPY\n"
+"      gl_Position = TrippyVertex(gl_Position);\n"
+"#endif\n"
 "}\n"
 "#endif\n"
 "\n"
 "      #ifdef 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"
 "      EyeVector.z = dot(EyeRelative, Attrib_TexCoord3.xyz);\n"
 "      gl_Position = ModelViewProjectionMatrix * Attrib_Position;\n"
 "      ModelViewProjectionPosition = gl_Position;\n"
+"#ifdef USETRIPPY\n"
+"      gl_Position = TrippyVertex(gl_Position);\n"
+"#endif\n"
 "}\n"
 "#endif\n"
 "\n"
 "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"
 "      VectorT = (ModelViewMatrix * vec4(Attrib_TexCoord2.xyz, 0));\n"
 "      VectorR = (ModelViewMatrix * vec4(Attrib_TexCoord3.xyz, 0));\n"
 "      gl_Position = ModelViewProjectionMatrix * Attrib_Position;\n"
+"#ifdef USETRIPPY\n"
+"      gl_Position = TrippyVertex(gl_Position);\n"
+"#endif\n"
 "}\n"
 "#endif // VERTEX_SHADER\n"
 "\n"
 "      position.xy = ModelViewPosition.xy * (position.z / ModelViewPosition.z);\n"
 "      // decode viewspace pixel normal\n"
 "      myhalf4 normalmap = dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord);\n"
-"      myhalf3 surfacenormal = normalize(normalmap.rgb - myhalf3(0.5,0.5,0.5));\n"
+"      myhalf3 surfacenormal = normalize(normalmap.rgb - cast_myhalf3(0.5,0.5,0.5));\n"
 "      // surfacenormal = pixel normal in viewspace\n"
 "      // LightVector = pixel to light in viewspace\n"
 "      // CubeVector = position in lightspace\n"
 "      // eyevector = pixel to view in viewspace\n"
 "      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)), 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)), SpecularPower * normalmap.a);\n"
 "#  endif\n"
 "#endif\n"
 "\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"
 "#ifdef USEREFLECTION\n"
 "      ModelViewProjectionPosition = gl_Position;\n"
 "#endif\n"
+"#ifdef USETRIPPY\n"
+"      gl_Position = TrippyVertex(gl_Position);\n"
+"#endif\n"
 "}\n"
 "#endif // VERTEX_SHADER\n"
 "\n"
 "#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)), 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)), 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)), 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)), 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"
 "#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 5e271ce942029f8cc21066878cce4ae298ef54dd..1296711385ed4c8770000b70bfa2f8e9475d46e9 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"
 "#endif\n"
 "#endif\n"
 "\n"
+"#ifdef VERTEX_SHADER\n"
+"#ifdef USETRIPPY\n"
+"// LordHavoc: based on shader code linked at: http://www.youtube.com/watch?v=JpksyojwqzE\n"
+"// tweaked scale\n"
+"float4 TrippyVertex(float4 position)\n"
+"(\n"
+"uniform float ClientTime : register(c2)\n"
+")\n"
+"{\n"
+"      float worldTime = ClientTime;\n"
+"      // tweaked for Quake\n"
+"      worldTime *= 10.0;\n"
+"      position *= 0.125;\n"
+"      //~tweaked for Quake\n"
+"      float distanceSquared = (position.x * position.x + position.z * position.z);\n"
+"      position.y += 5.0*sin(distanceSquared*sin(worldTime/143.0)/1000.0);\n"
+"      float y = position.y;\n"
+"      float x = position.x;\n"
+"      float om = sin(distanceSquared*sin(worldTime/256.0)/5000.0) * sin(worldTime/200.0);\n"
+"      position.y = x*sin(om)+y*cos(om);\n"
+"      position.x = x*cos(om)-y*sin(om);\n"
+"      return position;\n"
+"}\n"
+"#endif\n"
+"#endif\n"
+"\n"
 "#ifdef MODE_DEPTH_OR_SHADOW\n"
 "#ifdef VERTEX_SHADER\n"
 "void main\n"
@@ -38,6 +64,9 @@
 ")\n"
 "{\n"
 "      gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n"
+"#ifdef USETRIPPY\n"
+"      gl_Position = TrippyVertex(gl_Position);\n"
+"#endif\n"
 "      Depth = gl_Position.z;\n"
 "}\n"
 "#endif\n"
 ")\n"
 "{\n"
 "      gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n"
+"#ifdef USETRIPPY\n"
+"      gl_Position = TrippyVertex(gl_Position);\n"
+"#endif\n"
 "      gl_FrontColor = float4(gl_Position.z, gl_Position.z, gl_Position.z, 1.0);\n"
 "}\n"
 "#endif\n"
 "      TexCoord2 = gl_MultiTexCoord1.xy;\n"
 "#endif\n"
 "      gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n"
+"#ifdef USETRIPPY\n"
+"      gl_Position = TrippyVertex(gl_Position);\n"
+"#endif\n"
 "}\n"
 "#endif\n"
 "\n"
 "#ifdef USESPECULAR\n"
 "uniform sampler Texture_Second : register(s1),\n"
 "#endif\n"
+"#ifdef USEGAMMARAMPS\n"
+"uniform sampler Texture_GammaRamps : register(s2),\n"
+"#endif\n"
 "out float4 gl_FragColor : COLOR\n"
 ")\n"
 "{\n"
 "      gl_FragColor = lerp(gl_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"
 "      TexCoord = mul(TexMatrix, gl_MultiTexCoord0).xy;\n"
 "      gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n"
 "      ModelViewProjectionPosition = gl_Position;\n"
+"#ifdef USETRIPPY\n"
+"      gl_Position = TrippyVertex(gl_Position);\n"
+"#endif\n"
 "}\n"
 "#endif\n"
 "\n"
 "      EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
 "      gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n"
 "      ModelViewProjectionPosition = gl_Position;\n"
+"#ifdef USETRIPPY\n"
+"      gl_Position = TrippyVertex(gl_Position);\n"
+"#endif\n"
 "}\n"
 "#endif\n"
 "\n"
 "      VectorT = mul(ModelViewMatrix, float4(gl_MultiTexCoord2.xyz, 0)).xyz;\n"
 "      VectorR.xyz = mul(ModelViewMatrix, float4(gl_MultiTexCoord3.xyz, 0)).xyz;\n"
 "      gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n"
+"#ifdef USETRIPPY\n"
+"      gl_Position = TrippyVertex(gl_Position);\n"
+"#endif\n"
 "      VectorR.w = gl_Position.z;\n"
 "}\n"
 "#endif // VERTEX_SHADER\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"
 "#ifdef USEREFLECTION\n"
 "      ModelViewProjectionPosition = gl_Position;\n"
 "#endif\n"
+"#ifdef USETRIPPY\n"
+"      gl_Position = TrippyVertex(gl_Position);\n"
+"#endif\n"
 "}\n"
 "#endif // VERTEX_SHADER\n"
 "\n"
 "\n"
 "\n"
 "#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"
 "      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"
index fac45a4f6a23a4ce08e2aa8cdc8a0a5eea600bba..8376007a3a23128409bdd69875cbb8c7759c71ce 100644 (file)
@@ -182,38 +182,46 @@ cvar_t snd_swapstereo = {CVAR_SAVE, "snd_swapstereo", "0", "swaps left/right spe
 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_entchannel0volume = {CVAR_SAVE, "snd_entchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of regular entities"};
-cvar_t snd_entchannel1volume = {CVAR_SAVE, "snd_entchannel1volume", "1", "volume multiplier of the 1st entity channel of regular entities"};
-cvar_t snd_entchannel2volume = {CVAR_SAVE, "snd_entchannel2volume", "1", "volume multiplier of the 2nd entity channel of regular entities"};
-cvar_t snd_entchannel3volume = {CVAR_SAVE, "snd_entchannel3volume", "1", "volume multiplier of the 3rd entity channel of regular entities"};
-cvar_t snd_entchannel4volume = {CVAR_SAVE, "snd_entchannel4volume", "1", "volume multiplier of the 4th entity channel of regular entities"};
-cvar_t snd_entchannel5volume = {CVAR_SAVE, "snd_entchannel5volume", "1", "volume multiplier of the 5th entity channel of regular entities"};
-cvar_t snd_entchannel6volume = {CVAR_SAVE, "snd_entchannel6volume", "1", "volume multiplier of the 6th entity channel of regular entities"};
-cvar_t snd_entchannel7volume = {CVAR_SAVE, "snd_entchannel7volume", "1", "volume multiplier of the 7th entity channel of regular entities"};
-cvar_t snd_playerchannel0volume = {CVAR_SAVE, "snd_playerchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of player entities"};
-cvar_t snd_playerchannel1volume = {CVAR_SAVE, "snd_playerchannel1volume", "1", "volume multiplier of the 1st entity channel of player entities"};
-cvar_t snd_playerchannel2volume = {CVAR_SAVE, "snd_playerchannel2volume", "1", "volume multiplier of the 2nd entity channel of player entities"};
-cvar_t snd_playerchannel3volume = {CVAR_SAVE, "snd_playerchannel3volume", "1", "volume multiplier of the 3rd entity channel of player entities"};
-cvar_t snd_playerchannel4volume = {CVAR_SAVE, "snd_playerchannel4volume", "1", "volume multiplier of the 4th entity channel of player entities"};
-cvar_t snd_playerchannel5volume = {CVAR_SAVE, "snd_playerchannel5volume", "1", "volume multiplier of the 5th entity channel of player entities"};
-cvar_t snd_playerchannel6volume = {CVAR_SAVE, "snd_playerchannel6volume", "1", "volume multiplier of the 6th entity channel of player entities"};
-cvar_t snd_playerchannel7volume = {CVAR_SAVE, "snd_playerchannel7volume", "1", "volume multiplier of the 7th entity channel of player entities"};
-cvar_t snd_worldchannel0volume = {CVAR_SAVE, "snd_worldchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of the world entity"};
-cvar_t snd_worldchannel1volume = {CVAR_SAVE, "snd_worldchannel1volume", "1", "volume multiplier of the 1st entity channel of the world entity"};
-cvar_t snd_worldchannel2volume = {CVAR_SAVE, "snd_worldchannel2volume", "1", "volume multiplier of the 2nd entity channel of the world entity"};
-cvar_t snd_worldchannel3volume = {CVAR_SAVE, "snd_worldchannel3volume", "1", "volume multiplier of the 3rd entity channel of the world entity"};
-cvar_t snd_worldchannel4volume = {CVAR_SAVE, "snd_worldchannel4volume", "1", "volume multiplier of the 4th entity channel of the world entity"};
-cvar_t snd_worldchannel5volume = {CVAR_SAVE, "snd_worldchannel5volume", "1", "volume multiplier of the 5th entity channel of the world entity"};
-cvar_t snd_worldchannel6volume = {CVAR_SAVE, "snd_worldchannel6volume", "1", "volume multiplier of the 6th entity channel of the world entity"};
-cvar_t snd_worldchannel7volume = {CVAR_SAVE, "snd_worldchannel7volume", "1", "volume multiplier of the 7th entity channel of the world entity"};
-cvar_t snd_csqcchannel0volume = {CVAR_SAVE, "snd_csqcchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of the world entity"};
-cvar_t snd_csqcchannel1volume = {CVAR_SAVE, "snd_csqcchannel1volume", "1", "volume multiplier of the 1st entity channel of the world entity"};
-cvar_t snd_csqcchannel2volume = {CVAR_SAVE, "snd_csqcchannel2volume", "1", "volume multiplier of the 2nd entity channel of the world entity"};
-cvar_t snd_csqcchannel3volume = {CVAR_SAVE, "snd_csqcchannel3volume", "1", "volume multiplier of the 3rd entity channel of the world entity"};
-cvar_t snd_csqcchannel4volume = {CVAR_SAVE, "snd_csqcchannel4volume", "1", "volume multiplier of the 4th entity channel of the world entity"};
-cvar_t snd_csqcchannel5volume = {CVAR_SAVE, "snd_csqcchannel5volume", "1", "volume multiplier of the 5th entity channel of the world entity"};
-cvar_t snd_csqcchannel6volume = {CVAR_SAVE, "snd_csqcchannel6volume", "1", "volume multiplier of the 6th entity channel of the world entity"};
-cvar_t snd_csqcchannel7volume = {CVAR_SAVE, "snd_csqcchannel7volume", "1", "volume multiplier of the 7th entity channel of the world entity"};
+cvar_t snd_entchannel0volume = {CVAR_SAVE, "snd_entchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of regular entities (DEPRECATED)"};
+cvar_t snd_entchannel1volume = {CVAR_SAVE, "snd_entchannel1volume", "1", "volume multiplier of the 1st entity channel of regular entities (DEPRECATED)"};
+cvar_t snd_entchannel2volume = {CVAR_SAVE, "snd_entchannel2volume", "1", "volume multiplier of the 2nd entity channel of regular entities (DEPRECATED)"};
+cvar_t snd_entchannel3volume = {CVAR_SAVE, "snd_entchannel3volume", "1", "volume multiplier of the 3rd entity channel of regular entities (DEPRECATED)"};
+cvar_t snd_entchannel4volume = {CVAR_SAVE, "snd_entchannel4volume", "1", "volume multiplier of the 4th entity channel of regular entities (DEPRECATED)"};
+cvar_t snd_entchannel5volume = {CVAR_SAVE, "snd_entchannel5volume", "1", "volume multiplier of the 5th entity channel of regular entities (DEPRECATED)"};
+cvar_t snd_entchannel6volume = {CVAR_SAVE, "snd_entchannel6volume", "1", "volume multiplier of the 6th entity channel of regular entities (DEPRECATED)"};
+cvar_t snd_entchannel7volume = {CVAR_SAVE, "snd_entchannel7volume", "1", "volume multiplier of the 7th entity channel of regular entities (DEPRECATED)"};
+cvar_t snd_playerchannel0volume = {CVAR_SAVE, "snd_playerchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of player entities (DEPRECATED)"};
+cvar_t snd_playerchannel1volume = {CVAR_SAVE, "snd_playerchannel1volume", "1", "volume multiplier of the 1st entity channel of player entities (DEPRECATED)"};
+cvar_t snd_playerchannel2volume = {CVAR_SAVE, "snd_playerchannel2volume", "1", "volume multiplier of the 2nd entity channel of player entities (DEPRECATED)"};
+cvar_t snd_playerchannel3volume = {CVAR_SAVE, "snd_playerchannel3volume", "1", "volume multiplier of the 3rd entity channel of player entities (DEPRECATED)"};
+cvar_t snd_playerchannel4volume = {CVAR_SAVE, "snd_playerchannel4volume", "1", "volume multiplier of the 4th entity channel of player entities (DEPRECATED)"};
+cvar_t snd_playerchannel5volume = {CVAR_SAVE, "snd_playerchannel5volume", "1", "volume multiplier of the 5th entity channel of player entities (DEPRECATED)"};
+cvar_t snd_playerchannel6volume = {CVAR_SAVE, "snd_playerchannel6volume", "1", "volume multiplier of the 6th entity channel of player entities (DEPRECATED)"};
+cvar_t snd_playerchannel7volume = {CVAR_SAVE, "snd_playerchannel7volume", "1", "volume multiplier of the 7th entity channel of player entities (DEPRECATED)"};
+cvar_t snd_worldchannel0volume = {CVAR_SAVE, "snd_worldchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of the world entity (DEPRECATED)"};
+cvar_t snd_worldchannel1volume = {CVAR_SAVE, "snd_worldchannel1volume", "1", "volume multiplier of the 1st entity channel of the world entity (DEPRECATED)"};
+cvar_t snd_worldchannel2volume = {CVAR_SAVE, "snd_worldchannel2volume", "1", "volume multiplier of the 2nd entity channel of the world entity (DEPRECATED)"};
+cvar_t snd_worldchannel3volume = {CVAR_SAVE, "snd_worldchannel3volume", "1", "volume multiplier of the 3rd entity channel of the world entity (DEPRECATED)"};
+cvar_t snd_worldchannel4volume = {CVAR_SAVE, "snd_worldchannel4volume", "1", "volume multiplier of the 4th entity channel of the world entity (DEPRECATED)"};
+cvar_t snd_worldchannel5volume = {CVAR_SAVE, "snd_worldchannel5volume", "1", "volume multiplier of the 5th entity channel of the world entity (DEPRECATED)"};
+cvar_t snd_worldchannel6volume = {CVAR_SAVE, "snd_worldchannel6volume", "1", "volume multiplier of the 6th entity channel of the world entity (DEPRECATED)"};
+cvar_t snd_worldchannel7volume = {CVAR_SAVE, "snd_worldchannel7volume", "1", "volume multiplier of the 7th entity channel of the world entity (DEPRECATED)"};
+cvar_t snd_csqcchannel0volume = {CVAR_SAVE, "snd_csqcchannel0volume", "1", "volume multiplier of the auto-allocate entity channel CSQC entities (DEPRECATED)"};
+cvar_t snd_csqcchannel1volume = {CVAR_SAVE, "snd_csqcchannel1volume", "1", "volume multiplier of the 1st entity channel of CSQC entities (DEPRECATED)"};
+cvar_t snd_csqcchannel2volume = {CVAR_SAVE, "snd_csqcchannel2volume", "1", "volume multiplier of the 2nd entity channel of CSQC entities (DEPRECATED)"};
+cvar_t snd_csqcchannel3volume = {CVAR_SAVE, "snd_csqcchannel3volume", "1", "volume multiplier of the 3rd entity channel of CSQC entities (DEPRECATED)"};
+cvar_t snd_csqcchannel4volume = {CVAR_SAVE, "snd_csqcchannel4volume", "1", "volume multiplier of the 4th entity channel of CSQC entities (DEPRECATED)"};
+cvar_t snd_csqcchannel5volume = {CVAR_SAVE, "snd_csqcchannel5volume", "1", "volume multiplier of the 5th entity channel of CSQC entities (DEPRECATED)"};
+cvar_t snd_csqcchannel6volume = {CVAR_SAVE, "snd_csqcchannel6volume", "1", "volume multiplier of the 6th entity channel of CSQC entities (DEPRECATED)"};
+cvar_t snd_csqcchannel7volume = {CVAR_SAVE, "snd_csqcchannel7volume", "1", "volume multiplier of the 7th entity channel of CSQC entities (DEPRECATED)"};
+cvar_t snd_channel0volume = {CVAR_SAVE, "snd_channel0volume", "1", "volume multiplier of the auto-allocate entity channel"};
+cvar_t snd_channel1volume = {CVAR_SAVE, "snd_channel1volume", "1", "volume multiplier of the 1st entity channel"};
+cvar_t snd_channel2volume = {CVAR_SAVE, "snd_channel2volume", "1", "volume multiplier of the 2nd entity channel"};
+cvar_t snd_channel3volume = {CVAR_SAVE, "snd_channel3volume", "1", "volume multiplier of the 3rd entity channel"};
+cvar_t snd_channel4volume = {CVAR_SAVE, "snd_channel4volume", "1", "volume multiplier of the 4th entity channel"};
+cvar_t snd_channel5volume = {CVAR_SAVE, "snd_channel5volume", "1", "volume multiplier of the 5th entity channel"};
+cvar_t snd_channel6volume = {CVAR_SAVE, "snd_channel6volume", "1", "volume multiplier of the 6th entity channel"};
+cvar_t snd_channel7volume = {CVAR_SAVE, "snd_channel7volume", "1", "volume multiplier of the 7th entity channel"};
 
 // Local cvars
 static cvar_t nosound = {0, "nosound", "0", "disables sound"};
@@ -229,6 +237,9 @@ static cvar_t snd_speed = {CVAR_SAVE, "snd_speed", "48000", "sound output freque
 static cvar_t snd_width = {CVAR_SAVE, "snd_width", "2", "sound output precision, in bytes (1 and 2 supported)"};
 static cvar_t snd_channels = {CVAR_SAVE, "snd_channels", "2", "number of channels for the sound output (2 for stereo; up to 8 supported for 3D sound)"};
 
+static cvar_t snd_startloopingsounds = {0, "snd_startloopingsounds", "1", "whether to start sounds that would loop (you want this to be 1); existing sounds are not affected"};
+static cvar_t snd_startnonloopingsounds = {0, "snd_startnonloopingsounds", "1", "whether to start sounds that would not loop (you want this to be 1); existing sounds are not affected"};
+
 // Ambient sounds
 static sfx_t* ambient_sfxs [2] = { NULL, NULL };
 static const char* ambient_names [2] = { "sound/ambience/water1.wav", "sound/ambience/wind2.wav" };
@@ -307,11 +318,10 @@ static void S_SoundList_f (void)
 
                        size = sfx->memsize;
                        format = sfx->fetcher->getfmt(sfx);
-                       Con_Printf ("%c%c%c%c(%2db, %6s) %8i : %s\n",
+                       Con_Printf ("%c%c%c(%2db, %6s) %8i : %s\n",
                                                (sfx->loopstart < sfx->total_length) ? 'L' : ' ',
                                                (sfx->flags & SFXFLAG_STREAMED) ? 'S' : ' ',
-                                               (sfx->locks > 0) ? 'K' : ' ',
-                                               (sfx->flags & SFXFLAG_PERMANENTLOCK) ? 'P' : ' ',
+                                               (sfx->flags & SFXFLAG_MENUSOUND) ? 'P' : ' ',
                                                format->width * 8,
                                                (format->channels == 1) ? "mono" : "stereo",
                                                size,
@@ -811,6 +821,14 @@ void S_Init(void)
        Cvar_RegisterVariable(&snd_csqcchannel5volume);
        Cvar_RegisterVariable(&snd_csqcchannel6volume);
        Cvar_RegisterVariable(&snd_csqcchannel7volume);
+       Cvar_RegisterVariable(&snd_channel0volume);
+       Cvar_RegisterVariable(&snd_channel1volume);
+       Cvar_RegisterVariable(&snd_channel2volume);
+       Cvar_RegisterVariable(&snd_channel3volume);
+       Cvar_RegisterVariable(&snd_channel4volume);
+       Cvar_RegisterVariable(&snd_channel5volume);
+       Cvar_RegisterVariable(&snd_channel6volume);
+       Cvar_RegisterVariable(&snd_channel7volume);
 
        Cvar_RegisterVariable(&snd_spatialization_min_radius);
        Cvar_RegisterVariable(&snd_spatialization_max_radius);
@@ -827,6 +845,9 @@ void S_Init(void)
        Cvar_RegisterVariable(&snd_channels);
        Cvar_RegisterVariable(&snd_mutewhenidle);
 
+       Cvar_RegisterVariable(&snd_startloopingsounds);
+       Cvar_RegisterVariable(&snd_startnonloopingsounds);
+
 // COMMANDLINEOPTION: Sound: -nosound disables sound (including CD audio)
        if (COM_CheckParm("-nosound"))
        {
@@ -956,6 +977,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));
@@ -977,8 +1007,8 @@ void S_FreeSfx (sfx_t *sfx, qboolean force)
 {
        unsigned int i;
 
-       // Never free a locked sfx unless forced
-       if (!force && (sfx->locks > 0 || (sfx->flags & SFXFLAG_PERMANENTLOCK)))
+       // Do not free a precached sound during purge
+       if (!force && (sfx->flags & (SFXFLAG_LEVELSOUND | SFXFLAG_MENUSOUND)))
                return;
 
        if (developer_loading.integer)
@@ -1006,8 +1036,13 @@ void S_FreeSfx (sfx_t *sfx, qboolean force)
 
        // Stop all channels using this sfx
        for (i = 0; i < total_channels; i++)
+       {
                if (channels[i].sfx == sfx)
-                       S_StopChannel (i, true);
+               {
+                       Con_Printf("S_FreeSfx: stopping channel %i for sfx \"%s\"\n", i, sfx->name);
+                       S_StopChannel (i, true, false);
+               }
+       }
 
        // Free it
        if (sfx->fetcher != NULL && sfx->fetcher->free != NULL)
@@ -1030,28 +1065,21 @@ void S_ClearUsed (void)
        // Start the ambient sounds and make them loop
        for (i = 0; i < sizeof (ambient_sfxs) / sizeof (ambient_sfxs[0]); i++)
        {
-               // Precache it if it's not done (request a lock to make sure it will never be freed)
+               // Precache it if it's not done (and pass false for levelsound because these are permanent)
                if (ambient_sfxs[i] == NULL)
-                       ambient_sfxs[i] = S_PrecacheSound (ambient_names[i], false, true);
+                       ambient_sfxs[i] = S_PrecacheSound (ambient_names[i], false, false);
                if (ambient_sfxs[i] != NULL)
                {
-                       // Add a lock to the SFX while playing. It will be
-                       // removed by S_StopAllSounds at the end of the level
-                       S_LockSfx (ambient_sfxs[i]);
-
                        channels[i].sfx = ambient_sfxs[i];
+                       channels[i].sfx->flags |= SFXFLAG_MENUSOUND;
                        channels[i].flags |= CHANNELFLAG_FORCELOOP;
                        channels[i].master_vol = 0;
                }
        }
 
-       // Remove 1 lock from all sfx with the SFXFLAG_SERVERSOUND flag, and remove the flag
+       // Clear SFXFLAG_LEVELSOUND flag so that sounds not precached this level will be purged
        for (sfx = known_sfx; sfx != NULL; sfx = sfx->next)
-               if (sfx->flags & SFXFLAG_SERVERSOUND)
-               {
-                       S_UnlockSfx (sfx);
-                       sfx->flags &= ~SFXFLAG_SERVERSOUND;
-               }
+               sfx->flags &= ~SFXFLAG_LEVELSOUND;
 }
 
 /*
@@ -1064,11 +1092,12 @@ void S_PurgeUnused(void)
        sfx_t *sfx;
        sfx_t *sfxnext;
 
-       // Free all unlocked sfx
+       // Free all not-precached per-level sfx
        for (sfx = known_sfx;sfx;sfx = sfxnext)
        {
                sfxnext = sfx->next;
-               S_FreeSfx (sfx, false);
+               if (!(sfx->flags & (SFXFLAG_LEVELSOUND | SFXFLAG_MENUSOUND)))
+                       S_FreeSfx (sfx, false);
        }
 }
 
@@ -1078,7 +1107,7 @@ void S_PurgeUnused(void)
 S_PrecacheSound
 ==================
 */
-sfx_t *S_PrecacheSound (const char *name, qboolean complain, qboolean serversound)
+sfx_t *S_PrecacheSound (const char *name, qboolean complain, qboolean levelsound)
 {
        sfx_t *sfx;
 
@@ -1097,11 +1126,11 @@ sfx_t *S_PrecacheSound (const char *name, qboolean complain, qboolean serversoun
        // previously missing file
        sfx->flags &= ~ SFXFLAG_FILEMISSING;
 
-       if (serversound && !(sfx->flags & SFXFLAG_SERVERSOUND))
-       {
-               S_LockSfx (sfx);
-               sfx->flags |= SFXFLAG_SERVERSOUND;
-       }
+       // set a flag to indicate this has been precached for this level or permanently
+       if (levelsound)
+               sfx->flags |= SFXFLAG_LEVELSOUND;
+       else
+               sfx->flags |= SFXFLAG_MENUSOUND;
 
        if (!nosound.integer && snd_precache.integer)
                S_LoadSound(sfx, complain);
@@ -1140,31 +1169,6 @@ qboolean S_IsSoundPrecached (const sfx_t *sfx)
        return (sfx != NULL && sfx->fetcher != NULL) || (sfx == &changevolume_sfx);
 }
 
-/*
-==================
-S_LockSfx
-
-Add a lock to a SFX
-==================
-*/
-void S_LockSfx (sfx_t *sfx)
-{
-       sfx->locks++;
-}
-
-/*
-==================
-S_UnlockSfx
-
-Remove a lock from a SFX
-==================
-*/
-void S_UnlockSfx (sfx_t *sfx)
-{
-       sfx->locks--;
-}
-
-
 /*
 ==================
 S_BlockSound
@@ -1200,21 +1204,23 @@ channel_t *SND_PickChannel(int entnum, int entchannel)
        int first_to_die;
        int first_life_left, life_left;
        channel_t* ch;
+       sfx_t *sfx; // use this instead of ch->sfx->, because that is volatile.
 
 // Check for replacement sound, or find the best one to replace
        first_to_die = -1;
        first_life_left = 0x7fffffff;
 
        // entity channels try to replace the existing sound on the channel
-       if (entchannel != 0)
+       // channels <= 0 are autochannels
+       if (IS_CHAN_SINGLE(entchannel))
        {
                for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
                {
                        ch = &channels[ch_idx];
-                       if (ch->entnum == entnum && (ch->entchannel == entchannel || entchannel == -1) )
+                       if (ch->entnum == entnum && ch->entchannel == entchannel)
                        {
                                // always override sound from same entity
-                               S_StopChannel (ch_idx, true);
+                               S_StopChannel (ch_idx, true, false);
                                return &channels[ch_idx];
                        }
                }
@@ -1224,7 +1230,8 @@ channel_t *SND_PickChannel(int entnum, int entchannel)
        for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
        {
                ch = &channels[ch_idx];
-               if (!ch->sfx)
+               sfx = ch->sfx; // fetch the volatile variable
+               if (!sfx)
                {
                        // no sound on this channel
                        first_to_die = ch_idx;
@@ -1236,9 +1243,9 @@ channel_t *SND_PickChannel(int entnum, int entchannel)
                        continue;
 
                // don't override looped sounds
-               if ((ch->flags & CHANNELFLAG_FORCELOOP) || ch->sfx->loopstart < ch->sfx->total_length)
+               if ((ch->flags & CHANNELFLAG_FORCELOOP) || sfx->loopstart < sfx->total_length)
                        continue;
-               life_left = ch->sfx->total_length - ch->pos;
+               life_left = sfx->total_length - ch->pos;
 
                if (life_left < first_life_left)
                {
@@ -1250,7 +1257,7 @@ channel_t *SND_PickChannel(int entnum, int entchannel)
        if (first_to_die == -1)
                return NULL;
        
-       S_StopChannel (first_to_die, true);
+       S_StopChannel (first_to_die, true, false);
 
 emptychan_found:
        return &channels[first_to_die];
@@ -1302,6 +1309,7 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx)
                mastervol *= snd_staticvolume.value;
        else if(!(ch->flags & CHANNELFLAG_FULLVOLUME)) // same as SND_PaintChannel uses
        {
+               // old legacy separated cvars
                if(ch->entnum >= MAX_EDICTS)
                {
                        switch(ch->entchannel)
@@ -1362,6 +1370,19 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx)
                                default:                                          break;
                        }
                }
+
+               switch(ch->entchannel)
+               {
+                       case 0:  mastervol *= snd_channel0volume.value; break;
+                       case 1:  mastervol *= snd_channel1volume.value; break;
+                       case 2:  mastervol *= snd_channel2volume.value; break;
+                       case 3:  mastervol *= snd_channel3volume.value; break;
+                       case 4:  mastervol *= snd_channel4volume.value; break;
+                       case 5:  mastervol *= snd_channel5volume.value; break;
+                       case 6:  mastervol *= snd_channel6volume.value; break;
+                       case 7:  mastervol *= snd_channel7volume.value; break;
+                       default: mastervol *= Cvar_VariableValueOr(va("snd_channel%dvolume", CHAN_ENGINE2CVAR(ch->entchannel)), 1.0); break;
+               }
        }
 
        // If this channel does not manage its own volume (like CD tracks)
@@ -1558,13 +1579,25 @@ void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags,
                Con_Printf("S_PlaySfxOnChannel called with NULL??\n");
                return;
        }
+
+       if ((sfx->loopstart < sfx->total_length) || (flags & CHANNELFLAG_FORCELOOP))
+       {
+               if(!snd_startloopingsounds.integer)
+                       return;
+       }
+       else
+       {
+               if(!snd_startnonloopingsounds.integer)
+                       return;
+       }
+
        // Initialize the channel
        // a crash was reported on an in-use channel, so check here...
        if (target_chan->sfx)
        {
                int channelindex = (int)(target_chan - channels);
                Con_Printf("S_PlaySfxOnChannel(%s): channel %i already in use??  Clearing.\n", sfx->name, channelindex);
-               S_StopChannel (channelindex, true);
+               S_StopChannel (channelindex, true, false);
        }
        // We MUST set sfx LAST because otherwise we could crash a threaded mixer
        // (otherwise we'd have to call SndSys_LockRenderBuffer here)
@@ -1589,16 +1622,13 @@ void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags,
        S_SetChannelVolume(target_chan - channels, fvol);
        SND_Spatialize_WithSfx (target_chan, isstatic, sfx);
 
-       // Lock the SFX during play
-       S_LockSfx (sfx);
-
        // finally, set the sfx pointer, so the channel becomes valid for playback
        // and will be noticed by the mixer
        target_chan->sfx = sfx;
 }
 
 
-int S_StartSound_StartPosition (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)
 {
        channel_t *target_chan, *check, *ch;
        int             ch_idx, startpos;
@@ -1608,12 +1638,12 @@ int S_StartSound_StartPosition (int entnum, int entchannel, sfx_t *sfx, vec3_t o
 
        if(sfx == &changevolume_sfx)
        {
-               if(entchannel == 0)
+               if (!IS_CHAN_SINGLE(entchannel))
                        return -1;
                for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
                {
                        ch = &channels[ch_idx];
-                       if (ch->entnum == entnum && (ch->entchannel == entchannel || entchannel == -1) )
+                       if (ch->entnum == entnum && ch->entchannel == entchannel)
                        {
                                S_SetChannelVolume(ch_idx, fvol);
                                ch->dist_mult = attenuation / snd_soundradius.value;
@@ -1651,19 +1681,25 @@ int S_StartSound_StartPosition (int entnum, int entchannel, sfx_t *sfx, vec3_t o
                }
        }
 
-       S_PlaySfxOnChannel (sfx, target_chan, CHANNELFLAG_NONE, origin, fvol, attenuation, false, entnum, entchannel, startpos);
+       S_PlaySfxOnChannel (sfx, target_chan, flags, origin, fvol, attenuation, false, entnum, entchannel, startpos);
 
        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);
 }
 
-void S_StopChannel (unsigned int channel_ind, qboolean lockmutex)
+void S_StopChannel (unsigned int channel_ind, qboolean lockmutex, qboolean freesfx)
 {
        channel_t *ch;
+       sfx_t *sfx;
 
        if (channel_ind >= total_channels)
                return;
@@ -1676,10 +1712,9 @@ void S_StopChannel (unsigned int channel_ind, qboolean lockmutex)
                SndSys_LockRenderBuffer();
        
        ch = &channels[channel_ind];
+       sfx = ch->sfx;
        if (ch->sfx != NULL)
        {
-               sfx_t *sfx = ch->sfx;
-
                if (sfx->fetcher != NULL)
                {
                        snd_fetcher_endsb_t fetcher_endsb = sfx->fetcher->endsb;
@@ -1687,14 +1722,13 @@ void S_StopChannel (unsigned int channel_ind, qboolean lockmutex)
                                fetcher_endsb (ch->fetcher_data);
                }
 
-               // Remove the lock it holds
-               S_UnlockSfx (sfx);
-
                ch->fetcher_data = NULL;
                ch->sfx = NULL;
        }
        if (lockmutex && !simsound)
                SndSys_UnlockRenderBuffer();
+       if (freesfx)
+               S_FreeSfx(sfx, true);
 }
 
 
@@ -1724,7 +1758,7 @@ void S_StopSound(int entnum, int entchannel)
        for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++)
                if (channels[i].entnum == entnum && channels[i].entchannel == entchannel)
                {
-                       S_StopChannel (i, true);
+                       S_StopChannel (i, true, false);
                        return;
                }
 }
@@ -1747,7 +1781,8 @@ void S_StopAllSounds (void)
                size_t memsize;
 
                for (i = 0; i < total_channels; i++)
-                       S_StopChannel (i, false);
+                       if (channels[i].sfx)
+                               S_StopChannel (i, false, false);
 
                total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;   // no statics
                memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
@@ -1852,6 +1887,7 @@ void S_UpdateAmbientSounds (void)
        int                     ambient_channel;
        channel_t       *chan;
        unsigned char           ambientlevels[NUM_AMBIENTS];
+       sfx_t           *sfx;
 
        memset(ambientlevels, 0, sizeof(ambientlevels));
        if (cl.worldmodel && cl.worldmodel->brush.AmbientSoundLevelsForPoint)
@@ -1861,7 +1897,8 @@ void S_UpdateAmbientSounds (void)
        for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
        {
                chan = &channels[ambient_channel];
-               if (chan->sfx == NULL || chan->sfx->fetcher == NULL)
+               sfx = chan->sfx; // fetch the volatile variable
+               if (sfx == NULL || sfx->fetcher == NULL)
                        continue;
 
                vol = (int)ambientlevels[ambient_channel];
@@ -2239,9 +2276,12 @@ qboolean S_LocalSound (const char *sound)
                return false;
        }
 
-       // Local sounds must not be freed
-       sfx->flags |= SFXFLAG_PERMANENTLOCK;
+       // menu sounds must not be freed on level change
+       sfx->flags |= SFXFLAG_MENUSOUND;
 
+       // fun fact: in Quake 1, this used -1 "replace any entity channel",
+       // which we no longer support anyway
+       // changed by Black in r4297 "Changed S_LocalSound to play multiple sounds at a time."
        ch_ind = S_StartSound (cl.viewentity, 0, sfx, vec3_origin, 1, 0);
        if (ch_ind < 0)
                return false;
index c7c631f88f6b17e0af5b38c782552711858e1817..a166aba259e38fc336cd058dcd7e965c87310ce3 100644 (file)
@@ -53,9 +53,9 @@ typedef struct snd_ringbuffer_s
 // sfx_t flags
 #define SFXFLAG_NONE                   0
 #define SFXFLAG_FILEMISSING            (1 << 0) // wasn't able to load the associated sound file
-#define SFXFLAG_SERVERSOUND            (1 << 1) // the sfx is part of the server precache list
+#define SFXFLAG_LEVELSOUND             (1 << 1) // the sfx is part of the server or client precache list for this level
 #define SFXFLAG_STREAMED               (1 << 2) // informative only. You shouldn't need to know that
-#define SFXFLAG_PERMANENTLOCK  (1 << 3) // can never be freed (ex: used by the client code)
+#define SFXFLAG_MENUSOUND              (1 << 3) // not freed during level change (menu sounds, music, etc)
 
 typedef struct snd_fetcher_s snd_fetcher_t;
 struct sfx_s
@@ -64,11 +64,6 @@ struct sfx_s
        sfx_t                           *next;
        size_t                          memsize;                // total memory used (including sfx_t and fetcher data)
 
-                                                                               // One lock is automatically granted while the sfx is
-                                                                               // playing (and removed when stopped). Locks can also be
-       int                                     locks;                  // added by S_PrecacheSound.
-                                                                               // A SFX with no lock, no SFXFLAG_PERMANENTLOCK, and not precached after a level change is freed
-
        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
@@ -86,7 +81,7 @@ typedef struct channel_s
 {
        int                     listener_volume [SND_LISTENERS];        // 0-65536 volume per speaker
        int                             master_vol;             // 0-65536 master volume
-       sfx_t                   *sfx;                   // sfx number
+       sfx_t                   *sfx;                   // pointer to sound sample being used
        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
@@ -154,9 +149,6 @@ void S_MixToBuffer(void *stream, unsigned int frames);
 
 qboolean S_LoadSound (sfx_t *sfx, qboolean complain);
 
-void S_LockSfx (sfx_t *sfx);
-void S_UnlockSfx (sfx_t *sfx);
-
 snd_buffer_t *Snd_CreateSndBuffer (const unsigned char *samples, unsigned int sampleframes, const snd_format_t* in_format, unsigned int sb_speed);
 qboolean Snd_AppendToSndBuffer (snd_buffer_t* sb, const unsigned char *samples, unsigned int sampleframes, const snd_format_t* format);
 
index 05abc83a5fc95dbdaf803d97bfa9dc698152ab74..6bec880eae3974665dcc699feff687b8a84779fb 100644 (file)
--- a/snd_mix.c
+++ b/snd_mix.c
@@ -186,6 +186,11 @@ static qboolean SND_PaintChannel (channel_t *ch, portable_sampleframe_t *paint,
        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++)
@@ -199,11 +204,11 @@ static qboolean SND_PaintChannel (channel_t *ch, portable_sampleframe_t *paint,
                return false;
 
        sb_offset = ch->pos;
-       sb = ch->sfx->fetcher->getsb (ch->sfx->fetcher_data, &ch->fetcher_data, &sb_offset, count);
+       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",
-                                       ch->sfx->name); // , count); // or add this? FIXME
+                                       sfx->name); // , count); // or add this? FIXME
                return false;
        }
        else
@@ -505,6 +510,8 @@ 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)
@@ -520,15 +527,15 @@ void S_MixToBuffer(void *stream, unsigned int bufferframes)
                                // 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)
                                {
                                        SND_PaintChannel (ch, paintbuffer + ltime, count);
                                        ch->pos += count;
                                        ltime += count;
                                }
-
                                // if at end of sfx, loop or stop the channel
-                               if (ch->pos >= (int)sfx->total_length)
+                               else
                                {
                                        if (sfx->loopstart < sfx->total_length)
                                                ch->pos = sfx->loopstart;
@@ -536,7 +543,7 @@ void S_MixToBuffer(void *stream, unsigned int bufferframes)
                                                ch->pos = 0;
                                        else
                                        {
-                                               S_StopChannel (ch - channels, false);
+                                               S_StopChannel (ch - channels, false, false);
                                                break;
                                        }
                                }
index bc71a4f30835082a6164a480c8c333bcccdd7817..8385964425053d17c5f7a18f664b6bb219ba2101 100755 (executable)
@@ -74,7 +74,12 @@ int S_StartSound_StartPosition (int entnum, int entchannel, sfx_t *sfx, vec3_t o
        return -1;
 }
 
-void S_StopChannel (unsigned int channel_ind, qboolean lockmutex)
+int S_StartSound_StartPosition_Flags (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float startposition, int flags)
+{
+       return -1;
+}
+
+void S_StopChannel (unsigned int channel_ind, qboolean lockmutex, qboolean freesfx)
 {
 }
 
@@ -95,7 +100,7 @@ void S_SetChannelVolume (unsigned int ch_ind, float fvol)
 {
 }
 
-sfx_t *S_PrecacheSound (const char *sample, qboolean complain, qboolean serversound)
+sfx_t *S_PrecacheSound (const char *sample, qboolean complain, qboolean levelsound)
 {
        return NULL;
 }
diff --git a/sound.h b/sound.h
index 37e53b06f1e541983304a6a8e68603ca43184759..ff1e918767332683861acfac6c37414c5f29d93d 100644 (file)
--- a/sound.h
+++ b/sound.h
@@ -67,15 +67,38 @@ void S_UnloadAllSounds_f (void);
 void S_Update(const matrix4x4_t *listenermatrix);
 void S_ExtraUpdate (void);
 
-sfx_t *S_PrecacheSound (const char *sample, qboolean complain, qboolean serversound);
+sfx_t *S_PrecacheSound (const char *sample, qboolean complain, qboolean levelsound);
 float S_SoundLength(const char *name);
 void S_ClearUsed (void);
 void S_PurgeUnused (void);
 qboolean S_IsSoundPrecached (const sfx_t *sfx);
 
+// for sound() builtins
+#define CHANFLAG_RELIABLE 1
+
+// these define the "engine" channel namespace
+#define CHAN_MIN_AUTO       -128
+#define CHAN_MAX_AUTO          0
+#define CHAN_MIN_SINGLE        1
+#define CHAN_MAX_SINGLE      127
+#define IS_CHAN_AUTO(n)        ((n) >= CHAN_MIN_AUTO && (n) <= CHAN_MAX_AUTO)
+#define IS_CHAN_SINGLE(n)      ((n) >= CHAN_MIN_SINGLE && (n) <= CHAN_MAX_SINGLE)
+#define IS_CHAN(n)             (IS_CHAN_AUTO(n) || IS_CHAN_SINGLE(n))
+
+// engine channel == network channel
+#define CHAN_ENGINE2NET(c)     (c)
+#define CHAN_NET2ENGINE(c)     (c)
+
+// engine view of channel encodes the auto flag into the channel number (see CHAN_ constants below)
+// user view uses the flags bitmask for it
+#define CHAN_USER2ENGINE(c)    (c)
+#define CHAN_ENGINE2USER(c)    (c)
+#define CHAN_ENGINE2CVAR(c)    (abs(c))
+
 // S_StartSound returns the channel index, or -1 if an error occurred
 int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation);
 int S_StartSound_StartPosition (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);
 qboolean S_LocalSound (const char *s);
 
 void S_StaticSound (sfx_t *sfx, vec3_t origin, float fvol, float attenuation);
@@ -83,7 +106,7 @@ void S_StopSound (int entnum, int entchannel);
 void S_StopAllSounds (void);
 void S_PauseGameSounds (qboolean toggle);
 
-void S_StopChannel (unsigned int channel_ind, qboolean lockmutex);
+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);
 float S_GetChannelPosition (unsigned int ch_ind);
index acea7b01ed37f2665ae102de1aeb2af941a296dd..f6f00d33102ec3c30968a30ff05e0c9a3e446b5a 100644 (file)
--- a/sv_demo.c
+++ b/sv_demo.c
@@ -6,7 +6,6 @@ extern cvar_t sv_autodemo_perclient_discardable;
 void SV_StartDemoRecording(client_t *client, const char *filename, int forcetrack)
 {
        char name[MAX_QPATH];
-       prvm_eval_t *val;
 
        if(client->sv_demo_file != NULL)
                return; // we already have a demo
@@ -17,8 +16,7 @@ void SV_StartDemoRecording(client_t *client, const char *filename, int forcetrac
        Con_Printf("Recording demo for # %d (%s) to %s\n", PRVM_NUM_FOR_EDICT(client->edict), client->netaddress, name);
 
        // Reset discardable flag for every new demo.
-       if ((val = PRVM_EDICTFIELDVALUE(client->edict, prog->fieldoffsets.discardabledemo)))
-               val->_float = 0;
+       PRVM_serveredictfloat(client->edict, discardabledemo) = 0;
 
        client->sv_demo_file = FS_OpenRealFile(name, "wb", false);
        if(!client->sv_demo_file)
@@ -46,7 +44,7 @@ void SV_WriteDemoMessage(client_t *client, sizebuf_t *sendbuffer, qboolean clien
        FS_Write(client->sv_demo_file, &len, 4);
        for(i = 0; i < 3; ++i)
        {
-               f = LittleFloat(client->edict->fields.server->v_angle[i]);
+               f = LittleFloat(PRVM_serveredictvector(client->edict, v_angle)[i]);
                FS_Write(client->sv_demo_file, &f, 4);
        }
        FS_Write(client->sv_demo_file, sendbuffer->data, sendbuffer->cursize);
@@ -56,7 +54,6 @@ void SV_StopDemoRecording(client_t *client)
 {
        sizebuf_t buf;
        unsigned char bufdata[64];
-       prvm_eval_t *val;
 
        if(client->sv_demo_file == NULL)
                return;
@@ -67,7 +64,7 @@ void SV_StopDemoRecording(client_t *client)
        MSG_WriteByte(&buf, svc_disconnect);
        SV_WriteDemoMessage(client, &buf, false);
 
-       if (sv_autodemo_perclient_discardable.integer && (val = PRVM_EDICTFIELDVALUE(client->edict, prog->fieldoffsets.discardabledemo)) && val->_float)
+       if (sv_autodemo_perclient_discardable.integer && PRVM_serveredictfloat(client->edict, discardabledemo))
        {
                FS_RemoveOnClose(client->sv_demo_file);
                Con_Printf("Stopped recording discardable demo for # %d (%s)\n", PRVM_NUM_FOR_EDICT(client->edict), client->netaddress);
index 74457fec038aa437bf01733e99bd982a517223c7..bc6eaf0ad59db131b13eb1013c12a4ddd1c36ecb 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -53,6 +53,7 @@ cvar_t slowmo = {0, "slowmo", "1.0", "controls game speed, 0.5 is half speed, 2
 cvar_t sv_accelerate = {0, "sv_accelerate", "10", "rate at which a player accelerates to sv_maxspeed"};
 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2", "maximum cosine angle for quake's vertical autoaim, a value above 1 completely disables the autoaim, quake used 0.93"};
 cvar_t sv_airaccel_qw = {0, "sv_airaccel_qw", "1", "ratio of QW-style air control as opposed to simple acceleration; when < 0, the speed is clamped against the maximum allowed forward speed after the move"};
+cvar_t sv_airaccel_qw_stretchfactor = {0, "sv_airaccel_qw_stretchfactor", "0", "when set, the maximum acceleration increase the player may get compared to forward-acceleration when strafejumping"};
 cvar_t sv_airaccel_sideways_friction = {0, "sv_airaccel_sideways_friction", "", "anti-sideways movement stabilization (reduces speed gain when zigzagging); when < 0, only so much friction is applied that braking (by accelerating backwards) cannot be stronger"};
 cvar_t sv_airaccelerate = {0, "sv_airaccelerate", "-1", "rate at which a player accelerates to sv_maxairspeed while in the air, if less than 0 the sv_accelerate variable is used instead"};
 cvar_t sv_airstopaccelerate = {0, "sv_airstopaccelerate", "0", "when set, replacement for sv_airaccelerate when moving backwards"};
@@ -106,8 +107,8 @@ cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebounc
 cvar_t sv_gameplayfix_multiplethinksperframe = {0, "sv_gameplayfix_multiplethinksperframe", "1", "allows entities to think more often than the server framerate, primarily useful for very high fire rate weapons"};
 cvar_t sv_gameplayfix_noairborncorpse = {0, "sv_gameplayfix_noairborncorpse", "1", "causes entities (corpses, items, etc) sitting ontop of moving entities (players) to fall when the moving entity (player) is no longer supporting them"};
 cvar_t sv_gameplayfix_noairborncorpse_allowsuspendeditems = {0, "sv_gameplayfix_noairborncorpse_allowsuspendeditems", "1", "causes entities sitting ontop of objects that are instantaneously remove to float in midair (special hack to allow a common level design trick for floating items)"};
-cvar_t sv_gameplayfix_nudgeoutofsolid = {0, "sv_gameplayfix_nudgeoutofsolid", "1", "attempts to fix physics errors (where an object ended up in solid for some reason)"};
-cvar_t sv_gameplayfix_nudgeoutofsolid_bias = {0, "sv_gameplayfix_nudgeoutofsolid_bias", "0", "over-correction on nudgeoutofsolid logic, to prevent constant contact"};
+cvar_t sv_gameplayfix_nudgeoutofsolid = {0, "sv_gameplayfix_nudgeoutofsolid", "0", "attempts to fix physics errors (where an object ended up in solid for some reason)"};
+cvar_t sv_gameplayfix_nudgeoutofsolid_separation = {0, "sv_gameplayfix_nudgeoutofsolid_separation", "0.03125", "keep objects this distance apart to prevent collision issues on seams"};
 cvar_t sv_gameplayfix_q2airaccelerate = {0, "sv_gameplayfix_q2airaccelerate", "0", "Quake2-style air acceleration"};
 cvar_t sv_gameplayfix_nogravityonground = {0, "sv_gameplayfix_nogravityonground", "0", "turn off gravity when on ground (to get rid of sliding)"};
 cvar_t sv_gameplayfix_setmodelrealbox = {0, "sv_gameplayfix_setmodelrealbox", "1", "fixes a bug in Quake that made setmodel always set the entity box to ('-16 -16 -16', '16 16 16') rather than properly checking the model box, breaks some poorly coded mods"};
@@ -119,6 +120,7 @@ cvar_t sv_gameplayfix_nostepmoveonsteepslopes = {0, "sv_gameplayfix_nostepmoveon
 cvar_t sv_gameplayfix_swiminbmodels = {0, "sv_gameplayfix_swiminbmodels", "1", "causes pointcontents (used to determine if you are in a liquid) to check bmodel entities as well as the world model, so you can swim around in (possibly moving) water bmodel entities"};
 cvar_t sv_gameplayfix_upwardvelocityclearsongroundflag = {0, "sv_gameplayfix_upwardvelocityclearsongroundflag", "1", "prevents monsters, items, and most other objects from being stuck to the floor when pushed around by damage, and other situations in mods"};
 cvar_t sv_gameplayfix_downtracesupportsongroundflag = {0, "sv_gameplayfix_downtracesupportsongroundflag", "1", "prevents very short moves from clearing onground (which may make the player stick to the floor at high netfps)"};
+cvar_t sv_gameplayfix_q1bsptracelinereportstexture = {0, "sv_gameplayfix_q1bsptracelinereportstexture", "1", "enables mods to get accurate trace_texture results on q1bsp by using a surface-hitting traceline implementation rather than the standard solidbsp method, q3bsp always reports texture accurately"};
 cvar_t sv_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)"};
@@ -238,94 +240,169 @@ static const char *standardeffectnames[EFFECT_TOTAL] =
        "SVC_PARTICLE"
 };
 
-#define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
+#define SV_REQFUNCS 0
+#define sv_reqfuncs NULL
 
-prvm_required_field_t reqfields[] =
+//#define SV_REQFUNCS (sizeof(sv_reqfuncs) / sizeof(const char *))
+//static const char *sv_reqfuncs[] = {
+//};
+
+#define SV_REQFIELDS (sizeof(sv_reqfields) / sizeof(prvm_required_field_t))
+
+prvm_required_field_t sv_reqfields[] =
 {
-       {ev_entity, "cursor_trace_ent"},
-       {ev_entity, "drawonlytoclient"},
-       {ev_entity, "exteriormodeltoclient"},
-       {ev_entity, "nodrawtoclient"},
-       {ev_entity, "tag_entity"},
-       {ev_entity, "viewmodelforclient"},
-       {ev_float, "SendFlags"},
-       {ev_float, "Version"},
-       {ev_float, "alpha"},
-       {ev_float, "ammo_cells1"},
-       {ev_float, "ammo_lava_nails"},
-       {ev_float, "ammo_multi_rockets"},
-       {ev_float, "ammo_nails1"},
-       {ev_float, "ammo_plasma"},
-       {ev_float, "ammo_rockets1"},
-       {ev_float, "ammo_shells1"},
-       {ev_float, "button3"},
-       {ev_float, "button4"},
-       {ev_float, "button5"},
-       {ev_float, "button6"},
-       {ev_float, "button7"},
-       {ev_float, "button8"},
-       {ev_float, "button9"},
-       {ev_float, "button10"},
-       {ev_float, "button11"},
-       {ev_float, "button12"},
-       {ev_float, "button13"},
-       {ev_float, "button14"},
-       {ev_float, "button15"},
-       {ev_float, "button16"},
-       {ev_float, "buttonchat"},
-       {ev_float, "buttonuse"},
-       {ev_float, "clientcolors"},
-       {ev_float, "cursor_active"},
-       {ev_float, "disableclientprediction"},
-       {ev_float, "fullbright"},
-       {ev_float, "glow_color"},
-       {ev_float, "glow_size"},
-       {ev_float, "glow_trail"},
-       {ev_float, "gravity"},
-       {ev_float, "idealpitch"},
-       {ev_float, "items2"},
-       {ev_float, "light_lev"},
-       {ev_float, "modelflags"},
-       {ev_float, "pflags"},
-       {ev_float, "ping"},
-       {ev_float, "pitch_speed"},
-       {ev_float, "pmodel"},
-       {ev_float, "renderamt"}, // HalfLife support
-       {ev_float, "rendermode"}, // HalfLife support
-       {ev_float, "scale"},
-       {ev_float, "style"},
-       {ev_float, "tag_index"},
-       {ev_float, "viewzoom"},
-       {ev_function, "SendEntity"},
-       {ev_function, "contentstransition"}, // DRESK - Support for Entity Contents Transition Event
-       {ev_function, "customizeentityforclient"},
-       {ev_function, "movetypesteplandevent"}, // DRESK - Support for MOVETYPE_STEP Entity Land Event
-       {ev_string, "netaddress"},
-       {ev_string, "playermodel"},
-       {ev_string, "playerskin"},
-       {ev_vector, "color"},
-       {ev_vector, "colormod"},
-       {ev_vector, "cursor_screen"},
-       {ev_vector, "cursor_trace_endpos"},
-       {ev_vector, "cursor_trace_start"},
-       {ev_vector, "glowmod"},
-       {ev_vector, "movement"},
-       {ev_vector, "punchvector"},
-
-       // physics
-       //{ev_float, "solid"},
-       //{ev_float, "movetype"},
-       //{ev_float, "modelindex"},
-       {ev_vector, "mass"},
-       //{ev_vector, "origin"},
-       //{ev_vector, "velocity"},
-       //{ev_vector, "axis_forward"},
-       //{ev_vector, "axis_left"},
-       //{ev_vector, "axis_up"},
-       //{ev_vector, "spinvelocity"},
-       //{ev_vector, "angles"},
-       //{ev_vector, "avelocity"},
+#define PRVM_DECLARE_serverglobalfloat(x)
+#define PRVM_DECLARE_serverglobalvector(x)
+#define PRVM_DECLARE_serverglobalstring(x)
+#define PRVM_DECLARE_serverglobaledict(x)
+#define PRVM_DECLARE_serverglobalfunction(x)
+#define PRVM_DECLARE_clientglobalfloat(x)
+#define PRVM_DECLARE_clientglobalvector(x)
+#define PRVM_DECLARE_clientglobalstring(x)
+#define PRVM_DECLARE_clientglobaledict(x)
+#define PRVM_DECLARE_clientglobalfunction(x)
+#define PRVM_DECLARE_menuglobalfloat(x)
+#define PRVM_DECLARE_menuglobalvector(x)
+#define PRVM_DECLARE_menuglobalstring(x)
+#define PRVM_DECLARE_menuglobaledict(x)
+#define PRVM_DECLARE_menuglobalfunction(x)
+#define PRVM_DECLARE_serverfieldfloat(x) {ev_float, #x},
+#define PRVM_DECLARE_serverfieldvector(x) {ev_vector, #x},
+#define PRVM_DECLARE_serverfieldstring(x) {ev_string, #x},
+#define PRVM_DECLARE_serverfieldedict(x) {ev_entity, #x},
+#define PRVM_DECLARE_serverfieldfunction(x) {ev_function, #x},
+#define PRVM_DECLARE_clientfieldfloat(x)
+#define PRVM_DECLARE_clientfieldvector(x)
+#define PRVM_DECLARE_clientfieldstring(x)
+#define PRVM_DECLARE_clientfieldedict(x)
+#define PRVM_DECLARE_clientfieldfunction(x)
+#define PRVM_DECLARE_menufieldfloat(x)
+#define PRVM_DECLARE_menufieldvector(x)
+#define PRVM_DECLARE_menufieldstring(x)
+#define PRVM_DECLARE_menufieldedict(x)
+#define PRVM_DECLARE_menufieldfunction(x)
+#define PRVM_DECLARE_serverfunction(x)
+#define PRVM_DECLARE_clientfunction(x)
+#define PRVM_DECLARE_menufunction(x)
+#define PRVM_DECLARE_field(x)
+#define PRVM_DECLARE_global(x)
+#define PRVM_DECLARE_function(x)
+#include "prvm_offsets.h"
+#undef PRVM_DECLARE_serverglobalfloat
+#undef PRVM_DECLARE_serverglobalvector
+#undef PRVM_DECLARE_serverglobalstring
+#undef PRVM_DECLARE_serverglobaledict
+#undef PRVM_DECLARE_serverglobalfunction
+#undef PRVM_DECLARE_clientglobalfloat
+#undef PRVM_DECLARE_clientglobalvector
+#undef PRVM_DECLARE_clientglobalstring
+#undef PRVM_DECLARE_clientglobaledict
+#undef PRVM_DECLARE_clientglobalfunction
+#undef PRVM_DECLARE_menuglobalfloat
+#undef PRVM_DECLARE_menuglobalvector
+#undef PRVM_DECLARE_menuglobalstring
+#undef PRVM_DECLARE_menuglobaledict
+#undef PRVM_DECLARE_menuglobalfunction
+#undef PRVM_DECLARE_serverfieldfloat
+#undef PRVM_DECLARE_serverfieldvector
+#undef PRVM_DECLARE_serverfieldstring
+#undef PRVM_DECLARE_serverfieldedict
+#undef PRVM_DECLARE_serverfieldfunction
+#undef PRVM_DECLARE_clientfieldfloat
+#undef PRVM_DECLARE_clientfieldvector
+#undef PRVM_DECLARE_clientfieldstring
+#undef PRVM_DECLARE_clientfieldedict
+#undef PRVM_DECLARE_clientfieldfunction
+#undef PRVM_DECLARE_menufieldfloat
+#undef PRVM_DECLARE_menufieldvector
+#undef PRVM_DECLARE_menufieldstring
+#undef PRVM_DECLARE_menufieldedict
+#undef PRVM_DECLARE_menufieldfunction
+#undef PRVM_DECLARE_serverfunction
+#undef PRVM_DECLARE_clientfunction
+#undef PRVM_DECLARE_menufunction
+#undef PRVM_DECLARE_field
+#undef PRVM_DECLARE_global
+#undef PRVM_DECLARE_function
+};
+
+#define SV_REQGLOBALS (sizeof(sv_reqglobals) / sizeof(prvm_required_field_t))
 
+prvm_required_field_t sv_reqglobals[] =
+{
+#define PRVM_DECLARE_serverglobalfloat(x) {ev_float, #x},
+#define PRVM_DECLARE_serverglobalvector(x) {ev_vector, #x},
+#define PRVM_DECLARE_serverglobalstring(x) {ev_string, #x},
+#define PRVM_DECLARE_serverglobaledict(x) {ev_entity, #x},
+#define PRVM_DECLARE_serverglobalfunction(x) {ev_function, #x},
+#define PRVM_DECLARE_clientglobalfloat(x)
+#define PRVM_DECLARE_clientglobalvector(x)
+#define PRVM_DECLARE_clientglobalstring(x)
+#define PRVM_DECLARE_clientglobaledict(x)
+#define PRVM_DECLARE_clientglobalfunction(x)
+#define PRVM_DECLARE_menuglobalfloat(x)
+#define PRVM_DECLARE_menuglobalvector(x)
+#define PRVM_DECLARE_menuglobalstring(x)
+#define PRVM_DECLARE_menuglobaledict(x)
+#define PRVM_DECLARE_menuglobalfunction(x)
+#define PRVM_DECLARE_serverfieldfloat(x)
+#define PRVM_DECLARE_serverfieldvector(x)
+#define PRVM_DECLARE_serverfieldstring(x)
+#define PRVM_DECLARE_serverfieldedict(x)
+#define PRVM_DECLARE_serverfieldfunction(x)
+#define PRVM_DECLARE_clientfieldfloat(x)
+#define PRVM_DECLARE_clientfieldvector(x)
+#define PRVM_DECLARE_clientfieldstring(x)
+#define PRVM_DECLARE_clientfieldedict(x)
+#define PRVM_DECLARE_clientfieldfunction(x)
+#define PRVM_DECLARE_menufieldfloat(x)
+#define PRVM_DECLARE_menufieldvector(x)
+#define PRVM_DECLARE_menufieldstring(x)
+#define PRVM_DECLARE_menufieldedict(x)
+#define PRVM_DECLARE_menufieldfunction(x)
+#define PRVM_DECLARE_serverfunction(x)
+#define PRVM_DECLARE_clientfunction(x)
+#define PRVM_DECLARE_menufunction(x)
+#define PRVM_DECLARE_field(x)
+#define PRVM_DECLARE_global(x)
+#define PRVM_DECLARE_function(x)
+#include "prvm_offsets.h"
+#undef PRVM_DECLARE_serverglobalfloat
+#undef PRVM_DECLARE_serverglobalvector
+#undef PRVM_DECLARE_serverglobalstring
+#undef PRVM_DECLARE_serverglobaledict
+#undef PRVM_DECLARE_serverglobalfunction
+#undef PRVM_DECLARE_clientglobalfloat
+#undef PRVM_DECLARE_clientglobalvector
+#undef PRVM_DECLARE_clientglobalstring
+#undef PRVM_DECLARE_clientglobaledict
+#undef PRVM_DECLARE_clientglobalfunction
+#undef PRVM_DECLARE_menuglobalfloat
+#undef PRVM_DECLARE_menuglobalvector
+#undef PRVM_DECLARE_menuglobalstring
+#undef PRVM_DECLARE_menuglobaledict
+#undef PRVM_DECLARE_menuglobalfunction
+#undef PRVM_DECLARE_serverfieldfloat
+#undef PRVM_DECLARE_serverfieldvector
+#undef PRVM_DECLARE_serverfieldstring
+#undef PRVM_DECLARE_serverfieldedict
+#undef PRVM_DECLARE_serverfieldfunction
+#undef PRVM_DECLARE_clientfieldfloat
+#undef PRVM_DECLARE_clientfieldvector
+#undef PRVM_DECLARE_clientfieldstring
+#undef PRVM_DECLARE_clientfieldedict
+#undef PRVM_DECLARE_clientfieldfunction
+#undef PRVM_DECLARE_menufieldfloat
+#undef PRVM_DECLARE_menufieldvector
+#undef PRVM_DECLARE_menufieldstring
+#undef PRVM_DECLARE_menufieldedict
+#undef PRVM_DECLARE_menufieldfunction
+#undef PRVM_DECLARE_serverfunction
+#undef PRVM_DECLARE_clientfunction
+#undef PRVM_DECLARE_menufunction
+#undef PRVM_DECLARE_field
+#undef PRVM_DECLARE_global
+#undef PRVM_DECLARE_function
 };
 
 
@@ -378,6 +455,7 @@ void SV_Init (void)
        Cvar_RegisterVariable (&sv_accelerate);
        Cvar_RegisterVariable (&sv_aim);
        Cvar_RegisterVariable (&sv_airaccel_qw);
+       Cvar_RegisterVariable (&sv_airaccel_qw_stretchfactor);
        Cvar_RegisterVariable (&sv_airaccel_sideways_friction);
        Cvar_RegisterVariable (&sv_airaccelerate);
        Cvar_RegisterVariable (&sv_airstopaccelerate);
@@ -432,7 +510,7 @@ void SV_Init (void)
        Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
        Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse_allowsuspendeditems);
        Cvar_RegisterVariable (&sv_gameplayfix_nudgeoutofsolid);
-       Cvar_RegisterVariable (&sv_gameplayfix_nudgeoutofsolid_bias);
+       Cvar_RegisterVariable (&sv_gameplayfix_nudgeoutofsolid_separation);
        Cvar_RegisterVariable (&sv_gameplayfix_q2airaccelerate);
        Cvar_RegisterVariable (&sv_gameplayfix_nogravityonground);
        Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
@@ -444,6 +522,7 @@ void SV_Init (void)
        Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
        Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag);
        Cvar_RegisterVariable (&sv_gameplayfix_downtracesupportsongroundflag);
+       Cvar_RegisterVariable (&sv_gameplayfix_q1bsptracelinereportstexture);
        Cvar_RegisterVariable (&sv_gravity);
        Cvar_RegisterVariable (&sv_idealpitchscale);
        Cvar_RegisterVariable (&sv_jumpstep);
@@ -614,10 +693,13 @@ Larger attenuations will drop off.  (max 4 attenuation)
 
 ==================
 */
-void SV_StartSound (prvm_edict_t *entity, int channel, 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)
 {
+       sizebuf_t *dest;
        int sound_num, field_mask, i, ent;
 
+       dest = (reliable ? &sv.reliable_datagram : &sv.datagram);
+
        if (volume < 0 || volume > 255)
        {
                Con_Printf ("SV_StartSound: volume = %i\n", volume);
@@ -630,12 +712,14 @@ void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int v
                return;
        }
 
-       if (channel < 0 || channel > 7)
+       if (!IS_CHAN(channel))
        {
                Con_Printf ("SV_StartSound: channel = %i\n", channel);
                return;
        }
 
+       channel = CHAN_ENGINE2NET(channel);
+
        if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
                return;
 
@@ -651,32 +735,35 @@ void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int v
                field_mask |= SND_VOLUME;
        if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
                field_mask |= SND_ATTENUATION;
-       if (ent >= 8192)
+       if (ent >= 8192 || channel < 0 || channel > 7)
                field_mask |= SND_LARGEENTITY;
-       if (sound_num >= 256 || channel >= 8)
+       if (sound_num >= 256)
                field_mask |= SND_LARGESOUND;
 
 // directed messages go only to the entity they are targeted on
-       MSG_WriteByte (&sv.datagram, svc_sound);
-       MSG_WriteByte (&sv.datagram, field_mask);
+       MSG_WriteByte (dest, svc_sound);
+       MSG_WriteByte (dest, field_mask);
        if (field_mask & SND_VOLUME)
-               MSG_WriteByte (&sv.datagram, volume);
+               MSG_WriteByte (dest, volume);
        if (field_mask & SND_ATTENUATION)
-               MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
+               MSG_WriteByte (dest, (int)(attenuation*64));
        if (field_mask & SND_LARGEENTITY)
        {
-               MSG_WriteShort (&sv.datagram, ent);
-               MSG_WriteByte (&sv.datagram, channel);
+               MSG_WriteShort (dest, ent);
+               MSG_WriteChar (dest, channel);
        }
        else
-               MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
+               MSG_WriteShort (dest, (ent<<3) | channel);
        if ((field_mask & SND_LARGESOUND) || sv.protocol == PROTOCOL_NEHAHRABJP2)
-               MSG_WriteShort (&sv.datagram, sound_num);
+               MSG_WriteShort (dest, sound_num);
        else
-               MSG_WriteByte (&sv.datagram, sound_num);
+               MSG_WriteByte (dest, sound_num);
        for (i = 0;i < 3;i++)
-               MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
-       SV_FlushBroadcastMessages();
+               MSG_WriteCoord (dest, PRVM_serveredictvector(entity, origin)[i]+0.5*(PRVM_serveredictvector(entity, mins)[i]+PRVM_serveredictvector(entity, maxs)[i]), sv.protocol);
+
+       // TODO do we have to do anything here when dest is &sv.reliable_datagram?
+       if(!reliable)
+               SV_FlushBroadcastMessages();
 }
 
 /*
@@ -838,7 +925,6 @@ void SV_SendServerinfo (client_t *client)
        //[515]: init csprogs according to version of svprogs, check the crc, etc.
        if (sv.csqc_progname[0])
        {
-               prvm_eval_t *val;
                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));
@@ -861,11 +947,10 @@ void SV_SendServerinfo (client_t *client)
                }
 
                //[515]: init stufftext string (it is sent before svc_serverinfo)
-               val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.SV_InitCmd);
-               if (val)
+               if (PRVM_GetString(PRVM_serverglobalstring(SV_InitCmd)))
                {
                        MSG_WriteByte (&client->netconnection->message, svc_stufftext);
-                       MSG_WriteString (&client->netconnection->message, va("%s\n", PRVM_GetString(val->string)));
+                       MSG_WriteString (&client->netconnection->message, va("%s\n", PRVM_GetString(PRVM_serverglobalstring(SV_InitCmd))));
                }
        }
 
@@ -895,7 +980,7 @@ void SV_SendServerinfo (client_t *client)
        else
                MSG_WriteByte (&client->netconnection->message, GAME_COOP);
 
-       MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
+       MSG_WriteString (&client->netconnection->message,PRVM_GetString(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]);
@@ -907,8 +992,8 @@ void SV_SendServerinfo (client_t *client)
 
 // send music
        MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
-       MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
-       MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
+       MSG_WriteByte (&client->netconnection->message, (int)PRVM_serveredictfloat(prog->edicts, sounds));
+       MSG_WriteByte (&client->netconnection->message, (int)PRVM_serveredictfloat(prog->edicts, sounds));
 
 // set view
 // store this in clientcamera, too
@@ -1000,10 +1085,10 @@ 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
-               prog->globals.server->self = 0;
-               PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
+               PRVM_serverglobaledict(self) = 0;
+               PRVM_ExecuteProgram (PRVM_serverfunction(SetNewParms), "QC function SetNewParms is missing");
                for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
-                       client->spawn_parms[i] = (&prog->globals.server->parm1)[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);
@@ -1046,49 +1131,50 @@ static qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *c
        unsigned int customizeentityforclient;
        unsigned int sendentity;
        float f;
+       float *v;
        vec3_t cullmins, cullmaxs;
        dp_model_t *model;
-       prvm_eval_t *val, *val2;
 
        // fast path for games that do not use legacy entity networking
        // note: still networks clients even if they are legacy
-       sendentity = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.SendEntity)->function;
+       sendentity = PRVM_serveredictfunction(ent, SendEntity);
        if (sv_onlycsqcnetworking.integer && !sendentity && enumber > svs.maxclients)
                return false;
 
        // this 2 billion unit check is actually to detect NAN origins
        // (we really don't want to send those)
-       if (!(VectorLength2(ent->fields.server->origin) < 2000000000.0*2000000000.0))
+       if (!(VectorLength2(PRVM_serveredictvector(ent, origin)) < 2000000000.0*2000000000.0))
                return false;
 
        // EF_NODRAW prevents sending for any reason except for your own
        // client, so we must keep all clients in this superset
-       effects = (unsigned)ent->fields.server->effects;
+       effects = (unsigned)PRVM_serveredictfloat(ent, effects);
 
        // we can omit invisible entities with no effects that are not clients
        // LordHavoc: this could kill tags attached to an invisible entity, I
        // just hope we never have to support that case
-       i = (int)ent->fields.server->modelindex;
-       modelindex = (i >= 1 && i < MAX_MODELS && ent->fields.server->model && *PRVM_GetString(ent->fields.server->model) && sv.models[i]) ? i : 0;
+       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;
 
        flags = 0;
-       i = (int)(PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_size)->_float * 0.25f);
+       i = (int)(PRVM_serveredictfloat(ent, glow_size) * 0.25f);
        glowsize = (unsigned char)bound(0, i, 255);
-       if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_trail)->_float)
+       if (PRVM_serveredictfloat(ent, glow_trail))
                flags |= RENDER_GLOWTRAIL;
-       if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)->edict)
+       if (PRVM_serveredictedict(ent, viewmodelforclient))
                flags |= RENDER_VIEWMODEL;
 
-       f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[0]*256;
+       v = PRVM_serveredictvector(ent, color);
+       f = v[0]*256;
        light[0] = (unsigned short)bound(0, f, 65535);
-       f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[1]*256;
+       f = v[1]*256;
        light[1] = (unsigned short)bound(0, f, 65535);
-       f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[2]*256;
+       f = v[2]*256;
        light[2] = (unsigned short)bound(0, f, 65535);
-       f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.light_lev)->_float;
+       f = PRVM_serveredictfloat(ent, light_lev);
        light[3] = (unsigned short)bound(0, f, 65535);
-       lightstyle = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.style)->_float;
-       lightpflags = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.pflags)->_float;
+       lightstyle = (unsigned char)PRVM_serveredictfloat(ent, style);
+       lightpflags = (unsigned char)PRVM_serveredictfloat(ent, pflags);
 
        if (gamemode == GAME_TENEBRAE)
        {
@@ -1139,61 +1225,62 @@ static qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *c
 
        // early culling checks
        // (final culling is done by SV_MarkWriteEntityStateToClient)
-       customizeentityforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.customizeentityforclient)->function;
+       customizeentityforclient = PRVM_serveredictfunction(ent, customizeentityforclient);
        if (!customizeentityforclient && enumber > svs.maxclients && (!modelindex && !specialvisibilityradius))
                return false;
 
        *cs = defaultstate;
        cs->active = ACTIVE_NETWORK;
        cs->number = enumber;
-       VectorCopy(ent->fields.server->origin, cs->origin);
-       VectorCopy(ent->fields.server->angles, cs->angles);
+       VectorCopy(PRVM_serveredictvector(ent, origin), cs->origin);
+       VectorCopy(PRVM_serveredictvector(ent, angles), cs->angles);
        cs->flags = flags;
        cs->effects = effects;
-       cs->colormap = (unsigned)ent->fields.server->colormap;
+       cs->colormap = (unsigned)PRVM_serveredictfloat(ent, colormap);
        cs->modelindex = modelindex;
-       cs->skin = (unsigned)ent->fields.server->skin;
-       cs->frame = (unsigned)ent->fields.server->frame;
-       cs->viewmodelforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)->edict;
-       cs->exteriormodelforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.exteriormodeltoclient)->edict;
-       cs->nodrawtoclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.nodrawtoclient)->edict;
-       cs->drawonlytoclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.drawonlytoclient)->edict;
+       cs->skin = (unsigned)PRVM_serveredictfloat(ent, skin);
+       cs->frame = (unsigned)PRVM_serveredictfloat(ent, frame);
+       cs->viewmodelforclient = PRVM_serveredictedict(ent, viewmodelforclient);
+       cs->exteriormodelforclient = PRVM_serveredictedict(ent, exteriormodeltoclient);
+       cs->nodrawtoclient = PRVM_serveredictedict(ent, nodrawtoclient);
+       cs->drawonlytoclient = PRVM_serveredictedict(ent, drawonlytoclient);
        cs->customizeentityforclient = customizeentityforclient;
-       cs->tagentity = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)->edict;
-       cs->tagindex = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
+       cs->tagentity = PRVM_serveredictedict(ent, tag_entity);
+       cs->tagindex = (unsigned char)PRVM_serveredictfloat(ent, tag_index);
        cs->glowsize = glowsize;
+       cs->traileffectnum = PRVM_serveredictfloat(ent, traileffectnum);
 
        // don't need to init cs->colormod because the defaultstate did that for us
        //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
-       val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod);
-       if (val->vector[0] || val->vector[1] || val->vector[2])
+       v = PRVM_serveredictvector(ent, colormod);
+       if (VectorLength2(v))
        {
-               i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
-               i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
-               i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
+               i = (int)(v[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
+               i = (int)(v[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
+               i = (int)(v[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
        }
 
        // don't need to init cs->glowmod because the defaultstate did that for us
        //cs->glowmod[0] = cs->glowmod[1] = cs->glowmod[2] = 32;
-       val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glowmod);
-       if (val->vector[0] || val->vector[1] || val->vector[2])
+       v = PRVM_serveredictvector(ent, glowmod);
+       if (VectorLength2(v))
        {
-               i = (int)(val->vector[0] * 32.0f);cs->glowmod[0] = bound(0, i, 255);
-               i = (int)(val->vector[1] * 32.0f);cs->glowmod[1] = bound(0, i, 255);
-               i = (int)(val->vector[2] * 32.0f);cs->glowmod[2] = bound(0, i, 255);
+               i = (int)(v[0] * 32.0f);cs->glowmod[0] = bound(0, i, 255);
+               i = (int)(v[1] * 32.0f);cs->glowmod[1] = bound(0, i, 255);
+               i = (int)(v[2] * 32.0f);cs->glowmod[2] = bound(0, i, 255);
        }
 
        cs->modelindex = modelindex;
 
        cs->alpha = 255;
-       f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)->_float * 255.0f);
+       f = (PRVM_serveredictfloat(ent, alpha) * 255.0f);
        if (f)
        {
                i = (int)f;
                cs->alpha = (unsigned char)bound(0, i, 255);
        }
        // halflife
-       f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderamt)->_float);
+       f = (PRVM_serveredictfloat(ent, renderamt));
        if (f)
        {
                i = (int)f;
@@ -1201,7 +1288,7 @@ static qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *c
        }
 
        cs->scale = 16;
-       f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)->_float * 16.0f);
+       f = (PRVM_serveredictfloat(ent, scale) * 16.0f);
        if (f)
        {
                i = (int)f;
@@ -1209,26 +1296,45 @@ static qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *c
        }
 
        cs->glowcolor = 254;
-       f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_color)->_float);
+       f = PRVM_serveredictfloat(ent, glow_color);
        if (f)
                cs->glowcolor = (int)f;
 
-       if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.fullbright)->_float)
+       if (PRVM_serveredictfloat(ent, fullbright))
                cs->effects |= EF_FULLBRIGHT;
 
-       val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.modelflags);
-       if (val && val->_float)
-               cs->effects |= ((unsigned int)val->_float & 0xff) << 24;
+       f = PRVM_serveredictfloat(ent, modelflags);
+       if (f)
+               cs->effects |= ((unsigned int)f & 0xff) << 24;
 
-       if (ent->fields.server->movetype == MOVETYPE_STEP)
+       if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_STEP)
                cs->flags |= RENDER_STEP;
        if (cs->number != sv.writeentitiestoclient_cliententitynumber && (cs->effects & EF_LOWPRECISION) && cs->origin[0] >= -32768 && cs->origin[1] >= -32768 && cs->origin[2] >= -32768 && cs->origin[0] <= 32767 && cs->origin[1] <= 32767 && cs->origin[2] <= 32767)
                cs->flags |= RENDER_LOWPRECISION;
-       if (ent->fields.server->colormap >= 1024)
+       if (PRVM_serveredictfloat(ent, colormap) >= 1024)
                cs->flags |= RENDER_COLORMAPPED;
        if (cs->viewmodelforclient)
                cs->flags |= RENDER_VIEWMODEL; // show relative to the view
 
+       if (PRVM_serveredictfloat(ent, sendcomplexanimation))
+       {
+               cs->flags |= RENDER_COMPLEXANIMATION;
+               if (PRVM_serveredictfloat(ent, skeletonindex) >= 1)
+                       cs->skeletonobject = ent->priv.server->skeleton;
+               cs->framegroupblend[0].frame = PRVM_serveredictfloat(ent, frame);
+               cs->framegroupblend[1].frame = PRVM_serveredictfloat(ent, frame2);
+               cs->framegroupblend[2].frame = PRVM_serveredictfloat(ent, frame3);
+               cs->framegroupblend[3].frame = PRVM_serveredictfloat(ent, frame4);
+               cs->framegroupblend[0].start = PRVM_serveredictfloat(ent, frame1time);
+               cs->framegroupblend[1].start = PRVM_serveredictfloat(ent, frame2time);
+               cs->framegroupblend[2].start = PRVM_serveredictfloat(ent, frame3time);
+               cs->framegroupblend[3].start = PRVM_serveredictfloat(ent, frame4time);
+               cs->framegroupblend[1].lerp = PRVM_serveredictfloat(ent, lerpfrac);
+               cs->framegroupblend[2].lerp = PRVM_serveredictfloat(ent, lerpfrac3);
+               cs->framegroupblend[3].lerp = PRVM_serveredictfloat(ent, lerpfrac4);
+               cs->framegroupblend[0].lerp = 1.0f - cs->framegroupblend[1].lerp - cs->framegroupblend[2].lerp - cs->framegroupblend[3].lerp;
+       }
+
        cs->light[0] = light[0];
        cs->light[1] = light[1];
        cs->light[2] = light[2];
@@ -1263,8 +1369,8 @@ static qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *c
        else
        {
                // if there is no model (or it could not be loaded), use the physics box
-               VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
-               VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
+               VectorAdd(cs->origin, PRVM_serveredictvector(ent, mins), cullmins);
+               VectorAdd(cs->origin, PRVM_serveredictvector(ent, maxs), cullmaxs);
        }
        if (specialvisibilityradius)
        {
@@ -1302,14 +1408,11 @@ static qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *c
        // (to let the QC know that they've been read)
        if (sendentity)
        {
-               val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.SendFlags);
-               sendflags = (unsigned int)val->_float;
-               val->_float = 0;
+               sendflags = (unsigned int)PRVM_serveredictfloat(ent, SendFlags);
+               PRVM_serveredictfloat(ent, SendFlags) = 0;
                // legacy self.Version system
-               val2 = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.Version);
-               if (val2->_float)
+               if ((version = (unsigned int)PRVM_serveredictfloat(ent, Version)))
                {
-                       version = (unsigned int)val2->_float;
                        if (sv.csqcentityversion[enumber] != version)
                                sendflags = 0xFFFFFF;
                        sv.csqcentityversion[enumber] = version;
@@ -1405,16 +1508,16 @@ qboolean SV_CanSeeBox(int numtraces, vec_t enlarge, vec3_t eye, vec3_t entboxmin
        for (touchindex = 0;touchindex < originalnumtouchedicts;touchindex++)
        {
                touch = touchedicts[touchindex];
-               if (touch->fields.server->solid != SOLID_BSP)
+               if (PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
                        continue;
                model = SV_GetModelFromEdict(touch);
                if (!model || !model->brush.TraceLineOfSight)
                        continue;
                // skip obviously transparent entities
-               alpha = PRVM_EDICTFIELDVALUE(touch, prog->fieldoffsets.alpha)->_float;
+               alpha = PRVM_serveredictfloat(touch, alpha);
                if (alpha && alpha < 1)
                        continue;
-               if ((int)touch->fields.server->effects & EF_ADDITIVE)
+               if ((int)PRVM_serveredictfloat(touch, effects) & EF_ADDITIVE)
                        continue;
                touchedicts[numtouchedicts++] = touch;
        }
@@ -1437,7 +1540,7 @@ qboolean SV_CanSeeBox(int numtraces, vec_t enlarge, vec3_t eye, vec3_t entboxmin
                        {
                                // get the entity matrix
                                pitchsign = SV_GetPitchSign(touch);
-                               Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], pitchsign * touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1);
+                               Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], pitchsign * PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1);
                                Matrix4x4_Invert_Simple(&imatrix, &matrix);
                                // see if the ray hits this entity
                                Matrix4x4_Transform(&imatrix, eye, starttransformed);
@@ -1472,8 +1575,8 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s)
 
        if (s->customizeentityforclient)
        {
-               prog->globals.server->self = s->number;
-               prog->globals.server->other = sv.writeentitiestoclient_cliententitynumber;
+               PRVM_serverglobaledict(self) = s->number;
+               PRVM_serverglobaledict(other) = sv.writeentitiestoclient_cliententitynumber;
                PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
                if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
                        return;
@@ -1518,7 +1621,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s)
                        ed = PRVM_EDICT_NUM(s->number);
 
                        // if not touching a visible leaf
-                       if (sv_cullentities_pvs.integer && !r_novis.integer && sv.writeentitiestoclient_pvsbytes)
+                       if (sv_cullentities_pvs.integer && !r_novis.integer && !r_trippy.integer && sv.writeentitiestoclient_pvsbytes)
                        {
                                if (ed->priv.server->pvs_numclusters < 0)
                                {
@@ -1545,7 +1648,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s)
                        }
 
                        // or not seen by random tracelines
-                       if (sv_cullentities_trace.integer && !isbmodel && sv.worldmodel->brush.TraceLineOfSight)
+                       if (sv_cullentities_trace.integer && !isbmodel && sv.worldmodel->brush.TraceLineOfSight && !r_trippy.integer)
                        {
                                int samples =
                                        s->number <= svs.maxclients
@@ -1597,13 +1700,6 @@ void SV_AddCameraEyes(void)
        static int eye_levels[MAX_CLIENTNETWORKEYES];
        int n_cameras = 0;
        vec3_t mi, ma;
-       prvm_eval_t *valendpos, *val;
-
-       if(!prog->fieldoffsets.camera_transform)
-               return;
-       valendpos = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_endpos);
-       if(!valendpos)
-               return;
 
        for(i = 0; i < sv.writeentitiestoclient_numeyes; ++i)
                eye_levels[i] = 0;
@@ -1613,17 +1709,17 @@ void SV_AddCameraEyes(void)
        {
                if (!ed->priv.server->free)
                {
-                       if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.camera_transform)) && val->function)
+                       if(PRVM_serveredictfunction(ed, camera_transform))
                        {
-                               prog->globals.server->self = e;
-                               prog->globals.server->other = sv.writeentitiestoclient_cliententitynumber;
-                               VectorCopy(sv.writeentitiestoclient_eyes[0], valendpos->vector);
+                               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(val->function, "QC function e.camera_transform is missing");
-                               if(!VectorCompare(valendpos->vector, sv.writeentitiestoclient_eyes[0]))
+                               PRVM_ExecuteProgram(PRVM_serveredictfunction(ed, camera_transform), "QC function e.camera_transform is missing");
+                               if(!VectorCompare(PRVM_serverglobalvector(trace_endpos), sv.writeentitiestoclient_eyes[0]))
                                {
-                                       VectorCopy(valendpos->vector, camera_origins[n_cameras]);
+                                       VectorCopy(PRVM_serverglobalvector(trace_endpos), camera_origins[n_cameras]);
                                        cameras[n_cameras] = e;
                                        ++n_cameras;
                                        if(n_cameras >= MAX_LEVELNETWORKEYES)
@@ -1643,8 +1739,8 @@ void SV_AddCameraEyes(void)
                if(!cameras[j])
                        continue;
                ed = PRVM_EDICT_NUM(cameras[j]);
-               VectorAdd(ed->fields.server->origin, ed->fields.server->mins, mi);
-               VectorAdd(ed->fields.server->origin, ed->fields.server->maxs, ma);
+               VectorAdd(PRVM_serveredictvector(ed, origin), PRVM_serveredictvector(ed, mins), mi);
+               VectorAdd(PRVM_serveredictvector(ed, origin), PRVM_serveredictvector(ed, maxs), ma);
                for(k = 0; k < sv.writeentitiestoclient_numeyes; ++k)
                if(eye_levels[k] <= MAX_EYE_RECURSION)
                {
@@ -1692,7 +1788,7 @@ void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *
        // get eye location
        sv.writeentitiestoclient_cliententitynumber = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
        camera = PRVM_EDICT_NUM( client->clientcamera );
-       VectorAdd(camera->fields.server->origin, clent->fields.server->view_ofs, eye);
+       VectorAdd(PRVM_serveredictvector(camera, origin), PRVM_serveredictvector(clent, view_ofs), eye);
        sv.writeentitiestoclient_pvsbytes = 0;
        // get the PVS values for the eye location, later FatPVS calls will merge
        if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
@@ -1707,7 +1803,7 @@ void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *
        {
                vec_t predtime = bound(0, host_client->ping, sv_cullentities_trace_prediction_time.value);
                vec3_t predeye;
-               VectorMA(eye, predtime, camera->fields.server->velocity, predeye);
+               VectorMA(eye, predtime, PRVM_serveredictvector(camera, velocity), predeye);
                if (SV_CanSeeBox(1, 0, eye, predeye, predeye))
                {
                        VectorCopy(predeye, sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes]);
@@ -1802,7 +1898,7 @@ static void SV_CleanupEnts (void)
 
        ent = PRVM_NEXT_EDICT(prog->edicts);
        for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
-               ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
+               PRVM_serveredictfloat(ent, effects) = (int)PRVM_serveredictfloat(ent, effects) & ~EF_MUZZLEFLASH;
 }
 
 /*
@@ -1817,26 +1913,26 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
        int             i;
        prvm_edict_t    *other;
        int             items;
-       prvm_eval_t     *val;
        vec3_t  punchvector;
        int             viewzoom;
        const char *s;
        float   *statsf = (float *)stats;
+       float gravity;
 
 //
 // send a damage message
 //
-       if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
+       if (PRVM_serveredictfloat(ent, dmg_take) || PRVM_serveredictfloat(ent, dmg_save))
        {
-               other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
+               other = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, dmg_inflictor));
                MSG_WriteByte (msg, svc_damage);
-               MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
-               MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
+               MSG_WriteByte (msg, (int)PRVM_serveredictfloat(ent, dmg_save));
+               MSG_WriteByte (msg, (int)PRVM_serveredictfloat(ent, dmg_take));
                for (i=0 ; i<3 ; i++)
-                       MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
+                       MSG_WriteCoord (msg, PRVM_serveredictvector(other, origin)[i] + 0.5*(PRVM_serveredictvector(other, mins)[i] + PRVM_serveredictvector(other, maxs)[i]), sv.protocol);
 
-               ent->fields.server->dmg_take = 0;
-               ent->fields.server->dmg_save = 0;
+               PRVM_serveredictfloat(ent, dmg_take) = 0;
+               PRVM_serveredictfloat(ent, dmg_save) = 0;
        }
 
 //
@@ -1845,15 +1941,15 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
        SV_SetIdealPitch ();            // how much to look up / down ideally
 
 // a fixangle might get lost in a dropped packet.  Oh well.
-       if(ent->fields.server->fixangle)
+       if(PRVM_serveredictfloat(ent, fixangle))
        {
                // angle fixing was requested by global thinking code...
                // so store the current angles for later use
-               memcpy(host_client->fixangle_angles, ent->fields.server->angles, sizeof(host_client->fixangle_angles));
+               memcpy(host_client->fixangle_angles, PRVM_serveredictvector(ent, angles), sizeof(host_client->fixangle_angles));
                host_client->fixangle_angles_set = TRUE;
 
                // and clear fixangle for the next frame
-               ent->fields.server->fixangle = 0;
+               PRVM_serveredictfloat(ent, fixangle) = 0;
        }
 
        if (host_client->fixangle_angles_set)
@@ -1866,71 +1962,68 @@ 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
-       val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.items2);
        if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
-               items = (int)ent->fields.server->items | ((int)val->_float << 23);
+               items = (int)PRVM_serveredictfloat(ent, items) | ((int)PRVM_serveredictfloat(ent, items2) << 23);
        else
-               items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
+               items = (int)PRVM_serveredictfloat(ent, items) | ((int)PRVM_serverglobalfloat(serverflags) << 28);
 
-       VectorClear(punchvector);
-       if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.punchvector)))
-               VectorCopy(val->vector, punchvector);
+       VectorCopy(PRVM_serveredictvector(ent, punchvector), punchvector);
 
        // cache weapon model name and index in client struct to save time
        // (this search can be almost 1% of cpu time!)
-       s = PRVM_GetString(ent->fields.server->weaponmodel);
+       s = PRVM_GetString(PRVM_serveredictstring(ent, weaponmodel));
        if (strcmp(s, client->weaponmodel))
        {
                strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
                client->weaponmodelindex = SV_ModelIndex(s, 1);
        }
 
-       viewzoom = 255;
-       if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewzoom)))
-               viewzoom = (int)(val->_float * 255.0f);
+       viewzoom = (int)(PRVM_serveredictfloat(ent, viewzoom) * 255.0f);
        if (viewzoom == 0)
                viewzoom = 255;
 
        bits = 0;
 
-       if ((int)ent->fields.server->flags & FL_ONGROUND)
+       if ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
                bits |= SU_ONGROUND;
-       if (ent->fields.server->waterlevel >= 2)
+       if (PRVM_serveredictfloat(ent, waterlevel) >= 2)
                bits |= SU_INWATER;
-       if (ent->fields.server->idealpitch)
+       if (PRVM_serveredictfloat(ent, idealpitch))
                bits |= SU_IDEALPITCH;
 
        for (i=0 ; i<3 ; i++)
        {
-               if (ent->fields.server->punchangle[i])
+               if (PRVM_serveredictvector(ent, punchangle)[i])
                        bits |= (SU_PUNCH1<<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)
                        if (punchvector[i])
                                bits |= (SU_PUNCHVEC1<<i);
-               if (ent->fields.server->velocity[i])
+               if (PRVM_serveredictvector(ent, velocity)[i])
                        bits |= (SU_VELOCITY1<<i);
        }
 
+       gravity = PRVM_serveredictfloat(ent, gravity);if (!gravity) gravity = 1.0f;
+
        memset(stats, 0, sizeof(int[MAX_CL_STATS]));
-       stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
+       stats[STAT_VIEWHEIGHT] = (int)PRVM_serveredictvector(ent, view_ofs)[2];
        stats[STAT_ITEMS] = items;
-       stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
-       stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
+       stats[STAT_WEAPONFRAME] = (int)PRVM_serveredictfloat(ent, weaponframe);
+       stats[STAT_ARMOR] = (int)PRVM_serveredictfloat(ent, armorvalue);
        stats[STAT_WEAPON] = client->weaponmodelindex;
-       stats[STAT_HEALTH] = (int)ent->fields.server->health;
-       stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
-       stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
-       stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
-       stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
-       stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
-       stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
+       stats[STAT_HEALTH] = (int)PRVM_serveredictfloat(ent, health);
+       stats[STAT_AMMO] = (int)PRVM_serveredictfloat(ent, currentammo);
+       stats[STAT_SHELLS] = (int)PRVM_serveredictfloat(ent, ammo_shells);
+       stats[STAT_NAILS] = (int)PRVM_serveredictfloat(ent, ammo_nails);
+       stats[STAT_ROCKETS] = (int)PRVM_serveredictfloat(ent, ammo_rockets);
+       stats[STAT_CELLS] = (int)PRVM_serveredictfloat(ent, ammo_cells);
+       stats[STAT_ACTIVEWEAPON] = (int)PRVM_serveredictfloat(ent, weapon);
        stats[STAT_VIEWZOOM] = viewzoom;
-       stats[STAT_TOTALSECRETS] = (int)prog->globals.server->total_secrets;
-       stats[STAT_TOTALMONSTERS] = (int)prog->globals.server->total_monsters;
+       stats[STAT_TOTALSECRETS] = (int)PRVM_serverglobalfloat(total_secrets);
+       stats[STAT_TOTALMONSTERS] = (int)PRVM_serverglobalfloat(total_monsters);
        // the QC bumps these itself by sending svc_'s, so we have to keep them
        // zero or they'll be corrected by the engine
-       //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
-       //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
+       //stats[STAT_SECRETS] = PRVM_serverglobalfloat(found_secrets);
+       //stats[STAT_MONSTERS] = PRVM_serverglobalfloat(killed_monsters);
 
        // movement settings for prediction
        // note: these are not sent in protocols with lower MAX_CL_STATS limits
@@ -1948,13 +2041,13 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
        statsf[STAT_MOVEVARS_ACCELERATE] = sv_accelerate.value;
        statsf[STAT_MOVEVARS_AIRACCELERATE] = sv_airaccelerate.value >= 0 ? sv_airaccelerate.value : sv_accelerate.value;
        statsf[STAT_MOVEVARS_WATERACCELERATE] = sv_wateraccelerate.value >= 0 ? sv_wateraccelerate.value : sv_accelerate.value;
-       val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.gravity);
-       statsf[STAT_MOVEVARS_ENTGRAVITY] = (val && val->_float != 0) ? val->_float : 1.0f;
+       statsf[STAT_MOVEVARS_ENTGRAVITY] = gravity;
        statsf[STAT_MOVEVARS_JUMPVELOCITY] = sv_jumpvelocity.value;
        statsf[STAT_MOVEVARS_EDGEFRICTION] = sv_edgefriction.value;
        statsf[STAT_MOVEVARS_MAXAIRSPEED] = sv_maxairspeed.value;
        statsf[STAT_MOVEVARS_STEPHEIGHT] = sv_stepheight.value;
        statsf[STAT_MOVEVARS_AIRACCEL_QW] = sv_airaccel_qw.value;
+       statsf[STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR] = sv_airaccel_qw_stretchfactor.value;
        statsf[STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION] = sv_airaccel_sideways_friction.value;
        statsf[STAT_MOVEVARS_FRICTION] = sv_friction.value;
        statsf[STAT_MOVEVARS_WATERFRICTION] = sv_waterfriction.value >= 0 ? sv_waterfriction.value : sv_friction.value;
@@ -2004,16 +2097,16 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
                MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
 
        if (bits & SU_IDEALPITCH)
-               MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
+               MSG_WriteChar (msg, (int)PRVM_serveredictfloat(ent, idealpitch));
 
        for (i=0 ; i<3 ; i++)
        {
                if (bits & (SU_PUNCH1<<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)
-                               MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
+                               MSG_WriteChar(msg, (int)PRVM_serveredictvector(ent, punchangle)[i]);
                        else
-                               MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
+                               MSG_WriteAngle16i(msg, PRVM_serveredictvector(ent, punchangle)[i]);
                }
                if (bits & (SU_PUNCHVEC1<<i))
                {
@@ -2025,9 +2118,9 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
                if (bits & (SU_VELOCITY1<<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 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
-                               MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
+                               MSG_WriteChar(msg, (int)(PRVM_serveredictvector(ent, velocity)[i] * (1.0f / 16.0f)));
                        else
-                               MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
+                               MSG_WriteCoord32f(msg, PRVM_serveredictvector(ent, velocity)[i]);
                }
        }
 
@@ -2300,10 +2393,10 @@ static void SV_UpdateToReliableMessages (void)
 {
        int i, j;
        client_t *client;
-       prvm_eval_t *val;
        const char *name;
        const char *model;
        const char *skin;
+       int clientcamera;
 
 // check for changes to be sent over the reliable streams
        for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
@@ -2312,12 +2405,12 @@ static void SV_UpdateToReliableMessages (void)
                host_client->edict = PRVM_EDICT_NUM(i+1);
 
                // DP_SV_CLIENTNAME
-               name = PRVM_GetString(host_client->edict->fields.server->netname);
+               name = PRVM_GetString(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));
-               host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
+               PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(host_client->name);
                if (strcmp(host_client->old_name, host_client->name))
                {
                        if (host_client->spawned)
@@ -2331,9 +2424,7 @@ static void SV_UpdateToReliableMessages (void)
                }
 
                // DP_SV_CLIENTCOLORS
-               // this is always found (since it's added by the progs loader)
-               if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
-                       host_client->colors = (int)val->_float;
+               host_client->colors = (int)PRVM_serveredictfloat(host_client->edict, clientcolors);
                if (host_client->old_colors != host_client->colors)
                {
                        host_client->old_colors = host_client->colors;
@@ -2344,42 +2435,39 @@ static void SV_UpdateToReliableMessages (void)
                }
 
                // NEXUIZ_PLAYERMODEL
-               if( prog->fieldoffsets.playermodel >= 0 ) {
-                       model = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string);
-                       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_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
-               }
+               model = PRVM_GetString(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);
 
                // NEXUIZ_PLAYERSKIN
-               if( prog->fieldoffsets.playerskin >= 0 ) {
-                       skin = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string);
-                       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_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
-               }
+               skin = PRVM_GetString(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);
 
                // TODO: add an extension name for this [1/17/2008 Black]
-               if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcamera)) && val->edict > 0 ) {
+               clientcamera = PRVM_serveredictedict(host_client->edict, clientcamera);
+               if (clientcamera > 0)
+               {
                        int oldclientcamera = host_client->clientcamera;
-                       if( val->edict >= prog->max_edicts || PRVM_EDICT_NUM( val->edict )->priv.required->free ) {
-                               val->edict = host_client->clientcamera = PRVM_NUM_FOR_EDICT( host_client->edict );
-                       } else {
-                               host_client->clientcamera = val->edict;
-                       }
+                       if (clientcamera >= prog->max_edicts || PRVM_EDICT_NUM(clientcamera)->priv.required->free)
+                               clientcamera = PRVM_NUM_FOR_EDICT(host_client->edict);
+                       host_client->clientcamera = clientcamera;
 
-                       if( oldclientcamera != host_client->clientcamera ) {
-                               MSG_WriteByte (&host_client->netconnection->message, svc_setview );
-                               MSG_WriteShort (&host_client->netconnection->message, host_client->clientcamera);
+                       if (oldclientcamera != host_client->clientcamera)
+                       {
+                               MSG_WriteByte(&host_client->netconnection->message, svc_setview);
+                               MSG_WriteShort(&host_client->netconnection->message, host_client->clientcamera);
                        }
                }
 
                // frags
-               host_client->frags = (int)host_client->edict->fields.server->frags;
+               host_client->frags = (int)PRVM_serveredictfloat(host_client->edict, frags);
                if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC)
                        if(!host_client->spawned && host_client->netconnection)
                                host_client->frags = -666;
@@ -2888,7 +2976,7 @@ dp_model_t *SV_GetModelFromEdict(prvm_edict_t *ed)
        int modelindex;
        if (!ed || ed->priv.server->free)
                return NULL;
-       modelindex = (int)ed->fields.server->modelindex;
+       modelindex = (int)PRVM_serveredictfloat(ed, modelindex);
        return (modelindex > 0 && modelindex < MAX_MODELS) ? sv.models[modelindex] : NULL;
 }
 
@@ -2914,14 +3002,14 @@ static void SV_CreateBaseline (void)
 
                if (svent->priv.server->free)
                        continue;
-               if (entnum > svs.maxclients && !svent->fields.server->modelindex)
+               if (entnum > svs.maxclients && !PRVM_serveredictfloat(svent, modelindex))
                        continue;
 
                // create entity baseline
-               VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
-               VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
-               svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
-               svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
+               VectorCopy (PRVM_serveredictvector(svent, origin), svent->priv.server->baseline.origin);
+               VectorCopy (PRVM_serveredictvector(svent, angles), svent->priv.server->baseline.angles);
+               svent->priv.server->baseline.frame = (int)PRVM_serveredictfloat(svent, frame);
+               svent->priv.server->baseline.skin = (int)PRVM_serveredictfloat(svent, skin);
                if (entnum > 0 && entnum <= svs.maxclients)
                {
                        svent->priv.server->baseline.colormap = entnum;
@@ -2930,7 +3018,7 @@ static void SV_CreateBaseline (void)
                else
                {
                        svent->priv.server->baseline.colormap = 0;
-                       svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
+                       svent->priv.server->baseline.modelindex = (int)PRVM_serveredictfloat(svent, modelindex);
                }
 
                large = false;
@@ -3034,7 +3122,7 @@ void SV_SaveSpawnparms (void)
 {
        int             i, j;
 
-       svs.serverflags = (int)prog->globals.server->serverflags;
+       svs.serverflags = (int)PRVM_serverglobalfloat(serverflags);
 
        for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
        {
@@ -3042,10 +3130,10 @@ void SV_SaveSpawnparms (void)
                        continue;
 
        // call the progs to get default spawn parms for the new client
-               prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
-               PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
+               PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
+               PRVM_ExecuteProgram (PRVM_serverfunction(SetChangeParms), "QC function SetChangeParms is missing");
                for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
-                       host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
+                       host_client->spawn_parms[j] = (&PRVM_serverglobalfloat(parm1))[j];
        }
 }
 
@@ -3089,10 +3177,10 @@ void SV_SpawnServer (const char *server)
        {
                SV_VM_Begin();
                World_End(&sv.world);
-               if(prog->funcoffsets.SV_Shutdown)
+               if(PRVM_serverfunction(SV_Shutdown))
                {
-                       func_t s = prog->funcoffsets.SV_Shutdown;
-                       prog->funcoffsets.SV_Shutdown = 0; // prevent it from getting called again
+                       func_t s = PRVM_serverfunction(SV_Shutdown);
+                       PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again
                        PRVM_ExecuteProgram(s,"SV_Shutdown() required");
                }
                SV_VM_End();
@@ -3215,7 +3303,7 @@ void SV_SpawnServer (const char *server)
        prog->allowworldwrites = true;
        sv.paused = false;
 
-       prog->globals.server->time = sv.time = 1.0;
+       PRVM_serverglobalfloat(time) = sv.time = 1.0;
 
        Mod_ClearUsed();
        worldmodel->used = true;
@@ -3246,26 +3334,26 @@ void SV_SpawnServer (const char *server)
 //
        // AK possible hack since num_edicts is still 0
        ent = PRVM_EDICT_NUM(0);
-       memset (ent->fields.server, 0, prog->progs->entityfields * 4);
+       memset (ent->fields.vp, 0, prog->entityfields * 4);
        ent->priv.server->free = false;
-       ent->fields.server->model = PRVM_SetEngineString(sv.worldname);
-       ent->fields.server->modelindex = 1;             // world model
-       ent->fields.server->solid = SOLID_BSP;
-       ent->fields.server->movetype = MOVETYPE_PUSH;
-       VectorCopy(sv.world.mins, ent->fields.server->mins);
-       VectorCopy(sv.world.maxs, ent->fields.server->maxs);
-       VectorCopy(sv.world.mins, ent->fields.server->absmin);
-       VectorCopy(sv.world.maxs, ent->fields.server->absmax);
+       PRVM_serveredictstring(ent, model) = PRVM_SetEngineString(sv.worldname);
+       PRVM_serveredictfloat(ent, modelindex) = 1;             // world model
+       PRVM_serveredictfloat(ent, solid) = SOLID_BSP;
+       PRVM_serveredictfloat(ent, movetype) = MOVETYPE_PUSH;
+       VectorCopy(sv.world.mins, PRVM_serveredictvector(ent, mins));
+       VectorCopy(sv.world.maxs, PRVM_serveredictvector(ent, maxs));
+       VectorCopy(sv.world.mins, PRVM_serveredictvector(ent, absmin));
+       VectorCopy(sv.world.maxs, PRVM_serveredictvector(ent, absmax));
 
        if (coop.value)
-               prog->globals.server->coop = coop.integer;
+               PRVM_serverglobalfloat(coop) = coop.integer;
        else
-               prog->globals.server->deathmatch = deathmatch.integer;
+               PRVM_serverglobalfloat(deathmatch) = deathmatch.integer;
 
-       prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
+       PRVM_serverglobalstring(mapname) = PRVM_SetEngineString(sv.name);
 
 // serverflags are for cross level information (sigils)
-       prog->globals.server->serverflags = svs.serverflags;
+       PRVM_serverglobalfloat(serverflags) = svs.serverflags;
 
        // we need to reset the spawned flag on all connected clients here so that
        // their thinks don't run during startup (before PutClientInServer)
@@ -3290,14 +3378,14 @@ void SV_SpawnServer (const char *server)
 
 
        // LordHavoc: clear world angles (to fix e3m3.bsp)
-       VectorClear(prog->edicts->fields.server->angles);
+       VectorClear(PRVM_serveredictvector(prog->edicts, angles));
 
 // all setup is completed, any further precache statements are errors
 //     sv.state = ss_active; // LordHavoc: workaround for svc_precache bug
        prog->allowworldwrites = false;
 
 // run two frames to allow everything to settle
-       prog->globals.server->time = sv.time = 1.0001;
+       PRVM_serverglobalfloat(time) = sv.time = 1.0001;
        for (i = 0;i < 2;i++)
        {
                sv.frametime = 0.1;
@@ -3332,20 +3420,20 @@ void SV_SpawnServer (const char *server)
 
                        // copy spawn parms out of the client_t
                        for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
-                               (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
+                               (&PRVM_serverglobalfloat(parm1))[j] = host_client->spawn_parms[j];
 
                        // call the spawn function
                        host_client->clientconnectcalled = true;
-                       prog->globals.server->time = sv.time;
-                       prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
-                       PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
-                       PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
+                       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");
                        host_client->spawned = true;
                }
        }
 
        // update the map title cvar
-       strlcpy(sv.worldmessage, PRVM_GetString(prog->edicts->fields.server->message), sizeof(sv.worldmessage)); // map title (not related to filename)
+       strlcpy(sv.worldmessage, PRVM_GetString(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");
@@ -3383,69 +3471,46 @@ static void SV_VM_CB_InitEdict(prvm_edict_t *e)
 
        if (num >= 0 && num < svs.maxclients)
        {
-               prvm_eval_t *val;
                // set colormap and team on newly created player entity
-               e->fields.server->colormap = num + 1;
-               e->fields.server->team = (svs.clients[num].colors & 15) + 1;
+               PRVM_serveredictfloat(e, colormap) = num + 1;
+               PRVM_serveredictfloat(e, team) = (svs.clients[num].colors & 15) + 1;
                // set netname/clientcolors back to client values so that
                // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
                // reset them
-               e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
-               if ((val = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.clientcolors)))
-                       val->_float = svs.clients[num].colors;
+               PRVM_serveredictstring(e, netname) = PRVM_SetEngineString(svs.clients[num].name);
+               PRVM_serveredictfloat(e, clientcolors) = svs.clients[num].colors;
                // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
-               if( prog->fieldoffsets.playermodel >= 0 )
-                       PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
-               if( prog->fieldoffsets.playerskin >= 0 )
-                       PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
+               PRVM_serveredictstring(e, playermodel) = PRVM_SetEngineString(svs.clients[num].playermodel);
+               PRVM_serveredictstring(e, playerskin) = PRVM_SetEngineString(svs.clients[num].playerskin);
                // Assign netaddress (IP Address, etc)
-               if(prog->fieldoffsets.netaddress >= 0)
-               { // Valid Field; Process
-                       if(svs.clients[num].netconnection != NULL)
-                       {// Valid Address; Assign
-                               // Acquire Readable Address
-                               LHNETADDRESS_ToString(&svs.clients[num].netconnection->peeraddress, svs.clients[num].netaddress, sizeof(svs.clients[num].netaddress), false);
-                               PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.netaddress)->string = PRVM_SetEngineString(svs.clients[num].netaddress);
-                       }
-                       else
-                               // Invalid / Bot
-                               PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.netaddress)->string = PRVM_SetEngineString("null/botclient");
-               }
-               if(prog->fieldoffsets.crypto_idfp >= 0)
-               { // Valid Field; Process
-                       if(svs.clients[num].netconnection != NULL && svs.clients[num].netconnection->crypto.authenticated && svs.clients[num].netconnection->crypto.client_idfp[0])
-                               PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.crypto_idfp)->string = PRVM_SetEngineString(svs.clients[num].netconnection->crypto.client_idfp);
-                       else
-                               PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.crypto_idfp)->string = 0;
-               }
-               if(prog->fieldoffsets.crypto_keyfp >= 0)
-               { // Valid Field; Process
-                       if(svs.clients[num].netconnection != NULL && svs.clients[num].netconnection->crypto.authenticated && svs.clients[num].netconnection->crypto.client_keyfp[0])
-                               PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.crypto_keyfp)->string = PRVM_SetEngineString(svs.clients[num].netconnection->crypto.client_keyfp);
-                       else
-                               PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.crypto_keyfp)->string = 0;
-               }
-               if(prog->fieldoffsets.crypto_mykeyfp >= 0)
-               { // Valid Field; Process
-                       if(svs.clients[num].netconnection != NULL && svs.clients[num].netconnection->crypto.authenticated && svs.clients[num].netconnection->crypto.server_keyfp[0])
-                               PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.crypto_mykeyfp)->string = PRVM_SetEngineString(svs.clients[num].netconnection->crypto.server_keyfp);
-                       else
-                               PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.crypto_mykeyfp)->string = 0;
-               }
-               if(prog->fieldoffsets.crypto_encryptmethod >= 0)
-               { // Valid Field; Process
-                       if(svs.clients[num].netconnection != NULL && svs.clients[num].netconnection->crypto.authenticated && svs.clients[num].netconnection->crypto.use_aes)
-                               PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.crypto_encryptmethod)->string = PRVM_SetEngineString("AES128");
-                       else
-                               PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.crypto_encryptmethod)->string = 0;
-               }
-               if(prog->fieldoffsets.crypto_signmethod >= 0)
-               { // Valid Field; Process
-                       if(svs.clients[num].netconnection != NULL && svs.clients[num].netconnection->crypto.authenticated)
-                               PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.crypto_signmethod)->string = PRVM_SetEngineString("HMAC-SHA256");
-                       else
-                               PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.crypto_signmethod)->string = 0;
+               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);
                }
+               else
+                       PRVM_serveredictstring(e, netaddress) = PRVM_SetEngineString("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);
+               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);
+               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);
+               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");
+               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");
+               else
+                       PRVM_serveredictstring(e, crypto_signmethod) = 0;
        }
 }
 
@@ -3456,16 +3521,16 @@ static void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
 
        World_UnlinkEdict(ed);          // unlink from world bsp
 
-       ed->fields.server->model = 0;
-       ed->fields.server->takedamage = 0;
-       ed->fields.server->modelindex = 0;
-       ed->fields.server->colormap = 0;
-       ed->fields.server->skin = 0;
-       ed->fields.server->frame = 0;
-       VectorClear(ed->fields.server->origin);
-       VectorClear(ed->fields.server->angles);
-       ed->fields.server->nextthink = -1;
-       ed->fields.server->solid = 0;
+       PRVM_serveredictstring(ed, model) = 0;
+       PRVM_serveredictfloat(ed, takedamage) = 0;
+       PRVM_serveredictfloat(ed, modelindex) = 0;
+       PRVM_serveredictfloat(ed, colormap) = 0;
+       PRVM_serveredictfloat(ed, skin) = 0;
+       PRVM_serveredictfloat(ed, frame) = 0;
+       VectorClear(PRVM_serveredictvector(ed, origin));
+       VectorClear(PRVM_serveredictvector(ed, angles));
+       PRVM_serveredictfloat(ed, nextthink) = -1;
+       PRVM_serveredictfloat(ed, solid) = 0;
 
        VM_RemoveEdictSkeleton(ed);
        World_Physics_RemoveFromEntity(&sv.world, ed);
@@ -3495,11 +3560,11 @@ static void SV_VM_CB_CountEdicts(void)
                if (ent->priv.server->free)
                        continue;
                active++;
-               if (ent->fields.server->solid)
+               if (PRVM_serveredictfloat(ent, solid))
                        solid++;
-               if (ent->fields.server->model)
+               if (PRVM_serveredictstring(ent, model))
                        models++;
-               if (ent->fields.server->movetype == MOVETYPE_STEP)
+               if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_STEP)
                        step++;
        }
 
@@ -3517,14 +3582,14 @@ static qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
        {
                if (deathmatch.integer)
                {
-                       if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
+                       if (((int)PRVM_serveredictfloat(ent, spawnflags) & SPAWNFLAG_NOT_DEATHMATCH))
                        {
                                return false;
                        }
                }
-               else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY  ))
-                       || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
-                       || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD  )))
+               else if ((current_skill <= 0 && ((int)PRVM_serveredictfloat(ent, spawnflags) & SPAWNFLAG_NOT_EASY  ))
+                       || (current_skill == 1 && ((int)PRVM_serveredictfloat(ent, spawnflags) & SPAWNFLAG_NOT_MEDIUM))
+                       || (current_skill >= 2 && ((int)PRVM_serveredictfloat(ent, spawnflags) & SPAWNFLAG_NOT_HARD  )))
                {
                        return false;
                }
@@ -3542,8 +3607,6 @@ static void SV_VM_Setup(void)
        prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
        prog->builtins = vm_sv_builtins;
        prog->numbuiltins = vm_sv_numbuiltins;
-       prog->headercrc = PROGHEADER_CRC;
-       prog->headercrc2 = PROGHEADER_CRC_TENEBRAE;
        prog->max_edicts = 512;
        if (sv.protocol == PROTOCOL_QUAKE)
                prog->limit_edicts = 640; // before quake mission pack 1 this was 512
@@ -3572,36 +3635,150 @@ static void SV_VM_Setup(void)
        prog->error_cmd = Host_Error;
        prog->ExecuteProgram = SVVM_ExecuteProgram;
 
-       // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
-       PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields, 0, NULL );
+       PRVM_LoadProgs( 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"
        // so we have to set these offsets manually, matching the entvars_t
-       PRVM_ED_FindFieldOffset_FromStruct(entvars_t, angles);
-       PRVM_ED_FindFieldOffset_FromStruct(entvars_t, chain);
-       PRVM_ED_FindFieldOffset_FromStruct(entvars_t, classname);
-       PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frame);
-       PRVM_ED_FindFieldOffset_FromStruct(entvars_t, groundentity);
-       PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ideal_yaw);
-       PRVM_ED_FindFieldOffset_FromStruct(entvars_t, nextthink);
-       PRVM_ED_FindFieldOffset_FromStruct(entvars_t, think);
-       PRVM_ED_FindFieldOffset_FromStruct(entvars_t, yaw_speed);
-       PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, self);
-       PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, time);
-       PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_forward);
-       PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_right);
-       PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_up);
-       PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_allsolid);
-       PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_startsolid);
-       PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_fraction);
-       PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inwater);
-       PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inopen);
-       PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_endpos);
-       PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_normal);
-       PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_dist);
-       PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_ent);
-       // OP_STATE is always supported on server (due to entvars_t)
+       // but we only do this if the prog header crc matches, otherwise it's totally freeform
+       if (prog->progs_crc == PROGHEADER_CRC || prog->progs_crc == PROGHEADER_CRC_TENEBRAE)
+       {
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, modelindex);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, absmin);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, absmax);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ltime);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, movetype);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, solid);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, origin);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, oldorigin);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, velocity);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, angles);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, avelocity);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, punchangle);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, classname);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, model);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frame);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, skin);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, effects);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, mins);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, maxs);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, size);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, touch);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, use);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, think);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, blocked);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, nextthink);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, groundentity);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, health);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frags);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, weapon);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, weaponmodel);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, weaponframe);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, currentammo);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ammo_shells);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ammo_nails);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ammo_rockets);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ammo_cells);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, items);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, takedamage);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, chain);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, deadflag);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, view_ofs);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, button0);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, button1);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, button2);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, impulse);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, fixangle);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, v_angle);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, idealpitch);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, netname);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, enemy);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, flags);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, colormap);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, team);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, max_health);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, teleport_time);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, armortype);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, armorvalue);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, waterlevel);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, watertype);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ideal_yaw);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, yaw_speed);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, aiment);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, goalentity);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, spawnflags);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, target);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, targetname);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, dmg_take);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, dmg_save);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, dmg_inflictor);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, owner);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, movedir);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, message);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, sounds);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, noise);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, noise1);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, noise2);
+               PRVM_ED_FindFieldOffset_FromStruct(entvars_t, noise3);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, self);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, other);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, world);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, time);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, frametime);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, force_retouch);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, mapname);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, deathmatch);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, coop);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, teamplay);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, serverflags);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, total_secrets);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, total_monsters);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, found_secrets);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, killed_monsters);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm1);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm2);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm3);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm4);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm5);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm6);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm7);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm8);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm9);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm10);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm11);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm12);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm13);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm14);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm15);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm16);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_forward);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_up);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_right);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_allsolid);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_startsolid);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_fraction);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_endpos);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_normal);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_dist);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_ent);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inopen);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inwater);
+               PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, msg_entity);
+//             PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, main);
+//             PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, StartFrame);
+//             PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, PlayerPreThink);
+//             PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, PlayerPostThink);
+//             PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, ClientKill);
+//             PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, ClientConnect);
+//             PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, PutClientInServer);
+//             PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, ClientDisconnect);
+//             PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, SetNewParms);
+//             PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, SetChangeParms);
+       }
+       else
+               Con_DPrintf("%s: %s system vars have been modified (CRC %i != engine %i), will not load in other engines", PRVM_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
@@ -3616,7 +3793,7 @@ void SV_VM_Begin(void)
        PRVM_Begin;
        PRVM_SetProg( PRVM_SERVERPROG );
 
-       prog->globals.server->time = (float) sv.time;
+       PRVM_serverglobalfloat(time) = (float) sv.time;
 }
 
 void SV_VM_End(void)
index f8a1cfb6cabe0da5e392ae062a7f850f4fe0d007..d93d1f8b2b6fbc948b30515f9776fac46e1fccc8 100644 (file)
--- a/sv_move.c
+++ b/sv_move.c
@@ -40,8 +40,8 @@ qboolean SV_CheckBottom (prvm_edict_t *ent)
        int             x, y;
        float   mid, bottom;
 
-       VectorAdd (ent->fields.server->origin, ent->fields.server->mins, mins);
-       VectorAdd (ent->fields.server->origin, ent->fields.server->maxs, maxs);
+       VectorAdd (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), mins);
+       VectorAdd (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, maxs), maxs);
 
 // if all of the points under the corners are solid world, don't bother
 // with the tougher checks
@@ -114,39 +114,39 @@ qboolean SV_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean
        prvm_edict_t            *enemy;
 
 // try the move
-       VectorCopy (ent->fields.server->origin, oldorg);
-       VectorAdd (ent->fields.server->origin, move, neworg);
+       VectorCopy (PRVM_serveredictvector(ent, origin), oldorg);
+       VectorAdd (PRVM_serveredictvector(ent, origin), move, neworg);
 
 // flying monsters don't step up
-       if ( (int)ent->fields.server->flags & (FL_SWIM | FL_FLY) )
+       if ( (int)PRVM_serveredictfloat(ent, flags) & (FL_SWIM | FL_FLY) )
        {
        // try one move with vertical motion, then one without
                for (i=0 ; i<2 ; i++)
                {
-                       VectorAdd (ent->fields.server->origin, move, neworg);
+                       VectorAdd (PRVM_serveredictvector(ent, origin), move, neworg);
                        if (noenemy)
                                enemy = prog->edicts;
                        else
                        {
-                               enemy = PRVM_PROG_TO_EDICT(ent->fields.server->enemy);
+                               enemy = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, enemy));
                                if (i == 0 && enemy != prog->edicts)
                                {
-                                       dz = ent->fields.server->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.server->enemy)->fields.server->origin[2];
+                                       dz = PRVM_serveredictvector(ent, origin)[2] - PRVM_serveredictvector(enemy, origin)[2];
                                        if (dz > 40)
                                                neworg[2] -= 8;
                                        if (dz < 30)
                                                neworg[2] += 8;
                                }
                        }
-                       trace = SV_TraceBox(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, neworg, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
+                       trace = SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), neworg, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
 
                        if (trace.fraction == 1)
                        {
                                VectorCopy(trace.endpos, traceendpos);
-                               if (((int)ent->fields.server->flags & FL_SWIM) && !(SV_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
+                               if (((int)PRVM_serveredictfloat(ent, flags) & FL_SWIM) && !(SV_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
                                        return false;   // swim monster left water
 
-                               VectorCopy (traceendpos, ent->fields.server->origin);
+                               VectorCopy (traceendpos, PRVM_serveredictvector(ent, origin));
                                if (relink)
                                {
                                        SV_LinkEdict(ent);
@@ -167,27 +167,27 @@ qboolean SV_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean
        VectorCopy (neworg, end);
        end[2] -= sv_stepheight.value*2;
 
-       trace = SV_TraceBox(neworg, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
+       trace = SV_TraceBox(neworg, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
 
        if (trace.startsolid)
        {
                neworg[2] -= sv_stepheight.value;
-               trace = SV_TraceBox(neworg, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
+               trace = SV_TraceBox(neworg, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
                if (trace.startsolid)
                        return false;
        }
        if (trace.fraction == 1)
        {
        // if monster had the ground pulled out, go ahead and fall
-               if ( (int)ent->fields.server->flags & FL_PARTIALGROUND )
+               if ( (int)PRVM_serveredictfloat(ent, flags) & FL_PARTIALGROUND )
                {
-                       VectorAdd (ent->fields.server->origin, move, ent->fields.server->origin);
+                       VectorAdd (PRVM_serveredictvector(ent, origin), move, PRVM_serveredictvector(ent, origin));
                        if (relink)
                        {
                                SV_LinkEdict(ent);
                                SV_LinkEdict_TouchAreaGrid(ent);
                        }
-                       ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND;
+                       PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
                        return true;
                }
 
@@ -195,11 +195,11 @@ qboolean SV_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean
        }
 
 // check point traces down for dangling corners
-       VectorCopy (trace.endpos, ent->fields.server->origin);
+       VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
 
        if (!SV_CheckBottom (ent))
        {
-               if ( (int)ent->fields.server->flags & FL_PARTIALGROUND )
+               if ( (int)PRVM_serveredictfloat(ent, flags) & FL_PARTIALGROUND )
                {       // entity had floor mostly pulled out from underneath it
                        // and is trying to correct
                        if (relink)
@@ -209,24 +209,24 @@ qboolean SV_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean
                        }
                        return true;
                }
-               VectorCopy (oldorg, ent->fields.server->origin);
+               VectorCopy (oldorg, PRVM_serveredictvector(ent, origin));
                return false;
        }
 
-       if ( (int)ent->fields.server->flags & FL_PARTIALGROUND )
-               ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_PARTIALGROUND;
+       if ( (int)PRVM_serveredictfloat(ent, flags) & FL_PARTIALGROUND )
+               PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_PARTIALGROUND;
 
 // gameplayfix: check if reached pretty steep plane and bail
-       if ( ! ( (int)ent->fields.server->flags & (FL_SWIM | FL_FLY) ) && sv_gameplayfix_nostepmoveonsteepslopes.integer )
+       if ( ! ( (int)PRVM_serveredictfloat(ent, flags) & (FL_SWIM | FL_FLY) ) && sv_gameplayfix_nostepmoveonsteepslopes.integer )
        {
                if (trace.plane.normal[ 2 ] < 0.5)
                {
-                       VectorCopy (oldorg, ent->fields.server->origin);
+                       VectorCopy (oldorg, PRVM_serveredictvector(ent, origin));
                        return false;
                }
        }
 
-       ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
+       PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
 
 // the move is ok
        if (relink)
@@ -255,7 +255,7 @@ qboolean SV_StepDirection (prvm_edict_t *ent, float yaw, float dist)
        vec3_t          move, oldorigin;
        float           delta;
 
-       ent->fields.server->ideal_yaw = yaw;
+       PRVM_serveredictfloat(ent, ideal_yaw) = yaw;
        VM_changeyaw();
 
        yaw = yaw*M_PI*2 / 360;
@@ -263,13 +263,13 @@ qboolean SV_StepDirection (prvm_edict_t *ent, float yaw, float dist)
        move[1] = sin(yaw)*dist;
        move[2] = 0;
 
-       VectorCopy (ent->fields.server->origin, oldorigin);
+       VectorCopy (PRVM_serveredictvector(ent, origin), oldorigin);
        if (SV_movestep (ent, move, false, false, false))
        {
-               delta = ent->fields.server->angles[YAW] - ent->fields.server->ideal_yaw;
+               delta = PRVM_serveredictvector(ent, angles)[YAW] - PRVM_serveredictfloat(ent, ideal_yaw);
                if (delta > 45 && delta < 315)
                {               // not turned far enough, so don't take the step
-                       VectorCopy (oldorigin, ent->fields.server->origin);
+                       VectorCopy (oldorigin, PRVM_serveredictvector(ent, origin));
                }
                SV_LinkEdict(ent);
                SV_LinkEdict_TouchAreaGrid(ent);
@@ -289,7 +289,7 @@ SV_FixCheckBottom
 */
 void SV_FixCheckBottom (prvm_edict_t *ent)
 {
-       ent->fields.server->flags = (int)ent->fields.server->flags | FL_PARTIALGROUND;
+       PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_PARTIALGROUND;
 }
 
 
@@ -307,11 +307,11 @@ void SV_NewChaseDir (prvm_edict_t *actor, prvm_edict_t *enemy, float dist)
        float                   d[3];
        float           tdir, olddir, turnaround;
 
-       olddir = ANGLEMOD((int)(actor->fields.server->ideal_yaw/45)*45);
+       olddir = ANGLEMOD((int)(PRVM_serveredictfloat(actor, ideal_yaw)/45)*45);
        turnaround = ANGLEMOD(olddir - 180);
 
-       deltax = enemy->fields.server->origin[0] - actor->fields.server->origin[0];
-       deltay = enemy->fields.server->origin[1] - actor->fields.server->origin[1];
+       deltax = PRVM_serveredictvector(enemy, origin)[0] - PRVM_serveredictvector(actor, origin)[0];
+       deltay = PRVM_serveredictvector(enemy, origin)[1] - PRVM_serveredictvector(actor, origin)[1];
        if (deltax>10)
                d[1]= 0;
        else if (deltax<-10)
@@ -374,7 +374,7 @@ void SV_NewChaseDir (prvm_edict_t *actor, prvm_edict_t *enemy, float dist)
        if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
                        return;
 
-       actor->fields.server->ideal_yaw = olddir;               // can't move
+       PRVM_serveredictfloat(actor, ideal_yaw) = olddir;               // can't move
 
 // if a bridge was pulled out from underneath a monster, it may not have
 // a valid standing position at all
@@ -417,23 +417,23 @@ void SV_MoveToGoal (void)
 
        VM_SAFEPARMCOUNT(1, SV_MoveToGoal);
 
-       ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
-       goal = PRVM_PROG_TO_EDICT(ent->fields.server->goalentity);
+       ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
+       goal = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, goalentity));
        dist = PRVM_G_FLOAT(OFS_PARM0);
 
-       if ( !( (int)ent->fields.server->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
+       if ( !( (int)PRVM_serveredictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
        {
                PRVM_G_FLOAT(OFS_RETURN) = 0;
                return;
        }
 
 // if the next step hits the enemy, return immediately
-       if ( PRVM_PROG_TO_EDICT(ent->fields.server->enemy) != prog->edicts &&  SV_CloseEnough (ent, goal, dist) )
+       if ( PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, enemy)) != prog->edicts &&  SV_CloseEnough (ent, goal, dist) )
                return;
 
 // bump around...
        if ( (rand()&3)==1 ||
-       !SV_StepDirection (ent, ent->fields.server->ideal_yaw, dist))
+       !SV_StepDirection (ent, PRVM_serveredictfloat(ent, ideal_yaw), dist))
        {
                SV_NewChaseDir (ent, goal, dist);
        }
index 7558be896a987111e13bffa2f26f8f174138c480..7b9d705a4bd3d4270c549774fb6df9c9be38157e 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -52,9 +52,9 @@ int SV_GetPitchSign(prvm_edict_t *ent)
                        model->type == mod_alias
                        :
                        (
-                        (((unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.pflags)->_float) & PFLAGS_FULLDYNAMIC)
+                        (((unsigned char)PRVM_serveredictfloat(ent, pflags)) & PFLAGS_FULLDYNAMIC)
                         ||
-                        ((gamemode == GAME_TENEBRAE) && ((unsigned int)ent->fields.server->effects & (16 | 32)))
+                        ((gamemode == GAME_TENEBRAE) && ((unsigned int)PRVM_serveredictfloat(ent, effects) & (16 | 32)))
                        )
           )
                return -1;
@@ -71,22 +71,21 @@ LINE TESTING IN HULLS
 
 int SV_GenericHitSuperContentsMask(const prvm_edict_t *passedict)
 {
-       prvm_eval_t *val;
        if (passedict)
        {
-               val = PRVM_EDICTFIELDVALUE(passedict, prog->fieldoffsets.dphitcontentsmask);
-               if (val && val->_float)
-                       return (int)val->_float;
-               else if (passedict->fields.server->solid == SOLID_SLIDEBOX)
+               int dphitcontentsmask = (int)PRVM_serveredictfloat(passedict, dphitcontentsmask);
+               if (dphitcontentsmask)
+                       return dphitcontentsmask;
+               else if (PRVM_serveredictfloat(passedict, solid) == SOLID_SLIDEBOX)
                {
-                       if ((int)passedict->fields.server->flags & FL_MONSTER)
+                       if ((int)PRVM_serveredictfloat(passedict, flags) & FL_MONSTER)
                                return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_MONSTERCLIP;
                        else
                                return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP;
                }
-               else if (passedict->fields.server->solid == SOLID_CORPSE)
+               else if (PRVM_serveredictfloat(passedict, solid) == SOLID_CORPSE)
                        return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;
-               else if (passedict->fields.server->solid == SOLID_TRIGGER)
+               else if (PRVM_serveredictfloat(passedict, solid) == SOLID_TRIGGER)
                        return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;
                else
                        return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE;
@@ -170,7 +169,7 @@ trace_t SV_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int
        // precalculate prog value for passedict for comparisons
        passedictprog = PRVM_EDICT_TO_PROG(passedict);
        // precalculate passedict's owner edict pointer for comparisons
-       traceowner = passedict ? PRVM_PROG_TO_EDICT(passedict->fields.server->owner) : 0;
+       traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0;
 
        // clip to entities
        // because this uses World_EntitiestoBox, we know all entity boxes overlap
@@ -186,9 +185,9 @@ trace_t SV_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int
        {
                touch = touchedicts[i];
 
-               if (touch->fields.server->solid < SOLID_BBOX)
+               if (PRVM_serveredictfloat(touch, solid) < SOLID_BBOX)
                        continue;
-               if (type == MOVE_NOMONSTERS && touch->fields.server->solid != SOLID_BSP)
+               if (type == MOVE_NOMONSTERS && PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
                        continue;
 
                if (passedict)
@@ -200,36 +199,36 @@ trace_t SV_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int
                        if (traceowner == touch)
                                continue;
                        // don't clip owner against owned entities
-                       if (passedictprog == touch->fields.server->owner)
+                       if (passedictprog == PRVM_serveredictedict(touch, owner))
                                continue;
                        // don't clip points against points (they can't collide)
-                       if (VectorCompare(touch->fields.server->mins, touch->fields.server->maxs) && (type != MOVE_MISSILE || !((int)touch->fields.server->flags & FL_MONSTER)))
+                       if (VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)))
                                continue;
                }
 
-               bodysupercontents = touch->fields.server->solid == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
+               bodysupercontents = PRVM_serveredictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
 
                // might interact, so do an exact clip
                model = NULL;
-               if ((int) touch->fields.server->solid == SOLID_BSP || type == MOVE_HITMODEL)
+               if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
                {
                        model = SV_GetModelFromEdict(touch);
                        pitchsign = SV_GetPitchSign(touch);
                }
                if (model)
-                       Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], pitchsign * touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1);
+                       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, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2]);
+                       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_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model);
                VM_UpdateEdictSkeleton(touch, model, touch->priv.server->frameblend);
-               if (type == MOVE_MISSILE && (int)touch->fields.server->flags & FL_MONSTER)
-                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touch->fields.server->mins, touch->fields.server->maxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipstart, hitsupercontentsmask);
+               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
-                       Collision_ClipPointToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touch->fields.server->mins, touch->fields.server->maxs, bodysupercontents, &matrix, &imatrix, clipstart, hitsupercontentsmask);
+                       Collision_ClipPointToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, hitsupercontentsmask);
 
-               Collision_CombineTraces(&cliptrace, &trace, (void *)touch, touch->fields.server->solid == SOLID_BSP);
+               Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
        }
 
 finished:
@@ -336,7 +335,7 @@ trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
        // precalculate prog value for passedict for comparisons
        passedictprog = PRVM_EDICT_TO_PROG(passedict);
        // precalculate passedict's owner edict pointer for comparisons
-       traceowner = passedict ? PRVM_PROG_TO_EDICT(passedict->fields.server->owner) : 0;
+       traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0;
 
        // clip to entities
        // because this uses World_EntitiestoBox, we know all entity boxes overlap
@@ -352,9 +351,9 @@ trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
        {
                touch = touchedicts[i];
 
-               if (touch->fields.server->solid < SOLID_BBOX)
+               if (PRVM_serveredictfloat(touch, solid) < SOLID_BBOX)
                        continue;
-               if (type == MOVE_NOMONSTERS && touch->fields.server->solid != SOLID_BSP)
+               if (type == MOVE_NOMONSTERS && PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
                        continue;
 
                if (passedict)
@@ -366,36 +365,36 @@ trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
                        if (traceowner == touch)
                                continue;
                        // don't clip owner against owned entities
-                       if (passedictprog == touch->fields.server->owner)
+                       if (passedictprog == PRVM_serveredictedict(touch, owner))
                                continue;
                        // don't clip points against points (they can't collide)
-                       if (VectorCompare(touch->fields.server->mins, touch->fields.server->maxs) && (type != MOVE_MISSILE || !((int)touch->fields.server->flags & FL_MONSTER)))
+                       if (VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)))
                                continue;
                }
 
-               bodysupercontents = touch->fields.server->solid == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
+               bodysupercontents = PRVM_serveredictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
 
                // might interact, so do an exact clip
                model = NULL;
-               if ((int) touch->fields.server->solid == SOLID_BSP || type == MOVE_HITMODEL)
+               if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
                {
                        model = SV_GetModelFromEdict(touch);
                        pitchsign = SV_GetPitchSign(touch);
                }
                if (model)
-                       Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], pitchsign * touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1);
+                       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, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2]);
+                       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_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model);
                VM_UpdateEdictSkeleton(touch, model, touch->priv.server->frameblend);
-               if (type == MOVE_MISSILE && (int)touch->fields.server->flags & FL_MONSTER)
-                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touch->fields.server->mins, touch->fields.server->maxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
+               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
-                       Collision_ClipLineToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touch->fields.server->mins, touch->fields.server->maxs, bodysupercontents, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, false);
+                       Collision_ClipLineToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, false);
 
-               Collision_CombineTraces(&cliptrace, &trace, (void *)touch, touch->fields.server->solid == SOLID_BSP);
+               Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
        }
 
 finished:
@@ -549,7 +548,7 @@ trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
        // figure out whether this is a point trace for comparisons
        pointtrace = VectorCompare(clipmins, clipmaxs);
        // precalculate passedict's owner edict pointer for comparisons
-       traceowner = passedict ? PRVM_PROG_TO_EDICT(passedict->fields.server->owner) : 0;
+       traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0;
 
        // clip to entities
        // because this uses World_EntitiestoBox, we know all entity boxes overlap
@@ -565,9 +564,9 @@ trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
        {
                touch = touchedicts[i];
 
-               if (touch->fields.server->solid < SOLID_BBOX)
+               if (PRVM_serveredictfloat(touch, solid) < SOLID_BBOX)
                        continue;
-               if (type == MOVE_NOMONSTERS && touch->fields.server->solid != SOLID_BSP)
+               if (type == MOVE_NOMONSTERS && PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
                        continue;
 
                if (passedict)
@@ -579,36 +578,36 @@ trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
                        if (traceowner == touch)
                                continue;
                        // don't clip owner against owned entities
-                       if (passedictprog == touch->fields.server->owner)
+                       if (passedictprog == PRVM_serveredictedict(touch, owner))
                                continue;
                        // don't clip points against points (they can't collide)
-                       if (pointtrace && VectorCompare(touch->fields.server->mins, touch->fields.server->maxs) && (type != MOVE_MISSILE || !((int)touch->fields.server->flags & FL_MONSTER)))
+                       if (pointtrace && VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)))
                                continue;
                }
 
-               bodysupercontents = touch->fields.server->solid == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
+               bodysupercontents = PRVM_serveredictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
 
                // might interact, so do an exact clip
                model = NULL;
-               if ((int) touch->fields.server->solid == SOLID_BSP || type == MOVE_HITMODEL)
+               if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
                {
                        model = SV_GetModelFromEdict(touch);
                        pitchsign = SV_GetPitchSign(touch);
                }
                if (model)
-                       Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], pitchsign * touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1);
+                       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, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2]);
+                       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_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model);
                VM_UpdateEdictSkeleton(touch, model, touch->priv.server->frameblend);
-               if (type == MOVE_MISSILE && (int)touch->fields.server->flags & FL_MONSTER)
-                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touch->fields.server->mins, touch->fields.server->maxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
+               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
-                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touch->fields.server->mins, touch->fields.server->maxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
+                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
 
-               Collision_CombineTraces(&cliptrace, &trace, (void *)touch, touch->fields.server->solid == SOLID_BSP);
+               Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
        }
 
 finished:
@@ -633,7 +632,7 @@ trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
 #if COLLISIONPARANOID < 3
                if (trace.startsolid || endstuck)
 #endif
-                       Con_Printf("%s{e%i:%f %f %f:%f %f %f:%f:%f %f %f%s%s}\n", (trace.startsolid || endstuck) ? "^3" : "", passedict ? (int)(passedict - prog->edicts) : -1, passedict->fields.server->origin[0], passedict->fields.server->origin[1], passedict->fields.server->origin[2], end[0] - passedict->fields.server->origin[0], end[1] - passedict->fields.server->origin[1], end[2] - passedict->fields.server->origin[2], trace.fraction, trace.endpos[0] - passedict->fields.server->origin[0], trace.endpos[1] - passedict->fields.server->origin[1], trace.endpos[2] - passedict->fields.server->origin[2], trace.startsolid ? " startstuck" : "", endstuck ? " endstuck" : "");
+                       Con_Printf("%s{e%i:%f %f %f:%f %f %f:%f:%f %f %f%s%s}\n", (trace.startsolid || endstuck) ? "^3" : "", passedict ? (int)(passedict - prog->edicts) : -1, PRVM_serveredictvector(passedict, origin)[0], PRVM_serveredictvector(passedict, origin)[1], PRVM_serveredictvector(passedict, origin)[2], end[0] - PRVM_serveredictvector(passedict, origin)[0], end[1] - PRVM_serveredictvector(passedict, origin)[1], end[2] - PRVM_serveredictvector(passedict, origin)[2], trace.fraction, trace.endpos[0] - PRVM_serveredictvector(passedict, origin)[0], trace.endpos[1] - PRVM_serveredictvector(passedict, origin)[1], trace.endpos[2] - PRVM_serveredictvector(passedict, origin)[2], trace.startsolid ? " startstuck" : "", endstuck ? " endstuck" : "");
        }
        return trace;
 }
@@ -675,17 +674,17 @@ int SV_PointSuperContents(const vec3_t point)
                touch = touchedicts[i];
 
                // we only care about SOLID_BSP for pointcontents
-               if (touch->fields.server->solid != SOLID_BSP)
+               if (PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
                        continue;
 
                // might interact, so do an exact clip
                model = SV_GetModelFromEdict(touch);
                if (!model || !model->PointSuperContents)
                        continue;
-               Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1);
+               Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1);
                Matrix4x4_Invert_Simple(&imatrix, &matrix);
                Matrix4x4_Transform(&imatrix, point, transformed);
-               frame = (int)touch->fields.server->frame;
+               frame = (int)PRVM_serveredictfloat(touch, frame);
                supercontents |= model->PointSuperContents(model, bound(0, frame, (model->numframes - 1)), transformed);
        }
 
@@ -702,28 +701,23 @@ Linking entities into the world culling system
 
 void SV_LinkEdict_TouchAreaGrid_Call(prvm_edict_t *touch, prvm_edict_t *ent)
 {
-       prvm_eval_t *val;
-       prog->globals.server->self = PRVM_EDICT_TO_PROG(touch);
-       prog->globals.server->other = PRVM_EDICT_TO_PROG(ent);
-       prog->globals.server->time = sv.time;
-       prog->globals.server->trace_allsolid = false;
-       prog->globals.server->trace_startsolid = false;
-       prog->globals.server->trace_fraction = 1;
-       prog->globals.server->trace_inwater = false;
-       prog->globals.server->trace_inopen = true;
-       VectorCopy (touch->fields.server->origin, prog->globals.server->trace_endpos);
-       VectorSet (prog->globals.server->trace_plane_normal, 0, 0, 1);
-       prog->globals.server->trace_plane_dist = 0;
-       prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(ent);
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dpstartcontents)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphitcontents)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphitq3surfaceflags)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphittexturename)))
-               val->string = 0;
-       PRVM_ExecuteProgram (touch->fields.server->touch, "QC function self.touch is missing");
+       PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(touch);
+       PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(ent);
+       PRVM_serverglobalfloat(time) = sv.time;
+       PRVM_serverglobalfloat(trace_allsolid) = false;
+       PRVM_serverglobalfloat(trace_startsolid) = false;
+       PRVM_serverglobalfloat(trace_fraction) = 1;
+       PRVM_serverglobalfloat(trace_inwater) = false;
+       PRVM_serverglobalfloat(trace_inopen) = true;
+       VectorCopy (PRVM_serveredictvector(touch, origin), PRVM_serverglobalvector(trace_endpos));
+       VectorSet (PRVM_serverglobalvector(trace_plane_normal), 0, 0, 1);
+       PRVM_serverglobalfloat(trace_plane_dist) = 0;
+       PRVM_serverglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(ent);
+       PRVM_serverglobalfloat(trace_dpstartcontents) = 0;
+       PRVM_serverglobalfloat(trace_dphitcontents) = 0;
+       PRVM_serverglobalfloat(trace_dphitq3surfaceflags) = 0;
+       PRVM_serverglobalstring(trace_dphittexturename) = 0;
+       PRVM_ExecuteProgram (PRVM_serveredictfunction(touch, touch), "QC function self.touch is missing");
 }
 
 void SV_LinkEdict_TouchAreaGrid(prvm_edict_t *ent)
@@ -738,7 +732,7 @@ void SV_LinkEdict_TouchAreaGrid(prvm_edict_t *ent)
        if (ent->priv.server->free)
                return;
 
-       if (ent->fields.server->solid == SOLID_NOT)
+       if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT)
                return;
 
        // build a list of edicts to touch, because the link loop can be corrupted
@@ -751,18 +745,18 @@ void SV_LinkEdict_TouchAreaGrid(prvm_edict_t *ent)
                numtouchedicts = MAX_EDICTS;
        }
 
-       old_self = prog->globals.server->self;
-       old_other = prog->globals.server->other;
+       old_self = PRVM_serverglobaledict(self);
+       old_other = PRVM_serverglobaledict(other);
        for (i = 0;i < numtouchedicts;i++)
        {
                touch = touchedicts[i];
-               if (touch != ent && (int)touch->fields.server->solid == SOLID_TRIGGER && touch->fields.server->touch)
+               if (touch != ent && (int)PRVM_serveredictfloat(touch, solid) == SOLID_TRIGGER && PRVM_serveredictfunction(touch, touch))
                {
                        SV_LinkEdict_TouchAreaGrid_Call(touch, ent);
                }
        }
-       prog->globals.server->self = old_self;
-       prog->globals.server->other = old_other;
+       PRVM_serverglobaledict(self) = old_self;
+       PRVM_serverglobaledict(other) = old_other;
 }
 
 static void RotateBBox(const vec3_t mins, const vec3_t maxs, const vec3_t angles, vec3_t rotatedmins, vec3_t rotatedmaxs)
@@ -814,7 +808,7 @@ void SV_LinkEdict (prvm_edict_t *ent)
        if (ent->priv.server->free)
                return;
 
-       modelindex = (int)ent->fields.server->modelindex;
+       modelindex = (int)PRVM_serveredictfloat(ent, modelindex);
        if (modelindex < 0 || modelindex >= MAX_MODELS)
        {
                Con_Printf("edict %i: SOLID_BSP with invalid modelindex!\n", PRVM_NUM_FOR_EDICT(ent));
@@ -828,55 +822,55 @@ void SV_LinkEdict (prvm_edict_t *ent)
 
 // set the abs box
 
-       if (ent->fields.server->movetype == MOVETYPE_PHYSICS)
+       if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_PHYSICS)
        {
                // TODO maybe should do this for rotating SOLID_BSP too? Would behave better with rotating doors
                // TODO special handling for spheres?
-               RotateBBox(ent->fields.server->mins, ent->fields.server->maxs, ent->fields.server->angles, mins, maxs);
-               VectorAdd(ent->fields.server->origin, mins, mins);
-               VectorAdd(ent->fields.server->origin, maxs, maxs);
+               RotateBBox(PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, angles), mins, maxs);
+               VectorAdd(PRVM_serveredictvector(ent, origin), mins, mins);
+               VectorAdd(PRVM_serveredictvector(ent, origin), maxs, maxs);
        }
-       else if (ent->fields.server->solid == SOLID_BSP)
+       else if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
        {
                if (model != NULL)
                {
                        if (!model->TraceBox)
                                Con_DPrintf("edict %i: SOLID_BSP with non-collidable model\n", PRVM_NUM_FOR_EDICT(ent));
 
-                       if (ent->fields.server->angles[0] || ent->fields.server->angles[2] || ent->fields.server->avelocity[0] || ent->fields.server->avelocity[2])
+                       if (PRVM_serveredictvector(ent, angles)[0] || PRVM_serveredictvector(ent, angles)[2] || PRVM_serveredictvector(ent, avelocity)[0] || PRVM_serveredictvector(ent, avelocity)[2])
                        {
-                               VectorAdd(ent->fields.server->origin, model->rotatedmins, mins);
-                               VectorAdd(ent->fields.server->origin, model->rotatedmaxs, maxs);
+                               VectorAdd(PRVM_serveredictvector(ent, origin), model->rotatedmins, mins);
+                               VectorAdd(PRVM_serveredictvector(ent, origin), model->rotatedmaxs, maxs);
                        }
-                       else if (ent->fields.server->angles[1] || ent->fields.server->avelocity[1])
+                       else if (PRVM_serveredictvector(ent, angles)[1] || PRVM_serveredictvector(ent, avelocity)[1])
                        {
-                               VectorAdd(ent->fields.server->origin, model->yawmins, mins);
-                               VectorAdd(ent->fields.server->origin, model->yawmaxs, maxs);
+                               VectorAdd(PRVM_serveredictvector(ent, origin), model->yawmins, mins);
+                               VectorAdd(PRVM_serveredictvector(ent, origin), model->yawmaxs, maxs);
                        }
                        else
                        {
-                               VectorAdd(ent->fields.server->origin, model->normalmins, mins);
-                               VectorAdd(ent->fields.server->origin, model->normalmaxs, maxs);
+                               VectorAdd(PRVM_serveredictvector(ent, origin), model->normalmins, mins);
+                               VectorAdd(PRVM_serveredictvector(ent, origin), model->normalmaxs, maxs);
                        }
                }
                else
                {
                        // SOLID_BSP with no model is valid, mainly because some QC setup code does so temporarily
-                       VectorAdd(ent->fields.server->origin, ent->fields.server->mins, mins);
-                       VectorAdd(ent->fields.server->origin, ent->fields.server->maxs, maxs);
+                       VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), mins);
+                       VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, maxs), maxs);
                }
        }
        else
        {
-               VectorAdd(ent->fields.server->origin, ent->fields.server->mins, mins);
-               VectorAdd(ent->fields.server->origin, ent->fields.server->maxs, maxs);
+               VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), mins);
+               VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, maxs), maxs);
        }
 
 //
 // to make items easier to pick up and allow them to be grabbed off
 // of shelves, the abs sizes are expanded
 //
-       if ((int)ent->fields.server->flags & FL_ITEM)
+       if ((int)PRVM_serveredictfloat(ent, flags) & FL_ITEM)
        {
                mins[0] -= 15;
                mins[1] -= 15;
@@ -897,8 +891,8 @@ void SV_LinkEdict (prvm_edict_t *ent)
                maxs[2] += 1;
        }
 
-       VectorCopy(mins, ent->fields.server->absmin);
-       VectorCopy(maxs, ent->fields.server->absmax);
+       VectorCopy(mins, PRVM_serveredictvector(ent, absmin));
+       VectorCopy(maxs, PRVM_serveredictvector(ent, absmax));
 
        World_LinkEdict(&sv.world, ent, mins, maxs);
 }
@@ -924,13 +918,13 @@ static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
        vec3_t org;
        trace_t trace;
        contents = SV_GenericHitSuperContentsMask(ent);
-       VectorAdd(ent->fields.server->origin, offset, org);
-       trace = SV_TraceBox(org, ent->fields.server->mins, ent->fields.server->maxs, ent->fields.server->origin, MOVE_NOMONSTERS, ent, contents);
+       VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
+       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
        {
-               if (sv.worldmodel->brushq1.numclipnodes && !VectorCompare(ent->fields.server->mins, ent->fields.server->maxs))
+               if (sv.worldmodel->brushq1.numclipnodes && !VectorCompare(PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs)))
                {
                        // q1bsp/hlbsp use hulls and if the entity does not exactly match
                        // a hull size it is incorrectly tested, so this code tries to
@@ -938,8 +932,8 @@ static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
                        // FIXME: this breaks entities larger than the hull size
                        int i;
                        vec3_t v, m1, m2, s;
-                       VectorAdd(org, ent->fields.server->mins, m1);
-                       VectorAdd(org, ent->fields.server->maxs, m2);
+                       VectorAdd(org, PRVM_serveredictvector(ent, mins), m1);
+                       VectorAdd(org, PRVM_serveredictvector(ent, maxs), m2);
                        VectorSubtract(m2, m1, s);
 #define EPSILON (1.0f / 32.0f)
                        if (s[0] >= EPSILON*2) {m1[0] += EPSILON;m2[0] -= EPSILON;}
@@ -956,19 +950,19 @@ static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
                }
        }
        // if the trace found a better position for the entity, move it there
-       if (VectorDistance2(trace.endpos, ent->fields.server->origin) >= 0.0001)
+       if (VectorDistance2(trace.endpos, PRVM_serveredictvector(ent, origin)) >= 0.0001)
        {
 #if 0
                // please switch back to this code when trace.endpos sometimes being in solid bug is fixed
-               VectorCopy(trace.endpos, ent->fields.server->origin);
+               VectorCopy(trace.endpos, PRVM_serveredictvector(ent, origin));
 #else
                // verify if the endpos is REALLY outside solid
                VectorCopy(trace.endpos, org);
-               trace = SV_TraceBox(org, ent->fields.server->mins, ent->fields.server->maxs, org, MOVE_NOMONSTERS, ent, contents);
+               trace = SV_TraceBox(org, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), org, MOVE_NOMONSTERS, ent, contents);
                if(trace.startsolid)
                        Con_Printf("SV_TestEntityPosition: trace.endpos detected to be in solid. NOT using it.\n");
                else
-                       VectorCopy(org, ent->fields.server->origin);
+                       VectorCopy(org, PRVM_serveredictvector(ent, origin));
 #endif
        }
        return false;
@@ -990,10 +984,11 @@ void SV_CheckAllEnts (void)
        {
                if (check->priv.server->free)
                        continue;
-               if (check->fields.server->movetype == MOVETYPE_PUSH
-                || check->fields.server->movetype == MOVETYPE_NONE
-                || check->fields.server->movetype == MOVETYPE_FOLLOW
-                || check->fields.server->movetype == MOVETYPE_NOCLIP)
+               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
+                || PRVM_serveredictfloat(check, movetype) == MOVETYPE_FLY_WORLDONLY)
                        continue;
 
                if (SV_TestEntityPosition (check, vec3_origin))
@@ -1012,29 +1007,26 @@ returns true if entity had a valid contentstransition function call
 int SV_CheckContentsTransition(prvm_edict_t *ent, const int nContents)
 {
        int bValidFunctionCall;
-       prvm_eval_t *contentstransition;
 
        // Default Valid Function Call to False
        bValidFunctionCall = false;
 
-       if(ent->fields.server->watertype != nContents)
+       if(PRVM_serveredictfloat(ent, watertype) != nContents)
        { // Changed Contents
                // Acquire Contents Transition Function from QC
-               contentstransition = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.contentstransition);
-
-               if(contentstransition->function)
+               if(PRVM_serveredictfunction(ent, contentstransition))
                { // Valid Function; Execute
                        // Assign Valid Function
                        bValidFunctionCall = true;
                        // Prepare Parameters (Original Contents, New Contents)
                                // Original Contents
-                               PRVM_G_FLOAT(OFS_PARM0) = ent->fields.server->watertype;
+                               PRVM_G_FLOAT(OFS_PARM0) = PRVM_serveredictfloat(ent, watertype);
                                // New Contents
                                PRVM_G_FLOAT(OFS_PARM1) = nContents;
                                // Assign Self
-                               prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
+                               PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
                        // Execute VM Function
-                       PRVM_ExecuteProgram(contentstransition->function, "contentstransition: NULL function");
+                       PRVM_ExecuteProgram(PRVM_serveredictfunction(ent, contentstransition), "contentstransition: NULL function");
                }
        }
 
@@ -1058,32 +1050,32 @@ void SV_CheckVelocity (prvm_edict_t *ent)
 //
        for (i=0 ; i<3 ; i++)
        {
-               if (IS_NAN(ent->fields.server->velocity[i]))
+               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(ent->fields.server->classname));
-                       ent->fields.server->velocity[i] = 0;
+                       Con_Printf("Got a NaN velocity on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
+                       PRVM_serveredictvector(ent, velocity)[i] = 0;
                }
-               if (IS_NAN(ent->fields.server->origin[i]))
+               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(ent->fields.server->classname));
-                       ent->fields.server->origin[i] = 0;
+                       Con_Printf("Got a NaN origin on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
+                       PRVM_serveredictvector(ent, origin)[i] = 0;
                }
        }
 
        // LordHavoc: a hack to ensure that the (rather silly) id1 quakec
        // player_run/player_stand1 does not horribly malfunction if the
        // velocity becomes a denormalized float
-       if (VectorLength2(ent->fields.server->velocity) < 0.0001)
-               VectorClear(ent->fields.server->velocity);
+       if (VectorLength2(PRVM_serveredictvector(ent, velocity)) < 0.0001)
+               VectorClear(PRVM_serveredictvector(ent, velocity));
 
        // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
-       wishspeed = DotProduct(ent->fields.server->velocity, ent->fields.server->velocity);
+       wishspeed = DotProduct(PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, velocity));
        if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
        {
                wishspeed = sv_maxvelocity.value / sqrt(wishspeed);
-               ent->fields.server->velocity[0] *= wishspeed;
-               ent->fields.server->velocity[1] *= wishspeed;
-               ent->fields.server->velocity[2] *= wishspeed;
+               PRVM_serveredictvector(ent, velocity)[0] *= wishspeed;
+               PRVM_serveredictvector(ent, velocity)[1] *= wishspeed;
+               PRVM_serveredictvector(ent, velocity)[2] *= wishspeed;
        }
 }
 
@@ -1103,21 +1095,21 @@ qboolean SV_RunThink (prvm_edict_t *ent)
 
        // don't let things stay in the past.
        // it is possible to start that way by a trigger with a local time.
-       if (ent->fields.server->nextthink <= 0 || ent->fields.server->nextthink > sv.time + sv.frametime)
+       if (PRVM_serveredictfloat(ent, nextthink) <= 0 || PRVM_serveredictfloat(ent, nextthink) > sv.time + sv.frametime)
                return true;
 
        for (iterations = 0;iterations < 128  && !ent->priv.server->free;iterations++)
        {
-               prog->globals.server->time = max(sv.time, ent->fields.server->nextthink);
-               ent->fields.server->nextthink = 0;
-               prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
-               prog->globals.server->other = PRVM_EDICT_TO_PROG(prog->edicts);
-               PRVM_ExecuteProgram (ent->fields.server->think, "QC function self.think is missing");
+               PRVM_serverglobalfloat(time) = max(sv.time, PRVM_serveredictfloat(ent, nextthink));
+               PRVM_serveredictfloat(ent, nextthink) = 0;
+               PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
+               PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
+               PRVM_ExecuteProgram (PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
                // mods often set nextthink to time to cause a think every frame,
                // we don't want to loop in that case, so exit if the new nextthink is
                // <= the time the qc was told, also exit if it is past the end of the
                // frame
-               if (ent->fields.server->nextthink <= prog->globals.server->time || ent->fields.server->nextthink > sv.time + sv.frametime || !sv_gameplayfix_multiplethinksperframe.integer)
+               if (PRVM_serveredictfloat(ent, nextthink) <= PRVM_serverglobalfloat(time) || PRVM_serveredictfloat(ent, nextthink) > sv.time + sv.frametime || !sv_gameplayfix_multiplethinksperframe.integer)
                        break;
        }
        return !ent->priv.server->free;
@@ -1137,43 +1129,38 @@ void SV_Impact (prvm_edict_t *e1, trace_t *trace)
        int restorevm_tempstringsbuf_cursize;
        int old_self, old_other;
        prvm_edict_t *e2 = (prvm_edict_t *)trace->ent;
-       prvm_eval_t *val;
 
-       old_self = prog->globals.server->self;
-       old_other = prog->globals.server->other;
+       old_self = PRVM_serverglobaledict(self);
+       old_other = PRVM_serverglobaledict(other);
        restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
 
        VM_SetTraceGlobals(trace);
 
-       prog->globals.server->time = sv.time;
-       if (!e1->priv.server->free && !e2->priv.server->free && e1->fields.server->touch && e1->fields.server->solid != SOLID_NOT)
+       PRVM_serverglobalfloat(time) = sv.time;
+       if (!e1->priv.server->free && !e2->priv.server->free && PRVM_serveredictfunction(e1, touch) && PRVM_serveredictfloat(e1, solid) != SOLID_NOT)
        {
-               prog->globals.server->self = PRVM_EDICT_TO_PROG(e1);
-               prog->globals.server->other = PRVM_EDICT_TO_PROG(e2);
-               PRVM_ExecuteProgram (e1->fields.server->touch, "QC function self.touch is missing");
+               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");
        }
 
-       if (!e1->priv.server->free && !e2->priv.server->free && e2->fields.server->touch && e2->fields.server->solid != SOLID_NOT)
+       if (!e1->priv.server->free && !e2->priv.server->free && PRVM_serveredictfunction(e2, touch) && PRVM_serveredictfloat(e2, solid) != SOLID_NOT)
        {
-               prog->globals.server->self = PRVM_EDICT_TO_PROG(e2);
-               prog->globals.server->other = PRVM_EDICT_TO_PROG(e1);
-               VectorCopy(e2->fields.server->origin, prog->globals.server->trace_endpos);
-               VectorNegate(trace->plane.normal, prog->globals.server->trace_plane_normal);
-               prog->globals.server->trace_plane_dist = -trace->plane.dist;
-               prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(e1);
-               if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dpstartcontents)))
-                       val->_float = 0;
-               if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphitcontents)))
-                       val->_float = 0;
-               if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphitq3surfaceflags)))
-                       val->_float = 0;
-               if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphittexturename)))
-                       val->string = 0;
-               PRVM_ExecuteProgram (e2->fields.server->touch, "QC function self.touch is missing");
+               PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(e2);
+               PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(e1);
+               VectorCopy(PRVM_serveredictvector(e2, origin), PRVM_serverglobalvector(trace_endpos));
+               VectorNegate(trace->plane.normal, PRVM_serverglobalvector(trace_plane_normal));
+               PRVM_serverglobalfloat(trace_plane_dist) = -trace->plane.dist;
+               PRVM_serverglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(e1);
+               PRVM_serverglobalfloat(trace_dpstartcontents) = 0;
+               PRVM_serverglobalfloat(trace_dphitcontents) = 0;
+               PRVM_serverglobalfloat(trace_dphitq3surfaceflags) = 0;
+               PRVM_serverglobalstring(trace_dphittexturename) = 0;
+               PRVM_ExecuteProgram (PRVM_serveredictfunction(e2, touch), "QC function self.touch is missing");
        }
 
-       prog->globals.server->self = old_self;
-       prog->globals.server->other = old_other;
+       PRVM_serverglobaledict(self) = old_self;
+       PRVM_serverglobaledict(other) = old_other;
        vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
 }
 
@@ -1232,7 +1219,7 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo
        gravity = 0;
 
        if(sv_gameplayfix_nogravityonground.integer)
-               if((int)ent->fields.server->flags & FL_ONGROUND)
+               if((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
                        applygravity = false;
 
        if (applygravity)
@@ -1240,25 +1227,25 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo
                if (sv_gameplayfix_gravityunaffectedbyticrate.integer)
                {
                        gravity = SV_Gravity(ent) * 0.5f;
-                       ent->fields.server->velocity[2] -= gravity;
+                       PRVM_serveredictvector(ent, velocity)[2] -= gravity;
                }
                else
                {
                        applygravity = false;
-                       ent->fields.server->velocity[2] -= SV_Gravity(ent);
+                       PRVM_serveredictvector(ent, velocity)[2] -= SV_Gravity(ent);
                }
        }
        blocked = 0;
-       VectorCopy(ent->fields.server->velocity, original_velocity);
-       VectorCopy(ent->fields.server->velocity, primal_velocity);
+       VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
+       VectorCopy(PRVM_serveredictvector(ent, velocity), primal_velocity);
        numplanes = 0;
        time_left = time;
        for (bumpcount = 0;bumpcount < MAX_CLIP_PLANES;bumpcount++)
        {
-               if (!ent->fields.server->velocity[0] && !ent->fields.server->velocity[1] && !ent->fields.server->velocity[2])
+               if (!PRVM_serveredictvector(ent, velocity)[0] && !PRVM_serveredictvector(ent, velocity)[1] && !PRVM_serveredictvector(ent, velocity)[2])
                        break;
 
-               VectorScale(ent->fields.server->velocity, time_left, push);
+               VectorScale(PRVM_serveredictvector(ent, velocity), time_left, push);
                if(!SV_PushEntity(&trace, ent, push, false, false))
                {
                        // we got teleported by a touch function
@@ -1282,8 +1269,8 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo
                                        trace.ent = prog->edicts;
                                }
 
-                               ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
-                               ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
+                               PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
+                               PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
                        }
                }
                else if (stepheight)
@@ -1294,42 +1281,42 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo
                        trace_t steptrace;
                        trace_t steptrace2;
                        trace_t steptrace3;
-                       //Con_Printf("step %f %f %f : ", ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2]);
+                       //Con_Printf("step %f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
                        VectorSet(steppush, 0, 0, stepheight);
-                       VectorCopy(ent->fields.server->origin, org);
+                       VectorCopy(PRVM_serveredictvector(ent, origin), org);
                        if(!SV_PushEntity(&steptrace, ent, steppush, false, false))
                        {
                                blocked |= 8;
                                break;
                        }
-                       //Con_Printf("%f %f %f : ", ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2]);
+                       //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
                        if(!SV_PushEntity(&steptrace2, ent, push, false, false))
                        {
                                blocked |= 8;
                                break;
                        }
-                       //Con_Printf("%f %f %f : ", ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2]);
-                       VectorSet(steppush, 0, 0, org[2] - ent->fields.server->origin[2]);
+                       //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
+                       VectorSet(steppush, 0, 0, org[2] - PRVM_serveredictvector(ent, origin)[2]);
                        if(!SV_PushEntity(&steptrace3, ent, steppush, false, false))
                        {
                                blocked |= 8;
                                break;
                        }
-                       //Con_Printf("%f %f %f : ", ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2]);
+                       //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
                        // accept the new position if it made some progress...
-                       if (fabs(ent->fields.server->origin[0] - org[0]) >= 0.03125 || fabs(ent->fields.server->origin[1] - org[1]) >= 0.03125)
+                       if (fabs(PRVM_serveredictvector(ent, origin)[0] - org[0]) >= 0.03125 || fabs(PRVM_serveredictvector(ent, origin)[1] - org[1]) >= 0.03125)
                        {
-                               //Con_Printf("accepted (delta %f %f %f)\n", ent->fields.server->origin[0] - org[0], ent->fields.server->origin[1] - org[1], ent->fields.server->origin[2] - org[2]);
+                               //Con_Printf("accepted (delta %f %f %f)\n", PRVM_serveredictvector(ent, origin)[0] - org[0], PRVM_serveredictvector(ent, origin)[1] - org[1], PRVM_serveredictvector(ent, origin)[2] - org[2]);
                                trace = steptrace2;
-                               VectorCopy(ent->fields.server->origin, trace.endpos);
+                               VectorCopy(PRVM_serveredictvector(ent, origin), trace.endpos);
                                time_left *= 1 - trace.fraction;
                                numplanes = 0;
                                continue;
                        }
                        else
                        {
-                               //Con_Printf("REJECTED (delta %f %f %f)\n", ent->fields.server->origin[0] - org[0], ent->fields.server->origin[1] - org[1], ent->fields.server->origin[2] - org[2]);
-                               VectorCopy(org, ent->fields.server->origin);
+                               //Con_Printf("REJECTED (delta %f %f %f)\n", PRVM_serveredictvector(ent, origin)[0] - org[0], PRVM_serveredictvector(ent, origin)[1] - org[1], PRVM_serveredictvector(ent, origin)[2] - org[2]);
+                               VectorCopy(org, PRVM_serveredictvector(ent, origin));
                        }
                }
                else
@@ -1343,7 +1330,7 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo
                if (trace.fraction >= 0.001)
                {
                        // actually covered some distance
-                       VectorCopy(ent->fields.server->velocity, original_velocity);
+                       VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
                        numplanes = 0;
                }
 
@@ -1353,7 +1340,7 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo
                if (numplanes >= MAX_CLIP_PLANES)
                {
                        // this shouldn't really happen
-                       VectorClear(ent->fields.server->velocity);
+                       VectorClear(PRVM_serveredictvector(ent, velocity));
                        blocked = 3;
                        break;
                }
@@ -1364,7 +1351,7 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo
                                break;
                if (i < numplanes)
                {
-                       VectorAdd(ent->fields.server->velocity, trace.plane.normal, ent->fields.server->velocity);
+                       VectorAdd(PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity));
                        continue;
                }
                */
@@ -1392,49 +1379,49 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo
                if (i != numplanes)
                {
                        // go along this plane
-                       VectorCopy(new_velocity, ent->fields.server->velocity);
+                       VectorCopy(new_velocity, PRVM_serveredictvector(ent, velocity));
                }
                else
                {
                        // go along the crease
                        if (numplanes != 2)
                        {
-                               VectorClear(ent->fields.server->velocity);
+                               VectorClear(PRVM_serveredictvector(ent, velocity));
                                blocked = 7;
                                break;
                        }
                        CrossProduct(planes[0], planes[1], dir);
                        // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
                        VectorNormalize(dir);
-                       d = DotProduct(dir, ent->fields.server->velocity);
-                       VectorScale(dir, d, ent->fields.server->velocity);
+                       d = DotProduct(dir, PRVM_serveredictvector(ent, velocity));
+                       VectorScale(dir, d, PRVM_serveredictvector(ent, velocity));
                }
 
                // if current velocity is against the original velocity,
                // stop dead to avoid tiny occilations in sloping corners
-               if (DotProduct(ent->fields.server->velocity, primal_velocity) <= 0)
+               if (DotProduct(PRVM_serveredictvector(ent, velocity), primal_velocity) <= 0)
                {
-                       VectorClear(ent->fields.server->velocity);
+                       VectorClear(PRVM_serveredictvector(ent, velocity));
                        break;
                }
        }
 
-       //Con_Printf("entity %i final: blocked %i velocity %f %f %f\n", ent - prog->edicts, blocked, ent->fields.server->velocity[0], ent->fields.server->velocity[1], ent->fields.server->velocity[2]);
+       //Con_Printf("entity %i final: blocked %i velocity %f %f %f\n", ent - prog->edicts, blocked, PRVM_serveredictvector(ent, velocity)[0], PRVM_serveredictvector(ent, velocity)[1], PRVM_serveredictvector(ent, velocity)[2]);
 
        /*
        if ((blocked & 1) == 0 && bumpcount > 1)
        {
                // LordHavoc: fix the 'fall to your death in a wedge corner' glitch
                // flag ONGROUND if there's ground under it
-               trace = SV_TraceBox(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent, hitsupercontentsmask);
+               trace = SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, hitsupercontentsmask);
        }
        */
 
        // LordHavoc: this came from QW and allows you to get out of water more easily
-       if (sv_gameplayfix_easierwaterjump.integer && ((int)ent->fields.server->flags & FL_WATERJUMP) && !(blocked & 8))
-               VectorCopy(primal_velocity, ent->fields.server->velocity);
-       if (applygravity && !((int)ent->fields.server->flags & FL_ONGROUND))
-               ent->fields.server->velocity[2] -= gravity;
+       if (sv_gameplayfix_easierwaterjump.integer && ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP) && !(blocked & 8))
+               VectorCopy(primal_velocity, PRVM_serveredictvector(ent, velocity));
+       if (applygravity && !((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
+               PRVM_serveredictvector(ent, velocity)[2] -= gravity;
        return blocked;
 }
 
@@ -1447,13 +1434,10 @@ SV_Gravity
 static float SV_Gravity (prvm_edict_t *ent)
 {
        float ent_gravity;
-       prvm_eval_t *val;
 
-       val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.gravity);
-       if (val!=0 && val->_float)
-               ent_gravity = val->_float;
-       else
-               ent_gravity = 1.0;
+       ent_gravity = PRVM_serveredictfloat(ent, gravity);
+       if (!ent_gravity)
+               ent_gravity = 1.0f;
        return ent_gravity * sv_gravity.value * sv.frametime;
 }
 
@@ -1466,6 +1450,120 @@ PUSHMOVE
 ===============================================================================
 */
 
+static qboolean SV_NudgeOutOfSolid_PivotIsKnownGood(prvm_edict_t *ent, vec3_t pivot)
+{
+       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)
+{
+       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
@@ -1477,48 +1575,51 @@ 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)
 {
+       int solid;
+       int movetype;
        int type;
-       int bump;
+       vec3_t mins, maxs;
        vec3_t original, original_velocity;
+       vec3_t start;
        vec3_t end;
 
-       VectorCopy(ent->fields.server->origin, original);
-       VectorAdd (ent->fields.server->origin, push, end);
+       solid = (int)PRVM_serveredictfloat(ent, solid);
+       movetype = (int)PRVM_serveredictfloat(ent, movetype);
+       VectorCopy(PRVM_serveredictvector(ent, mins), mins);
+       VectorCopy(PRVM_serveredictvector(ent, maxs), maxs);
+
+       // move start position out of solids
+       if (sv_gameplayfix_nudgeoutofsolid.integer && sv_gameplayfix_nudgeoutofsolid_separation.value >= 0)
+       {
+               SV_NudgeOutOfSolid(ent);
+       }
+
+       VectorCopy(PRVM_serveredictvector(ent, origin), start);
+       VectorAdd(start, push, end);
 
-       if (ent->fields.server->movetype == MOVETYPE_FLYMISSILE)
+       if (movetype == MOVETYPE_FLYMISSILE)
                type = MOVE_MISSILE;
-       else if (ent->fields.server->solid == SOLID_TRIGGER || ent->fields.server->solid == SOLID_NOT)
+       else if (movetype == MOVETYPE_FLY_WORLDONLY)
+               type = MOVE_WORLDONLY;
+       else if (solid == SOLID_TRIGGER || solid == SOLID_NOT)
                type = MOVE_NOMONSTERS; // only clip against bmodels
        else
                type = MOVE_NORMAL;
 
-       *trace = SV_TraceBox(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent));
-       bump = 0;
-       while (trace->bmodelstartsolid && sv_gameplayfix_nudgeoutofsolid.integer)
-       {
-               vec_t nudge = -trace->startdepth + sv_gameplayfix_nudgeoutofsolid_bias.value;
-               VectorMA(ent->fields.server->origin, nudge, trace->startdepthnormal, ent->fields.server->origin);
-               *trace = SV_TraceBox(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent));
-               bump++;
-               if (bump > 10)
-               {
-                       VectorCopy(original, ent->fields.server->origin);
-                       break;
-               }
-       }
+       *trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent));
        if (trace->bmodelstartsolid && failonbmodelstartsolid)
                return true;
 
-       VectorCopy (trace->endpos, ent->fields.server->origin);
+       VectorCopy(trace->endpos, PRVM_serveredictvector(ent, origin));
 
-       VectorCopy(ent->fields.server->origin, original);
-       VectorCopy(ent->fields.server->velocity, original_velocity);
+       VectorCopy(PRVM_serveredictvector(ent, origin), original);
+       VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
 
        SV_LinkEdict(ent);
 
 #if 0
        if(!trace->startsolid)
-       if(SV_TraceBox(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, ent->fields.server->origin, type, ent, SV_GenericHitSuperContentsMask(ent)).startsolid)
+       if(SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, origin), type, ent, SV_GenericHitSuperContentsMask(ent)).startsolid)
        {
                Con_Printf("something eeeeevil happened\n");
        }
@@ -1527,10 +1628,10 @@ static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, q
        if (dolink)
                SV_LinkEdict_TouchAreaGrid(ent);
 
-       if((ent->fields.server->solid >= SOLID_TRIGGER && trace->ent && (!((int)ent->fields.server->flags & FL_ONGROUND) || ent->fields.server->groundentity != PRVM_EDICT_TO_PROG(trace->ent))))
+       if((PRVM_serveredictfloat(ent, solid) >= SOLID_TRIGGER && trace->ent && (!((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND) || PRVM_serveredictedict(ent, groundentity) != PRVM_EDICT_TO_PROG(trace->ent))))
                SV_Impact (ent, trace);
 
-       return VectorCompare(ent->fields.server->origin, original) && VectorCompare(ent->fields.server->velocity, original_velocity);
+       return VectorCompare(PRVM_serveredictvector(ent, origin), original) && VectorCompare(PRVM_serveredictvector(ent, velocity), original_velocity);
 }
 
 
@@ -1555,14 +1656,15 @@ 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 (!pusher->fields.server->velocity[0] && !pusher->fields.server->velocity[1] && !pusher->fields.server->velocity[2] && !pusher->fields.server->avelocity[0] && !pusher->fields.server->avelocity[1] && !pusher->fields.server->avelocity[2])
+       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])
        {
-               pusher->fields.server->ltime += movetime;
+               PRVM_serveredictfloat(pusher, ltime) += movetime;
                return;
        }
 
-       switch ((int) pusher->fields.server->solid)
+       switch ((int) PRVM_serveredictfloat(pusher, solid))
        {
        // LordHavoc: valid pusher types
        case SOLID_BSP:
@@ -1573,46 +1675,46 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
        // LordHavoc: no collisions
        case SOLID_NOT:
        case SOLID_TRIGGER:
-               VectorMA (pusher->fields.server->origin, movetime, pusher->fields.server->velocity, pusher->fields.server->origin);
-               VectorMA (pusher->fields.server->angles, movetime, pusher->fields.server->avelocity, pusher->fields.server->angles);
-               pusher->fields.server->angles[0] -= 360.0 * floor(pusher->fields.server->angles[0] * (1.0 / 360.0));
-               pusher->fields.server->angles[1] -= 360.0 * floor(pusher->fields.server->angles[1] * (1.0 / 360.0));
-               pusher->fields.server->angles[2] -= 360.0 * floor(pusher->fields.server->angles[2] * (1.0 / 360.0));
-               pusher->fields.server->ltime += movetime;
+               VectorMA (PRVM_serveredictvector(pusher, origin), movetime, PRVM_serveredictvector(pusher, velocity), PRVM_serveredictvector(pusher, origin));
+               VectorMA (PRVM_serveredictvector(pusher, angles), movetime, PRVM_serveredictvector(pusher, avelocity), PRVM_serveredictvector(pusher, angles));
+               PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0));
+               PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0));
+               PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0));
+               PRVM_serveredictfloat(pusher, ltime) += movetime;
                SV_LinkEdict(pusher);
                return;
        default:
-               Con_Printf("SV_PushMove: entity #%i, unrecognized solid type %f\n", PRVM_NUM_FOR_EDICT(pusher), pusher->fields.server->solid);
+               Con_Printf("SV_PushMove: entity #%i, unrecognized solid type %f\n", PRVM_NUM_FOR_EDICT(pusher), PRVM_serveredictfloat(pusher, solid));
                return;
        }
-       index = (int) pusher->fields.server->modelindex;
+       index = (int) PRVM_serveredictfloat(pusher, modelindex);
        if (index < 1 || index >= MAX_MODELS)
        {
-               Con_Printf("SV_PushMove: entity #%i has an invalid modelindex %f\n", PRVM_NUM_FOR_EDICT(pusher), pusher->fields.server->modelindex);
+               Con_Printf("SV_PushMove: entity #%i has an invalid modelindex %f\n", PRVM_NUM_FOR_EDICT(pusher), PRVM_serveredictfloat(pusher, modelindex));
                return;
        }
        pushermodel = SV_GetModelByIndex(index);
-       pusherowner = pusher->fields.server->owner;
+       pusherowner = PRVM_serveredictedict(pusher, owner);
        pusherprog = PRVM_EDICT_TO_PROG(pusher);
 
-       rotated = VectorLength2(pusher->fields.server->angles) + VectorLength2(pusher->fields.server->avelocity) > 0;
+       rotated = VectorLength2(PRVM_serveredictvector(pusher, angles)) + VectorLength2(PRVM_serveredictvector(pusher, avelocity)) > 0;
 
        movetime2 = movetime;
-       VectorScale(pusher->fields.server->velocity, movetime2, move1);
-       VectorScale(pusher->fields.server->avelocity, movetime2, moveangle);
+       VectorScale(PRVM_serveredictvector(pusher, velocity), movetime2, move1);
+       VectorScale(PRVM_serveredictvector(pusher, avelocity), movetime2, moveangle);
        if (moveangle[0] || moveangle[2])
        {
                for (i = 0;i < 3;i++)
                {
                        if (move1[i] > 0)
                        {
-                               mins[i] = pushermodel->rotatedmins[i] + pusher->fields.server->origin[i] - 1;
-                               maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->fields.server->origin[i] + 1;
+                               mins[i] = pushermodel->rotatedmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
+                               maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
                        }
                        else
                        {
-                               mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->fields.server->origin[i] - 1;
-                               maxs[i] = pushermodel->rotatedmaxs[i] + pusher->fields.server->origin[i] + 1;
+                               mins[i] = pushermodel->rotatedmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
+                               maxs[i] = pushermodel->rotatedmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
                        }
                }
        }
@@ -1622,13 +1724,13 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                {
                        if (move1[i] > 0)
                        {
-                               mins[i] = pushermodel->yawmins[i] + pusher->fields.server->origin[i] - 1;
-                               maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->fields.server->origin[i] + 1;
+                               mins[i] = pushermodel->yawmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
+                               maxs[i] = pushermodel->yawmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
                        }
                        else
                        {
-                               mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->fields.server->origin[i] - 1;
-                               maxs[i] = pushermodel->yawmaxs[i] + pusher->fields.server->origin[i] + 1;
+                               mins[i] = pushermodel->yawmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
+                               maxs[i] = pushermodel->yawmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
                        }
                }
        }
@@ -1638,13 +1740,13 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                {
                        if (move1[i] > 0)
                        {
-                               mins[i] = pushermodel->normalmins[i] + pusher->fields.server->origin[i] - 1;
-                               maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->fields.server->origin[i] + 1;
+                               mins[i] = pushermodel->normalmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
+                               maxs[i] = pushermodel->normalmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
                        }
                        else
                        {
-                               mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->fields.server->origin[i] - 1;
-                               maxs[i] = pushermodel->normalmaxs[i] + pusher->fields.server->origin[i] + 1;
+                               mins[i] = pushermodel->normalmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
+                               maxs[i] = pushermodel->normalmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
                        }
                }
        }
@@ -1652,50 +1754,53 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
        VectorNegate (moveangle, a);
        AngleVectorsFLU (a, forward, left, up);
 
-       VectorCopy (pusher->fields.server->origin, pushorig);
-       VectorCopy (pusher->fields.server->angles, pushang);
-       pushltime = pusher->fields.server->ltime;
+       VectorCopy (PRVM_serveredictvector(pusher, origin), pushorig);
+       VectorCopy (PRVM_serveredictvector(pusher, angles), pushang);
+       pushltime = PRVM_serveredictfloat(pusher, ltime);
 
 // move the pusher to its final position
 
-       VectorMA (pusher->fields.server->origin, movetime, pusher->fields.server->velocity, pusher->fields.server->origin);
-       VectorMA (pusher->fields.server->angles, movetime, pusher->fields.server->avelocity, pusher->fields.server->angles);
-       pusher->fields.server->ltime += movetime;
+       VectorMA (PRVM_serveredictvector(pusher, origin), movetime, PRVM_serveredictvector(pusher, velocity), PRVM_serveredictvector(pusher, origin));
+       VectorMA (PRVM_serveredictvector(pusher, angles), movetime, PRVM_serveredictvector(pusher, avelocity), PRVM_serveredictvector(pusher, angles));
+       PRVM_serveredictfloat(pusher, ltime) += movetime;
        SV_LinkEdict(pusher);
 
        pushermodel = SV_GetModelFromEdict(pusher);
-       Matrix4x4_CreateFromQuakeEntity(&pusherfinalmatrix, pusher->fields.server->origin[0], pusher->fields.server->origin[1], pusher->fields.server->origin[2], pusher->fields.server->angles[0], pusher->fields.server->angles[1], pusher->fields.server->angles[2], 1);
+       Matrix4x4_CreateFromQuakeEntity(&pusherfinalmatrix, PRVM_serveredictvector(pusher, origin)[0], PRVM_serveredictvector(pusher, origin)[1], PRVM_serveredictvector(pusher, origin)[2], PRVM_serveredictvector(pusher, angles)[0], PRVM_serveredictvector(pusher, angles)[1], PRVM_serveredictvector(pusher, angles)[2], 1);
        Matrix4x4_Invert_Simple(&pusherfinalimatrix, &pusherfinalmatrix);
 
-       savesolid = pusher->fields.server->solid;
+       savesolid = PRVM_serveredictfloat(pusher, solid);
 
 // 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 = World_EntitiesInBox(&sv.world, mins, maxs, MAX_EDICTS, checkentities);
        for (e = 0;e < numcheckentities;e++)
        {
                prvm_edict_t *check = checkentities[e];
-               int movetype = (int)check->fields.server->movetype;
+               int movetype = (int)PRVM_serveredictfloat(check, movetype);
                switch(movetype)
                {
                case MOVETYPE_NONE:
                case MOVETYPE_PUSH:
                case MOVETYPE_FOLLOW:
                case MOVETYPE_NOCLIP:
-               case MOVETYPE_FAKEPUSH:
+               case MOVETYPE_FLY_WORLDONLY:
                        continue;
                default:
                        break;
                }
 
-               if (check->fields.server->owner == pusherprog)
+               if (PRVM_serveredictedict(check, owner) == pusherprog)
                        continue;
 
                if (pusherowner == PRVM_EDICT_TO_PROG(check))
                        continue;
 
-               //Con_Printf("%i %s ", PRVM_NUM_FOR_EDICT(check), PRVM_GetString(check->fields.server->classname));
+               //Con_Printf("%i %s ", PRVM_NUM_FOR_EDICT(check), PRVM_GetString(PRVM_serveredictstring(check, classname)));
 
                // tell any MOVETYPE_STEP entity that it may need to check for water transitions
                check->priv.server->waterposition_forceupdate = true;
@@ -1705,10 +1810,10 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                // if the entity is standing on the pusher, it will definitely be moved
                // if the entity is not standing on the pusher, but is in the pusher's
                // final position, move it
-               if (!((int)check->fields.server->flags & FL_ONGROUND) || PRVM_PROG_TO_EDICT(check->fields.server->groundentity) != pusher)
+               if (!((int)PRVM_serveredictfloat(check, flags) & FL_ONGROUND) || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher)
                {
-                       Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents);
-                       //trace = SV_TraceBox(check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, MOVE_NOMONSTERS, check, checkcontents);
+                       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);
+                       //trace = SV_TraceBox(PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), MOVE_NOMONSTERS, check, checkcontents);
                        if (!trace.startsolid)
                        {
                                //Con_Printf("- not in solid\n");
@@ -1716,10 +1821,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 (check->fields.server->origin, pusher->fields.server->origin, org);
+                       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);
@@ -1731,114 +1840,97 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
 
                //Con_Printf("- pushing %f %f %f\n", move[0], move[1], move[2]);
 
-               VectorCopy (check->fields.server->origin, check->priv.server->moved_from);
-               VectorCopy (check->fields.server->angles, check->priv.server->moved_fromangles);
+               VectorCopy (PRVM_serveredictvector(check, origin), check->priv.server->moved_from);
+               VectorCopy (PRVM_serveredictvector(check, angles), check->priv.server->moved_fromangles);
                moved_edicts[num_moved++] = PRVM_NUM_FOR_EDICT(check);
 
                // physics objects need better collisions than this code can do
                if (movetype == MOVETYPE_PHYSICS)
                {
-                       VectorAdd(check->fields.server->origin, move, check->fields.server->origin);
+                       VectorAdd(PRVM_serveredictvector(check, origin), move, PRVM_serveredictvector(check, origin));
                        SV_LinkEdict(check);
                        SV_LinkEdict_TouchAreaGrid(check);
                        continue;
                }
 
                // try moving the contacted entity
-               pusher->fields.server->solid = SOLID_NOT;
+               PRVM_serveredictfloat(pusher, solid) = SOLID_NOT;
                if(!SV_PushEntity (&trace, check, move, true, true))
                {
                        // entity "check" got teleported
-                       check->fields.server->angles[1] += trace.fraction * moveangle[1];
-                       pusher->fields.server->solid = savesolid; // was SOLID_BSP
+                       PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
+                       PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP
                        continue; // pushed enough
                }
                // FIXME: turn players specially
-               check->fields.server->angles[1] += trace.fraction * moveangle[1];
-               pusher->fields.server->solid = savesolid; // was SOLID_BSP
+               PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
+               PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP
                //Con_Printf("%s:%d frac %f startsolid %d bmodelstartsolid %d allsolid %d\n", __FILE__, __LINE__, trace.fraction, trace.startsolid, trace.bmodelstartsolid, trace.allsolid);
 
                // this trace.fraction < 1 check causes items to fall off of pushers
                // if they pass under or through a wall
                // the groundentity check causes items to fall off of ledges
-               if (check->fields.server->movetype != MOVETYPE_WALK && (trace.fraction < 1 || PRVM_PROG_TO_EDICT(check->fields.server->groundentity) != pusher))
-                       check->fields.server->flags = (int)check->fields.server->flags & ~FL_ONGROUND;
+               if (PRVM_serveredictfloat(check, movetype) != MOVETYPE_WALK && (trace.fraction < 1 || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher))
+                       PRVM_serveredictfloat(check, flags) = (int)PRVM_serveredictfloat(check, flags) & ~FL_ONGROUND;
 
                // if it is still inside the pusher, block
-               Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents);
+               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;
-                       pusher->fields.server->solid = SOLID_NOT;
-                       VectorScale(move, 1.1, move2);
-                       VectorCopy (check->priv.server->moved_from, check->fields.server->origin);
-                       VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles);
-                       if(!SV_PushEntity (&trace2, check, move2, true, true))
-                       {
-                               // entity "check" got teleported
-                               continue;
-                       }
-                       pusher->fields.server->solid = savesolid;
-                       Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->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
-                               pusher->fields.server->solid = SOLID_NOT;
-                               VectorScale(move, 0.9, move2);
-                               VectorCopy (check->priv.server->moved_from, check->fields.server->origin);
-                               VectorCopy (check->priv.server->moved_fromangles, check->fields.server->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;
                                }
-                               pusher->fields.server->solid = savesolid;
-                               Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents);
-                               if (trace.startsolid)
-                               {
-                                       // still inside pusher, so it's really blocked
-
-                                       // fail the move
-                                       if (check->fields.server->mins[0] == check->fields.server->maxs[0])
-                                               continue;
-                                       if (check->fields.server->solid == SOLID_NOT || check->fields.server->solid == SOLID_TRIGGER)
-                                       {
-                                               // corpse
-                                               check->fields.server->mins[0] = check->fields.server->mins[1] = 0;
-                                               VectorCopy (check->fields.server->mins, check->fields.server->maxs);
-                                               continue;
-                                       }
-
-                                       VectorCopy (pushorig, pusher->fields.server->origin);
-                                       VectorCopy (pushang, pusher->fields.server->angles);
-                                       pusher->fields.server->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, ed->fields.server->origin);
-                                               VectorCopy (ed->priv.server->moved_fromangles, ed->fields.server->angles);
-                                               SV_LinkEdict(ed);
-                                       }
-
-                                       // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
-                                       if (pusher->fields.server->blocked)
-                                       {
-                                               prog->globals.server->self = PRVM_EDICT_TO_PROG(pusher);
-                                               prog->globals.server->other = PRVM_EDICT_TO_PROG(check);
-                                               PRVM_ExecuteProgram (pusher->fields.server->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_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;
                }
        }
-       pusher->fields.server->angles[0] -= 360.0 * floor(pusher->fields.server->angles[0] * (1.0 / 360.0));
-       pusher->fields.server->angles[1] -= 360.0 * floor(pusher->fields.server->angles[1] * (1.0 / 360.0));
-       pusher->fields.server->angles[2] -= 360.0 * floor(pusher->fields.server->angles[2] * (1.0 / 360.0));
+       PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0));
+       PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0));
+       PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0));
 }
 
 /*
@@ -1851,12 +1943,12 @@ void SV_Physics_Pusher (prvm_edict_t *ent)
 {
        float thinktime, oldltime, movetime;
 
-       oldltime = ent->fields.server->ltime;
+       oldltime = PRVM_serveredictfloat(ent, ltime);
 
-       thinktime = ent->fields.server->nextthink;
-       if (thinktime < ent->fields.server->ltime + sv.frametime)
+       thinktime = PRVM_serveredictfloat(ent, nextthink);
+       if (thinktime < PRVM_serveredictfloat(ent, ltime) + sv.frametime)
        {
-               movetime = thinktime - ent->fields.server->ltime;
+               movetime = thinktime - PRVM_serveredictfloat(ent, ltime);
                if (movetime < 0)
                        movetime = 0;
        }
@@ -1864,16 +1956,16 @@ void SV_Physics_Pusher (prvm_edict_t *ent)
                movetime = sv.frametime;
 
        if (movetime)
-               // advances ent->fields.server->ltime if not blocked
+               // advances PRVM_serveredictfloat(ent, ltime) if not blocked
                SV_PushMove (ent, movetime);
 
-       if (thinktime > oldltime && thinktime <= ent->fields.server->ltime)
+       if (thinktime > oldltime && thinktime <= PRVM_serveredictfloat(ent, ltime))
        {
-               ent->fields.server->nextthink = 0;
-               prog->globals.server->time = sv.time;
-               prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
-               prog->globals.server->other = PRVM_EDICT_TO_PROG(prog->edicts);
-               PRVM_ExecuteProgram (ent->fields.server->think, "QC function self.think is missing");
+               PRVM_serveredictfloat(ent, nextthink) = 0;
+               PRVM_serverglobalfloat(time) = sv.time;
+               PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
+               PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
+               PRVM_ExecuteProgram (PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
        }
 }
 
@@ -1930,7 +2022,7 @@ unstickresult_t SV_UnstickEntityReturnOffset (prvm_edict_t *ent, vec3_t offset)
                }
        }
 
-       maxunstick = (int) ((ent->fields.server->maxs[2] - ent->fields.server->mins[2]) * 0.36);
+       maxunstick = (int) ((PRVM_serveredictvector(ent, maxs)[2] - PRVM_serveredictvector(ent, mins)[2]) * 0.36);
        // magic number 0.36 allows unsticking by up to 17 units with the largest supported bbox
 
        for(i = 2; i <= maxunstick; ++i)
@@ -1963,11 +2055,11 @@ qboolean SV_UnstickEntity (prvm_edict_t *ent)
                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(ent->fields.server->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(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(ent->fields.server->classname));
+                               Con_DPrintf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
                        return false;
                default:
                        Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
@@ -1990,21 +2082,21 @@ void SV_CheckStuck (prvm_edict_t *ent)
        switch(SV_UnstickEntityReturnOffset(ent, offset))
        {
                case UNSTICK_GOOD:
-                       VectorCopy (ent->fields.server->origin, ent->fields.server->oldorigin);
+                       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(ent->fields.server->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(PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
                        break;
                case UNSTICK_STUCK:
-                       VectorSubtract(ent->fields.server->oldorigin, ent->fields.server->origin, offset);
+                       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(ent->fields.server->classname));
+                               Con_DPrintf("Unstuck player entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(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(ent->fields.server->classname));
+                               Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
                        break;
                default:
                        Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
@@ -2023,9 +2115,9 @@ qboolean SV_CheckWater (prvm_edict_t *ent)
        int nNativeContents;
        vec3_t point;
 
-       point[0] = ent->fields.server->origin[0];
-       point[1] = ent->fields.server->origin[1];
-       point[2] = ent->fields.server->origin[2] + ent->fields.server->mins[2] + 1;
+       point[0] = PRVM_serveredictvector(ent, origin)[0];
+       point[1] = PRVM_serveredictvector(ent, origin)[1];
+       point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, mins)[2] + 1;
 
        // DRESK - Support for Entity Contents Transition Event
        // NOTE: Some logic needed to be slightly re-ordered
@@ -2037,29 +2129,29 @@ qboolean SV_CheckWater (prvm_edict_t *ent)
        nNativeContents = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont);
 
        // DRESK - Support for Entity Contents Transition Event
-       if(ent->fields.server->watertype)
+       if(PRVM_serveredictfloat(ent, watertype))
                // Entity did NOT Spawn; Check
                SV_CheckContentsTransition(ent, nNativeContents);
 
 
-       ent->fields.server->waterlevel = 0;
-       ent->fields.server->watertype = CONTENTS_EMPTY;
+       PRVM_serveredictfloat(ent, waterlevel) = 0;
+       PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY;
        cont = SV_PointSuperContents(point);
        if (cont & (SUPERCONTENTS_LIQUIDSMASK))
        {
-               ent->fields.server->watertype = nNativeContents;
-               ent->fields.server->waterlevel = 1;
-               point[2] = ent->fields.server->origin[2] + (ent->fields.server->mins[2] + ent->fields.server->maxs[2])*0.5;
+               PRVM_serveredictfloat(ent, watertype) = nNativeContents;
+               PRVM_serveredictfloat(ent, waterlevel) = 1;
+               point[2] = PRVM_serveredictvector(ent, origin)[2] + (PRVM_serveredictvector(ent, mins)[2] + PRVM_serveredictvector(ent, maxs)[2])*0.5;
                if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
                {
-                       ent->fields.server->waterlevel = 2;
-                       point[2] = ent->fields.server->origin[2] + ent->fields.server->view_ofs[2];
+                       PRVM_serveredictfloat(ent, waterlevel) = 2;
+                       point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, view_ofs)[2];
                        if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
-                               ent->fields.server->waterlevel = 3;
+                               PRVM_serveredictfloat(ent, waterlevel) = 3;
                }
        }
 
-       return ent->fields.server->waterlevel > 1;
+       return PRVM_serveredictfloat(ent, waterlevel) > 1;
 }
 
 /*
@@ -2073,15 +2165,15 @@ void SV_WallFriction (prvm_edict_t *ent, float *stepnormal)
        float d, i;
        vec3_t forward, into, side;
 
-       AngleVectors (ent->fields.server->v_angle, forward, NULL, NULL);
+       AngleVectors (PRVM_serveredictvector(ent, v_angle), forward, NULL, NULL);
        if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
        {
                // cut the tangential velocity
-               i = DotProduct (stepnormal, ent->fields.server->velocity);
+               i = DotProduct (stepnormal, PRVM_serveredictvector(ent, velocity));
                VectorScale (stepnormal, i, into);
-               VectorSubtract (ent->fields.server->velocity, into, side);
-               ent->fields.server->velocity[0] = side[0] * (1 + d);
-               ent->fields.server->velocity[1] = side[1] * (1 + d);
+               VectorSubtract (PRVM_serveredictvector(ent, velocity), into, side);
+               PRVM_serveredictvector(ent, velocity)[0] = side[0] * (1 + d);
+               PRVM_serveredictvector(ent, velocity)[1] = side[1] * (1 + d);
        }
 }
 
@@ -2103,7 +2195,7 @@ int SV_TryUnstick (prvm_edict_t *ent, vec3_t oldvel)
        int i, clip;
        vec3_t oldorg, dir;
 
-       VectorCopy (ent->fields.server->origin, oldorg);
+       VectorCopy (PRVM_serveredictvector(ent, origin), oldorg);
        VectorClear (dir);
 
        for (i=0 ; i<8 ; i++)
@@ -2124,24 +2216,24 @@ int SV_TryUnstick (prvm_edict_t *ent, vec3_t oldvel)
                SV_PushEntity (&trace, ent, dir, false, true);
 
                // retry the original move
-               ent->fields.server->velocity[0] = oldvel[0];
-               ent->fields.server->velocity[1] = oldvel[1];
-               ent->fields.server->velocity[2] = 0;
+               PRVM_serveredictvector(ent, velocity)[0] = oldvel[0];
+               PRVM_serveredictvector(ent, velocity)[1] = oldvel[1];
+               PRVM_serveredictvector(ent, velocity)[2] = 0;
                clip = SV_FlyMove (ent, 0.1, NULL, SV_GenericHitSuperContentsMask(ent));
 
-               if (fabs(oldorg[1] - ent->fields.server->origin[1]) > 4
-                || fabs(oldorg[0] - ent->fields.server->origin[0]) > 4)
+               if (fabs(oldorg[1] - PRVM_serveredictvector(ent, origin)[1]) > 4
+                || fabs(oldorg[0] - PRVM_serveredictvector(ent, origin)[0]) > 4)
                {
                        Con_DPrint("TryUnstick - success.\n");
                        return clip;
                }
 
                // go back to the original pos and try again
-               VectorCopy (oldorg, ent->fields.server->origin);
+               VectorCopy (oldorg, PRVM_serveredictvector(ent, origin));
        }
 
        // still not moving
-       VectorClear (ent->fields.server->velocity);
+       VectorClear (PRVM_serveredictvector(ent, velocity));
        Con_DPrint("TryUnstick - failure.\n");
        return 7;
 }
@@ -2174,17 +2266,17 @@ void SV_WalkMove (prvm_edict_t *ent)
 
        SV_CheckStuck (ent);
 
-       applygravity = !SV_CheckWater (ent) && ent->fields.server->movetype == MOVETYPE_WALK && ! ((int)ent->fields.server->flags & FL_WATERJUMP);
+       applygravity = !SV_CheckWater (ent) && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_WALK && ! ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP);
 
        hitsupercontentsmask = SV_GenericHitSuperContentsMask(ent);
 
        SV_CheckVelocity(ent);
 
        // do a regular slide move unless it looks like you ran into a step
-       oldonground = (int)ent->fields.server->flags & FL_ONGROUND;
+       oldonground = (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND;
 
-       VectorCopy (ent->fields.server->origin, start_origin);
-       VectorCopy (ent->fields.server->velocity, start_velocity);
+       VectorCopy (PRVM_serveredictvector(ent, origin), start_origin);
+       VectorCopy (PRVM_serveredictvector(ent, velocity), start_velocity);
 
        clip = SV_FlyMove (ent, sv.frametime, applygravity, NULL, hitsupercontentsmask, sv_gameplayfix_stepmultipletimes.integer ? sv_stepheight.value : 0);
 
@@ -2194,22 +2286,24 @@ void SV_WalkMove (prvm_edict_t *ent)
                // only try this if there was no floor in the way in the trace (no,
                // this check seems to be not REALLY necessary, because if clip & 1,
                // our trace will hit that thing too)
-               VectorSet(upmove, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2] + 1);
-               VectorSet(downmove, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2] - 1);
-               if (ent->fields.server->movetype == MOVETYPE_FLYMISSILE)
+               VectorSet(upmove, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] + 1);
+               VectorSet(downmove, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] - 1);
+               if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLYMISSILE)
                        type = MOVE_MISSILE;
-               else if (ent->fields.server->solid == SOLID_TRIGGER || ent->fields.server->solid == SOLID_NOT)
+               else if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLY_WORLDONLY)
+                       type = MOVE_WORLDONLY;
+               else if (PRVM_serveredictfloat(ent, solid) == SOLID_TRIGGER || PRVM_serveredictfloat(ent, solid) == SOLID_NOT)
                        type = MOVE_NOMONSTERS; // only clip against bmodels
                else
                        type = MOVE_NORMAL;
-               trace = SV_TraceBox(upmove, ent->fields.server->mins, ent->fields.server->maxs, downmove, type, ent, SV_GenericHitSuperContentsMask(ent));
+               trace = SV_TraceBox(upmove, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), downmove, type, ent, SV_GenericHitSuperContentsMask(ent));
                if(trace.fraction < 1 && trace.plane.normal[2] > 0.7)
                        clip |= 1; // but we HAVE found a floor
        }
 
        // if the move did not hit the ground at any point, we're not on ground
        if(!(clip & 1))
-               ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND;
+               PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
 
        SV_CheckVelocity(ent);
        SV_LinkEdict(ent);
@@ -2218,17 +2312,17 @@ void SV_WalkMove (prvm_edict_t *ent)
        if(clip & 8) // teleport
                return;
 
-       if ((int)ent->fields.server->flags & FL_WATERJUMP)
+       if ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP)
                return;
 
        if (sv_nostep.integer)
                return;
 
-       VectorCopy(ent->fields.server->origin, originalmove_origin);
-       VectorCopy(ent->fields.server->velocity, originalmove_velocity);
+       VectorCopy(PRVM_serveredictvector(ent, origin), originalmove_origin);
+       VectorCopy(PRVM_serveredictvector(ent, velocity), originalmove_velocity);
        //originalmove_clip = clip;
-       originalmove_flags = (int)ent->fields.server->flags;
-       originalmove_groundentity = ent->fields.server->groundentity;
+       originalmove_flags = (int)PRVM_serveredictfloat(ent, flags);
+       originalmove_groundentity = PRVM_serveredictedict(ent, groundentity);
 
        // if move didn't block on a step, return
        if (clip & 2)
@@ -2237,22 +2331,22 @@ void SV_WalkMove (prvm_edict_t *ent)
                if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125)
                        return;
 
-               if (ent->fields.server->movetype != MOVETYPE_FLY)
+               if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_FLY)
                {
                        // return if gibbed by a trigger
-                       if (ent->fields.server->movetype != MOVETYPE_WALK)
+                       if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_WALK)
                                return;
 
                        // only step up while jumping if that is enabled
                        if (!(sv_jumpstep.integer && sv_gameplayfix_stepwhilejumping.integer))
-                               if (!oldonground && ent->fields.server->waterlevel == 0)
+                               if (!oldonground && PRVM_serveredictfloat(ent, waterlevel) == 0)
                                        return;
                }
 
                // try moving up and forward to go up a step
                // back to start pos
-               VectorCopy (start_origin, ent->fields.server->origin);
-               VectorCopy (start_velocity, ent->fields.server->velocity);
+               VectorCopy (start_origin, PRVM_serveredictvector(ent, origin));
+               VectorCopy (start_velocity, PRVM_serveredictvector(ent, velocity));
 
                // move up
                VectorClear (upmove);
@@ -2264,9 +2358,9 @@ void SV_WalkMove (prvm_edict_t *ent)
                }
 
                // move forward
-               ent->fields.server->velocity[2] = 0;
+               PRVM_serveredictvector(ent, velocity)[2] = 0;
                clip = SV_FlyMove (ent, sv.frametime, applygravity, stepnormal, hitsupercontentsmask, 0);
-               ent->fields.server->velocity[2] += start_velocity[2];
+               PRVM_serveredictvector(ent, velocity)[2] += start_velocity[2];
                if(clip & 8)
                {
                        // we got teleported when upstepping... must abort the move
@@ -2281,16 +2375,16 @@ void SV_WalkMove (prvm_edict_t *ent)
                // check for stuckness, possibly due to the limited precision of floats
                // in the clipping hulls
                if (clip
-                && fabs(originalmove_origin[1] - ent->fields.server->origin[1]) < 0.03125
-                && fabs(originalmove_origin[0] - ent->fields.server->origin[0]) < 0.03125)
+                && fabs(originalmove_origin[1] - PRVM_serveredictvector(ent, origin)[1]) < 0.03125
+                && fabs(originalmove_origin[0] - PRVM_serveredictvector(ent, origin)[0]) < 0.03125)
                {
                        //Con_Printf("wall\n");
                        // stepping up didn't make any progress, revert to original move
-                       VectorCopy(originalmove_origin, ent->fields.server->origin);
-                       VectorCopy(originalmove_velocity, ent->fields.server->velocity);
+                       VectorCopy(originalmove_origin, PRVM_serveredictvector(ent, origin));
+                       VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity));
                        //clip = originalmove_clip;
-                       ent->fields.server->flags = originalmove_flags;
-                       ent->fields.server->groundentity = originalmove_groundentity;
+                       PRVM_serveredictfloat(ent, flags) = originalmove_flags;
+                       PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity;
                        // now try to unstick if needed
                        //clip = SV_TryUnstick (ent, oldvel);
                        return;
@@ -2303,7 +2397,7 @@ void SV_WalkMove (prvm_edict_t *ent)
                        SV_WallFriction (ent, stepnormal);
        }
        // don't do the down move if stepdown is disabled, moving upward, not in water, or the move started offground or ended onground
-       else if (!sv_gameplayfix_stepdown.integer || ent->fields.server->waterlevel >= 3 || start_velocity[2] >= (1.0 / 32.0) || !oldonground || ((int)ent->fields.server->flags & FL_ONGROUND))
+       else if (!sv_gameplayfix_stepdown.integer || PRVM_serveredictfloat(ent, waterlevel) >= 3 || start_velocity[2] >= (1.0 / 32.0) || !oldonground || ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
                return;
 
        // move down
@@ -2321,11 +2415,11 @@ void SV_WalkMove (prvm_edict_t *ent)
                // up while already jumping (also known as the Quake2 double jump bug)
 #if 0
                // LordHavoc: disabled this check so you can walk on monsters/players
-               //if (ent->fields.server->solid == SOLID_BSP)
+               //if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
                {
                        //Con_Printf("onground\n");
-                       ent->fields.server->flags =     (int)ent->fields.server->flags | FL_ONGROUND;
-                       ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(downtrace.ent);
+                       PRVM_serveredictfloat(ent, flags) =     (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
+                       PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(downtrace.ent);
                }
 #endif
        }
@@ -2335,11 +2429,11 @@ void SV_WalkMove (prvm_edict_t *ent)
                // if the push down didn't end up on good ground, use the move without
                // the step up.  This happens near wall / slope combinations, and can
                // cause the player to hop up higher on a slope too steep to climb
-               VectorCopy(originalmove_origin, ent->fields.server->origin);
-               VectorCopy(originalmove_velocity, ent->fields.server->velocity);
+               VectorCopy(originalmove_origin, PRVM_serveredictvector(ent, origin));
+               VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity));
                //clip = originalmove_clip;
-               ent->fields.server->flags = originalmove_flags;
-               ent->fields.server->groundentity = originalmove_groundentity;
+               PRVM_serveredictfloat(ent, flags) = originalmove_flags;
+               PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity;
        }
 
        SV_CheckVelocity(ent);
@@ -2366,30 +2460,30 @@ void SV_Physics_Follow (prvm_edict_t *ent)
                return;
 
        // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
-       e = PRVM_PROG_TO_EDICT(ent->fields.server->aiment);
-       if (e->fields.server->angles[0] == ent->fields.server->punchangle[0] && e->fields.server->angles[1] == ent->fields.server->punchangle[1] && e->fields.server->angles[2] == ent->fields.server->punchangle[2])
+       e = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, aiment));
+       if (PRVM_serveredictvector(e, angles)[0] == PRVM_serveredictvector(ent, punchangle)[0] && PRVM_serveredictvector(e, angles)[1] == PRVM_serveredictvector(ent, punchangle)[1] && PRVM_serveredictvector(e, angles)[2] == PRVM_serveredictvector(ent, punchangle)[2])
        {
                // quick case for no rotation
-               VectorAdd(e->fields.server->origin, ent->fields.server->view_ofs, ent->fields.server->origin);
+               VectorAdd(PRVM_serveredictvector(e, origin), PRVM_serveredictvector(ent, view_ofs), PRVM_serveredictvector(ent, origin));
        }
        else
        {
-               angles[0] = -ent->fields.server->punchangle[0];
-               angles[1] =  ent->fields.server->punchangle[1];
-               angles[2] =  ent->fields.server->punchangle[2];
+               angles[0] = -PRVM_serveredictvector(ent, punchangle)[0];
+               angles[1] =  PRVM_serveredictvector(ent, punchangle)[1];
+               angles[2] =  PRVM_serveredictvector(ent, punchangle)[2];
                AngleVectors (angles, vf, vr, vu);
-               v[0] = ent->fields.server->view_ofs[0] * vf[0] + ent->fields.server->view_ofs[1] * vr[0] + ent->fields.server->view_ofs[2] * vu[0];
-               v[1] = ent->fields.server->view_ofs[0] * vf[1] + ent->fields.server->view_ofs[1] * vr[1] + ent->fields.server->view_ofs[2] * vu[1];
-               v[2] = ent->fields.server->view_ofs[0] * vf[2] + ent->fields.server->view_ofs[1] * vr[2] + ent->fields.server->view_ofs[2] * vu[2];
-               angles[0] = -e->fields.server->angles[0];
-               angles[1] =  e->fields.server->angles[1];
-               angles[2] =  e->fields.server->angles[2];
+               v[0] = PRVM_serveredictvector(ent, view_ofs)[0] * vf[0] + PRVM_serveredictvector(ent, view_ofs)[1] * vr[0] + PRVM_serveredictvector(ent, view_ofs)[2] * vu[0];
+               v[1] = PRVM_serveredictvector(ent, view_ofs)[0] * vf[1] + PRVM_serveredictvector(ent, view_ofs)[1] * vr[1] + PRVM_serveredictvector(ent, view_ofs)[2] * vu[1];
+               v[2] = PRVM_serveredictvector(ent, view_ofs)[0] * vf[2] + PRVM_serveredictvector(ent, view_ofs)[1] * vr[2] + PRVM_serveredictvector(ent, view_ofs)[2] * vu[2];
+               angles[0] = -PRVM_serveredictvector(e, angles)[0];
+               angles[1] =  PRVM_serveredictvector(e, angles)[1];
+               angles[2] =  PRVM_serveredictvector(e, angles)[2];
                AngleVectors (angles, vf, vr, vu);
-               ent->fields.server->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->fields.server->origin[0];
-               ent->fields.server->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->fields.server->origin[1];
-               ent->fields.server->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->fields.server->origin[2];
+               PRVM_serveredictvector(ent, origin)[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + PRVM_serveredictvector(e, origin)[0];
+               PRVM_serveredictvector(ent, origin)[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + PRVM_serveredictvector(e, origin)[1];
+               PRVM_serveredictvector(ent, origin)[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + PRVM_serveredictvector(e, origin)[2];
        }
-       VectorAdd (e->fields.server->angles, ent->fields.server->v_angle, ent->fields.server->angles);
+       VectorAdd (PRVM_serveredictvector(e, angles), PRVM_serveredictvector(ent, v_angle), PRVM_serveredictvector(ent, angles));
        SV_LinkEdict(ent);
        //SV_LinkEdict_TouchAreaGrid(ent);
 }
@@ -2411,12 +2505,12 @@ SV_CheckWaterTransition
 void SV_CheckWaterTransition (prvm_edict_t *ent)
 {
        int cont;
-       cont = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(ent->fields.server->origin));
-       if (!ent->fields.server->watertype)
+       cont = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_serveredictvector(ent, origin)));
+       if (!PRVM_serveredictfloat(ent, watertype))
        {
                // just spawned here
-               ent->fields.server->watertype = cont;
-               ent->fields.server->waterlevel = 1;
+               PRVM_serveredictfloat(ent, watertype) = cont;
+               PRVM_serveredictfloat(ent, waterlevel) = 1;
                return;
        }
 
@@ -2427,19 +2521,19 @@ void SV_CheckWaterTransition (prvm_edict_t *ent)
        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 && ((ent->fields.server->watertype == CONTENTS_WATER || ent->fields.server->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME)))
-                       SV_StartSound (ent, 0, sv_sound_watersplash.string, 255, 1);
+               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);
        }
 
        if (cont <= CONTENTS_WATER)
        {
-               ent->fields.server->watertype = cont;
-               ent->fields.server->waterlevel = 1;
+               PRVM_serveredictfloat(ent, watertype) = cont;
+               PRVM_serveredictfloat(ent, waterlevel) = 1;
        }
        else
        {
-               ent->fields.server->watertype = CONTENTS_EMPTY;
-               ent->fields.server->waterlevel = 0;
+               PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY;
+               PRVM_serveredictfloat(ent, waterlevel) = 0;
        }
 }
 
@@ -2459,15 +2553,15 @@ void SV_Physics_Toss (prvm_edict_t *ent)
        prvm_edict_t *groundentity;
 
 // if onground, return without moving
-       if ((int)ent->fields.server->flags & FL_ONGROUND)
+       if ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
        {
-               groundentity = PRVM_PROG_TO_EDICT(ent->fields.server->groundentity);
-               if (ent->fields.server->velocity[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
+               groundentity = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, groundentity));
+               if (PRVM_serveredictvector(ent, velocity)[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
                {
                        // don't stick to ground if onground and moving upward
-                       ent->fields.server->flags -= FL_ONGROUND;
+                       PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND;
                }
-               else if (!ent->fields.server->groundentity || !sv_gameplayfix_noairborncorpse.integer)
+               else if (!PRVM_serveredictedict(ent, groundentity) || !sv_gameplayfix_noairborncorpse.integer)
                {
                        // we can trust FL_ONGROUND if groundentity is world because it never moves
                        return;
@@ -2477,7 +2571,7 @@ void SV_Physics_Toss (prvm_edict_t *ent)
                        // if ent was supported by a brush model on previous frame,
                        // and groundentity is now freed, set groundentity to 0 (world)
                        // which leaves it suspended in the air
-                       ent->fields.server->groundentity = 0;
+                       PRVM_serveredictedict(ent, groundentity) = 0;
                        if (sv_gameplayfix_noairborncorpse_allowsuspendeditems.integer)
                                return;
                }
@@ -2492,17 +2586,17 @@ void SV_Physics_Toss (prvm_edict_t *ent)
        SV_CheckVelocity (ent);
 
 // add gravity
-       if (ent->fields.server->movetype == MOVETYPE_TOSS || ent->fields.server->movetype == MOVETYPE_BOUNCE)
-               ent->fields.server->velocity[2] -= SV_Gravity(ent);
+       if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_TOSS || PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCE)
+               PRVM_serveredictvector(ent, velocity)[2] -= SV_Gravity(ent);
 
 // move angles
-       VectorMA (ent->fields.server->angles, sv.frametime, ent->fields.server->avelocity, ent->fields.server->angles);
+       VectorMA (PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
 
        movetime = sv.frametime;
        for (bump = 0;bump < MAX_CLIP_PLANES && movetime > 0;bump++)
        {
        // move origin
-               VectorScale (ent->fields.server->velocity, movetime, move);
+               VectorScale (PRVM_serveredictvector(ent, velocity), movetime, move);
                if(!SV_PushEntity (&trace, ent, move, true, true))
                        return; // teleported
                if (ent->priv.server->free)
@@ -2519,81 +2613,77 @@ void SV_Physics_Toss (prvm_edict_t *ent)
                if (trace.fraction == 1)
                        break;
                movetime *= 1 - min(1, trace.fraction);
-               if (ent->fields.server->movetype == MOVETYPE_BOUNCEMISSILE)
+               if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCEMISSILE)
                {
-                       prvm_eval_t *val;
-                       float bouncefactor = 1.0f;
-                       val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.bouncefactor);
-                       if (val!=0 && val->_float)
-                               bouncefactor = val->_float;
+                       float bouncefactor;
+                       bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
+                       if (!bouncefactor)
+                               bouncefactor = 1.0f;
 
-                       ClipVelocity (ent->fields.server->velocity, trace.plane.normal, ent->fields.server->velocity, 1 + bouncefactor);
-                       ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND;
+                       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 (ent->fields.server->movetype == MOVETYPE_BOUNCE)
+               else if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCE)
                {
                        float d, ent_gravity;
-                       prvm_eval_t *val;
-                       float bouncefactor = 0.5f;
-                       float bouncestop = 60.0f / 800.0f;
+                       float bouncefactor;
+                       float bouncestop;
 
-                       val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.bouncefactor);
-                       if (val!=0 && val->_float)
-                               bouncefactor = val->_float;
+                       bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
+                       if (!bouncefactor)
+                               bouncefactor = 0.5f;
 
-                       val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.bouncestop);
-                       if (val!=0 && val->_float)
-                               bouncestop = val->_float;
+                       bouncestop = PRVM_serveredictfloat(ent, bouncestop);
+                       if (!bouncestop)
+                               bouncestop = 60.0f / 800.0f;
 
-                       ClipVelocity (ent->fields.server->velocity, trace.plane.normal, ent->fields.server->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
-                       val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.gravity);
-                       if (val!=0 && val->_float)
-                               ent_gravity = val->_float;
-                       else
-                               ent_gravity = 1.0;
                        if (sv_gameplayfix_grenadebouncedownslopes.integer)
                        {
-                               d = DotProduct(trace.plane.normal, ent->fields.server->velocity);
+                               d = DotProduct(trace.plane.normal, PRVM_serveredictvector(ent, velocity));
                                if (trace.plane.normal[2] > 0.7 && fabs(d) < sv_gravity.value * bouncestop * ent_gravity)
                                {
-                                       ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
-                                       ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
-                                       VectorClear (ent->fields.server->velocity);
-                                       VectorClear (ent->fields.server->avelocity);
+                                       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
-                                       ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND;
+                                       PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
                        }
                        else
                        {
-                               if (trace.plane.normal[2] > 0.7 && ent->fields.server->velocity[2] < sv_gravity.value * bouncestop * ent_gravity)
+                               if (trace.plane.normal[2] > 0.7 && PRVM_serveredictvector(ent, velocity)[2] < sv_gravity.value * bouncestop * ent_gravity)
                                {
-                                       ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
-                                       ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
-                                       VectorClear (ent->fields.server->velocity);
-                                       VectorClear (ent->fields.server->avelocity);
+                                       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
-                                       ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND;
+                                       PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
                        }
                }
                else
                {
-                       ClipVelocity (ent->fields.server->velocity, trace.plane.normal, ent->fields.server->velocity, 1.0);
+                       ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1.0);
                        if (trace.plane.normal[2] > 0.7)
                        {
-                               ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
-                               ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
-                               if (((prvm_edict_t *)trace.ent)->fields.server->solid == SOLID_BSP)
+                               PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
+                               PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
+                               if (PRVM_serveredictfloat(((prvm_edict_t *)trace.ent), solid) == SOLID_BSP)
                                        ent->priv.server->suspendedinairflag = true;
-                               VectorClear (ent->fields.server->velocity);
-                               VectorClear (ent->fields.server->avelocity);
+                               VectorClear (PRVM_serveredictvector(ent, velocity));
+                               VectorClear (PRVM_serveredictvector(ent, avelocity));
                        }
                        else
-                               ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND;
+                               PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
                }
-               if (!sv_gameplayfix_slidemoveprojectiles.integer || (ent->fields.server->movetype != MOVETYPE_BOUNCE && ent->fields.server->movetype == MOVETYPE_BOUNCEMISSILE) || ((int)ent->fields.server->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))
                        break;
        }
 
@@ -2622,14 +2712,13 @@ will fall if the floor is pulled out from under them.
 */
 void SV_Physics_Step (prvm_edict_t *ent)
 {
-       int flags = (int)ent->fields.server->flags;
+       int flags = (int)PRVM_serveredictfloat(ent, flags);
 
        // DRESK
        // Backup Velocity in the event that movetypesteplandevent is called,
        // to provide a parameter with the entity's velocity at impact.
-       prvm_eval_t *movetypesteplandevent;
        vec3_t backupVelocity;
-       VectorCopy(ent->fields.server->velocity, backupVelocity);
+       VectorCopy(PRVM_serveredictvector(ent, velocity), backupVelocity);
        // don't fall at all if fly/swim
        if (!(flags & (FL_FLY | FL_SWIM)))
        {
@@ -2637,9 +2726,9 @@ void SV_Physics_Step (prvm_edict_t *ent)
                {
                        // freefall if onground and moving upward
                        // freefall if not standing on a world surface (it may be a lift or trap door)
-                       if (ent->fields.server->velocity[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
+                       if (PRVM_serveredictvector(ent, velocity)[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
                        {
-                               ent->fields.server->flags -= FL_ONGROUND;
+                               PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND;
                                SV_CheckVelocity(ent);
                                SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0);
                                SV_LinkEdict(ent);
@@ -2650,7 +2739,7 @@ void SV_Physics_Step (prvm_edict_t *ent)
                else
                {
                        // freefall if not onground
-                       int hitsound = ent->fields.server->velocity[2] < sv_gravity.value * -0.1;
+                       int hitsound = PRVM_serveredictvector(ent, velocity)[2] < sv_gravity.value * -0.1;
 
                        SV_CheckVelocity(ent);
                        SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0);
@@ -2658,12 +2747,10 @@ void SV_Physics_Step (prvm_edict_t *ent)
                        SV_LinkEdict_TouchAreaGrid(ent);
 
                        // just hit ground
-                       if (hitsound && (int)ent->fields.server->flags & FL_ONGROUND)
+                       if (hitsound && (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
                        {
                                // DRESK - Check for Entity Land Event Function
-                               movetypesteplandevent = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.movetypesteplandevent);
-
-                               if(movetypesteplandevent->function)
+                               if(PRVM_serveredictfunction(ent, movetypesteplandevent))
                                { // Valid Function; Execute
                                        // Prepare Parameters
                                                // Assign Velocity at Impact
@@ -2671,14 +2758,14 @@ void SV_Physics_Step (prvm_edict_t *ent)
                                                PRVM_G_VECTOR(OFS_PARM0)[1] = backupVelocity[1];
                                                PRVM_G_VECTOR(OFS_PARM0)[2] = backupVelocity[2];
                                                // Assign Self
-                                               prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
+                                               PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
                                        // Execute VM Function
-                                       PRVM_ExecuteProgram(movetypesteplandevent->function, "movetypesteplandevent: NULL function");
+                                       PRVM_ExecuteProgram(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);
+                                       SV_StartSound(ent, 0, sv_sound_land.string, 255, 1, false);
                        }
                        ent->priv.server->waterposition_forceupdate = true;
                }
@@ -2688,10 +2775,10 @@ void SV_Physics_Step (prvm_edict_t *ent)
        if (!SV_RunThink(ent))
                return;
 
-       if (ent->priv.server->waterposition_forceupdate || !VectorCompare(ent->fields.server->origin, ent->priv.server->waterposition_origin))
+       if (ent->priv.server->waterposition_forceupdate || !VectorCompare(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin))
        {
                ent->priv.server->waterposition_forceupdate = false;
-               VectorCopy(ent->fields.server->origin, ent->priv.server->waterposition_origin);
+               VectorCopy(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin);
                SV_CheckWaterTransition(ent);
        }
 }
@@ -2710,7 +2797,7 @@ static void SV_Physics_Entity (prvm_edict_t *ent)
        ent->priv.server->move = true;
        if (!runmove && sv_gameplayfix_delayprojectiles.integer > 0)
                return;
-       switch ((int) ent->fields.server->movetype)
+       switch ((int) PRVM_serveredictfloat(ent, movetype))
        {
        case MOVETYPE_PUSH:
        case MOVETYPE_FAKEPUSH:
@@ -2718,7 +2805,7 @@ static void SV_Physics_Entity (prvm_edict_t *ent)
                break;
        case MOVETYPE_NONE:
                // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
-               if (ent->fields.server->nextthink > 0 && ent->fields.server->nextthink <= sv.time + sv.frametime)
+               if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime)
                        SV_RunThink (ent);
                break;
        case MOVETYPE_FOLLOW:
@@ -2728,8 +2815,8 @@ static void SV_Physics_Entity (prvm_edict_t *ent)
                if (SV_RunThink(ent))
                {
                        SV_CheckWater(ent);
-                       VectorMA(ent->fields.server->origin, sv.frametime, ent->fields.server->velocity, ent->fields.server->origin);
-                       VectorMA(ent->fields.server->angles, sv.frametime, ent->fields.server->avelocity, ent->fields.server->angles);
+                       VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
+                       VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
                }
                SV_LinkEdict(ent);
                break;
@@ -2745,6 +2832,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);
@@ -2757,7 +2845,7 @@ static void SV_Physics_Entity (prvm_edict_t *ent)
                }
                break;
        default:
-               Con_Printf ("SV_Physics: bad movetype %i\n", (int)ent->fields.server->movetype);
+               Con_Printf ("SV_Physics: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
                break;
        }
 }
@@ -2768,15 +2856,15 @@ void SV_Physics_ClientMove(void)
        ent = host_client->edict;
 
        // call player physics, this needs the proper frametime
-       prog->globals.server->frametime = sv.frametime;
+       PRVM_serverglobalfloat(frametime) = sv.frametime;
        SV_ClientThink();
 
        // call standard client pre-think, with frametime = 0
-       prog->globals.server->time = sv.time;
-       prog->globals.server->frametime = 0;
-       prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
-       PRVM_ExecuteProgram (prog->globals.server->PlayerPreThink, "QC function PlayerPreThink is missing");
-       prog->globals.server->frametime = sv.frametime;
+       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");
+       PRVM_serverglobalfloat(frametime) = sv.frametime;
 
        // make sure the velocity is sane (not a NaN)
        SV_CheckVelocity(ent);
@@ -2785,21 +2873,21 @@ void SV_Physics_ClientMove(void)
        SV_WalkMove (ent);
 
        // call standard player post-think, with frametime = 0
-       prog->globals.server->time = sv.time;
-       prog->globals.server->frametime = 0;
-       prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
-       PRVM_ExecuteProgram (prog->globals.server->PlayerPostThink, "QC function PlayerPostThink is missing");
-       prog->globals.server->frametime = sv.frametime;
+       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");
+       PRVM_serverglobalfloat(frametime) = sv.frametime;
 
-       if(ent->fields.server->fixangle)
+       if(PRVM_serveredictfloat(ent, fixangle))
        {
                // angle fixing was requested by physics code...
                // so store the current angles for later use
-               memcpy(host_client->fixangle_angles, ent->fields.server->angles, sizeof(host_client->fixangle_angles));
+               memcpy(host_client->fixangle_angles, PRVM_serveredictvector(ent, angles), sizeof(host_client->fixangle_angles));
                host_client->fixangle_angles_set = TRUE;
 
                // and clear fixangle for the next frame
-               ent->fields.server->fixangle = 0;
+               PRVM_serveredictfloat(ent, fixangle) = 0;
        }
 }
 
@@ -2823,9 +2911,9 @@ static void SV_Physics_ClientEntity_PreThink(prvm_edict_t *ent)
        SV_CheckVelocity(ent);
 
        // call standard client pre-think
-       prog->globals.server->time = sv.time;
-       prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
-       PRVM_ExecuteProgram(prog->globals.server->PlayerPreThink, "QC function PlayerPreThink is missing");
+       PRVM_serverglobalfloat(time) = sv.time;
+       PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
+       PRVM_ExecuteProgram(PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
 
        // make sure the velocity is still sane (not a NaN)
        SV_CheckVelocity(ent);
@@ -2841,22 +2929,22 @@ static void SV_Physics_ClientEntity_PostThink(prvm_edict_t *ent)
        SV_CheckVelocity(ent);
 
        // call standard player post-think
-       prog->globals.server->time = sv.time;
-       prog->globals.server->self = PRVM_EDICT_TO_PROG(ent);
-       PRVM_ExecuteProgram(prog->globals.server->PlayerPostThink, "QC function PlayerPostThink is missing");
+       PRVM_serverglobalfloat(time) = sv.time;
+       PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
+       PRVM_ExecuteProgram(PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
 
        // make sure the velocity is still sane (not a NaN)
        SV_CheckVelocity(ent);
 
-       if(ent->fields.server->fixangle)
+       if(PRVM_serveredictfloat(ent, fixangle))
        {
                // angle fixing was requested by physics code...
                // so store the current angles for later use
-               memcpy(host_client->fixangle_angles, ent->fields.server->angles, sizeof(host_client->fixangle_angles));
+               memcpy(host_client->fixangle_angles, PRVM_serveredictvector(ent, angles), sizeof(host_client->fixangle_angles));
                host_client->fixangle_angles_set = TRUE;
 
                // and clear fixangle for the next frame
-               ent->fields.server->fixangle = 0;
+               PRVM_serveredictfloat(ent, fixangle) = 0;
        }
 
        // decrement the countdown variable used to decide when to go back to
@@ -2879,7 +2967,7 @@ static void SV_Physics_ClientEntity(prvm_edict_t *ent)
        // make sure the velocity is sane (not a NaN)
        SV_CheckVelocity(ent);
 
-       switch ((int) ent->fields.server->movetype)
+       switch ((int) PRVM_serveredictfloat(ent, movetype))
        {
        case MOVETYPE_PUSH:
        case MOVETYPE_FAKEPUSH:
@@ -2887,7 +2975,7 @@ static void SV_Physics_ClientEntity(prvm_edict_t *ent)
                break;
        case MOVETYPE_NONE:
                // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
-               if (ent->fields.server->nextthink > 0 && ent->fields.server->nextthink <= sv.time + sv.frametime)
+               if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime)
                        SV_RunThink (ent);
                break;
        case MOVETYPE_FOLLOW:
@@ -2896,8 +2984,8 @@ static void SV_Physics_ClientEntity(prvm_edict_t *ent)
        case MOVETYPE_NOCLIP:
                SV_RunThink(ent);
                SV_CheckWater(ent);
-               VectorMA(ent->fields.server->origin, sv.frametime, ent->fields.server->velocity, ent->fields.server->origin);
-               VectorMA(ent->fields.server->angles, sv.frametime, ent->fields.server->avelocity, ent->fields.server->angles);
+               VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
+               VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
                break;
        case MOVETYPE_STEP:
                SV_Physics_Step (ent);
@@ -2917,6 +3005,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;
@@ -2924,7 +3013,7 @@ static void SV_Physics_ClientEntity(prvm_edict_t *ent)
                SV_RunThink (ent);
                break;
        default:
-               Con_Printf ("SV_Physics_ClientEntity: bad movetype %i\n", (int)ent->fields.server->movetype);
+               Con_Printf ("SV_Physics_ClientEntity: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
                break;
        }
 
@@ -2948,11 +3037,11 @@ void SV_Physics (void)
        prvm_edict_t *ent;
 
 // let the progs know that a new frame has started
-       prog->globals.server->self = PRVM_EDICT_TO_PROG(prog->edicts);
-       prog->globals.server->other = PRVM_EDICT_TO_PROG(prog->edicts);
-       prog->globals.server->time = sv.time;
-       prog->globals.server->frametime = sv.frametime;
-       PRVM_ExecuteProgram (prog->globals.server->StartFrame, "QC function StartFrame is missing");
+       PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts);
+       PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
+       PRVM_serverglobalfloat(time) = sv.time;
+       PRVM_serverglobalfloat(frametime) = sv.frametime;
+       PRVM_ExecuteProgram (PRVM_serverfunction(StartFrame), "QC function StartFrame is missing");
 
        // run physics engine
        World_Physics_Frame(&sv.world, sv.frametime, sv_gravity.value);
@@ -2962,7 +3051,7 @@ void SV_Physics (void)
 //
 
        // if force_retouch, relink all the entities
-       if (prog->globals.server->force_retouch > 0)
+       if (PRVM_serverglobalfloat(force_retouch) > 0)
                for (i = 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
                        if (!ent->priv.server->free)
                                SV_LinkEdict_TouchAreaGrid(ent); // force retouch even for stationary
@@ -3010,16 +3099,16 @@ void SV_Physics (void)
                                        SV_Physics_Entity(ent);
        }
 
-       if (prog->globals.server->force_retouch > 0)
-               prog->globals.server->force_retouch = max(0, prog->globals.server->force_retouch - 1);
+       if (PRVM_serverglobalfloat(force_retouch) > 0)
+               PRVM_serverglobalfloat(force_retouch) = max(0, PRVM_serverglobalfloat(force_retouch) - 1);
 
        // LordHavoc: endframe support
-       if (prog->funcoffsets.EndFrame)
+       if (PRVM_serverfunction(EndFrame))
        {
-               prog->globals.server->self = PRVM_EDICT_TO_PROG(prog->edicts);
-               prog->globals.server->other = PRVM_EDICT_TO_PROG(prog->edicts);
-               prog->globals.server->time = sv.time;
-               PRVM_ExecuteProgram (prog->funcoffsets.EndFrame, "QC function EndFrame is missing");
+               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");
        }
 
        // decrement prog->num_edicts if the highest number entities died
index 548a1298dd62eafa2469e84d2c283d64201c81a3..7b59de998cae788d0c60b2b9b9536c710ff650d6 100644 (file)
--- a/sv_user.c
+++ b/sv_user.c
@@ -41,18 +41,18 @@ void SV_SetIdealPitch (void)
        int             i, j;
        int             steps;
 
-       if (!((int)host_client->edict->fields.server->flags & FL_ONGROUND))
+       if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_ONGROUND))
                return;
 
-       angleval = host_client->edict->fields.server->angles[YAW] * M_PI*2 / 360;
+       angleval = PRVM_serveredictvector(host_client->edict, angles)[YAW] * M_PI*2 / 360;
        sinval = sin(angleval);
        cosval = cos(angleval);
 
        for (i=0 ; i<MAX_FORWARD ; i++)
        {
-               top[0] = host_client->edict->fields.server->origin[0] + cosval*(i+3)*12;
-               top[1] = host_client->edict->fields.server->origin[1] + sinval*(i+3)*12;
-               top[2] = host_client->edict->fields.server->origin[2] + host_client->edict->fields.server->view_ofs[2];
+               top[0] = PRVM_serveredictvector(host_client->edict, origin)[0] + cosval*(i+3)*12;
+               top[1] = PRVM_serveredictvector(host_client->edict, origin)[1] + sinval*(i+3)*12;
+               top[2] = PRVM_serveredictvector(host_client->edict, origin)[2] + PRVM_serveredictvector(host_client->edict, view_ofs)[2];
 
                bottom[0] = top[0];
                bottom[1] = top[1];
@@ -88,13 +88,13 @@ void SV_SetIdealPitch (void)
 
        if (!dir)
        {
-               host_client->edict->fields.server->idealpitch = 0;
+               PRVM_serveredictfloat(host_client->edict, idealpitch) = 0;
                return;
        }
 
        if (steps < 2)
                return;
-       host_client->edict->fields.server->idealpitch = -dir * sv_idealpitchscale.value;
+       PRVM_serveredictfloat(host_client->edict, idealpitch) = -dir * sv_idealpitchscale.value;
 }
 
 static vec3_t wishdir, forward, right, up;
@@ -114,14 +114,14 @@ void SV_UserFriction (void)
        vec3_t start, stop;
        trace_t trace;
 
-       speed = sqrt(host_client->edict->fields.server->velocity[0]*host_client->edict->fields.server->velocity[0]+host_client->edict->fields.server->velocity[1]*host_client->edict->fields.server->velocity[1]);
+       speed = sqrt(PRVM_serveredictvector(host_client->edict, velocity)[0]*PRVM_serveredictvector(host_client->edict, velocity)[0]+PRVM_serveredictvector(host_client->edict, velocity)[1]*PRVM_serveredictvector(host_client->edict, velocity)[1]);
        if (!speed)
                return;
 
        // if the leading edge is over a dropoff, increase friction
-       start[0] = stop[0] = host_client->edict->fields.server->origin[0] + host_client->edict->fields.server->velocity[0]/speed*16;
-       start[1] = stop[1] = host_client->edict->fields.server->origin[1] + host_client->edict->fields.server->velocity[1]/speed*16;
-       start[2] = host_client->edict->fields.server->origin[2] + host_client->edict->fields.server->mins[2];
+       start[0] = stop[0] = PRVM_serveredictvector(host_client->edict, origin)[0] + PRVM_serveredictvector(host_client->edict, velocity)[0]/speed*16;
+       start[1] = stop[1] = PRVM_serveredictvector(host_client->edict, origin)[1] + PRVM_serveredictvector(host_client->edict, velocity)[1]/speed*16;
+       start[2] = PRVM_serveredictvector(host_client->edict, origin)[2] + PRVM_serveredictvector(host_client->edict, mins)[2];
        stop[2] = start[2] - 34;
 
        trace = SV_TraceLine(start, stop, MOVE_NOMONSTERS, host_client->edict, SV_GenericHitSuperContentsMask(host_client->edict));
@@ -140,7 +140,7 @@ void SV_UserFriction (void)
        else
                newspeed /= speed;
 
-       VectorScale(host_client->edict->fields.server->velocity, newspeed, host_client->edict->fields.server->velocity);
+       VectorScale(PRVM_serveredictvector(host_client->edict, velocity), newspeed, PRVM_serveredictvector(host_client->edict, velocity));
 }
 
 /*
@@ -153,7 +153,7 @@ void SV_Accelerate (void)
        int i;
        float addspeed, accelspeed, currentspeed;
 
-       currentspeed = DotProduct (host_client->edict->fields.server->velocity, wishdir);
+       currentspeed = DotProduct (PRVM_serveredictvector(host_client->edict, velocity), wishdir);
        addspeed = wishspeed - currentspeed;
        if (addspeed <= 0)
                return;
@@ -162,7 +162,7 @@ void SV_Accelerate (void)
                accelspeed = addspeed;
 
        for (i=0 ; i<3 ; i++)
-               host_client->edict->fields.server->velocity[i] += accelspeed*wishdir[i];
+               PRVM_serveredictvector(host_client->edict, velocity)[i] += accelspeed*wishdir[i];
 }
 
 extern cvar_t sv_gameplayfix_q2airaccelerate;
@@ -174,7 +174,7 @@ void SV_AirAccelerate (vec3_t wishveloc)
        wishspd = VectorNormalizeLength (wishveloc);
        if (wishspd > sv_maxairspeed.value)
                wishspd = sv_maxairspeed.value;
-       currentspeed = DotProduct (host_client->edict->fields.server->velocity, wishveloc);
+       currentspeed = DotProduct (PRVM_serveredictvector(host_client->edict, velocity), wishveloc);
        addspeed = wishspd - currentspeed;
        if (addspeed <= 0)
                return;
@@ -183,31 +183,32 @@ void SV_AirAccelerate (vec3_t wishveloc)
                accelspeed = addspeed;
 
        for (i=0 ; i<3 ; i++)
-               host_client->edict->fields.server->velocity[i] += accelspeed*wishveloc[i];
+               PRVM_serveredictvector(host_client->edict, velocity)[i] += accelspeed*wishveloc[i];
 }
 
 
 void DropPunchAngle (void)
 {
        float len;
-       prvm_eval_t *val;
+       vec3_t v;
 
-       len = VectorNormalizeLength (host_client->edict->fields.server->punchangle);
+       len = VectorNormalizeLength (PRVM_serveredictvector(host_client->edict, punchangle));
 
        len -= 10*sv.frametime;
        if (len < 0)
                len = 0;
-       VectorScale (host_client->edict->fields.server->punchangle, len, host_client->edict->fields.server->punchangle);
+       VectorScale (PRVM_serveredictvector(host_client->edict, punchangle), len, PRVM_serveredictvector(host_client->edict, punchangle));
 
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.punchvector)))
+       VectorCopy(PRVM_serveredictvector(host_client->edict, punchvector), v);
+       len = VectorNormalizeLength(v);
+       if (len > 0)
        {
-               len = VectorNormalizeLength (val->vector);
-
                len -= 20*sv.frametime;
                if (len < 0)
                        len = 0;
-               VectorScale (val->vector, len, val->vector);
+               VectorScale(v, len, v);
        }
+       VectorCopy(v, PRVM_serveredictvector(host_client->edict, punchvector));
 }
 
 /*
@@ -220,16 +221,16 @@ void SV_FreeMove (void)
        int i;
        float wishspeed;
 
-       AngleVectors (host_client->edict->fields.server->v_angle, forward, right, up);
+       AngleVectors (PRVM_serveredictvector(host_client->edict, v_angle), forward, right, up);
 
        for (i = 0; i < 3; i++)
-               host_client->edict->fields.server->velocity[i] = forward[i] * cmd.forwardmove + right[i] * cmd.sidemove;
+               PRVM_serveredictvector(host_client->edict, velocity)[i] = forward[i] * cmd.forwardmove + right[i] * cmd.sidemove;
 
-       host_client->edict->fields.server->velocity[2] += cmd.upmove;
+       PRVM_serveredictvector(host_client->edict, velocity)[2] += cmd.upmove;
 
-       wishspeed = VectorLength(host_client->edict->fields.server->velocity);
+       wishspeed = VectorLength(PRVM_serveredictvector(host_client->edict, velocity));
        if (wishspeed > sv_maxspeed.value)
-               VectorScale(host_client->edict->fields.server->velocity, sv_maxspeed.value / wishspeed, host_client->edict->fields.server->velocity);
+               VectorScale(PRVM_serveredictvector(host_client->edict, velocity), sv_maxspeed.value / wishspeed, PRVM_serveredictvector(host_client->edict, velocity));
 }
 
 /*
@@ -245,7 +246,7 @@ void SV_WaterMove (void)
        float speed, newspeed, wishspeed, addspeed, accelspeed, temp;
 
        // user intentions
-       AngleVectors (host_client->edict->fields.server->v_angle, forward, right, up);
+       AngleVectors (PRVM_serveredictvector(host_client->edict, v_angle), forward, right, up);
 
        for (i=0 ; i<3 ; i++)
                wishvel[i] = forward[i]*cmd.forwardmove + right[i]*cmd.sidemove;
@@ -265,14 +266,14 @@ void SV_WaterMove (void)
        wishspeed *= 0.7;
 
        // water friction
-       speed = VectorLength(host_client->edict->fields.server->velocity);
+       speed = VectorLength(PRVM_serveredictvector(host_client->edict, velocity));
        if (speed)
        {
                newspeed = speed - sv.frametime * speed * (sv_waterfriction.value < 0 ? sv_friction.value : sv_waterfriction.value);
                if (newspeed < 0)
                        newspeed = 0;
                temp = newspeed/speed;
-               VectorScale(host_client->edict->fields.server->velocity, temp, host_client->edict->fields.server->velocity);
+               VectorScale(PRVM_serveredictvector(host_client->edict, velocity), temp, PRVM_serveredictvector(host_client->edict, velocity));
        }
        else
                newspeed = 0;
@@ -291,18 +292,18 @@ void SV_WaterMove (void)
                accelspeed = addspeed;
 
        for (i=0 ; i<3 ; i++)
-               host_client->edict->fields.server->velocity[i] += accelspeed * wishvel[i];
+               PRVM_serveredictvector(host_client->edict, velocity)[i] += accelspeed * wishvel[i];
 }
 
 void SV_WaterJump (void)
 {
-       if (sv.time > host_client->edict->fields.server->teleport_time || !host_client->edict->fields.server->waterlevel)
+       if (sv.time > PRVM_serveredictfloat(host_client->edict, teleport_time) || !PRVM_serveredictfloat(host_client->edict, waterlevel))
        {
-               host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags & ~FL_WATERJUMP;
-               host_client->edict->fields.server->teleport_time = 0;
+               PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) & ~FL_WATERJUMP;
+               PRVM_serveredictfloat(host_client->edict, teleport_time) = 0;
        }
-       host_client->edict->fields.server->velocity[0] = host_client->edict->fields.server->movedir[0];
-       host_client->edict->fields.server->velocity[1] = host_client->edict->fields.server->movedir[1];
+       PRVM_serveredictvector(host_client->edict, velocity)[0] = PRVM_serveredictvector(host_client->edict, movedir)[0];
+       PRVM_serveredictvector(host_client->edict, velocity)[1] = PRVM_serveredictvector(host_client->edict, movedir)[1];
 }
 
 
@@ -320,20 +321,20 @@ void SV_AirMove (void)
 
        // LordHavoc: correct quake movement speed bug when looking up/down
        wishvel[0] = wishvel[2] = 0;
-       wishvel[1] = host_client->edict->fields.server->angles[1];
+       wishvel[1] = PRVM_serveredictvector(host_client->edict, angles)[1];
        AngleVectors (wishvel, forward, right, up);
 
        fmove = cmd.forwardmove;
        smove = cmd.sidemove;
 
 // hack to not let you back into teleporter
-       if (sv.time < host_client->edict->fields.server->teleport_time && fmove < 0)
+       if (sv.time < PRVM_serveredictfloat(host_client->edict, teleport_time) && fmove < 0)
                fmove = 0;
 
        for (i=0 ; i<3 ; i++)
                wishvel[i] = forward[i]*fmove + right[i]*smove;
 
-       if ((int)host_client->edict->fields.server->movetype != MOVETYPE_WALK)
+       if ((int)PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_WALK)
                wishvel[2] += cmd.upmove;
 
        VectorCopy (wishvel, wishdir);
@@ -345,10 +346,10 @@ void SV_AirMove (void)
                wishspeed = sv_maxspeed.value;
        }
 
-       if (host_client->edict->fields.server->movetype == MOVETYPE_NOCLIP)
+       if (PRVM_serveredictfloat(host_client->edict, movetype) == MOVETYPE_NOCLIP)
        {
                // noclip
-               VectorCopy (wishvel, host_client->edict->fields.server->velocity);
+               VectorCopy (wishvel, PRVM_serveredictvector(host_client->edict, velocity));
        }
        else if (onground)
        {
@@ -381,39 +382,39 @@ void SV_ClientThink (void)
        SV_CheckVelocity(host_client->edict);
 
        // LordHavoc: QuakeC replacement for SV_ClientThink (player movement)
-       if (prog->funcoffsets.SV_PlayerPhysics && sv_playerphysicsqc.integer)
+       if (PRVM_serverfunction(SV_PlayerPhysics) && sv_playerphysicsqc.integer)
        {
-               prog->globals.server->time = sv.time;
-               prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
-               PRVM_ExecuteProgram (prog->funcoffsets.SV_PlayerPhysics, "QC function SV_PlayerPhysics is missing");
+               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");
                SV_CheckVelocity(host_client->edict);
                return;
        }
 
-       if (host_client->edict->fields.server->movetype == MOVETYPE_NONE)
+       if (PRVM_serveredictfloat(host_client->edict, movetype) == MOVETYPE_NONE)
                return;
 
-       onground = ((int)host_client->edict->fields.server->flags & FL_ONGROUND) != 0;
+       onground = ((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_ONGROUND) != 0;
 
        DropPunchAngle ();
 
        // if dead, behave differently
-       if (host_client->edict->fields.server->health <= 0)
+       if (PRVM_serveredictfloat(host_client->edict, health) <= 0)
                return;
 
        cmd = host_client->cmd;
 
        // angles
        // show 1/3 the pitch angle and all the roll angle
-       VectorAdd (host_client->edict->fields.server->v_angle, host_client->edict->fields.server->punchangle, v_angle);
-       host_client->edict->fields.server->angles[ROLL] = V_CalcRoll (host_client->edict->fields.server->angles, host_client->edict->fields.server->velocity)*4;
-       if (!host_client->edict->fields.server->fixangle)
+       VectorAdd (PRVM_serveredictvector(host_client->edict, v_angle), PRVM_serveredictvector(host_client->edict, punchangle), v_angle);
+       PRVM_serveredictvector(host_client->edict, angles)[ROLL] = V_CalcRoll (PRVM_serveredictvector(host_client->edict, angles), PRVM_serveredictvector(host_client->edict, velocity))*4;
+       if (!PRVM_serveredictfloat(host_client->edict, fixangle))
        {
-               host_client->edict->fields.server->angles[PITCH] = -v_angle[PITCH]/3;
-               host_client->edict->fields.server->angles[YAW] = v_angle[YAW];
+               PRVM_serveredictvector(host_client->edict, angles)[PITCH] = -v_angle[PITCH]/3;
+               PRVM_serveredictvector(host_client->edict, angles)[YAW] = v_angle[YAW];
        }
 
-       if ( (int)host_client->edict->fields.server->flags & FL_WATERJUMP )
+       if ( (int)PRVM_serveredictfloat(host_client->edict, flags) & FL_WATERJUMP )
        {
                SV_WaterJump ();
                SV_CheckVelocity(host_client->edict);
@@ -422,8 +423,8 @@ void SV_ClientThink (void)
 
        /*
        // Player is (somehow) outside of the map, or flying, or noclipping
-       if (host_client->edict->fields.server->movetype != MOVETYPE_NOCLIP && (host_client->edict->fields.server->movetype == MOVETYPE_FLY || SV_TestEntityPosition (host_client->edict)))
-       //if (host_client->edict->fields.server->movetype == MOVETYPE_NOCLIP || host_client->edict->fields.server->movetype == MOVETYPE_FLY || SV_TestEntityPosition (host_client->edict))
+       if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_NOCLIP && (PRVM_serveredictfloat(host_client->edict, movetype) == MOVETYPE_FLY || SV_TestEntityPosition (host_client->edict)))
+       //if (PRVM_serveredictfloat(host_client->edict, movetype) == MOVETYPE_NOCLIP || PRVM_serveredictfloat(host_client->edict, movetype) == MOVETYPE_FLY || SV_TestEntityPosition (host_client->edict))
        {
                SV_FreeMove ();
                return;
@@ -431,7 +432,7 @@ void SV_ClientThink (void)
        */
 
        // walk
-       if ((host_client->edict->fields.server->waterlevel >= 2) && (host_client->edict->fields.server->movetype != MOVETYPE_NOCLIP))
+       if ((PRVM_serveredictfloat(host_client->edict, waterlevel) >= 2) && (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_NOCLIP))
        {
                SV_WaterMove ();
                SV_CheckVelocity(host_client->edict);
@@ -584,7 +585,6 @@ void SV_ExecuteClientMoves(void)
 #ifdef NUM_PING_TIMES
        double total;
 #endif
-       prvm_eval_t *val;
        if (sv_numreadmoves < 1)
                return;
        // only start accepting input once the player is spawned
@@ -597,7 +597,7 @@ void SV_ExecuteClientMoves(void)
        if (ceil(max(sv_readmoves[sv_numreadmoves-1].receivetime - sv_readmoves[sv_numreadmoves-1].time, 0) * 1000.0) < sv_clmovement_minping.integer)
                host_client->clmovement_disabletimeout = realtime + sv_clmovement_minping_disabletime.value / 1000.0;
        // several conditions govern whether clientside movement prediction is allowed
-       if (sv_readmoves[sv_numreadmoves-1].sequence && sv_clmovement_enable.integer && sv_clmovement_inputtimeout.value > 0 && host_client->clmovement_disabletimeout <= realtime && host_client->edict->fields.server->movetype == MOVETYPE_WALK && (!(val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.disableclientprediction)) || !val->_float))
+       if (sv_readmoves[sv_numreadmoves-1].sequence && sv_clmovement_enable.integer && sv_clmovement_inputtimeout.value > 0 && host_client->clmovement_disabletimeout <= realtime && PRVM_serveredictfloat(host_client->edict, movetype) == MOVETYPE_WALK && (!PRVM_serveredictfloat(host_client->edict, disableclientprediction)))
        {
                // process the moves in order and ignore old ones
                // but always trust the latest move
@@ -646,21 +646,21 @@ void SV_ExecuteClientMoves(void)
                                //  determined by the sv_clmovement_inputtimeout cvar)
                                if (moveframetime <= 0)
                                        continue;
-                               oldframetime = prog->globals.server->frametime;
+                               oldframetime = PRVM_serverglobalfloat(frametime);
                                oldframetime2 = sv.frametime;
                                // update ping time for qc to see while executing this move
                                host_client->ping = host_client->cmd.receivetime - host_client->cmd.time;
                                // the server and qc frametime values must be changed temporarily
-                               prog->globals.server->frametime = sv.frametime = moveframetime;
+                               PRVM_serverglobalfloat(frametime) = sv.frametime = moveframetime;
                                // if move is more than 50ms, split it into two moves (this matches QWSV behavior and the client prediction)
                                if (sv.frametime > 0.05)
                                {
-                                       prog->globals.server->frametime = sv.frametime = moveframetime * 0.5f;
+                                       PRVM_serverglobalfloat(frametime) = sv.frametime = moveframetime * 0.5f;
                                        SV_Physics_ClientMove();
                                }
                                SV_Physics_ClientMove();
                                sv.frametime = oldframetime2;
-                               prog->globals.server->frametime = oldframetime;
+                               PRVM_serverglobalfloat(frametime) = oldframetime;
                                host_client->clmovement_inputtimeout = sv_clmovement_inputtimeout.value;
                        }
                }
@@ -705,7 +705,6 @@ void SV_ExecuteClientMoves(void)
 
 void SV_ApplyClientMove (void)
 {
-       prvm_eval_t *val;
        usercmd_t *move = &host_client->cmd;
        int j, movementloss, packetloss;
 
@@ -720,10 +719,10 @@ void SV_ApplyClientMove (void)
        move->applied = true;
 
        // set the edict fields
-       host_client->edict->fields.server->button0 = move->buttons & 1;
-       host_client->edict->fields.server->button2 = (move->buttons & 2)>>1;
+       PRVM_serveredictfloat(host_client->edict, button0) = move->buttons & 1;
+       PRVM_serveredictfloat(host_client->edict, button2) = (move->buttons & 2)>>1;
        if (move->impulse)
-               host_client->edict->fields.server->impulse = move->impulse;
+               PRVM_serveredictfloat(host_client->edict, impulse) = move->impulse;
        // only send the impulse to qc once
        move->impulse = 0;
 
@@ -738,32 +737,32 @@ void SV_ApplyClientMove (void)
                                movementloss++;
        }
 
-       VectorCopy(move->viewangles, host_client->edict->fields.server->v_angle);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button3))) val->_float = ((move->buttons >> 2) & 1);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button4))) val->_float = ((move->buttons >> 3) & 1);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button5))) val->_float = ((move->buttons >> 4) & 1);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button6))) val->_float = ((move->buttons >> 5) & 1);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button7))) val->_float = ((move->buttons >> 6) & 1);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button8))) val->_float = ((move->buttons >> 7) & 1);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button9))) val->_float = ((move->buttons >> 11) & 1);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button10))) val->_float = ((move->buttons >> 12) & 1);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button11))) val->_float = ((move->buttons >> 13) & 1);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button12))) val->_float = ((move->buttons >> 14) & 1);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button13))) val->_float = ((move->buttons >> 15) & 1);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button14))) val->_float = ((move->buttons >> 16) & 1);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button15))) val->_float = ((move->buttons >> 17) & 1);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.button16))) val->_float = ((move->buttons >> 18) & 1);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.buttonuse))) val->_float = ((move->buttons >> 8) & 1);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.buttonchat))) val->_float = ((move->buttons >> 9) & 1);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.cursor_active))) val->_float = ((move->buttons >> 10) & 1);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.movement))) VectorSet(val->vector, move->forwardmove, move->sidemove, move->upmove);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.cursor_screen))) VectorCopy(move->cursor_screen, val->vector);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.cursor_trace_start))) VectorCopy(move->cursor_start, val->vector);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.cursor_trace_endpos))) VectorCopy(move->cursor_impact, val->vector);
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.cursor_trace_ent))) val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM(move->cursor_entitynumber));
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ping))) val->_float = host_client->ping * 1000.0;
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.packetloss))) val->_float = packetloss / (float) NETGRAPH_PACKETS;
-       if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.movementloss))) val->_float = movementloss / (float) NETGRAPH_PACKETS;
+       VectorCopy(move->viewangles, PRVM_serveredictvector(host_client->edict, v_angle));
+       PRVM_serveredictfloat(host_client->edict, button3) = ((move->buttons >> 2) & 1);
+       PRVM_serveredictfloat(host_client->edict, button4) = ((move->buttons >> 3) & 1);
+       PRVM_serveredictfloat(host_client->edict, button5) = ((move->buttons >> 4) & 1);
+       PRVM_serveredictfloat(host_client->edict, button6) = ((move->buttons >> 5) & 1);
+       PRVM_serveredictfloat(host_client->edict, button7) = ((move->buttons >> 6) & 1);
+       PRVM_serveredictfloat(host_client->edict, button8) = ((move->buttons >> 7) & 1);
+       PRVM_serveredictfloat(host_client->edict, button9) = ((move->buttons >> 11) & 1);
+       PRVM_serveredictfloat(host_client->edict, button10) = ((move->buttons >> 12) & 1);
+       PRVM_serveredictfloat(host_client->edict, button11) = ((move->buttons >> 13) & 1);
+       PRVM_serveredictfloat(host_client->edict, button12) = ((move->buttons >> 14) & 1);
+       PRVM_serveredictfloat(host_client->edict, button13) = ((move->buttons >> 15) & 1);
+       PRVM_serveredictfloat(host_client->edict, button14) = ((move->buttons >> 16) & 1);
+       PRVM_serveredictfloat(host_client->edict, button15) = ((move->buttons >> 17) & 1);
+       PRVM_serveredictfloat(host_client->edict, button16) = ((move->buttons >> 18) & 1);
+       PRVM_serveredictfloat(host_client->edict, buttonuse) = ((move->buttons >> 8) & 1);
+       PRVM_serveredictfloat(host_client->edict, buttonchat) = ((move->buttons >> 9) & 1);
+       PRVM_serveredictfloat(host_client->edict, cursor_active) = ((move->buttons >> 10) & 1);
+       VectorSet(PRVM_serveredictvector(host_client->edict, movement), move->forwardmove, move->sidemove, move->upmove);
+       VectorCopy(move->cursor_screen, PRVM_serveredictvector(host_client->edict, cursor_screen));
+       VectorCopy(move->cursor_start, PRVM_serveredictvector(host_client->edict, cursor_trace_start));
+       VectorCopy(move->cursor_impact, PRVM_serveredictvector(host_client->edict, cursor_trace_endpos));
+       PRVM_serveredictedict(host_client->edict, cursor_trace_ent) = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM(move->cursor_entitynumber));
+       PRVM_serveredictfloat(host_client->edict, ping) = host_client->ping * 1000.0;
+       PRVM_serveredictfloat(host_client->edict, ping_packetloss) = packetloss / (float) NETGRAPH_PACKETS;
+       PRVM_serveredictfloat(host_client->edict, ping_movementloss) = movementloss / (float) NETGRAPH_PACKETS;
 }
 
 void SV_FrameLost(int framenum)
@@ -864,13 +863,13 @@ void SV_ReadClientMessage(void)
                         || strncasecmp(s, "begin", 5) == 0
                         || strncasecmp(s, "prespawn", 8) == 0)
                                Cmd_ExecuteString (s, src_client);
-                       else if (prog->funcoffsets.SV_ParseClientCommand)
+                       else if (PRVM_serverfunction(SV_ParseClientCommand))
                        {
                                int restorevm_tempstringsbuf_cursize;
                                restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
                                PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(s);
-                               prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
-                               PRVM_ExecuteProgram (prog->funcoffsets.SV_ParseClientCommand, "QC function SV_ParseClientCommand is missing");
+                               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;
                        }
                        else
index 0efb61bf19375155dafd386dcf5327f0e4071195..617d1e3362f303c59743330dc94f44eb24b09981 100644 (file)
@@ -51,6 +51,7 @@ const char *vm_sv_extensions =
 "DP_ENT_GLOWMOD "
 "DP_ENT_LOWPRECISION "
 "DP_ENT_SCALE "
+"DP_ENT_TRAILEFFECTNUM "
 "DP_ENT_VIEWMODEL "
 "DP_GECKO_SUPPORT "
 "DP_GFX_EXTERNALTEXTURES "
@@ -73,6 +74,7 @@ const char *vm_sv_extensions =
 "DP_LITSUPPORT "
 "DP_MONSTERWALK "
 "DP_MOVETYPEBOUNCEMISSILE "
+"DP_MOVETYPEFLYWORLDONLY "
 "DP_MOVETYPEFOLLOW "
 "DP_NULL_MODEL "
 "DP_QC_ASINACOSATANATAN2TAN "
@@ -139,6 +141,7 @@ const char *vm_sv_extensions =
 "DP_SKELETONOBJECTS "
 "DP_SND_DIRECTIONLESSATTNNONE "
 "DP_SND_FAKETRACKS "
+"DP_SND_SOUND7_WIP1 "
 "DP_SND_OGGVORBIS "
 "DP_SND_SETPARAMS "
 "DP_SND_STEREOWAV "
@@ -242,7 +245,7 @@ static void VM_SV_setorigin (void)
                return;
        }
        org = PRVM_G_VECTOR(OFS_PARM1);
-       VectorCopy (org, e->fields.server->origin);
+       VectorCopy (org, PRVM_serveredictvector(e, origin));
        SV_LinkEdict(e);
 }
 
@@ -256,9 +259,9 @@ static void SetMinMaxSize (prvm_edict_t *e, float *min, float *max, qboolean rot
                        PRVM_ERROR("SetMinMaxSize: backwards mins/maxs");
 
 // set derived values
-       VectorCopy (min, e->fields.server->mins);
-       VectorCopy (max, e->fields.server->maxs);
-       VectorSubtract (max, min, e->fields.server->size);
+       VectorCopy (min, PRVM_serveredictvector(e, mins));
+       VectorCopy (max, PRVM_serveredictvector(e, maxs));
+       VectorSubtract (max, min, PRVM_serveredictvector(e, size));
 
        SV_LinkEdict(e);
 }
@@ -325,8 +328,8 @@ static void VM_SV_setmodel (void)
                return;
        }
        i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1);
-       e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
-       e->fields.server->modelindex = i;
+       PRVM_serveredictstring(e, model) = PRVM_SetEngineString(sv.model_precache[i]);
+       PRVM_serveredictfloat(e, modelindex) = i;
 
        mod = SV_GetModelByIndex(i);
 
@@ -509,20 +512,39 @@ static void VM_SV_sound (void)
        int                     channel;
        prvm_edict_t            *entity;
        int             volume;
+       int flags;
        float attenuation;
+       float pitchchange;
 
-       VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_sound);
+       VM_SAFEPARMCOUNTRANGE(4, 7, VM_SV_sound);
 
        entity = PRVM_G_EDICT(OFS_PARM0);
        channel = (int)PRVM_G_FLOAT(OFS_PARM1);
        sample = PRVM_G_STRING(OFS_PARM2);
        volume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255);
-       attenuation = PRVM_G_FLOAT(OFS_PARM4);
        if (prog->argc < 5)
        {
                Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n");
                attenuation = 1;
        }
+       else
+               attenuation = PRVM_G_FLOAT(OFS_PARM4);
+       if (prog->argc < 6)
+               pitchchange = 0;
+       else
+               pitchchange = PRVM_G_FLOAT(OFS_PARM5);
+
+       if (prog->argc < 7)
+       {
+               flags = 0;
+               if(channel >= 8 && channel <= 15) // weird QW feature
+               {
+                       flags |= CHANFLAG_RELIABLE;
+                       channel -= 8;
+               }
+       }
+       else
+               flags = PRVM_G_FLOAT(OFS_PARM6);
 
        if (volume < 0 || volume > 255)
        {
@@ -536,13 +558,15 @@ static void VM_SV_sound (void)
                return;
        }
 
-       if (channel < 0 || channel > 7)
+       channel = CHAN_USER2ENGINE(channel);
+
+       if (!IS_CHAN(channel))
        {
-               VM_Warning("SV_StartSound: channel must be in range 0-7\n");
+               VM_Warning("SV_StartSound: channel must be in range 0-127\n");
                return;
        }
 
-       SV_StartSound (entity, channel, sample, volume, attenuation);
+       SV_StartSound (entity, channel, sample, volume, attenuation, flags & CHANFLAG_RELIABLE);
 }
 
 /*
@@ -667,40 +691,37 @@ static trace_t SV_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
        vec3_t original_velocity;
        vec3_t original_angles;
        vec3_t original_avelocity;
-       prvm_eval_t *val;
        trace_t trace;
 
-       VectorCopy(tossent->fields.server->origin   , original_origin   );
-       VectorCopy(tossent->fields.server->velocity , original_velocity );
-       VectorCopy(tossent->fields.server->angles   , original_angles   );
-       VectorCopy(tossent->fields.server->avelocity, original_avelocity);
+       VectorCopy(PRVM_serveredictvector(tossent, origin)   , original_origin   );
+       VectorCopy(PRVM_serveredictvector(tossent, velocity) , original_velocity );
+       VectorCopy(PRVM_serveredictvector(tossent, angles)   , original_angles   );
+       VectorCopy(PRVM_serveredictvector(tossent, avelocity), original_avelocity);
 
-       val = PRVM_EDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity);
-       if (val != NULL && val->_float != 0)
-               gravity = val->_float;
-       else
-               gravity = 1.0;
+       gravity = PRVM_serveredictfloat(tossent, gravity);
+       if (!gravity)
+               gravity = 1.0f;
        gravity *= sv_gravity.value * 0.025;
 
        for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
        {
                SV_CheckVelocity (tossent);
-               tossent->fields.server->velocity[2] -= gravity;
-               VectorMA (tossent->fields.server->angles, 0.05, tossent->fields.server->avelocity, tossent->fields.server->angles);
-               VectorScale (tossent->fields.server->velocity, 0.05, move);
-               VectorAdd (tossent->fields.server->origin, move, end);
-               trace = SV_TraceBox(tossent->fields.server->origin, tossent->fields.server->mins, tossent->fields.server->maxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent));
-               VectorCopy (trace.endpos, tossent->fields.server->origin);
-               tossent->fields.server->velocity[2] -= gravity;
+               PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
+               VectorMA (PRVM_serveredictvector(tossent, angles), 0.05, PRVM_serveredictvector(tossent, avelocity), PRVM_serveredictvector(tossent, angles));
+               VectorScale (PRVM_serveredictvector(tossent, velocity), 0.05, move);
+               VectorAdd (PRVM_serveredictvector(tossent, origin), move, end);
+               trace = SV_TraceBox(PRVM_serveredictvector(tossent, origin), PRVM_serveredictvector(tossent, mins), PRVM_serveredictvector(tossent, maxs), end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent));
+               VectorCopy (trace.endpos, PRVM_serveredictvector(tossent, origin));
+               PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
 
                if (trace.fraction < 1)
                        break;
        }
 
-       VectorCopy(original_origin   , tossent->fields.server->origin   );
-       VectorCopy(original_velocity , tossent->fields.server->velocity );
-       VectorCopy(original_angles   , tossent->fields.server->angles   );
-       VectorCopy(original_avelocity, tossent->fields.server->avelocity);
+       VectorCopy(original_origin   , PRVM_serveredictvector(tossent, origin)   );
+       VectorCopy(original_velocity , PRVM_serveredictvector(tossent, velocity) );
+       VectorCopy(original_angles   , PRVM_serveredictvector(tossent, angles)   );
+       VectorCopy(original_avelocity, PRVM_serveredictvector(tossent, avelocity));
 
        return trace;
 }
@@ -757,14 +778,14 @@ static int VM_SV_newcheckclient (int check)
                // look up the client's edict
                ent = PRVM_EDICT_NUM(i);
                // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
-               if (i != check && (ent->priv.server->free || ent->fields.server->health <= 0 || ((int)ent->fields.server->flags & FL_NOTARGET)))
+               if (i != check && (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0 || ((int)PRVM_serveredictfloat(ent, flags) & FL_NOTARGET)))
                        continue;
                // found a valid client (possibly the same one again)
                break;
        }
 
 // get the PVS for the entity
-       VectorAdd(ent->fields.server->origin, ent->fields.server->view_ofs, org);
+       VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, view_ofs), org);
        checkpvsbytes = 0;
        if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
                checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs), false);
@@ -804,15 +825,15 @@ static void VM_SV_checkclient (void)
 
        // return check if it might be visible
        ent = PRVM_EDICT_NUM(sv.lastcheck);
-       if (ent->priv.server->free || ent->fields.server->health <= 0)
+       if (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0)
        {
                VM_RETURN_EDICT(prog->edicts);
                return;
        }
 
        // if current entity can't possibly see the check entity, return 0
-       self = PRVM_PROG_TO_EDICT(prog->globals.server->self);
-       VectorAdd(self->fields.server->origin, self->fields.server->view_ofs, view);
+       self = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
+       VectorAdd(PRVM_serveredictvector(self, origin), PRVM_serveredictvector(self, view_ofs), view);
        if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
        {
                c_notvis++;
@@ -873,7 +894,7 @@ static void VM_SV_checkpvs (void)
                PRVM_G_FLOAT(OFS_RETURN) = 2;
                return;
        }
-       PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, viewee->fields.server->absmin, viewee->fields.server->absmax);
+       PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, PRVM_serveredictvector(viewee, absmin), PRVM_serveredictvector(viewee, absmax));
 #else
        // using fat PVS like FTEQW does (slow)
        if(!sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
@@ -889,7 +910,7 @@ static void VM_SV_checkpvs (void)
                PRVM_G_FLOAT(OFS_RETURN) = 2;
                return;
        }
-       PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, viewee->fields.server->absmin, viewee->fields.server->absmax);
+       PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, PRVM_serveredictvector(viewee, absmin), PRVM_serveredictvector(viewee, absmax));
 #endif
 }
 
@@ -979,23 +1000,23 @@ static void VM_SV_findradius (void)
                prog->xfunction->builtinsprofile++;
                // Quake did not return non-solid entities but darkplaces does
                // (note: this is the reason you can't blow up fallen zombies)
-               if (ent->fields.server->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
+               if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
                        continue;
                // LordHavoc: compare against bounding box rather than center so it
                // doesn't miss large objects, and use DotProduct instead of Length
                // for a major speedup
-               VectorSubtract(org, ent->fields.server->origin, eorg);
+               VectorSubtract(org, PRVM_serveredictvector(ent, origin), eorg);
                if (sv_gameplayfix_findradiusdistancetobox.integer)
                {
-                       eorg[0] -= bound(ent->fields.server->mins[0], eorg[0], ent->fields.server->maxs[0]);
-                       eorg[1] -= bound(ent->fields.server->mins[1], eorg[1], ent->fields.server->maxs[1]);
-                       eorg[2] -= bound(ent->fields.server->mins[2], eorg[2], ent->fields.server->maxs[2]);
+                       eorg[0] -= bound(PRVM_serveredictvector(ent, mins)[0], eorg[0], PRVM_serveredictvector(ent, maxs)[0]);
+                       eorg[1] -= bound(PRVM_serveredictvector(ent, mins)[1], eorg[1], PRVM_serveredictvector(ent, maxs)[1]);
+                       eorg[2] -= bound(PRVM_serveredictvector(ent, mins)[2], eorg[2], PRVM_serveredictvector(ent, maxs)[2]);
                }
                else
-                       VectorMAMAM(1, eorg, -0.5f, ent->fields.server->mins, -0.5f, ent->fields.server->maxs, eorg);
+                       VectorMAMAM(1, eorg, -0.5f, PRVM_serveredictvector(ent, mins), -0.5f, PRVM_serveredictvector(ent, maxs), eorg);
                if (DotProduct(eorg, eorg) < radius2)
                {
-                       PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_EDICT_TO_PROG(chain);
+                       PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain);
                        chain = ent;
                }
        }
@@ -1037,7 +1058,7 @@ static void VM_SV_walkmove (void)
        // assume failure if it returns early
        PRVM_G_FLOAT(OFS_RETURN) = 0;
 
-       ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
+       ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
        if (ent == prog->edicts)
        {
                VM_Warning("walkmove: can not modify world entity\n");
@@ -1052,7 +1073,7 @@ static void VM_SV_walkmove (void)
        dist = PRVM_G_FLOAT(OFS_PARM1);
        settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
 
-       if ( !( (int)ent->fields.server->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
+       if ( !( (int)PRVM_serveredictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
                return;
 
        yaw = yaw*M_PI*2 / 360;
@@ -1063,14 +1084,14 @@ static void VM_SV_walkmove (void)
 
 // save program state, because SV_movestep may call other progs
        oldf = prog->xfunction;
-       oldself = prog->globals.server->self;
+       oldself = PRVM_serverglobaledict(self);
 
        PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true, false, settrace);
 
 
 // restore program state
        prog->xfunction = oldf;
-       prog->globals.server->self = oldself;
+       PRVM_serverglobaledict(self) = oldself;
 }
 
 /*
@@ -1091,7 +1112,7 @@ static void VM_SV_droptofloor (void)
        // assume failure if it returns early
        PRVM_G_FLOAT(OFS_RETURN) = 0;
 
-       ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
+       ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
        if (ent == prog->edicts)
        {
                VM_Warning("droptofloor: can not modify world entity\n");
@@ -1103,37 +1124,37 @@ static void VM_SV_droptofloor (void)
                return;
        }
 
-       VectorCopy (ent->fields.server->origin, end);
+       VectorCopy (PRVM_serveredictvector(ent, origin), end);
        end[2] -= 256;
 
        if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
                SV_UnstickEntity(ent);
 
-       trace = SV_TraceBox(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(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)
        {
                vec3_t offset, org;
-               VectorSet(offset, 0.5f * (ent->fields.server->mins[0] + ent->fields.server->maxs[0]), 0.5f * (ent->fields.server->mins[1] + ent->fields.server->maxs[1]), ent->fields.server->mins[2]);
-               VectorAdd(ent->fields.server->origin, offset, org);
+               VectorSet(offset, 0.5f * (PRVM_serveredictvector(ent, mins)[0] + PRVM_serveredictvector(ent, maxs)[0]), 0.5f * (PRVM_serveredictvector(ent, mins)[1] + PRVM_serveredictvector(ent, maxs)[1]), PRVM_serveredictvector(ent, mins)[2]);
+               VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
                trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
                VectorSubtract(trace.endpos, offset, trace.endpos);
                if (trace.startsolid)
                {
-                       Con_DPrintf("droptofloor at %f %f %f - COULD NOT FIX BADLY PLACED ENTITY\n", ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2]);
+                       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);
                        SV_LinkEdict(ent);
-                       ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
-                       ent->fields.server->groundentity = 0;
+                       PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
+                       PRVM_serveredictedict(ent, groundentity) = 0;
                        PRVM_G_FLOAT(OFS_RETURN) = 1;
                }
                else if (trace.fraction < 1)
                {
-                       Con_DPrintf("droptofloor at %f %f %f - FIXED BADLY PLACED ENTITY\n", ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2]);
-                       VectorCopy (trace.endpos, ent->fields.server->origin);
+                       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);
                        SV_LinkEdict(ent);
-                       ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
-                       ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
+                       PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
+                       PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
                        PRVM_G_FLOAT(OFS_RETURN) = 1;
                        // if support is destroyed, keep suspended (gross hack for floating items in various maps)
                        ent->priv.server->suspendedinairflag = true;
@@ -1144,10 +1165,10 @@ static void VM_SV_droptofloor (void)
                if (trace.fraction != 1)
                {
                        if (trace.fraction < 1)
-                               VectorCopy (trace.endpos, ent->fields.server->origin);
+                               VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
                        SV_LinkEdict(ent);
-                       ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
-                       ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
+                       PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
+                       PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
                        PRVM_G_FLOAT(OFS_RETURN) = 1;
                        // if support is destroyed, keep suspended (gross hack for floating items in various maps)
                        ent->priv.server->suspendedinairflag = true;
@@ -1238,7 +1259,7 @@ static void VM_SV_aim (void)
        VM_SAFEPARMCOUNT(2, VM_SV_aim);
 
        // assume failure if it returns early
-       VectorCopy(prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
+       VectorCopy(PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN));
        // if sv_aim is so high it can't possibly accept anything, skip out early
        if (sv_aim.value >= 1)
                return;
@@ -1256,17 +1277,17 @@ static void VM_SV_aim (void)
        }
        //speed = PRVM_G_FLOAT(OFS_PARM1);
 
-       VectorCopy (ent->fields.server->origin, start);
+       VectorCopy (PRVM_serveredictvector(ent, origin), start);
        start[2] += 20;
 
 // try sending a trace straight
-       VectorCopy (prog->globals.server->v_forward, dir);
+       VectorCopy (PRVM_serverglobalvector(v_forward), dir);
        VectorMA (start, 2048, dir, end);
        tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
-       if (tr.ent && ((prvm_edict_t *)tr.ent)->fields.server->takedamage == DAMAGE_AIM
-       && (!teamplay.integer || ent->fields.server->team <=0 || ent->fields.server->team != ((prvm_edict_t *)tr.ent)->fields.server->team) )
+       if (tr.ent && PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), takedamage) == DAMAGE_AIM
+       && (!teamplay.integer || PRVM_serveredictfloat(ent, team) <=0 || PRVM_serveredictfloat(ent, team) != PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), team)) )
        {
-               VectorCopy (prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
+               VectorCopy (PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN));
                return;
        }
 
@@ -1280,18 +1301,18 @@ static void VM_SV_aim (void)
        for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
        {
                prog->xfunction->builtinsprofile++;
-               if (check->fields.server->takedamage != DAMAGE_AIM)
+               if (PRVM_serveredictfloat(check, takedamage) != DAMAGE_AIM)
                        continue;
                if (check == ent)
                        continue;
-               if (teamplay.integer && ent->fields.server->team > 0 && ent->fields.server->team == check->fields.server->team)
+               if (teamplay.integer && PRVM_serveredictfloat(ent, team) > 0 && PRVM_serveredictfloat(ent, team) == PRVM_serveredictfloat(check, team))
                        continue;       // don't aim at teammate
                for (j=0 ; j<3 ; j++)
-                       end[j] = check->fields.server->origin[j]
-                       + 0.5*(check->fields.server->mins[j] + check->fields.server->maxs[j]);
+                       end[j] = PRVM_serveredictvector(check, origin)[j]
+                       + 0.5*(PRVM_serveredictvector(check, mins)[j] + PRVM_serveredictvector(check, maxs)[j]);
                VectorSubtract (end, start, dir);
                VectorNormalize (dir);
-               dist = DotProduct (dir, prog->globals.server->v_forward);
+               dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
                if (dist < bestdist)
                        continue;       // to far to turn
                tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
@@ -1304,9 +1325,9 @@ static void VM_SV_aim (void)
 
        if (bestent)
        {
-               VectorSubtract (bestent->fields.server->origin, ent->fields.server->origin, dir);
-               dist = DotProduct (dir, prog->globals.server->v_forward);
-               VectorScale (prog->globals.server->v_forward, dist, end);
+               VectorSubtract (PRVM_serveredictvector(bestent, origin), PRVM_serveredictvector(ent, origin), dir);
+               dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
+               VectorScale (PRVM_serverglobalvector(v_forward), dist, end);
                end[2] = dir[2];
                VectorNormalize (end);
                VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
@@ -1344,7 +1365,7 @@ sizebuf_t *WriteDest (void)
                return &sv.datagram;
 
        case MSG_ONE:
-               ent = PRVM_PROG_TO_EDICT(prog->globals.server->msg_entity);
+               ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(msg_entity));
                entnum = PRVM_NUM_FOR_EDICT(ent);
                if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection)
                {
@@ -1471,7 +1492,7 @@ static void VM_SV_makestatic (void)
        if (prog->argc >= 1)
                ent = PRVM_G_EDICT(OFS_PARM0);
        else
-               ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
+               ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
        if (ent == prog->edicts)
        {
                VM_Warning("makestatic: can not modify world entity\n");
@@ -1484,34 +1505,34 @@ static void VM_SV_makestatic (void)
        }
 
        large = false;
-       if (ent->fields.server->modelindex >= 256 || ent->fields.server->frame >= 256)
+       if (PRVM_serveredictfloat(ent, modelindex) >= 256 || PRVM_serveredictfloat(ent, frame) >= 256)
                large = true;
 
        if (large)
        {
                MSG_WriteByte (&sv.signon,svc_spawnstatic2);
-               MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
-               MSG_WriteShort (&sv.signon, (int)ent->fields.server->frame);
+               MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
+               MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
        }
        else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
        {
                MSG_WriteByte (&sv.signon,svc_spawnstatic);
-               MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
-               MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
+               MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
+               MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
        }
        else
        {
                MSG_WriteByte (&sv.signon,svc_spawnstatic);
-               MSG_WriteByte (&sv.signon, (int)ent->fields.server->modelindex);
-               MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
+               MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
+               MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
        }
 
-       MSG_WriteByte (&sv.signon, (int)ent->fields.server->colormap);
-       MSG_WriteByte (&sv.signon, (int)ent->fields.server->skin);
+       MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, colormap));
+       MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, skin));
        for (i=0 ; i<3 ; i++)
        {
-               MSG_WriteCoord(&sv.signon, ent->fields.server->origin[i], sv.protocol);
-               MSG_WriteAngle(&sv.signon, ent->fields.server->angles[i], sv.protocol);
+               MSG_WriteCoord(&sv.signon, PRVM_serveredictvector(ent, origin)[i], sv.protocol);
+               MSG_WriteAngle(&sv.signon, PRVM_serveredictvector(ent, angles)[i], sv.protocol);
        }
 
 // throw the entity away now
@@ -1544,7 +1565,7 @@ static void VM_SV_setspawnparms (void)
        // copy spawn parms out of the client_t
        client = svs.clients + i-1;
        for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
-               (&prog->globals.server->parm1)[i] = client->spawn_parms[i];
+               (&PRVM_serverglobalfloat(parm1))[i] = client->spawn_parms[i];
 }
 
 /*
@@ -1713,7 +1734,7 @@ static void VM_SV_copyentity (void)
                VM_Warning("copyentity: can not modify free entity\n");
                return;
        }
-       memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
+       memcpy(out->fields.vp, in->fields.vp, prog->entityfields * 4);
        SV_LinkEdict(out);
 }
 
@@ -1731,7 +1752,6 @@ static void VM_SV_setcolor (void)
 {
        client_t *client;
        int entnum, i;
-       prvm_eval_t *val;
 
        VM_SAFEPARMCOUNT(2, VM_SV_setcolor);
        entnum = PRVM_G_EDICTNUM(OFS_PARM0);
@@ -1746,9 +1766,8 @@ static void VM_SV_setcolor (void)
        client = svs.clients + entnum-1;
        if (client->edict)
        {
-               if ((val = PRVM_EDICTFIELDVALUE(client->edict, prog->fieldoffsets.clientcolors)))
-                       val->_float = i;
-               client->edict->fields.server->team = (i & 15) + 1;
+               PRVM_serveredictfloat(client->edict, clientcolors) = i;
+               PRVM_serveredictfloat(client->edict, team) = (i & 15) + 1;
        }
        client->colors = i;
        if (client->old_colors != client->colors)
@@ -2296,8 +2315,8 @@ static void VM_SV_setattachment (void)
        prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
        prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
        const char *tagname = PRVM_G_STRING(OFS_PARM2);
-       prvm_eval_t *v;
        dp_model_t *model;
+       int tagindex;
        VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
 
        if (e == prog->edicts)
@@ -2314,25 +2333,23 @@ static void VM_SV_setattachment (void)
        if (tagentity == NULL)
                tagentity = prog->edicts;
 
-       v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
-       if (v)
-               v->edict = PRVM_EDICT_TO_PROG(tagentity);
+       tagindex = 0;
 
-       v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
-       if (v)
-               v->_float = 0;
        if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
        {
                model = SV_GetModelFromEdict(tagentity);
                if (model)
                {
-                       v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.server->skin, tagname);
-                       if (v->_float == 0)
+                       tagindex = Mod_Alias_GetTagIndexForName(model, (int)PRVM_serveredictfloat(tagentity, skin), tagname);
+                       if (tagindex == 0)
                                Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity), model->name);
                }
                else
                        Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity));
        }
+
+       PRVM_serveredictedict(e, tag_entity) = PRVM_EDICT_TO_PROG(tagentity);
+       PRVM_serveredictfloat(e, tag_index) = tagindex;
 }
 
 /////////////////////////////////////////
@@ -2342,11 +2359,11 @@ int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
 {
        int i;
 
-       i = (int)e->fields.server->modelindex;
+       i = (int)PRVM_serveredictfloat(e, modelindex);
        if (i < 1 || i >= MAX_MODELS)
                return -1;
 
-       return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)e->fields.server->skin, 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)
@@ -2360,7 +2377,7 @@ int SV_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, cons
 
        if (tagindex >= 0 && (model = SV_GetModelFromEdict(e)) && model->num_bones)
        {
-               r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)e->fields.server->skin, e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
+               r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)PRVM_serveredictfloat(e, skin), e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
 
                if(!r) // success?
                        *parentindex += 1;
@@ -2373,21 +2390,19 @@ int SV_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, cons
 
 void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
 {
-       prvm_eval_t *val;
        float scale;
        float pitchsign = 1;
 
-       scale = 1;
-       val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
-       if (val && val->_float != 0)
-               scale = val->_float;
+       scale = PRVM_serveredictfloat(ent, scale);
+       if (!scale)
+               scale = 1.0f;
        
        if (viewmatrix)
-               Matrix4x4_CreateFromQuakeEntity(out, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2] + ent->fields.server->view_ofs[2], ent->fields.server->v_angle[0], ent->fields.server->v_angle[1], ent->fields.server->v_angle[2], scale * cl_viewmodel_scale.value);
+               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);
-               Matrix4x4_CreateFromQuakeEntity(out, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2], pitchsign * ent->fields.server->angles[0], ent->fields.server->angles[1], ent->fields.server->angles[2], scale);
+               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);
        }
 }
 
@@ -2418,7 +2433,6 @@ extern cvar_t cl_bobup;
 int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
 {
        int ret;
-       prvm_eval_t *val;
        int modelindex, attachloop;
        matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
        dp_model_t *model;
@@ -2430,7 +2444,7 @@ int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
        if (ent->priv.server->free)
                return 2;
 
-       modelindex = (int)ent->fields.server->modelindex;
+       modelindex = (int)PRVM_serveredictfloat(ent, modelindex);
        if (modelindex <= 0 || modelindex >= MAX_MODELS)
                return 3;
 
@@ -2456,10 +2470,10 @@ int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
                Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
                Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
                // next iteration we process the parent entity
-               if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
+               if (PRVM_serveredictedict(ent, tag_entity))
                {
-                       tagindex = (int)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
-                       ent = PRVM_EDICT_NUM(val->edict);
+                       tagindex = (int)PRVM_serveredictfloat(ent, tag_index);
+                       ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, tag_entity));
                }
                else
                        break;
@@ -2467,17 +2481,17 @@ int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
        }
 
        // RENDER_VIEWMODEL magic
-       if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)) && val->edict)
+       if (PRVM_serveredictedict(ent, viewmodelforclient))
        {
                Matrix4x4_Copy(&tagmatrix, out);
-               ent = PRVM_EDICT_NUM(val->edict);
+               ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, viewmodelforclient));
 
                SV_GetEntityMatrix(ent, &entitymatrix, true);
                Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
 
                /*
                // Cl_bob, ported from rendering code
-               if (ent->fields.server->health > 0 && cl_bob.value && cl_bobcycle.value)
+               if (PRVM_serveredictfloat(ent, health) > 0 && cl_bob.value && cl_bobcycle.value)
                {
                        double bob, cycle;
                        // LordHavoc: this code is *weird*, but not replacable (I think it
@@ -2492,7 +2506,7 @@ int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
                                cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
                        // bob is proportional to velocity in the xy plane
                        // (don't count Z, or jumping messes it up)
-                       bob = sqrt(ent->fields.server->velocity[0]*ent->fields.server->velocity[0] + ent->fields.server->velocity[1]*ent->fields.server->velocity[1])*cl_bob.value;
+                       bob = sqrt(PRVM_serveredictvector(ent, velocity)[0]*PRVM_serveredictvector(ent, velocity)[0] + PRVM_serveredictvector(ent, velocity)[1]*PRVM_serveredictvector(ent, velocity)[1])*cl_bob.value;
                        bob = bob*0.3 + bob*0.7*cycle;
                        Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
                }
@@ -2548,7 +2562,6 @@ static void VM_SV_gettaginfo (void)
        int parentindex;
        const char *tagname;
        int returncode;
-       prvm_eval_t *val;
        vec3_t fo, le, up, trans;
        const dp_model_t *model;
 
@@ -2558,8 +2571,8 @@ static void VM_SV_gettaginfo (void)
        tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
 
        returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
-       Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, le, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
-       VectorScale(le, -1, prog->globals.server->v_right);
+       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_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model);
@@ -2567,18 +2580,12 @@ static void VM_SV_gettaginfo (void)
        SV_GetExtendedTagInfo(e, tagindex, &parentindex, &tagname, &tag_localmatrix);
        Matrix4x4_ToVectors(&tag_localmatrix, fo, le, up, trans);
 
-       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_parent)))
-               val->_float = parentindex;
-       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_name)))
-               val->string = tagname ? PRVM_SetTempString(tagname) : 0;
-       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_offset)))
-               VectorCopy(trans, val->vector);
-       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_forward)))
-               VectorCopy(fo, val->vector);
-       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_right)))
-               VectorScale(le, -1, val->vector);
-       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_up)))
-               VectorCopy(up, val->vector);
+       PRVM_serverglobalfloat(gettaginfo_parent) = parentindex;
+       PRVM_serverglobalstring(gettaginfo_name) = tagname ? PRVM_SetTempString(tagname) : 0;
+       VectorCopy(trans, PRVM_serverglobalvector(gettaginfo_offset));
+       VectorCopy(fo, PRVM_serverglobalvector(gettaginfo_forward));
+       VectorScale(le, -1, PRVM_serverglobalvector(gettaginfo_right));
+       VectorCopy(up, PRVM_serverglobalvector(gettaginfo_up));
 
        switch(returncode)
        {
@@ -2709,8 +2716,8 @@ static void VM_SV_setmodelindex (void)
                return;
        }
 
-       e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
-       e->fields.server->modelindex = i;
+       PRVM_serveredictstring(e, model) = PRVM_SetEngineString(sv.model_precache[i]);
+       PRVM_serveredictfloat(e, modelindex) = i;
 
        mod = SV_GetModelByIndex(i);
 
@@ -2955,18 +2962,18 @@ static void VM_SV_skel_get_bonerel(void)
        matrix4x4_t matrix;
        vec3_t forward, left, up, origin;
        VectorClear(PRVM_G_VECTOR(OFS_RETURN));
-       VectorClear(prog->globals.client->v_forward);
-       VectorClear(prog->globals.client->v_right);
-       VectorClear(prog->globals.client->v_up);
+       VectorClear(PRVM_clientglobalvector(v_forward));
+       VectorClear(PRVM_clientglobalvector(v_right));
+       VectorClear(PRVM_clientglobalvector(v_up));
        if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
                return;
        if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
                return;
        matrix = skeleton->relativetransforms[bonenum];
        Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
-       VectorCopy(forward, prog->globals.client->v_forward);
-       VectorNegate(left, prog->globals.client->v_right);
-       VectorCopy(up, prog->globals.client->v_up);
+       VectorCopy(forward, PRVM_clientglobalvector(v_forward));
+       VectorNegate(left, PRVM_clientglobalvector(v_right));
+       VectorCopy(up, PRVM_clientglobalvector(v_up));
        VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
 }
 
@@ -2980,9 +2987,9 @@ static void VM_SV_skel_get_boneabs(void)
        matrix4x4_t temp;
        vec3_t forward, left, up, origin;
        VectorClear(PRVM_G_VECTOR(OFS_RETURN));
-       VectorClear(prog->globals.client->v_forward);
-       VectorClear(prog->globals.client->v_right);
-       VectorClear(prog->globals.client->v_up);
+       VectorClear(PRVM_clientglobalvector(v_forward));
+       VectorClear(PRVM_clientglobalvector(v_right));
+       VectorClear(PRVM_clientglobalvector(v_up));
        if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
                return;
        if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
@@ -2995,9 +3002,9 @@ static void VM_SV_skel_get_boneabs(void)
                Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
        }
        Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
-       VectorCopy(forward, prog->globals.client->v_forward);
-       VectorNegate(left, prog->globals.client->v_right);
-       VectorCopy(up, prog->globals.client->v_up);
+       VectorCopy(forward, PRVM_clientglobalvector(v_forward));
+       VectorNegate(left, PRVM_clientglobalvector(v_right));
+       VectorCopy(up, PRVM_clientglobalvector(v_up));
        VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
 }
 
@@ -3013,9 +3020,9 @@ static void VM_SV_skel_set_bone(void)
                return;
        if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
                return;
-       VectorCopy(prog->globals.client->v_forward, forward);
-       VectorNegate(prog->globals.client->v_right, left);
-       VectorCopy(prog->globals.client->v_up, up);
+       VectorCopy(PRVM_clientglobalvector(v_forward), forward);
+       VectorNegate(PRVM_clientglobalvector(v_right), left);
+       VectorCopy(PRVM_clientglobalvector(v_up), up);
        VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
        Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
        skeleton->relativetransforms[bonenum] = matrix;
@@ -3035,9 +3042,9 @@ static void VM_SV_skel_mul_bone(void)
        if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
                return;
        VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
-       VectorCopy(prog->globals.client->v_forward, forward);
-       VectorNegate(prog->globals.client->v_right, left);
-       VectorCopy(prog->globals.client->v_up, up);
+       VectorCopy(PRVM_clientglobalvector(v_forward), forward);
+       VectorNegate(PRVM_clientglobalvector(v_right), left);
+       VectorCopy(PRVM_clientglobalvector(v_up), up);
        Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
        temp = skeleton->relativetransforms[bonenum];
        Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
@@ -3057,9 +3064,9 @@ static void VM_SV_skel_mul_bones(void)
        if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
                return;
        VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
-       VectorCopy(prog->globals.client->v_forward, forward);
-       VectorNegate(prog->globals.client->v_right, left);
-       VectorCopy(prog->globals.client->v_up, up);
+       VectorCopy(PRVM_clientglobalvector(v_forward), forward);
+       VectorNegate(PRVM_clientglobalvector(v_right), left);
+       VectorCopy(PRVM_clientglobalvector(v_up), up);
        Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
        firstbone = max(0, firstbone);
        lastbone = min(lastbone, skeleton->model->num_bones - 1);
@@ -3784,10 +3791,10 @@ void VM_SV_Cmd_Init(void)
 void VM_SV_Cmd_Reset(void)
 {
        World_End(&sv.world);
-       if(prog->funcoffsets.SV_Shutdown)
+       if(PRVM_serverfunction(SV_Shutdown))
        {
-               func_t s = prog->funcoffsets.SV_Shutdown;
-               prog->funcoffsets.SV_Shutdown = 0; // prevent it from getting called again
+               func_t s = PRVM_serverfunction(SV_Shutdown);
+               PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again
                PRVM_ExecuteProgram(s,"SV_Shutdown() required");
        }
 
index 4ed624e461afa78057d462689d0e0dde7c04f85a..bb6ce36bff76923f8f86178285578a92cfbdf061 100644 (file)
@@ -1,14 +1,14 @@
+#ifdef WIN32
+# ifndef DONT_USE_SETDLLDIRECTORY
+#  define _WIN32_WINNT 0x0502
+# endif
+#endif
+
 #include "quakedef.h"
 
 #define SUPPORTDLL
 
 #ifdef WIN32
-# ifdef _WIN64
-#  ifndef _WIN32_WINNT
-#   define _WIN32_WINNT 0x0502
-#  endif
-   // for SetDllDirectory
-# endif
 # include <windows.h>
 # include <mmsystem.h> // timeGetTime
 # include <time.h> // localtime
@@ -133,13 +133,15 @@ notfound:
        {
                Con_DPrintf (" \"%s\"", dllnames[i]);
 #ifdef WIN32
-# ifdef _WIN64
+# ifndef DONT_USE_SETDLLDIRECTORY
+#  ifdef _WIN64
                SetDllDirectory("bin64");
+#  else
+               SetDllDirectory("bin32");
+#  endif
 # endif
                dllhandle = LoadLibrary (dllnames[i]);
-# ifdef _WIN64
-               SetDllDirectory(NULL);
-# endif
+               // no need to unset this - we want ALL dlls to be loaded from there, anyway
 #else
                dllhandle = dlopen (dllnames[i], RTLD_LAZY | RTLD_GLOBAL);
 #endif
@@ -261,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)
 {
@@ -289,8 +291,11 @@ double Sys_DoubleTime(void)
        double newtime;
        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
@@ -415,7 +420,13 @@ 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)
diff --git a/todo b/todo
index 764cf7d06f6d1eca75aa76f111de79f5dee00787..adfa4ebecf3f2e5722cc6a7bc139ab6e7db7caa2 100644 (file)
--- a/todo
+++ b/todo
@@ -6,6 +6,7 @@
 0 bug darkplaces client csqc: entities not being drawn with VF_PERSPECTIVE 0? (daemon)
 0 bug darkplaces client csqc: input queue functions needed for csqc prediction aren't implemented (Spike)
 0 bug darkplaces client csqc: precaches on client don't work, have to precache on server - what's going wrong here? (daemon, Urre)
+0 bug darkplaces client csqc: string stats should be sent as a single stat with WriteString (Spike)
 0 bug darkplaces client csqc: there is no WriteFloat, making ReadFloat useless (Urre)
 0 bug darkplaces client csqc: unproject Z handling differs in DP and FTEQW, project also must be directly compatible with unproject (avirox)
 0 bug darkplaces client csqc: world not being drawn with VF_PERSPECTIVE 0? (VorteX)
@@ -31,6 +32,7 @@
 0 bug darkplaces effects: add a cvar to disable colored dlights (leileilol)
 0 bug darkplaces effects: dlights don't look anything like quake ones, bring back lightmap dlights as a cvar - with both classic and old dp falloff modes (leileilol)
 0 bug darkplaces effects: quake mode blood trails don't have the appropriate slight gravity - there may be other effects missing this also (leileilol)
+0 bug darkplaces filesystem: -game nehahra does not load properly; menu does not work properly - probably not activating gamemode
 0 bug darkplaces loader: crash when a mdl model has more replacement skins than the model contains (Lardarse)
 0 bug darkplaces loader: make rtlight entity loader support q3map/q3map2 lights properly, they use a spawnflag for LINEAR mode, by default they use 1/(x*x) falloff (Carni, motorsep)
 0 bug darkplaces loader: mcbsp hull selection is ignoring the custom hulls supported by mcbsp (div0)
@@ -55,6 +57,7 @@
 0 bug darkplaces server: SV_PushMove is ignoring model type in its angles_x handling, where as the renderer checks only model type to determine angles_x handling (Urre)
 0 bug darkplaces server: SV_PushMove's call to SV_ClipMoveToEntity should do a trace, not just a point test, to support hollow pusher models (Urre)
 0 bug darkplaces server: X-Men mod has flying enemies that tend to go through the floor, sometimes preventing a level from being completed.  x1m1 has two alcoves that open to reveal Storm and Archangel but often Storm disappears through the ground of hear alcove and then the level can't be completed.  A similar problem with Storm apears in x1m3 in an alcove.  (ewwfq yahoo com)
+0 bug darkplaces server: savegames do not contain parms for multiple players, restoring a savegame leaves parms for other players as they were at the time of loading the savegame, clearly wrong (daemon)
 0 bug darkplaces server: savegames do not save precaches, which means that automatic precaching frequently results in invalid modelindex values when reloading the savegame, and this bug also exists in many quake mods that randomly choose multiple variants of a monster, each with separate precaches, resulting in a different precache order when reloading the savegame
 0 bug darkplaces wgl client: during video mode setup, sometimes another application's window becomes permanently top most, not darkplaces' fullscreen window, why? (tZork)
 0 bug darkplaces windows sound: freezing on exit sometimes when freeing sound buffer during sound shutdown (Black)
 0 optimization darkplaces server: implement first unused/last used entity range optimization on entity spawn/remove similar to the client particles (LordHavoc)
 0 optimization darkplaces visibility: R_Q1BSP_BoxTouchingPVS and R_Q3BSP_BoxTouchingPVS should check pvsframe on nodes as well as leafs (Vic)
 0 optimization darkplaces: calculate worldmodel farclip (corner to corner radius) at load
+0 optimize darkplaces renderer: get rid of attenuation texture on lights because math is faster, add fastpath for no normalmap (Lava_Croft)
 1 bug darkplaces WGL client: figure out why for some people GDI input has stuttering problems with gl_finish 0 mode (Kinn, Urre, romi, Spike, Black)
 1 bug darkplaces WGL/GLX/SDL client bug: if sound is unavailable (causing a freeze waiting for it to become available), the config is reset (SavageX)
 1 bug darkplaces bsd filesystem: read() is failing (not returning the requested amount) on freebsd when reading files, whether actual files or in a pk3 - somehow it is still able to read the pk3 zip directory though (suminigashi, Elric)
index bb775b7fd91b749a4593382f52691135c58f4250..b726e220d9768ca01d82b973aba0d5d464fecdd2 100644 (file)
--- a/utf8lib.c
+++ b/utf8lib.c
@@ -798,3 +798,2142 @@ size_t u8_strpad(char *out, size_t outsize, const char *in, qboolean leftalign,
                return dpsnprintf(out, outsize, "%*s%.*s%*s", lpad, "", prec, in, rpad, "");
        }
 }
+
+
+/*
+The two following functions (u8_toupper, u8_tolower) are derived from
+ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt and the following license
+holds for these:
+
+Copyright Â© 1991-2011 Unicode, Inc. All rights reserved. Distributed under the
+Terms of Use in http://www.unicode.org/copyright.html.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+the Unicode data files and any associated documentation (the "Data Files") or
+Unicode software and any associated documentation (the "Software") to deal in
+the Data Files or Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, and/or sell copies
+of the Data Files or Software, and to permit persons to whom the Data Files or
+Software are furnished to do so, provided that (a) the above copyright
+notice(s) and this permission notice appear with all copies of the Data Files
+or Software, (b) both the above copyright notice(s) and this permission notice
+appear in associated documentation, and (c) there is clear notice in each
+modified Data File or in the Software as well as in the documentation
+associated with the Data File(s) or Software that the data or software has been
+modified.
+
+THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD
+PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
+DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR
+SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder shall not be
+used in advertising or otherwise to promote the sale, use or other dealings in
+these Data Files or Software without prior written authorization of the
+copyright holder.
+*/
+
+Uchar u8_toupper(Uchar ch)
+{
+       switch(ch)
+       {
+               case 0x0061: return 0x0041;
+               case 0x0062: return 0x0042;
+               case 0x0063: return 0x0043;
+               case 0x0064: return 0x0044;
+               case 0x0065: return 0x0045;
+               case 0x0066: return 0x0046;
+               case 0x0067: return 0x0047;
+               case 0x0068: return 0x0048;
+               case 0x0069: return 0x0049;
+               case 0x006A: return 0x004A;
+               case 0x006B: return 0x004B;
+               case 0x006C: return 0x004C;
+               case 0x006D: return 0x004D;
+               case 0x006E: return 0x004E;
+               case 0x006F: return 0x004F;
+               case 0x0070: return 0x0050;
+               case 0x0071: return 0x0051;
+               case 0x0072: return 0x0052;
+               case 0x0073: return 0x0053;
+               case 0x0074: return 0x0054;
+               case 0x0075: return 0x0055;
+               case 0x0076: return 0x0056;
+               case 0x0077: return 0x0057;
+               case 0x0078: return 0x0058;
+               case 0x0079: return 0x0059;
+               case 0x007A: return 0x005A;
+               case 0x00B5: return 0x039C;
+               case 0x00E0: return 0x00C0;
+               case 0x00E1: return 0x00C1;
+               case 0x00E2: return 0x00C2;
+               case 0x00E3: return 0x00C3;
+               case 0x00E4: return 0x00C4;
+               case 0x00E5: return 0x00C5;
+               case 0x00E6: return 0x00C6;
+               case 0x00E7: return 0x00C7;
+               case 0x00E8: return 0x00C8;
+               case 0x00E9: return 0x00C9;
+               case 0x00EA: return 0x00CA;
+               case 0x00EB: return 0x00CB;
+               case 0x00EC: return 0x00CC;
+               case 0x00ED: return 0x00CD;
+               case 0x00EE: return 0x00CE;
+               case 0x00EF: return 0x00CF;
+               case 0x00F0: return 0x00D0;
+               case 0x00F1: return 0x00D1;
+               case 0x00F2: return 0x00D2;
+               case 0x00F3: return 0x00D3;
+               case 0x00F4: return 0x00D4;
+               case 0x00F5: return 0x00D5;
+               case 0x00F6: return 0x00D6;
+               case 0x00F8: return 0x00D8;
+               case 0x00F9: return 0x00D9;
+               case 0x00FA: return 0x00DA;
+               case 0x00FB: return 0x00DB;
+               case 0x00FC: return 0x00DC;
+               case 0x00FD: return 0x00DD;
+               case 0x00FE: return 0x00DE;
+               case 0x00FF: return 0x0178;
+               case 0x0101: return 0x0100;
+               case 0x0103: return 0x0102;
+               case 0x0105: return 0x0104;
+               case 0x0107: return 0x0106;
+               case 0x0109: return 0x0108;
+               case 0x010B: return 0x010A;
+               case 0x010D: return 0x010C;
+               case 0x010F: return 0x010E;
+               case 0x0111: return 0x0110;
+               case 0x0113: return 0x0112;
+               case 0x0115: return 0x0114;
+               case 0x0117: return 0x0116;
+               case 0x0119: return 0x0118;
+               case 0x011B: return 0x011A;
+               case 0x011D: return 0x011C;
+               case 0x011F: return 0x011E;
+               case 0x0121: return 0x0120;
+               case 0x0123: return 0x0122;
+               case 0x0125: return 0x0124;
+               case 0x0127: return 0x0126;
+               case 0x0129: return 0x0128;
+               case 0x012B: return 0x012A;
+               case 0x012D: return 0x012C;
+               case 0x012F: return 0x012E;
+               case 0x0131: return 0x0049;
+               case 0x0133: return 0x0132;
+               case 0x0135: return 0x0134;
+               case 0x0137: return 0x0136;
+               case 0x013A: return 0x0139;
+               case 0x013C: return 0x013B;
+               case 0x013E: return 0x013D;
+               case 0x0140: return 0x013F;
+               case 0x0142: return 0x0141;
+               case 0x0144: return 0x0143;
+               case 0x0146: return 0x0145;
+               case 0x0148: return 0x0147;
+               case 0x014B: return 0x014A;
+               case 0x014D: return 0x014C;
+               case 0x014F: return 0x014E;
+               case 0x0151: return 0x0150;
+               case 0x0153: return 0x0152;
+               case 0x0155: return 0x0154;
+               case 0x0157: return 0x0156;
+               case 0x0159: return 0x0158;
+               case 0x015B: return 0x015A;
+               case 0x015D: return 0x015C;
+               case 0x015F: return 0x015E;
+               case 0x0161: return 0x0160;
+               case 0x0163: return 0x0162;
+               case 0x0165: return 0x0164;
+               case 0x0167: return 0x0166;
+               case 0x0169: return 0x0168;
+               case 0x016B: return 0x016A;
+               case 0x016D: return 0x016C;
+               case 0x016F: return 0x016E;
+               case 0x0171: return 0x0170;
+               case 0x0173: return 0x0172;
+               case 0x0175: return 0x0174;
+               case 0x0177: return 0x0176;
+               case 0x017A: return 0x0179;
+               case 0x017C: return 0x017B;
+               case 0x017E: return 0x017D;
+               case 0x017F: return 0x0053;
+               case 0x0180: return 0x0243;
+               case 0x0183: return 0x0182;
+               case 0x0185: return 0x0184;
+               case 0x0188: return 0x0187;
+               case 0x018C: return 0x018B;
+               case 0x0192: return 0x0191;
+               case 0x0195: return 0x01F6;
+               case 0x0199: return 0x0198;
+               case 0x019A: return 0x023D;
+               case 0x019E: return 0x0220;
+               case 0x01A1: return 0x01A0;
+               case 0x01A3: return 0x01A2;
+               case 0x01A5: return 0x01A4;
+               case 0x01A8: return 0x01A7;
+               case 0x01AD: return 0x01AC;
+               case 0x01B0: return 0x01AF;
+               case 0x01B4: return 0x01B3;
+               case 0x01B6: return 0x01B5;
+               case 0x01B9: return 0x01B8;
+               case 0x01BD: return 0x01BC;
+               case 0x01BF: return 0x01F7;
+               case 0x01C5: return 0x01C4;
+               case 0x01C6: return 0x01C4;
+               case 0x01C8: return 0x01C7;
+               case 0x01C9: return 0x01C7;
+               case 0x01CB: return 0x01CA;
+               case 0x01CC: return 0x01CA;
+               case 0x01CE: return 0x01CD;
+               case 0x01D0: return 0x01CF;
+               case 0x01D2: return 0x01D1;
+               case 0x01D4: return 0x01D3;
+               case 0x01D6: return 0x01D5;
+               case 0x01D8: return 0x01D7;
+               case 0x01DA: return 0x01D9;
+               case 0x01DC: return 0x01DB;
+               case 0x01DD: return 0x018E;
+               case 0x01DF: return 0x01DE;
+               case 0x01E1: return 0x01E0;
+               case 0x01E3: return 0x01E2;
+               case 0x01E5: return 0x01E4;
+               case 0x01E7: return 0x01E6;
+               case 0x01E9: return 0x01E8;
+               case 0x01EB: return 0x01EA;
+               case 0x01ED: return 0x01EC;
+               case 0x01EF: return 0x01EE;
+               case 0x01F2: return 0x01F1;
+               case 0x01F3: return 0x01F1;
+               case 0x01F5: return 0x01F4;
+               case 0x01F9: return 0x01F8;
+               case 0x01FB: return 0x01FA;
+               case 0x01FD: return 0x01FC;
+               case 0x01FF: return 0x01FE;
+               case 0x0201: return 0x0200;
+               case 0x0203: return 0x0202;
+               case 0x0205: return 0x0204;
+               case 0x0207: return 0x0206;
+               case 0x0209: return 0x0208;
+               case 0x020B: return 0x020A;
+               case 0x020D: return 0x020C;
+               case 0x020F: return 0x020E;
+               case 0x0211: return 0x0210;
+               case 0x0213: return 0x0212;
+               case 0x0215: return 0x0214;
+               case 0x0217: return 0x0216;
+               case 0x0219: return 0x0218;
+               case 0x021B: return 0x021A;
+               case 0x021D: return 0x021C;
+               case 0x021F: return 0x021E;
+               case 0x0223: return 0x0222;
+               case 0x0225: return 0x0224;
+               case 0x0227: return 0x0226;
+               case 0x0229: return 0x0228;
+               case 0x022B: return 0x022A;
+               case 0x022D: return 0x022C;
+               case 0x022F: return 0x022E;
+               case 0x0231: return 0x0230;
+               case 0x0233: return 0x0232;
+               case 0x023C: return 0x023B;
+               case 0x023F: return 0x2C7E;
+               case 0x0240: return 0x2C7F;
+               case 0x0242: return 0x0241;
+               case 0x0247: return 0x0246;
+               case 0x0249: return 0x0248;
+               case 0x024B: return 0x024A;
+               case 0x024D: return 0x024C;
+               case 0x024F: return 0x024E;
+               case 0x0250: return 0x2C6F;
+               case 0x0251: return 0x2C6D;
+               case 0x0252: return 0x2C70;
+               case 0x0253: return 0x0181;
+               case 0x0254: return 0x0186;
+               case 0x0256: return 0x0189;
+               case 0x0257: return 0x018A;
+               case 0x0259: return 0x018F;
+               case 0x025B: return 0x0190;
+               case 0x0260: return 0x0193;
+               case 0x0263: return 0x0194;
+               case 0x0265: return 0xA78D;
+               case 0x0268: return 0x0197;
+               case 0x0269: return 0x0196;
+               case 0x026B: return 0x2C62;
+               case 0x026F: return 0x019C;
+               case 0x0271: return 0x2C6E;
+               case 0x0272: return 0x019D;
+               case 0x0275: return 0x019F;
+               case 0x027D: return 0x2C64;
+               case 0x0280: return 0x01A6;
+               case 0x0283: return 0x01A9;
+               case 0x0288: return 0x01AE;
+               case 0x0289: return 0x0244;
+               case 0x028A: return 0x01B1;
+               case 0x028B: return 0x01B2;
+               case 0x028C: return 0x0245;
+               case 0x0292: return 0x01B7;
+               case 0x0345: return 0x0399;
+               case 0x0371: return 0x0370;
+               case 0x0373: return 0x0372;
+               case 0x0377: return 0x0376;
+               case 0x037B: return 0x03FD;
+               case 0x037C: return 0x03FE;
+               case 0x037D: return 0x03FF;
+               case 0x03AC: return 0x0386;
+               case 0x03AD: return 0x0388;
+               case 0x03AE: return 0x0389;
+               case 0x03AF: return 0x038A;
+               case 0x03B1: return 0x0391;
+               case 0x03B2: return 0x0392;
+               case 0x03B3: return 0x0393;
+               case 0x03B4: return 0x0394;
+               case 0x03B5: return 0x0395;
+               case 0x03B6: return 0x0396;
+               case 0x03B7: return 0x0397;
+               case 0x03B8: return 0x0398;
+               case 0x03B9: return 0x0399;
+               case 0x03BA: return 0x039A;
+               case 0x03BB: return 0x039B;
+               case 0x03BC: return 0x039C;
+               case 0x03BD: return 0x039D;
+               case 0x03BE: return 0x039E;
+               case 0x03BF: return 0x039F;
+               case 0x03C0: return 0x03A0;
+               case 0x03C1: return 0x03A1;
+               case 0x03C2: return 0x03A3;
+               case 0x03C3: return 0x03A3;
+               case 0x03C4: return 0x03A4;
+               case 0x03C5: return 0x03A5;
+               case 0x03C6: return 0x03A6;
+               case 0x03C7: return 0x03A7;
+               case 0x03C8: return 0x03A8;
+               case 0x03C9: return 0x03A9;
+               case 0x03CA: return 0x03AA;
+               case 0x03CB: return 0x03AB;
+               case 0x03CC: return 0x038C;
+               case 0x03CD: return 0x038E;
+               case 0x03CE: return 0x038F;
+               case 0x03D0: return 0x0392;
+               case 0x03D1: return 0x0398;
+               case 0x03D5: return 0x03A6;
+               case 0x03D6: return 0x03A0;
+               case 0x03D7: return 0x03CF;
+               case 0x03D9: return 0x03D8;
+               case 0x03DB: return 0x03DA;
+               case 0x03DD: return 0x03DC;
+               case 0x03DF: return 0x03DE;
+               case 0x03E1: return 0x03E0;
+               case 0x03E3: return 0x03E2;
+               case 0x03E5: return 0x03E4;
+               case 0x03E7: return 0x03E6;
+               case 0x03E9: return 0x03E8;
+               case 0x03EB: return 0x03EA;
+               case 0x03ED: return 0x03EC;
+               case 0x03EF: return 0x03EE;
+               case 0x03F0: return 0x039A;
+               case 0x03F1: return 0x03A1;
+               case 0x03F2: return 0x03F9;
+               case 0x03F5: return 0x0395;
+               case 0x03F8: return 0x03F7;
+               case 0x03FB: return 0x03FA;
+               case 0x0430: return 0x0410;
+               case 0x0431: return 0x0411;
+               case 0x0432: return 0x0412;
+               case 0x0433: return 0x0413;
+               case 0x0434: return 0x0414;
+               case 0x0435: return 0x0415;
+               case 0x0436: return 0x0416;
+               case 0x0437: return 0x0417;
+               case 0x0438: return 0x0418;
+               case 0x0439: return 0x0419;
+               case 0x043A: return 0x041A;
+               case 0x043B: return 0x041B;
+               case 0x043C: return 0x041C;
+               case 0x043D: return 0x041D;
+               case 0x043E: return 0x041E;
+               case 0x043F: return 0x041F;
+               case 0x0440: return 0x0420;
+               case 0x0441: return 0x0421;
+               case 0x0442: return 0x0422;
+               case 0x0443: return 0x0423;
+               case 0x0444: return 0x0424;
+               case 0x0445: return 0x0425;
+               case 0x0446: return 0x0426;
+               case 0x0447: return 0x0427;
+               case 0x0448: return 0x0428;
+               case 0x0449: return 0x0429;
+               case 0x044A: return 0x042A;
+               case 0x044B: return 0x042B;
+               case 0x044C: return 0x042C;
+               case 0x044D: return 0x042D;
+               case 0x044E: return 0x042E;
+               case 0x044F: return 0x042F;
+               case 0x0450: return 0x0400;
+               case 0x0451: return 0x0401;
+               case 0x0452: return 0x0402;
+               case 0x0453: return 0x0403;
+               case 0x0454: return 0x0404;
+               case 0x0455: return 0x0405;
+               case 0x0456: return 0x0406;
+               case 0x0457: return 0x0407;
+               case 0x0458: return 0x0408;
+               case 0x0459: return 0x0409;
+               case 0x045A: return 0x040A;
+               case 0x045B: return 0x040B;
+               case 0x045C: return 0x040C;
+               case 0x045D: return 0x040D;
+               case 0x045E: return 0x040E;
+               case 0x045F: return 0x040F;
+               case 0x0461: return 0x0460;
+               case 0x0463: return 0x0462;
+               case 0x0465: return 0x0464;
+               case 0x0467: return 0x0466;
+               case 0x0469: return 0x0468;
+               case 0x046B: return 0x046A;
+               case 0x046D: return 0x046C;
+               case 0x046F: return 0x046E;
+               case 0x0471: return 0x0470;
+               case 0x0473: return 0x0472;
+               case 0x0475: return 0x0474;
+               case 0x0477: return 0x0476;
+               case 0x0479: return 0x0478;
+               case 0x047B: return 0x047A;
+               case 0x047D: return 0x047C;
+               case 0x047F: return 0x047E;
+               case 0x0481: return 0x0480;
+               case 0x048B: return 0x048A;
+               case 0x048D: return 0x048C;
+               case 0x048F: return 0x048E;
+               case 0x0491: return 0x0490;
+               case 0x0493: return 0x0492;
+               case 0x0495: return 0x0494;
+               case 0x0497: return 0x0496;
+               case 0x0499: return 0x0498;
+               case 0x049B: return 0x049A;
+               case 0x049D: return 0x049C;
+               case 0x049F: return 0x049E;
+               case 0x04A1: return 0x04A0;
+               case 0x04A3: return 0x04A2;
+               case 0x04A5: return 0x04A4;
+               case 0x04A7: return 0x04A6;
+               case 0x04A9: return 0x04A8;
+               case 0x04AB: return 0x04AA;
+               case 0x04AD: return 0x04AC;
+               case 0x04AF: return 0x04AE;
+               case 0x04B1: return 0x04B0;
+               case 0x04B3: return 0x04B2;
+               case 0x04B5: return 0x04B4;
+               case 0x04B7: return 0x04B6;
+               case 0x04B9: return 0x04B8;
+               case 0x04BB: return 0x04BA;
+               case 0x04BD: return 0x04BC;
+               case 0x04BF: return 0x04BE;
+               case 0x04C2: return 0x04C1;
+               case 0x04C4: return 0x04C3;
+               case 0x04C6: return 0x04C5;
+               case 0x04C8: return 0x04C7;
+               case 0x04CA: return 0x04C9;
+               case 0x04CC: return 0x04CB;
+               case 0x04CE: return 0x04CD;
+               case 0x04CF: return 0x04C0;
+               case 0x04D1: return 0x04D0;
+               case 0x04D3: return 0x04D2;
+               case 0x04D5: return 0x04D4;
+               case 0x04D7: return 0x04D6;
+               case 0x04D9: return 0x04D8;
+               case 0x04DB: return 0x04DA;
+               case 0x04DD: return 0x04DC;
+               case 0x04DF: return 0x04DE;
+               case 0x04E1: return 0x04E0;
+               case 0x04E3: return 0x04E2;
+               case 0x04E5: return 0x04E4;
+               case 0x04E7: return 0x04E6;
+               case 0x04E9: return 0x04E8;
+               case 0x04EB: return 0x04EA;
+               case 0x04ED: return 0x04EC;
+               case 0x04EF: return 0x04EE;
+               case 0x04F1: return 0x04F0;
+               case 0x04F3: return 0x04F2;
+               case 0x04F5: return 0x04F4;
+               case 0x04F7: return 0x04F6;
+               case 0x04F9: return 0x04F8;
+               case 0x04FB: return 0x04FA;
+               case 0x04FD: return 0x04FC;
+               case 0x04FF: return 0x04FE;
+               case 0x0501: return 0x0500;
+               case 0x0503: return 0x0502;
+               case 0x0505: return 0x0504;
+               case 0x0507: return 0x0506;
+               case 0x0509: return 0x0508;
+               case 0x050B: return 0x050A;
+               case 0x050D: return 0x050C;
+               case 0x050F: return 0x050E;
+               case 0x0511: return 0x0510;
+               case 0x0513: return 0x0512;
+               case 0x0515: return 0x0514;
+               case 0x0517: return 0x0516;
+               case 0x0519: return 0x0518;
+               case 0x051B: return 0x051A;
+               case 0x051D: return 0x051C;
+               case 0x051F: return 0x051E;
+               case 0x0521: return 0x0520;
+               case 0x0523: return 0x0522;
+               case 0x0525: return 0x0524;
+               case 0x0527: return 0x0526;
+               case 0x0561: return 0x0531;
+               case 0x0562: return 0x0532;
+               case 0x0563: return 0x0533;
+               case 0x0564: return 0x0534;
+               case 0x0565: return 0x0535;
+               case 0x0566: return 0x0536;
+               case 0x0567: return 0x0537;
+               case 0x0568: return 0x0538;
+               case 0x0569: return 0x0539;
+               case 0x056A: return 0x053A;
+               case 0x056B: return 0x053B;
+               case 0x056C: return 0x053C;
+               case 0x056D: return 0x053D;
+               case 0x056E: return 0x053E;
+               case 0x056F: return 0x053F;
+               case 0x0570: return 0x0540;
+               case 0x0571: return 0x0541;
+               case 0x0572: return 0x0542;
+               case 0x0573: return 0x0543;
+               case 0x0574: return 0x0544;
+               case 0x0575: return 0x0545;
+               case 0x0576: return 0x0546;
+               case 0x0577: return 0x0547;
+               case 0x0578: return 0x0548;
+               case 0x0579: return 0x0549;
+               case 0x057A: return 0x054A;
+               case 0x057B: return 0x054B;
+               case 0x057C: return 0x054C;
+               case 0x057D: return 0x054D;
+               case 0x057E: return 0x054E;
+               case 0x057F: return 0x054F;
+               case 0x0580: return 0x0550;
+               case 0x0581: return 0x0551;
+               case 0x0582: return 0x0552;
+               case 0x0583: return 0x0553;
+               case 0x0584: return 0x0554;
+               case 0x0585: return 0x0555;
+               case 0x0586: return 0x0556;
+               case 0x1D79: return 0xA77D;
+               case 0x1D7D: return 0x2C63;
+               case 0x1E01: return 0x1E00;
+               case 0x1E03: return 0x1E02;
+               case 0x1E05: return 0x1E04;
+               case 0x1E07: return 0x1E06;
+               case 0x1E09: return 0x1E08;
+               case 0x1E0B: return 0x1E0A;
+               case 0x1E0D: return 0x1E0C;
+               case 0x1E0F: return 0x1E0E;
+               case 0x1E11: return 0x1E10;
+               case 0x1E13: return 0x1E12;
+               case 0x1E15: return 0x1E14;
+               case 0x1E17: return 0x1E16;
+               case 0x1E19: return 0x1E18;
+               case 0x1E1B: return 0x1E1A;
+               case 0x1E1D: return 0x1E1C;
+               case 0x1E1F: return 0x1E1E;
+               case 0x1E21: return 0x1E20;
+               case 0x1E23: return 0x1E22;
+               case 0x1E25: return 0x1E24;
+               case 0x1E27: return 0x1E26;
+               case 0x1E29: return 0x1E28;
+               case 0x1E2B: return 0x1E2A;
+               case 0x1E2D: return 0x1E2C;
+               case 0x1E2F: return 0x1E2E;
+               case 0x1E31: return 0x1E30;
+               case 0x1E33: return 0x1E32;
+               case 0x1E35: return 0x1E34;
+               case 0x1E37: return 0x1E36;
+               case 0x1E39: return 0x1E38;
+               case 0x1E3B: return 0x1E3A;
+               case 0x1E3D: return 0x1E3C;
+               case 0x1E3F: return 0x1E3E;
+               case 0x1E41: return 0x1E40;
+               case 0x1E43: return 0x1E42;
+               case 0x1E45: return 0x1E44;
+               case 0x1E47: return 0x1E46;
+               case 0x1E49: return 0x1E48;
+               case 0x1E4B: return 0x1E4A;
+               case 0x1E4D: return 0x1E4C;
+               case 0x1E4F: return 0x1E4E;
+               case 0x1E51: return 0x1E50;
+               case 0x1E53: return 0x1E52;
+               case 0x1E55: return 0x1E54;
+               case 0x1E57: return 0x1E56;
+               case 0x1E59: return 0x1E58;
+               case 0x1E5B: return 0x1E5A;
+               case 0x1E5D: return 0x1E5C;
+               case 0x1E5F: return 0x1E5E;
+               case 0x1E61: return 0x1E60;
+               case 0x1E63: return 0x1E62;
+               case 0x1E65: return 0x1E64;
+               case 0x1E67: return 0x1E66;
+               case 0x1E69: return 0x1E68;
+               case 0x1E6B: return 0x1E6A;
+               case 0x1E6D: return 0x1E6C;
+               case 0x1E6F: return 0x1E6E;
+               case 0x1E71: return 0x1E70;
+               case 0x1E73: return 0x1E72;
+               case 0x1E75: return 0x1E74;
+               case 0x1E77: return 0x1E76;
+               case 0x1E79: return 0x1E78;
+               case 0x1E7B: return 0x1E7A;
+               case 0x1E7D: return 0x1E7C;
+               case 0x1E7F: return 0x1E7E;
+               case 0x1E81: return 0x1E80;
+               case 0x1E83: return 0x1E82;
+               case 0x1E85: return 0x1E84;
+               case 0x1E87: return 0x1E86;
+               case 0x1E89: return 0x1E88;
+               case 0x1E8B: return 0x1E8A;
+               case 0x1E8D: return 0x1E8C;
+               case 0x1E8F: return 0x1E8E;
+               case 0x1E91: return 0x1E90;
+               case 0x1E93: return 0x1E92;
+               case 0x1E95: return 0x1E94;
+               case 0x1E9B: return 0x1E60;
+               case 0x1EA1: return 0x1EA0;
+               case 0x1EA3: return 0x1EA2;
+               case 0x1EA5: return 0x1EA4;
+               case 0x1EA7: return 0x1EA6;
+               case 0x1EA9: return 0x1EA8;
+               case 0x1EAB: return 0x1EAA;
+               case 0x1EAD: return 0x1EAC;
+               case 0x1EAF: return 0x1EAE;
+               case 0x1EB1: return 0x1EB0;
+               case 0x1EB3: return 0x1EB2;
+               case 0x1EB5: return 0x1EB4;
+               case 0x1EB7: return 0x1EB6;
+               case 0x1EB9: return 0x1EB8;
+               case 0x1EBB: return 0x1EBA;
+               case 0x1EBD: return 0x1EBC;
+               case 0x1EBF: return 0x1EBE;
+               case 0x1EC1: return 0x1EC0;
+               case 0x1EC3: return 0x1EC2;
+               case 0x1EC5: return 0x1EC4;
+               case 0x1EC7: return 0x1EC6;
+               case 0x1EC9: return 0x1EC8;
+               case 0x1ECB: return 0x1ECA;
+               case 0x1ECD: return 0x1ECC;
+               case 0x1ECF: return 0x1ECE;
+               case 0x1ED1: return 0x1ED0;
+               case 0x1ED3: return 0x1ED2;
+               case 0x1ED5: return 0x1ED4;
+               case 0x1ED7: return 0x1ED6;
+               case 0x1ED9: return 0x1ED8;
+               case 0x1EDB: return 0x1EDA;
+               case 0x1EDD: return 0x1EDC;
+               case 0x1EDF: return 0x1EDE;
+               case 0x1EE1: return 0x1EE0;
+               case 0x1EE3: return 0x1EE2;
+               case 0x1EE5: return 0x1EE4;
+               case 0x1EE7: return 0x1EE6;
+               case 0x1EE9: return 0x1EE8;
+               case 0x1EEB: return 0x1EEA;
+               case 0x1EED: return 0x1EEC;
+               case 0x1EEF: return 0x1EEE;
+               case 0x1EF1: return 0x1EF0;
+               case 0x1EF3: return 0x1EF2;
+               case 0x1EF5: return 0x1EF4;
+               case 0x1EF7: return 0x1EF6;
+               case 0x1EF9: return 0x1EF8;
+               case 0x1EFB: return 0x1EFA;
+               case 0x1EFD: return 0x1EFC;
+               case 0x1EFF: return 0x1EFE;
+               case 0x1F00: return 0x1F08;
+               case 0x1F01: return 0x1F09;
+               case 0x1F02: return 0x1F0A;
+               case 0x1F03: return 0x1F0B;
+               case 0x1F04: return 0x1F0C;
+               case 0x1F05: return 0x1F0D;
+               case 0x1F06: return 0x1F0E;
+               case 0x1F07: return 0x1F0F;
+               case 0x1F10: return 0x1F18;
+               case 0x1F11: return 0x1F19;
+               case 0x1F12: return 0x1F1A;
+               case 0x1F13: return 0x1F1B;
+               case 0x1F14: return 0x1F1C;
+               case 0x1F15: return 0x1F1D;
+               case 0x1F20: return 0x1F28;
+               case 0x1F21: return 0x1F29;
+               case 0x1F22: return 0x1F2A;
+               case 0x1F23: return 0x1F2B;
+               case 0x1F24: return 0x1F2C;
+               case 0x1F25: return 0x1F2D;
+               case 0x1F26: return 0x1F2E;
+               case 0x1F27: return 0x1F2F;
+               case 0x1F30: return 0x1F38;
+               case 0x1F31: return 0x1F39;
+               case 0x1F32: return 0x1F3A;
+               case 0x1F33: return 0x1F3B;
+               case 0x1F34: return 0x1F3C;
+               case 0x1F35: return 0x1F3D;
+               case 0x1F36: return 0x1F3E;
+               case 0x1F37: return 0x1F3F;
+               case 0x1F40: return 0x1F48;
+               case 0x1F41: return 0x1F49;
+               case 0x1F42: return 0x1F4A;
+               case 0x1F43: return 0x1F4B;
+               case 0x1F44: return 0x1F4C;
+               case 0x1F45: return 0x1F4D;
+               case 0x1F51: return 0x1F59;
+               case 0x1F53: return 0x1F5B;
+               case 0x1F55: return 0x1F5D;
+               case 0x1F57: return 0x1F5F;
+               case 0x1F60: return 0x1F68;
+               case 0x1F61: return 0x1F69;
+               case 0x1F62: return 0x1F6A;
+               case 0x1F63: return 0x1F6B;
+               case 0x1F64: return 0x1F6C;
+               case 0x1F65: return 0x1F6D;
+               case 0x1F66: return 0x1F6E;
+               case 0x1F67: return 0x1F6F;
+               case 0x1F70: return 0x1FBA;
+               case 0x1F71: return 0x1FBB;
+               case 0x1F72: return 0x1FC8;
+               case 0x1F73: return 0x1FC9;
+               case 0x1F74: return 0x1FCA;
+               case 0x1F75: return 0x1FCB;
+               case 0x1F76: return 0x1FDA;
+               case 0x1F77: return 0x1FDB;
+               case 0x1F78: return 0x1FF8;
+               case 0x1F79: return 0x1FF9;
+               case 0x1F7A: return 0x1FEA;
+               case 0x1F7B: return 0x1FEB;
+               case 0x1F7C: return 0x1FFA;
+               case 0x1F7D: return 0x1FFB;
+               case 0x1F80: return 0x1F88;
+               case 0x1F81: return 0x1F89;
+               case 0x1F82: return 0x1F8A;
+               case 0x1F83: return 0x1F8B;
+               case 0x1F84: return 0x1F8C;
+               case 0x1F85: return 0x1F8D;
+               case 0x1F86: return 0x1F8E;
+               case 0x1F87: return 0x1F8F;
+               case 0x1F90: return 0x1F98;
+               case 0x1F91: return 0x1F99;
+               case 0x1F92: return 0x1F9A;
+               case 0x1F93: return 0x1F9B;
+               case 0x1F94: return 0x1F9C;
+               case 0x1F95: return 0x1F9D;
+               case 0x1F96: return 0x1F9E;
+               case 0x1F97: return 0x1F9F;
+               case 0x1FA0: return 0x1FA8;
+               case 0x1FA1: return 0x1FA9;
+               case 0x1FA2: return 0x1FAA;
+               case 0x1FA3: return 0x1FAB;
+               case 0x1FA4: return 0x1FAC;
+               case 0x1FA5: return 0x1FAD;
+               case 0x1FA6: return 0x1FAE;
+               case 0x1FA7: return 0x1FAF;
+               case 0x1FB0: return 0x1FB8;
+               case 0x1FB1: return 0x1FB9;
+               case 0x1FB3: return 0x1FBC;
+               case 0x1FBE: return 0x0399;
+               case 0x1FC3: return 0x1FCC;
+               case 0x1FD0: return 0x1FD8;
+               case 0x1FD1: return 0x1FD9;
+               case 0x1FE0: return 0x1FE8;
+               case 0x1FE1: return 0x1FE9;
+               case 0x1FE5: return 0x1FEC;
+               case 0x1FF3: return 0x1FFC;
+               case 0x214E: return 0x2132;
+               case 0x2170: return 0x2160;
+               case 0x2171: return 0x2161;
+               case 0x2172: return 0x2162;
+               case 0x2173: return 0x2163;
+               case 0x2174: return 0x2164;
+               case 0x2175: return 0x2165;
+               case 0x2176: return 0x2166;
+               case 0x2177: return 0x2167;
+               case 0x2178: return 0x2168;
+               case 0x2179: return 0x2169;
+               case 0x217A: return 0x216A;
+               case 0x217B: return 0x216B;
+               case 0x217C: return 0x216C;
+               case 0x217D: return 0x216D;
+               case 0x217E: return 0x216E;
+               case 0x217F: return 0x216F;
+               case 0x2184: return 0x2183;
+               case 0x24D0: return 0x24B6;
+               case 0x24D1: return 0x24B7;
+               case 0x24D2: return 0x24B8;
+               case 0x24D3: return 0x24B9;
+               case 0x24D4: return 0x24BA;
+               case 0x24D5: return 0x24BB;
+               case 0x24D6: return 0x24BC;
+               case 0x24D7: return 0x24BD;
+               case 0x24D8: return 0x24BE;
+               case 0x24D9: return 0x24BF;
+               case 0x24DA: return 0x24C0;
+               case 0x24DB: return 0x24C1;
+               case 0x24DC: return 0x24C2;
+               case 0x24DD: return 0x24C3;
+               case 0x24DE: return 0x24C4;
+               case 0x24DF: return 0x24C5;
+               case 0x24E0: return 0x24C6;
+               case 0x24E1: return 0x24C7;
+               case 0x24E2: return 0x24C8;
+               case 0x24E3: return 0x24C9;
+               case 0x24E4: return 0x24CA;
+               case 0x24E5: return 0x24CB;
+               case 0x24E6: return 0x24CC;
+               case 0x24E7: return 0x24CD;
+               case 0x24E8: return 0x24CE;
+               case 0x24E9: return 0x24CF;
+               case 0x2C30: return 0x2C00;
+               case 0x2C31: return 0x2C01;
+               case 0x2C32: return 0x2C02;
+               case 0x2C33: return 0x2C03;
+               case 0x2C34: return 0x2C04;
+               case 0x2C35: return 0x2C05;
+               case 0x2C36: return 0x2C06;
+               case 0x2C37: return 0x2C07;
+               case 0x2C38: return 0x2C08;
+               case 0x2C39: return 0x2C09;
+               case 0x2C3A: return 0x2C0A;
+               case 0x2C3B: return 0x2C0B;
+               case 0x2C3C: return 0x2C0C;
+               case 0x2C3D: return 0x2C0D;
+               case 0x2C3E: return 0x2C0E;
+               case 0x2C3F: return 0x2C0F;
+               case 0x2C40: return 0x2C10;
+               case 0x2C41: return 0x2C11;
+               case 0x2C42: return 0x2C12;
+               case 0x2C43: return 0x2C13;
+               case 0x2C44: return 0x2C14;
+               case 0x2C45: return 0x2C15;
+               case 0x2C46: return 0x2C16;
+               case 0x2C47: return 0x2C17;
+               case 0x2C48: return 0x2C18;
+               case 0x2C49: return 0x2C19;
+               case 0x2C4A: return 0x2C1A;
+               case 0x2C4B: return 0x2C1B;
+               case 0x2C4C: return 0x2C1C;
+               case 0x2C4D: return 0x2C1D;
+               case 0x2C4E: return 0x2C1E;
+               case 0x2C4F: return 0x2C1F;
+               case 0x2C50: return 0x2C20;
+               case 0x2C51: return 0x2C21;
+               case 0x2C52: return 0x2C22;
+               case 0x2C53: return 0x2C23;
+               case 0x2C54: return 0x2C24;
+               case 0x2C55: return 0x2C25;
+               case 0x2C56: return 0x2C26;
+               case 0x2C57: return 0x2C27;
+               case 0x2C58: return 0x2C28;
+               case 0x2C59: return 0x2C29;
+               case 0x2C5A: return 0x2C2A;
+               case 0x2C5B: return 0x2C2B;
+               case 0x2C5C: return 0x2C2C;
+               case 0x2C5D: return 0x2C2D;
+               case 0x2C5E: return 0x2C2E;
+               case 0x2C61: return 0x2C60;
+               case 0x2C65: return 0x023A;
+               case 0x2C66: return 0x023E;
+               case 0x2C68: return 0x2C67;
+               case 0x2C6A: return 0x2C69;
+               case 0x2C6C: return 0x2C6B;
+               case 0x2C73: return 0x2C72;
+               case 0x2C76: return 0x2C75;
+               case 0x2C81: return 0x2C80;
+               case 0x2C83: return 0x2C82;
+               case 0x2C85: return 0x2C84;
+               case 0x2C87: return 0x2C86;
+               case 0x2C89: return 0x2C88;
+               case 0x2C8B: return 0x2C8A;
+               case 0x2C8D: return 0x2C8C;
+               case 0x2C8F: return 0x2C8E;
+               case 0x2C91: return 0x2C90;
+               case 0x2C93: return 0x2C92;
+               case 0x2C95: return 0x2C94;
+               case 0x2C97: return 0x2C96;
+               case 0x2C99: return 0x2C98;
+               case 0x2C9B: return 0x2C9A;
+               case 0x2C9D: return 0x2C9C;
+               case 0x2C9F: return 0x2C9E;
+               case 0x2CA1: return 0x2CA0;
+               case 0x2CA3: return 0x2CA2;
+               case 0x2CA5: return 0x2CA4;
+               case 0x2CA7: return 0x2CA6;
+               case 0x2CA9: return 0x2CA8;
+               case 0x2CAB: return 0x2CAA;
+               case 0x2CAD: return 0x2CAC;
+               case 0x2CAF: return 0x2CAE;
+               case 0x2CB1: return 0x2CB0;
+               case 0x2CB3: return 0x2CB2;
+               case 0x2CB5: return 0x2CB4;
+               case 0x2CB7: return 0x2CB6;
+               case 0x2CB9: return 0x2CB8;
+               case 0x2CBB: return 0x2CBA;
+               case 0x2CBD: return 0x2CBC;
+               case 0x2CBF: return 0x2CBE;
+               case 0x2CC1: return 0x2CC0;
+               case 0x2CC3: return 0x2CC2;
+               case 0x2CC5: return 0x2CC4;
+               case 0x2CC7: return 0x2CC6;
+               case 0x2CC9: return 0x2CC8;
+               case 0x2CCB: return 0x2CCA;
+               case 0x2CCD: return 0x2CCC;
+               case 0x2CCF: return 0x2CCE;
+               case 0x2CD1: return 0x2CD0;
+               case 0x2CD3: return 0x2CD2;
+               case 0x2CD5: return 0x2CD4;
+               case 0x2CD7: return 0x2CD6;
+               case 0x2CD9: return 0x2CD8;
+               case 0x2CDB: return 0x2CDA;
+               case 0x2CDD: return 0x2CDC;
+               case 0x2CDF: return 0x2CDE;
+               case 0x2CE1: return 0x2CE0;
+               case 0x2CE3: return 0x2CE2;
+               case 0x2CEC: return 0x2CEB;
+               case 0x2CEE: return 0x2CED;
+               case 0x2D00: return 0x10A0;
+               case 0x2D01: return 0x10A1;
+               case 0x2D02: return 0x10A2;
+               case 0x2D03: return 0x10A3;
+               case 0x2D04: return 0x10A4;
+               case 0x2D05: return 0x10A5;
+               case 0x2D06: return 0x10A6;
+               case 0x2D07: return 0x10A7;
+               case 0x2D08: return 0x10A8;
+               case 0x2D09: return 0x10A9;
+               case 0x2D0A: return 0x10AA;
+               case 0x2D0B: return 0x10AB;
+               case 0x2D0C: return 0x10AC;
+               case 0x2D0D: return 0x10AD;
+               case 0x2D0E: return 0x10AE;
+               case 0x2D0F: return 0x10AF;
+               case 0x2D10: return 0x10B0;
+               case 0x2D11: return 0x10B1;
+               case 0x2D12: return 0x10B2;
+               case 0x2D13: return 0x10B3;
+               case 0x2D14: return 0x10B4;
+               case 0x2D15: return 0x10B5;
+               case 0x2D16: return 0x10B6;
+               case 0x2D17: return 0x10B7;
+               case 0x2D18: return 0x10B8;
+               case 0x2D19: return 0x10B9;
+               case 0x2D1A: return 0x10BA;
+               case 0x2D1B: return 0x10BB;
+               case 0x2D1C: return 0x10BC;
+               case 0x2D1D: return 0x10BD;
+               case 0x2D1E: return 0x10BE;
+               case 0x2D1F: return 0x10BF;
+               case 0x2D20: return 0x10C0;
+               case 0x2D21: return 0x10C1;
+               case 0x2D22: return 0x10C2;
+               case 0x2D23: return 0x10C3;
+               case 0x2D24: return 0x10C4;
+               case 0x2D25: return 0x10C5;
+               case 0xA641: return 0xA640;
+               case 0xA643: return 0xA642;
+               case 0xA645: return 0xA644;
+               case 0xA647: return 0xA646;
+               case 0xA649: return 0xA648;
+               case 0xA64B: return 0xA64A;
+               case 0xA64D: return 0xA64C;
+               case 0xA64F: return 0xA64E;
+               case 0xA651: return 0xA650;
+               case 0xA653: return 0xA652;
+               case 0xA655: return 0xA654;
+               case 0xA657: return 0xA656;
+               case 0xA659: return 0xA658;
+               case 0xA65B: return 0xA65A;
+               case 0xA65D: return 0xA65C;
+               case 0xA65F: return 0xA65E;
+               case 0xA661: return 0xA660;
+               case 0xA663: return 0xA662;
+               case 0xA665: return 0xA664;
+               case 0xA667: return 0xA666;
+               case 0xA669: return 0xA668;
+               case 0xA66B: return 0xA66A;
+               case 0xA66D: return 0xA66C;
+               case 0xA681: return 0xA680;
+               case 0xA683: return 0xA682;
+               case 0xA685: return 0xA684;
+               case 0xA687: return 0xA686;
+               case 0xA689: return 0xA688;
+               case 0xA68B: return 0xA68A;
+               case 0xA68D: return 0xA68C;
+               case 0xA68F: return 0xA68E;
+               case 0xA691: return 0xA690;
+               case 0xA693: return 0xA692;
+               case 0xA695: return 0xA694;
+               case 0xA697: return 0xA696;
+               case 0xA723: return 0xA722;
+               case 0xA725: return 0xA724;
+               case 0xA727: return 0xA726;
+               case 0xA729: return 0xA728;
+               case 0xA72B: return 0xA72A;
+               case 0xA72D: return 0xA72C;
+               case 0xA72F: return 0xA72E;
+               case 0xA733: return 0xA732;
+               case 0xA735: return 0xA734;
+               case 0xA737: return 0xA736;
+               case 0xA739: return 0xA738;
+               case 0xA73B: return 0xA73A;
+               case 0xA73D: return 0xA73C;
+               case 0xA73F: return 0xA73E;
+               case 0xA741: return 0xA740;
+               case 0xA743: return 0xA742;
+               case 0xA745: return 0xA744;
+               case 0xA747: return 0xA746;
+               case 0xA749: return 0xA748;
+               case 0xA74B: return 0xA74A;
+               case 0xA74D: return 0xA74C;
+               case 0xA74F: return 0xA74E;
+               case 0xA751: return 0xA750;
+               case 0xA753: return 0xA752;
+               case 0xA755: return 0xA754;
+               case 0xA757: return 0xA756;
+               case 0xA759: return 0xA758;
+               case 0xA75B: return 0xA75A;
+               case 0xA75D: return 0xA75C;
+               case 0xA75F: return 0xA75E;
+               case 0xA761: return 0xA760;
+               case 0xA763: return 0xA762;
+               case 0xA765: return 0xA764;
+               case 0xA767: return 0xA766;
+               case 0xA769: return 0xA768;
+               case 0xA76B: return 0xA76A;
+               case 0xA76D: return 0xA76C;
+               case 0xA76F: return 0xA76E;
+               case 0xA77A: return 0xA779;
+               case 0xA77C: return 0xA77B;
+               case 0xA77F: return 0xA77E;
+               case 0xA781: return 0xA780;
+               case 0xA783: return 0xA782;
+               case 0xA785: return 0xA784;
+               case 0xA787: return 0xA786;
+               case 0xA78C: return 0xA78B;
+               case 0xA791: return 0xA790;
+               case 0xA7A1: return 0xA7A0;
+               case 0xA7A3: return 0xA7A2;
+               case 0xA7A5: return 0xA7A4;
+               case 0xA7A7: return 0xA7A6;
+               case 0xA7A9: return 0xA7A8;
+               case 0xFF41: return 0xFF21;
+               case 0xFF42: return 0xFF22;
+               case 0xFF43: return 0xFF23;
+               case 0xFF44: return 0xFF24;
+               case 0xFF45: return 0xFF25;
+               case 0xFF46: return 0xFF26;
+               case 0xFF47: return 0xFF27;
+               case 0xFF48: return 0xFF28;
+               case 0xFF49: return 0xFF29;
+               case 0xFF4A: return 0xFF2A;
+               case 0xFF4B: return 0xFF2B;
+               case 0xFF4C: return 0xFF2C;
+               case 0xFF4D: return 0xFF2D;
+               case 0xFF4E: return 0xFF2E;
+               case 0xFF4F: return 0xFF2F;
+               case 0xFF50: return 0xFF30;
+               case 0xFF51: return 0xFF31;
+               case 0xFF52: return 0xFF32;
+               case 0xFF53: return 0xFF33;
+               case 0xFF54: return 0xFF34;
+               case 0xFF55: return 0xFF35;
+               case 0xFF56: return 0xFF36;
+               case 0xFF57: return 0xFF37;
+               case 0xFF58: return 0xFF38;
+               case 0xFF59: return 0xFF39;
+               case 0xFF5A: return 0xFF3A;
+               case 0x10428: return 0x10400;
+               case 0x10429: return 0x10401;
+               case 0x1042A: return 0x10402;
+               case 0x1042B: return 0x10403;
+               case 0x1042C: return 0x10404;
+               case 0x1042D: return 0x10405;
+               case 0x1042E: return 0x10406;
+               case 0x1042F: return 0x10407;
+               case 0x10430: return 0x10408;
+               case 0x10431: return 0x10409;
+               case 0x10432: return 0x1040A;
+               case 0x10433: return 0x1040B;
+               case 0x10434: return 0x1040C;
+               case 0x10435: return 0x1040D;
+               case 0x10436: return 0x1040E;
+               case 0x10437: return 0x1040F;
+               case 0x10438: return 0x10410;
+               case 0x10439: return 0x10411;
+               case 0x1043A: return 0x10412;
+               case 0x1043B: return 0x10413;
+               case 0x1043C: return 0x10414;
+               case 0x1043D: return 0x10415;
+               case 0x1043E: return 0x10416;
+               case 0x1043F: return 0x10417;
+               case 0x10440: return 0x10418;
+               case 0x10441: return 0x10419;
+               case 0x10442: return 0x1041A;
+               case 0x10443: return 0x1041B;
+               case 0x10444: return 0x1041C;
+               case 0x10445: return 0x1041D;
+               case 0x10446: return 0x1041E;
+               case 0x10447: return 0x1041F;
+               case 0x10448: return 0x10420;
+               case 0x10449: return 0x10421;
+               case 0x1044A: return 0x10422;
+               case 0x1044B: return 0x10423;
+               case 0x1044C: return 0x10424;
+               case 0x1044D: return 0x10425;
+               case 0x1044E: return 0x10426;
+               case 0x1044F: return 0x10427;
+               default: return ch;
+       }
+}
+
+Uchar u8_tolower(Uchar ch)
+{
+       switch(ch)
+       {
+               case 0x0041: return 0x0061;
+               case 0x0042: return 0x0062;
+               case 0x0043: return 0x0063;
+               case 0x0044: return 0x0064;
+               case 0x0045: return 0x0065;
+               case 0x0046: return 0x0066;
+               case 0x0047: return 0x0067;
+               case 0x0048: return 0x0068;
+               case 0x0049: return 0x0069;
+               case 0x004A: return 0x006A;
+               case 0x004B: return 0x006B;
+               case 0x004C: return 0x006C;
+               case 0x004D: return 0x006D;
+               case 0x004E: return 0x006E;
+               case 0x004F: return 0x006F;
+               case 0x0050: return 0x0070;
+               case 0x0051: return 0x0071;
+               case 0x0052: return 0x0072;
+               case 0x0053: return 0x0073;
+               case 0x0054: return 0x0074;
+               case 0x0055: return 0x0075;
+               case 0x0056: return 0x0076;
+               case 0x0057: return 0x0077;
+               case 0x0058: return 0x0078;
+               case 0x0059: return 0x0079;
+               case 0x005A: return 0x007A;
+               case 0x00C0: return 0x00E0;
+               case 0x00C1: return 0x00E1;
+               case 0x00C2: return 0x00E2;
+               case 0x00C3: return 0x00E3;
+               case 0x00C4: return 0x00E4;
+               case 0x00C5: return 0x00E5;
+               case 0x00C6: return 0x00E6;
+               case 0x00C7: return 0x00E7;
+               case 0x00C8: return 0x00E8;
+               case 0x00C9: return 0x00E9;
+               case 0x00CA: return 0x00EA;
+               case 0x00CB: return 0x00EB;
+               case 0x00CC: return 0x00EC;
+               case 0x00CD: return 0x00ED;
+               case 0x00CE: return 0x00EE;
+               case 0x00CF: return 0x00EF;
+               case 0x00D0: return 0x00F0;
+               case 0x00D1: return 0x00F1;
+               case 0x00D2: return 0x00F2;
+               case 0x00D3: return 0x00F3;
+               case 0x00D4: return 0x00F4;
+               case 0x00D5: return 0x00F5;
+               case 0x00D6: return 0x00F6;
+               case 0x00D8: return 0x00F8;
+               case 0x00D9: return 0x00F9;
+               case 0x00DA: return 0x00FA;
+               case 0x00DB: return 0x00FB;
+               case 0x00DC: return 0x00FC;
+               case 0x00DD: return 0x00FD;
+               case 0x00DE: return 0x00FE;
+               case 0x0100: return 0x0101;
+               case 0x0102: return 0x0103;
+               case 0x0104: return 0x0105;
+               case 0x0106: return 0x0107;
+               case 0x0108: return 0x0109;
+               case 0x010A: return 0x010B;
+               case 0x010C: return 0x010D;
+               case 0x010E: return 0x010F;
+               case 0x0110: return 0x0111;
+               case 0x0112: return 0x0113;
+               case 0x0114: return 0x0115;
+               case 0x0116: return 0x0117;
+               case 0x0118: return 0x0119;
+               case 0x011A: return 0x011B;
+               case 0x011C: return 0x011D;
+               case 0x011E: return 0x011F;
+               case 0x0120: return 0x0121;
+               case 0x0122: return 0x0123;
+               case 0x0124: return 0x0125;
+               case 0x0126: return 0x0127;
+               case 0x0128: return 0x0129;
+               case 0x012A: return 0x012B;
+               case 0x012C: return 0x012D;
+               case 0x012E: return 0x012F;
+               case 0x0130: return 0x0069;
+               case 0x0132: return 0x0133;
+               case 0x0134: return 0x0135;
+               case 0x0136: return 0x0137;
+               case 0x0139: return 0x013A;
+               case 0x013B: return 0x013C;
+               case 0x013D: return 0x013E;
+               case 0x013F: return 0x0140;
+               case 0x0141: return 0x0142;
+               case 0x0143: return 0x0144;
+               case 0x0145: return 0x0146;
+               case 0x0147: return 0x0148;
+               case 0x014A: return 0x014B;
+               case 0x014C: return 0x014D;
+               case 0x014E: return 0x014F;
+               case 0x0150: return 0x0151;
+               case 0x0152: return 0x0153;
+               case 0x0154: return 0x0155;
+               case 0x0156: return 0x0157;
+               case 0x0158: return 0x0159;
+               case 0x015A: return 0x015B;
+               case 0x015C: return 0x015D;
+               case 0x015E: return 0x015F;
+               case 0x0160: return 0x0161;
+               case 0x0162: return 0x0163;
+               case 0x0164: return 0x0165;
+               case 0x0166: return 0x0167;
+               case 0x0168: return 0x0169;
+               case 0x016A: return 0x016B;
+               case 0x016C: return 0x016D;
+               case 0x016E: return 0x016F;
+               case 0x0170: return 0x0171;
+               case 0x0172: return 0x0173;
+               case 0x0174: return 0x0175;
+               case 0x0176: return 0x0177;
+               case 0x0178: return 0x00FF;
+               case 0x0179: return 0x017A;
+               case 0x017B: return 0x017C;
+               case 0x017D: return 0x017E;
+               case 0x0181: return 0x0253;
+               case 0x0182: return 0x0183;
+               case 0x0184: return 0x0185;
+               case 0x0186: return 0x0254;
+               case 0x0187: return 0x0188;
+               case 0x0189: return 0x0256;
+               case 0x018A: return 0x0257;
+               case 0x018B: return 0x018C;
+               case 0x018E: return 0x01DD;
+               case 0x018F: return 0x0259;
+               case 0x0190: return 0x025B;
+               case 0x0191: return 0x0192;
+               case 0x0193: return 0x0260;
+               case 0x0194: return 0x0263;
+               case 0x0196: return 0x0269;
+               case 0x0197: return 0x0268;
+               case 0x0198: return 0x0199;
+               case 0x019C: return 0x026F;
+               case 0x019D: return 0x0272;
+               case 0x019F: return 0x0275;
+               case 0x01A0: return 0x01A1;
+               case 0x01A2: return 0x01A3;
+               case 0x01A4: return 0x01A5;
+               case 0x01A6: return 0x0280;
+               case 0x01A7: return 0x01A8;
+               case 0x01A9: return 0x0283;
+               case 0x01AC: return 0x01AD;
+               case 0x01AE: return 0x0288;
+               case 0x01AF: return 0x01B0;
+               case 0x01B1: return 0x028A;
+               case 0x01B2: return 0x028B;
+               case 0x01B3: return 0x01B4;
+               case 0x01B5: return 0x01B6;
+               case 0x01B7: return 0x0292;
+               case 0x01B8: return 0x01B9;
+               case 0x01BC: return 0x01BD;
+               case 0x01C4: return 0x01C6;
+               case 0x01C5: return 0x01C6;
+               case 0x01C7: return 0x01C9;
+               case 0x01C8: return 0x01C9;
+               case 0x01CA: return 0x01CC;
+               case 0x01CB: return 0x01CC;
+               case 0x01CD: return 0x01CE;
+               case 0x01CF: return 0x01D0;
+               case 0x01D1: return 0x01D2;
+               case 0x01D3: return 0x01D4;
+               case 0x01D5: return 0x01D6;
+               case 0x01D7: return 0x01D8;
+               case 0x01D9: return 0x01DA;
+               case 0x01DB: return 0x01DC;
+               case 0x01DE: return 0x01DF;
+               case 0x01E0: return 0x01E1;
+               case 0x01E2: return 0x01E3;
+               case 0x01E4: return 0x01E5;
+               case 0x01E6: return 0x01E7;
+               case 0x01E8: return 0x01E9;
+               case 0x01EA: return 0x01EB;
+               case 0x01EC: return 0x01ED;
+               case 0x01EE: return 0x01EF;
+               case 0x01F1: return 0x01F3;
+               case 0x01F2: return 0x01F3;
+               case 0x01F4: return 0x01F5;
+               case 0x01F6: return 0x0195;
+               case 0x01F7: return 0x01BF;
+               case 0x01F8: return 0x01F9;
+               case 0x01FA: return 0x01FB;
+               case 0x01FC: return 0x01FD;
+               case 0x01FE: return 0x01FF;
+               case 0x0200: return 0x0201;
+               case 0x0202: return 0x0203;
+               case 0x0204: return 0x0205;
+               case 0x0206: return 0x0207;
+               case 0x0208: return 0x0209;
+               case 0x020A: return 0x020B;
+               case 0x020C: return 0x020D;
+               case 0x020E: return 0x020F;
+               case 0x0210: return 0x0211;
+               case 0x0212: return 0x0213;
+               case 0x0214: return 0x0215;
+               case 0x0216: return 0x0217;
+               case 0x0218: return 0x0219;
+               case 0x021A: return 0x021B;
+               case 0x021C: return 0x021D;
+               case 0x021E: return 0x021F;
+               case 0x0220: return 0x019E;
+               case 0x0222: return 0x0223;
+               case 0x0224: return 0x0225;
+               case 0x0226: return 0x0227;
+               case 0x0228: return 0x0229;
+               case 0x022A: return 0x022B;
+               case 0x022C: return 0x022D;
+               case 0x022E: return 0x022F;
+               case 0x0230: return 0x0231;
+               case 0x0232: return 0x0233;
+               case 0x023A: return 0x2C65;
+               case 0x023B: return 0x023C;
+               case 0x023D: return 0x019A;
+               case 0x023E: return 0x2C66;
+               case 0x0241: return 0x0242;
+               case 0x0243: return 0x0180;
+               case 0x0244: return 0x0289;
+               case 0x0245: return 0x028C;
+               case 0x0246: return 0x0247;
+               case 0x0248: return 0x0249;
+               case 0x024A: return 0x024B;
+               case 0x024C: return 0x024D;
+               case 0x024E: return 0x024F;
+               case 0x0370: return 0x0371;
+               case 0x0372: return 0x0373;
+               case 0x0376: return 0x0377;
+               case 0x0386: return 0x03AC;
+               case 0x0388: return 0x03AD;
+               case 0x0389: return 0x03AE;
+               case 0x038A: return 0x03AF;
+               case 0x038C: return 0x03CC;
+               case 0x038E: return 0x03CD;
+               case 0x038F: return 0x03CE;
+               case 0x0391: return 0x03B1;
+               case 0x0392: return 0x03B2;
+               case 0x0393: return 0x03B3;
+               case 0x0394: return 0x03B4;
+               case 0x0395: return 0x03B5;
+               case 0x0396: return 0x03B6;
+               case 0x0397: return 0x03B7;
+               case 0x0398: return 0x03B8;
+               case 0x0399: return 0x03B9;
+               case 0x039A: return 0x03BA;
+               case 0x039B: return 0x03BB;
+               case 0x039C: return 0x03BC;
+               case 0x039D: return 0x03BD;
+               case 0x039E: return 0x03BE;
+               case 0x039F: return 0x03BF;
+               case 0x03A0: return 0x03C0;
+               case 0x03A1: return 0x03C1;
+               case 0x03A3: return 0x03C3;
+               case 0x03A4: return 0x03C4;
+               case 0x03A5: return 0x03C5;
+               case 0x03A6: return 0x03C6;
+               case 0x03A7: return 0x03C7;
+               case 0x03A8: return 0x03C8;
+               case 0x03A9: return 0x03C9;
+               case 0x03AA: return 0x03CA;
+               case 0x03AB: return 0x03CB;
+               case 0x03CF: return 0x03D7;
+               case 0x03D8: return 0x03D9;
+               case 0x03DA: return 0x03DB;
+               case 0x03DC: return 0x03DD;
+               case 0x03DE: return 0x03DF;
+               case 0x03E0: return 0x03E1;
+               case 0x03E2: return 0x03E3;
+               case 0x03E4: return 0x03E5;
+               case 0x03E6: return 0x03E7;
+               case 0x03E8: return 0x03E9;
+               case 0x03EA: return 0x03EB;
+               case 0x03EC: return 0x03ED;
+               case 0x03EE: return 0x03EF;
+               case 0x03F4: return 0x03B8;
+               case 0x03F7: return 0x03F8;
+               case 0x03F9: return 0x03F2;
+               case 0x03FA: return 0x03FB;
+               case 0x03FD: return 0x037B;
+               case 0x03FE: return 0x037C;
+               case 0x03FF: return 0x037D;
+               case 0x0400: return 0x0450;
+               case 0x0401: return 0x0451;
+               case 0x0402: return 0x0452;
+               case 0x0403: return 0x0453;
+               case 0x0404: return 0x0454;
+               case 0x0405: return 0x0455;
+               case 0x0406: return 0x0456;
+               case 0x0407: return 0x0457;
+               case 0x0408: return 0x0458;
+               case 0x0409: return 0x0459;
+               case 0x040A: return 0x045A;
+               case 0x040B: return 0x045B;
+               case 0x040C: return 0x045C;
+               case 0x040D: return 0x045D;
+               case 0x040E: return 0x045E;
+               case 0x040F: return 0x045F;
+               case 0x0410: return 0x0430;
+               case 0x0411: return 0x0431;
+               case 0x0412: return 0x0432;
+               case 0x0413: return 0x0433;
+               case 0x0414: return 0x0434;
+               case 0x0415: return 0x0435;
+               case 0x0416: return 0x0436;
+               case 0x0417: return 0x0437;
+               case 0x0418: return 0x0438;
+               case 0x0419: return 0x0439;
+               case 0x041A: return 0x043A;
+               case 0x041B: return 0x043B;
+               case 0x041C: return 0x043C;
+               case 0x041D: return 0x043D;
+               case 0x041E: return 0x043E;
+               case 0x041F: return 0x043F;
+               case 0x0420: return 0x0440;
+               case 0x0421: return 0x0441;
+               case 0x0422: return 0x0442;
+               case 0x0423: return 0x0443;
+               case 0x0424: return 0x0444;
+               case 0x0425: return 0x0445;
+               case 0x0426: return 0x0446;
+               case 0x0427: return 0x0447;
+               case 0x0428: return 0x0448;
+               case 0x0429: return 0x0449;
+               case 0x042A: return 0x044A;
+               case 0x042B: return 0x044B;
+               case 0x042C: return 0x044C;
+               case 0x042D: return 0x044D;
+               case 0x042E: return 0x044E;
+               case 0x042F: return 0x044F;
+               case 0x0460: return 0x0461;
+               case 0x0462: return 0x0463;
+               case 0x0464: return 0x0465;
+               case 0x0466: return 0x0467;
+               case 0x0468: return 0x0469;
+               case 0x046A: return 0x046B;
+               case 0x046C: return 0x046D;
+               case 0x046E: return 0x046F;
+               case 0x0470: return 0x0471;
+               case 0x0472: return 0x0473;
+               case 0x0474: return 0x0475;
+               case 0x0476: return 0x0477;
+               case 0x0478: return 0x0479;
+               case 0x047A: return 0x047B;
+               case 0x047C: return 0x047D;
+               case 0x047E: return 0x047F;
+               case 0x0480: return 0x0481;
+               case 0x048A: return 0x048B;
+               case 0x048C: return 0x048D;
+               case 0x048E: return 0x048F;
+               case 0x0490: return 0x0491;
+               case 0x0492: return 0x0493;
+               case 0x0494: return 0x0495;
+               case 0x0496: return 0x0497;
+               case 0x0498: return 0x0499;
+               case 0x049A: return 0x049B;
+               case 0x049C: return 0x049D;
+               case 0x049E: return 0x049F;
+               case 0x04A0: return 0x04A1;
+               case 0x04A2: return 0x04A3;
+               case 0x04A4: return 0x04A5;
+               case 0x04A6: return 0x04A7;
+               case 0x04A8: return 0x04A9;
+               case 0x04AA: return 0x04AB;
+               case 0x04AC: return 0x04AD;
+               case 0x04AE: return 0x04AF;
+               case 0x04B0: return 0x04B1;
+               case 0x04B2: return 0x04B3;
+               case 0x04B4: return 0x04B5;
+               case 0x04B6: return 0x04B7;
+               case 0x04B8: return 0x04B9;
+               case 0x04BA: return 0x04BB;
+               case 0x04BC: return 0x04BD;
+               case 0x04BE: return 0x04BF;
+               case 0x04C0: return 0x04CF;
+               case 0x04C1: return 0x04C2;
+               case 0x04C3: return 0x04C4;
+               case 0x04C5: return 0x04C6;
+               case 0x04C7: return 0x04C8;
+               case 0x04C9: return 0x04CA;
+               case 0x04CB: return 0x04CC;
+               case 0x04CD: return 0x04CE;
+               case 0x04D0: return 0x04D1;
+               case 0x04D2: return 0x04D3;
+               case 0x04D4: return 0x04D5;
+               case 0x04D6: return 0x04D7;
+               case 0x04D8: return 0x04D9;
+               case 0x04DA: return 0x04DB;
+               case 0x04DC: return 0x04DD;
+               case 0x04DE: return 0x04DF;
+               case 0x04E0: return 0x04E1;
+               case 0x04E2: return 0x04E3;
+               case 0x04E4: return 0x04E5;
+               case 0x04E6: return 0x04E7;
+               case 0x04E8: return 0x04E9;
+               case 0x04EA: return 0x04EB;
+               case 0x04EC: return 0x04ED;
+               case 0x04EE: return 0x04EF;
+               case 0x04F0: return 0x04F1;
+               case 0x04F2: return 0x04F3;
+               case 0x04F4: return 0x04F5;
+               case 0x04F6: return 0x04F7;
+               case 0x04F8: return 0x04F9;
+               case 0x04FA: return 0x04FB;
+               case 0x04FC: return 0x04FD;
+               case 0x04FE: return 0x04FF;
+               case 0x0500: return 0x0501;
+               case 0x0502: return 0x0503;
+               case 0x0504: return 0x0505;
+               case 0x0506: return 0x0507;
+               case 0x0508: return 0x0509;
+               case 0x050A: return 0x050B;
+               case 0x050C: return 0x050D;
+               case 0x050E: return 0x050F;
+               case 0x0510: return 0x0511;
+               case 0x0512: return 0x0513;
+               case 0x0514: return 0x0515;
+               case 0x0516: return 0x0517;
+               case 0x0518: return 0x0519;
+               case 0x051A: return 0x051B;
+               case 0x051C: return 0x051D;
+               case 0x051E: return 0x051F;
+               case 0x0520: return 0x0521;
+               case 0x0522: return 0x0523;
+               case 0x0524: return 0x0525;
+               case 0x0526: return 0x0527;
+               case 0x0531: return 0x0561;
+               case 0x0532: return 0x0562;
+               case 0x0533: return 0x0563;
+               case 0x0534: return 0x0564;
+               case 0x0535: return 0x0565;
+               case 0x0536: return 0x0566;
+               case 0x0537: return 0x0567;
+               case 0x0538: return 0x0568;
+               case 0x0539: return 0x0569;
+               case 0x053A: return 0x056A;
+               case 0x053B: return 0x056B;
+               case 0x053C: return 0x056C;
+               case 0x053D: return 0x056D;
+               case 0x053E: return 0x056E;
+               case 0x053F: return 0x056F;
+               case 0x0540: return 0x0570;
+               case 0x0541: return 0x0571;
+               case 0x0542: return 0x0572;
+               case 0x0543: return 0x0573;
+               case 0x0544: return 0x0574;
+               case 0x0545: return 0x0575;
+               case 0x0546: return 0x0576;
+               case 0x0547: return 0x0577;
+               case 0x0548: return 0x0578;
+               case 0x0549: return 0x0579;
+               case 0x054A: return 0x057A;
+               case 0x054B: return 0x057B;
+               case 0x054C: return 0x057C;
+               case 0x054D: return 0x057D;
+               case 0x054E: return 0x057E;
+               case 0x054F: return 0x057F;
+               case 0x0550: return 0x0580;
+               case 0x0551: return 0x0581;
+               case 0x0552: return 0x0582;
+               case 0x0553: return 0x0583;
+               case 0x0554: return 0x0584;
+               case 0x0555: return 0x0585;
+               case 0x0556: return 0x0586;
+               case 0x10A0: return 0x2D00;
+               case 0x10A1: return 0x2D01;
+               case 0x10A2: return 0x2D02;
+               case 0x10A3: return 0x2D03;
+               case 0x10A4: return 0x2D04;
+               case 0x10A5: return 0x2D05;
+               case 0x10A6: return 0x2D06;
+               case 0x10A7: return 0x2D07;
+               case 0x10A8: return 0x2D08;
+               case 0x10A9: return 0x2D09;
+               case 0x10AA: return 0x2D0A;
+               case 0x10AB: return 0x2D0B;
+               case 0x10AC: return 0x2D0C;
+               case 0x10AD: return 0x2D0D;
+               case 0x10AE: return 0x2D0E;
+               case 0x10AF: return 0x2D0F;
+               case 0x10B0: return 0x2D10;
+               case 0x10B1: return 0x2D11;
+               case 0x10B2: return 0x2D12;
+               case 0x10B3: return 0x2D13;
+               case 0x10B4: return 0x2D14;
+               case 0x10B5: return 0x2D15;
+               case 0x10B6: return 0x2D16;
+               case 0x10B7: return 0x2D17;
+               case 0x10B8: return 0x2D18;
+               case 0x10B9: return 0x2D19;
+               case 0x10BA: return 0x2D1A;
+               case 0x10BB: return 0x2D1B;
+               case 0x10BC: return 0x2D1C;
+               case 0x10BD: return 0x2D1D;
+               case 0x10BE: return 0x2D1E;
+               case 0x10BF: return 0x2D1F;
+               case 0x10C0: return 0x2D20;
+               case 0x10C1: return 0x2D21;
+               case 0x10C2: return 0x2D22;
+               case 0x10C3: return 0x2D23;
+               case 0x10C4: return 0x2D24;
+               case 0x10C5: return 0x2D25;
+               case 0x1E00: return 0x1E01;
+               case 0x1E02: return 0x1E03;
+               case 0x1E04: return 0x1E05;
+               case 0x1E06: return 0x1E07;
+               case 0x1E08: return 0x1E09;
+               case 0x1E0A: return 0x1E0B;
+               case 0x1E0C: return 0x1E0D;
+               case 0x1E0E: return 0x1E0F;
+               case 0x1E10: return 0x1E11;
+               case 0x1E12: return 0x1E13;
+               case 0x1E14: return 0x1E15;
+               case 0x1E16: return 0x1E17;
+               case 0x1E18: return 0x1E19;
+               case 0x1E1A: return 0x1E1B;
+               case 0x1E1C: return 0x1E1D;
+               case 0x1E1E: return 0x1E1F;
+               case 0x1E20: return 0x1E21;
+               case 0x1E22: return 0x1E23;
+               case 0x1E24: return 0x1E25;
+               case 0x1E26: return 0x1E27;
+               case 0x1E28: return 0x1E29;
+               case 0x1E2A: return 0x1E2B;
+               case 0x1E2C: return 0x1E2D;
+               case 0x1E2E: return 0x1E2F;
+               case 0x1E30: return 0x1E31;
+               case 0x1E32: return 0x1E33;
+               case 0x1E34: return 0x1E35;
+               case 0x1E36: return 0x1E37;
+               case 0x1E38: return 0x1E39;
+               case 0x1E3A: return 0x1E3B;
+               case 0x1E3C: return 0x1E3D;
+               case 0x1E3E: return 0x1E3F;
+               case 0x1E40: return 0x1E41;
+               case 0x1E42: return 0x1E43;
+               case 0x1E44: return 0x1E45;
+               case 0x1E46: return 0x1E47;
+               case 0x1E48: return 0x1E49;
+               case 0x1E4A: return 0x1E4B;
+               case 0x1E4C: return 0x1E4D;
+               case 0x1E4E: return 0x1E4F;
+               case 0x1E50: return 0x1E51;
+               case 0x1E52: return 0x1E53;
+               case 0x1E54: return 0x1E55;
+               case 0x1E56: return 0x1E57;
+               case 0x1E58: return 0x1E59;
+               case 0x1E5A: return 0x1E5B;
+               case 0x1E5C: return 0x1E5D;
+               case 0x1E5E: return 0x1E5F;
+               case 0x1E60: return 0x1E61;
+               case 0x1E62: return 0x1E63;
+               case 0x1E64: return 0x1E65;
+               case 0x1E66: return 0x1E67;
+               case 0x1E68: return 0x1E69;
+               case 0x1E6A: return 0x1E6B;
+               case 0x1E6C: return 0x1E6D;
+               case 0x1E6E: return 0x1E6F;
+               case 0x1E70: return 0x1E71;
+               case 0x1E72: return 0x1E73;
+               case 0x1E74: return 0x1E75;
+               case 0x1E76: return 0x1E77;
+               case 0x1E78: return 0x1E79;
+               case 0x1E7A: return 0x1E7B;
+               case 0x1E7C: return 0x1E7D;
+               case 0x1E7E: return 0x1E7F;
+               case 0x1E80: return 0x1E81;
+               case 0x1E82: return 0x1E83;
+               case 0x1E84: return 0x1E85;
+               case 0x1E86: return 0x1E87;
+               case 0x1E88: return 0x1E89;
+               case 0x1E8A: return 0x1E8B;
+               case 0x1E8C: return 0x1E8D;
+               case 0x1E8E: return 0x1E8F;
+               case 0x1E90: return 0x1E91;
+               case 0x1E92: return 0x1E93;
+               case 0x1E94: return 0x1E95;
+               case 0x1E9E: return 0x00DF;
+               case 0x1EA0: return 0x1EA1;
+               case 0x1EA2: return 0x1EA3;
+               case 0x1EA4: return 0x1EA5;
+               case 0x1EA6: return 0x1EA7;
+               case 0x1EA8: return 0x1EA9;
+               case 0x1EAA: return 0x1EAB;
+               case 0x1EAC: return 0x1EAD;
+               case 0x1EAE: return 0x1EAF;
+               case 0x1EB0: return 0x1EB1;
+               case 0x1EB2: return 0x1EB3;
+               case 0x1EB4: return 0x1EB5;
+               case 0x1EB6: return 0x1EB7;
+               case 0x1EB8: return 0x1EB9;
+               case 0x1EBA: return 0x1EBB;
+               case 0x1EBC: return 0x1EBD;
+               case 0x1EBE: return 0x1EBF;
+               case 0x1EC0: return 0x1EC1;
+               case 0x1EC2: return 0x1EC3;
+               case 0x1EC4: return 0x1EC5;
+               case 0x1EC6: return 0x1EC7;
+               case 0x1EC8: return 0x1EC9;
+               case 0x1ECA: return 0x1ECB;
+               case 0x1ECC: return 0x1ECD;
+               case 0x1ECE: return 0x1ECF;
+               case 0x1ED0: return 0x1ED1;
+               case 0x1ED2: return 0x1ED3;
+               case 0x1ED4: return 0x1ED5;
+               case 0x1ED6: return 0x1ED7;
+               case 0x1ED8: return 0x1ED9;
+               case 0x1EDA: return 0x1EDB;
+               case 0x1EDC: return 0x1EDD;
+               case 0x1EDE: return 0x1EDF;
+               case 0x1EE0: return 0x1EE1;
+               case 0x1EE2: return 0x1EE3;
+               case 0x1EE4: return 0x1EE5;
+               case 0x1EE6: return 0x1EE7;
+               case 0x1EE8: return 0x1EE9;
+               case 0x1EEA: return 0x1EEB;
+               case 0x1EEC: return 0x1EED;
+               case 0x1EEE: return 0x1EEF;
+               case 0x1EF0: return 0x1EF1;
+               case 0x1EF2: return 0x1EF3;
+               case 0x1EF4: return 0x1EF5;
+               case 0x1EF6: return 0x1EF7;
+               case 0x1EF8: return 0x1EF9;
+               case 0x1EFA: return 0x1EFB;
+               case 0x1EFC: return 0x1EFD;
+               case 0x1EFE: return 0x1EFF;
+               case 0x1F08: return 0x1F00;
+               case 0x1F09: return 0x1F01;
+               case 0x1F0A: return 0x1F02;
+               case 0x1F0B: return 0x1F03;
+               case 0x1F0C: return 0x1F04;
+               case 0x1F0D: return 0x1F05;
+               case 0x1F0E: return 0x1F06;
+               case 0x1F0F: return 0x1F07;
+               case 0x1F18: return 0x1F10;
+               case 0x1F19: return 0x1F11;
+               case 0x1F1A: return 0x1F12;
+               case 0x1F1B: return 0x1F13;
+               case 0x1F1C: return 0x1F14;
+               case 0x1F1D: return 0x1F15;
+               case 0x1F28: return 0x1F20;
+               case 0x1F29: return 0x1F21;
+               case 0x1F2A: return 0x1F22;
+               case 0x1F2B: return 0x1F23;
+               case 0x1F2C: return 0x1F24;
+               case 0x1F2D: return 0x1F25;
+               case 0x1F2E: return 0x1F26;
+               case 0x1F2F: return 0x1F27;
+               case 0x1F38: return 0x1F30;
+               case 0x1F39: return 0x1F31;
+               case 0x1F3A: return 0x1F32;
+               case 0x1F3B: return 0x1F33;
+               case 0x1F3C: return 0x1F34;
+               case 0x1F3D: return 0x1F35;
+               case 0x1F3E: return 0x1F36;
+               case 0x1F3F: return 0x1F37;
+               case 0x1F48: return 0x1F40;
+               case 0x1F49: return 0x1F41;
+               case 0x1F4A: return 0x1F42;
+               case 0x1F4B: return 0x1F43;
+               case 0x1F4C: return 0x1F44;
+               case 0x1F4D: return 0x1F45;
+               case 0x1F59: return 0x1F51;
+               case 0x1F5B: return 0x1F53;
+               case 0x1F5D: return 0x1F55;
+               case 0x1F5F: return 0x1F57;
+               case 0x1F68: return 0x1F60;
+               case 0x1F69: return 0x1F61;
+               case 0x1F6A: return 0x1F62;
+               case 0x1F6B: return 0x1F63;
+               case 0x1F6C: return 0x1F64;
+               case 0x1F6D: return 0x1F65;
+               case 0x1F6E: return 0x1F66;
+               case 0x1F6F: return 0x1F67;
+               case 0x1F88: return 0x1F80;
+               case 0x1F89: return 0x1F81;
+               case 0x1F8A: return 0x1F82;
+               case 0x1F8B: return 0x1F83;
+               case 0x1F8C: return 0x1F84;
+               case 0x1F8D: return 0x1F85;
+               case 0x1F8E: return 0x1F86;
+               case 0x1F8F: return 0x1F87;
+               case 0x1F98: return 0x1F90;
+               case 0x1F99: return 0x1F91;
+               case 0x1F9A: return 0x1F92;
+               case 0x1F9B: return 0x1F93;
+               case 0x1F9C: return 0x1F94;
+               case 0x1F9D: return 0x1F95;
+               case 0x1F9E: return 0x1F96;
+               case 0x1F9F: return 0x1F97;
+               case 0x1FA8: return 0x1FA0;
+               case 0x1FA9: return 0x1FA1;
+               case 0x1FAA: return 0x1FA2;
+               case 0x1FAB: return 0x1FA3;
+               case 0x1FAC: return 0x1FA4;
+               case 0x1FAD: return 0x1FA5;
+               case 0x1FAE: return 0x1FA6;
+               case 0x1FAF: return 0x1FA7;
+               case 0x1FB8: return 0x1FB0;
+               case 0x1FB9: return 0x1FB1;
+               case 0x1FBA: return 0x1F70;
+               case 0x1FBB: return 0x1F71;
+               case 0x1FBC: return 0x1FB3;
+               case 0x1FC8: return 0x1F72;
+               case 0x1FC9: return 0x1F73;
+               case 0x1FCA: return 0x1F74;
+               case 0x1FCB: return 0x1F75;
+               case 0x1FCC: return 0x1FC3;
+               case 0x1FD8: return 0x1FD0;
+               case 0x1FD9: return 0x1FD1;
+               case 0x1FDA: return 0x1F76;
+               case 0x1FDB: return 0x1F77;
+               case 0x1FE8: return 0x1FE0;
+               case 0x1FE9: return 0x1FE1;
+               case 0x1FEA: return 0x1F7A;
+               case 0x1FEB: return 0x1F7B;
+               case 0x1FEC: return 0x1FE5;
+               case 0x1FF8: return 0x1F78;
+               case 0x1FF9: return 0x1F79;
+               case 0x1FFA: return 0x1F7C;
+               case 0x1FFB: return 0x1F7D;
+               case 0x1FFC: return 0x1FF3;
+               case 0x2126: return 0x03C9;
+               case 0x212A: return 0x006B;
+               case 0x212B: return 0x00E5;
+               case 0x2132: return 0x214E;
+               case 0x2160: return 0x2170;
+               case 0x2161: return 0x2171;
+               case 0x2162: return 0x2172;
+               case 0x2163: return 0x2173;
+               case 0x2164: return 0x2174;
+               case 0x2165: return 0x2175;
+               case 0x2166: return 0x2176;
+               case 0x2167: return 0x2177;
+               case 0x2168: return 0x2178;
+               case 0x2169: return 0x2179;
+               case 0x216A: return 0x217A;
+               case 0x216B: return 0x217B;
+               case 0x216C: return 0x217C;
+               case 0x216D: return 0x217D;
+               case 0x216E: return 0x217E;
+               case 0x216F: return 0x217F;
+               case 0x2183: return 0x2184;
+               case 0x24B6: return 0x24D0;
+               case 0x24B7: return 0x24D1;
+               case 0x24B8: return 0x24D2;
+               case 0x24B9: return 0x24D3;
+               case 0x24BA: return 0x24D4;
+               case 0x24BB: return 0x24D5;
+               case 0x24BC: return 0x24D6;
+               case 0x24BD: return 0x24D7;
+               case 0x24BE: return 0x24D8;
+               case 0x24BF: return 0x24D9;
+               case 0x24C0: return 0x24DA;
+               case 0x24C1: return 0x24DB;
+               case 0x24C2: return 0x24DC;
+               case 0x24C3: return 0x24DD;
+               case 0x24C4: return 0x24DE;
+               case 0x24C5: return 0x24DF;
+               case 0x24C6: return 0x24E0;
+               case 0x24C7: return 0x24E1;
+               case 0x24C8: return 0x24E2;
+               case 0x24C9: return 0x24E3;
+               case 0x24CA: return 0x24E4;
+               case 0x24CB: return 0x24E5;
+               case 0x24CC: return 0x24E6;
+               case 0x24CD: return 0x24E7;
+               case 0x24CE: return 0x24E8;
+               case 0x24CF: return 0x24E9;
+               case 0x2C00: return 0x2C30;
+               case 0x2C01: return 0x2C31;
+               case 0x2C02: return 0x2C32;
+               case 0x2C03: return 0x2C33;
+               case 0x2C04: return 0x2C34;
+               case 0x2C05: return 0x2C35;
+               case 0x2C06: return 0x2C36;
+               case 0x2C07: return 0x2C37;
+               case 0x2C08: return 0x2C38;
+               case 0x2C09: return 0x2C39;
+               case 0x2C0A: return 0x2C3A;
+               case 0x2C0B: return 0x2C3B;
+               case 0x2C0C: return 0x2C3C;
+               case 0x2C0D: return 0x2C3D;
+               case 0x2C0E: return 0x2C3E;
+               case 0x2C0F: return 0x2C3F;
+               case 0x2C10: return 0x2C40;
+               case 0x2C11: return 0x2C41;
+               case 0x2C12: return 0x2C42;
+               case 0x2C13: return 0x2C43;
+               case 0x2C14: return 0x2C44;
+               case 0x2C15: return 0x2C45;
+               case 0x2C16: return 0x2C46;
+               case 0x2C17: return 0x2C47;
+               case 0x2C18: return 0x2C48;
+               case 0x2C19: return 0x2C49;
+               case 0x2C1A: return 0x2C4A;
+               case 0x2C1B: return 0x2C4B;
+               case 0x2C1C: return 0x2C4C;
+               case 0x2C1D: return 0x2C4D;
+               case 0x2C1E: return 0x2C4E;
+               case 0x2C1F: return 0x2C4F;
+               case 0x2C20: return 0x2C50;
+               case 0x2C21: return 0x2C51;
+               case 0x2C22: return 0x2C52;
+               case 0x2C23: return 0x2C53;
+               case 0x2C24: return 0x2C54;
+               case 0x2C25: return 0x2C55;
+               case 0x2C26: return 0x2C56;
+               case 0x2C27: return 0x2C57;
+               case 0x2C28: return 0x2C58;
+               case 0x2C29: return 0x2C59;
+               case 0x2C2A: return 0x2C5A;
+               case 0x2C2B: return 0x2C5B;
+               case 0x2C2C: return 0x2C5C;
+               case 0x2C2D: return 0x2C5D;
+               case 0x2C2E: return 0x2C5E;
+               case 0x2C60: return 0x2C61;
+               case 0x2C62: return 0x026B;
+               case 0x2C63: return 0x1D7D;
+               case 0x2C64: return 0x027D;
+               case 0x2C67: return 0x2C68;
+               case 0x2C69: return 0x2C6A;
+               case 0x2C6B: return 0x2C6C;
+               case 0x2C6D: return 0x0251;
+               case 0x2C6E: return 0x0271;
+               case 0x2C6F: return 0x0250;
+               case 0x2C70: return 0x0252;
+               case 0x2C72: return 0x2C73;
+               case 0x2C75: return 0x2C76;
+               case 0x2C7E: return 0x023F;
+               case 0x2C7F: return 0x0240;
+               case 0x2C80: return 0x2C81;
+               case 0x2C82: return 0x2C83;
+               case 0x2C84: return 0x2C85;
+               case 0x2C86: return 0x2C87;
+               case 0x2C88: return 0x2C89;
+               case 0x2C8A: return 0x2C8B;
+               case 0x2C8C: return 0x2C8D;
+               case 0x2C8E: return 0x2C8F;
+               case 0x2C90: return 0x2C91;
+               case 0x2C92: return 0x2C93;
+               case 0x2C94: return 0x2C95;
+               case 0x2C96: return 0x2C97;
+               case 0x2C98: return 0x2C99;
+               case 0x2C9A: return 0x2C9B;
+               case 0x2C9C: return 0x2C9D;
+               case 0x2C9E: return 0x2C9F;
+               case 0x2CA0: return 0x2CA1;
+               case 0x2CA2: return 0x2CA3;
+               case 0x2CA4: return 0x2CA5;
+               case 0x2CA6: return 0x2CA7;
+               case 0x2CA8: return 0x2CA9;
+               case 0x2CAA: return 0x2CAB;
+               case 0x2CAC: return 0x2CAD;
+               case 0x2CAE: return 0x2CAF;
+               case 0x2CB0: return 0x2CB1;
+               case 0x2CB2: return 0x2CB3;
+               case 0x2CB4: return 0x2CB5;
+               case 0x2CB6: return 0x2CB7;
+               case 0x2CB8: return 0x2CB9;
+               case 0x2CBA: return 0x2CBB;
+               case 0x2CBC: return 0x2CBD;
+               case 0x2CBE: return 0x2CBF;
+               case 0x2CC0: return 0x2CC1;
+               case 0x2CC2: return 0x2CC3;
+               case 0x2CC4: return 0x2CC5;
+               case 0x2CC6: return 0x2CC7;
+               case 0x2CC8: return 0x2CC9;
+               case 0x2CCA: return 0x2CCB;
+               case 0x2CCC: return 0x2CCD;
+               case 0x2CCE: return 0x2CCF;
+               case 0x2CD0: return 0x2CD1;
+               case 0x2CD2: return 0x2CD3;
+               case 0x2CD4: return 0x2CD5;
+               case 0x2CD6: return 0x2CD7;
+               case 0x2CD8: return 0x2CD9;
+               case 0x2CDA: return 0x2CDB;
+               case 0x2CDC: return 0x2CDD;
+               case 0x2CDE: return 0x2CDF;
+               case 0x2CE0: return 0x2CE1;
+               case 0x2CE2: return 0x2CE3;
+               case 0x2CEB: return 0x2CEC;
+               case 0x2CED: return 0x2CEE;
+               case 0xA640: return 0xA641;
+               case 0xA642: return 0xA643;
+               case 0xA644: return 0xA645;
+               case 0xA646: return 0xA647;
+               case 0xA648: return 0xA649;
+               case 0xA64A: return 0xA64B;
+               case 0xA64C: return 0xA64D;
+               case 0xA64E: return 0xA64F;
+               case 0xA650: return 0xA651;
+               case 0xA652: return 0xA653;
+               case 0xA654: return 0xA655;
+               case 0xA656: return 0xA657;
+               case 0xA658: return 0xA659;
+               case 0xA65A: return 0xA65B;
+               case 0xA65C: return 0xA65D;
+               case 0xA65E: return 0xA65F;
+               case 0xA660: return 0xA661;
+               case 0xA662: return 0xA663;
+               case 0xA664: return 0xA665;
+               case 0xA666: return 0xA667;
+               case 0xA668: return 0xA669;
+               case 0xA66A: return 0xA66B;
+               case 0xA66C: return 0xA66D;
+               case 0xA680: return 0xA681;
+               case 0xA682: return 0xA683;
+               case 0xA684: return 0xA685;
+               case 0xA686: return 0xA687;
+               case 0xA688: return 0xA689;
+               case 0xA68A: return 0xA68B;
+               case 0xA68C: return 0xA68D;
+               case 0xA68E: return 0xA68F;
+               case 0xA690: return 0xA691;
+               case 0xA692: return 0xA693;
+               case 0xA694: return 0xA695;
+               case 0xA696: return 0xA697;
+               case 0xA722: return 0xA723;
+               case 0xA724: return 0xA725;
+               case 0xA726: return 0xA727;
+               case 0xA728: return 0xA729;
+               case 0xA72A: return 0xA72B;
+               case 0xA72C: return 0xA72D;
+               case 0xA72E: return 0xA72F;
+               case 0xA732: return 0xA733;
+               case 0xA734: return 0xA735;
+               case 0xA736: return 0xA737;
+               case 0xA738: return 0xA739;
+               case 0xA73A: return 0xA73B;
+               case 0xA73C: return 0xA73D;
+               case 0xA73E: return 0xA73F;
+               case 0xA740: return 0xA741;
+               case 0xA742: return 0xA743;
+               case 0xA744: return 0xA745;
+               case 0xA746: return 0xA747;
+               case 0xA748: return 0xA749;
+               case 0xA74A: return 0xA74B;
+               case 0xA74C: return 0xA74D;
+               case 0xA74E: return 0xA74F;
+               case 0xA750: return 0xA751;
+               case 0xA752: return 0xA753;
+               case 0xA754: return 0xA755;
+               case 0xA756: return 0xA757;
+               case 0xA758: return 0xA759;
+               case 0xA75A: return 0xA75B;
+               case 0xA75C: return 0xA75D;
+               case 0xA75E: return 0xA75F;
+               case 0xA760: return 0xA761;
+               case 0xA762: return 0xA763;
+               case 0xA764: return 0xA765;
+               case 0xA766: return 0xA767;
+               case 0xA768: return 0xA769;
+               case 0xA76A: return 0xA76B;
+               case 0xA76C: return 0xA76D;
+               case 0xA76E: return 0xA76F;
+               case 0xA779: return 0xA77A;
+               case 0xA77B: return 0xA77C;
+               case 0xA77D: return 0x1D79;
+               case 0xA77E: return 0xA77F;
+               case 0xA780: return 0xA781;
+               case 0xA782: return 0xA783;
+               case 0xA784: return 0xA785;
+               case 0xA786: return 0xA787;
+               case 0xA78B: return 0xA78C;
+               case 0xA78D: return 0x0265;
+               case 0xA790: return 0xA791;
+               case 0xA7A0: return 0xA7A1;
+               case 0xA7A2: return 0xA7A3;
+               case 0xA7A4: return 0xA7A5;
+               case 0xA7A6: return 0xA7A7;
+               case 0xA7A8: return 0xA7A9;
+               case 0xFF21: return 0xFF41;
+               case 0xFF22: return 0xFF42;
+               case 0xFF23: return 0xFF43;
+               case 0xFF24: return 0xFF44;
+               case 0xFF25: return 0xFF45;
+               case 0xFF26: return 0xFF46;
+               case 0xFF27: return 0xFF47;
+               case 0xFF28: return 0xFF48;
+               case 0xFF29: return 0xFF49;
+               case 0xFF2A: return 0xFF4A;
+               case 0xFF2B: return 0xFF4B;
+               case 0xFF2C: return 0xFF4C;
+               case 0xFF2D: return 0xFF4D;
+               case 0xFF2E: return 0xFF4E;
+               case 0xFF2F: return 0xFF4F;
+               case 0xFF30: return 0xFF50;
+               case 0xFF31: return 0xFF51;
+               case 0xFF32: return 0xFF52;
+               case 0xFF33: return 0xFF53;
+               case 0xFF34: return 0xFF54;
+               case 0xFF35: return 0xFF55;
+               case 0xFF36: return 0xFF56;
+               case 0xFF37: return 0xFF57;
+               case 0xFF38: return 0xFF58;
+               case 0xFF39: return 0xFF59;
+               case 0xFF3A: return 0xFF5A;
+               case 0x10400: return 0x10428;
+               case 0x10401: return 0x10429;
+               case 0x10402: return 0x1042A;
+               case 0x10403: return 0x1042B;
+               case 0x10404: return 0x1042C;
+               case 0x10405: return 0x1042D;
+               case 0x10406: return 0x1042E;
+               case 0x10407: return 0x1042F;
+               case 0x10408: return 0x10430;
+               case 0x10409: return 0x10431;
+               case 0x1040A: return 0x10432;
+               case 0x1040B: return 0x10433;
+               case 0x1040C: return 0x10434;
+               case 0x1040D: return 0x10435;
+               case 0x1040E: return 0x10436;
+               case 0x1040F: return 0x10437;
+               case 0x10410: return 0x10438;
+               case 0x10411: return 0x10439;
+               case 0x10412: return 0x1043A;
+               case 0x10413: return 0x1043B;
+               case 0x10414: return 0x1043C;
+               case 0x10415: return 0x1043D;
+               case 0x10416: return 0x1043E;
+               case 0x10417: return 0x1043F;
+               case 0x10418: return 0x10440;
+               case 0x10419: return 0x10441;
+               case 0x1041A: return 0x10442;
+               case 0x1041B: return 0x10443;
+               case 0x1041C: return 0x10444;
+               case 0x1041D: return 0x10445;
+               case 0x1041E: return 0x10446;
+               case 0x1041F: return 0x10447;
+               case 0x10420: return 0x10448;
+               case 0x10421: return 0x10449;
+               case 0x10422: return 0x1044A;
+               case 0x10423: return 0x1044B;
+               case 0x10424: return 0x1044C;
+               case 0x10425: return 0x1044D;
+               case 0x10426: return 0x1044E;
+               case 0x10427: return 0x1044F;
+               default: return ch;
+       }
+}
index 2c0380243f4cffd28ef673015790b27e234f8c5e..9124c4e7905ea72ed0123aca9c20daf7a02e9f7e 100644 (file)
--- a/utf8lib.h
+++ b/utf8lib.h
@@ -59,4 +59,7 @@ extern Uchar u8_quake2utf8map[256];
 #define u8_getnchar_noendptr(c,n) (utf8_enable.integer ? u8_getnchar_utf8_enabled(c,NULL,n) : ((n) <= 0 ? 0  : (u8_quake2utf8map[(unsigned char)*(c)])))
 #define u8_getnchar_check(c,e,n) ((e) ? u8_getchar((c),(e),(n)) : u8_getchar_noendptr((c),(n)))
 
+Uchar u8_toupper(Uchar ch);
+Uchar u8_tolower(Uchar ch);
+
 #endif // UTF8LIB_H__
diff --git a/vid.h b/vid.h
index aca91a1eed8dd247e415393d993c55e30a9c3a04..4840ae4a53451c476e45edaaa08e934e48df812d 100644 (file)
--- a/vid.h
+++ b/vid.h
@@ -69,6 +69,7 @@ typedef struct viddef_support_s
        qboolean ext_texture_edge_clamp;
        qboolean ext_texture_filter_anisotropic;
        qboolean ext_texture_srgb;
+       qboolean arb_multisample;
 }
 viddef_support_t;
 
@@ -99,10 +100,15 @@ typedef struct viddef_s
        qboolean stereobuffer;
        int samples;
        qboolean stencil;
+       qboolean sRGB2D; // whether 2D rendering is sRGB corrected (based on sRGBcapable2D)
+       qboolean sRGB3D; // whether 3D rendering is sRGB corrected (based on sRGBcapable3D)
+       qboolean sRGBcapable2D; // whether 2D rendering can be sRGB corrected (renderpath, v_hwgamma)
+       qboolean sRGBcapable3D; // whether 3D rendering can be sRGB corrected (renderpath, v_hwgamma)
 
        renderpath_t renderpath;
        qboolean forcevbo; // some renderpaths can not operate without it
        qboolean useinterleavedarrays; // required by some renderpaths
+       qboolean allowalphatocoverage; // indicates the GL_AlphaToCoverage function works on this renderpath and framebuffer
 
        unsigned int texunits;
        unsigned int teximageunits;
@@ -133,6 +139,33 @@ extern viddef_t vid;
 extern void (*vid_menudrawfn)(void);
 extern void (*vid_menukeyfn)(int key);
 
+#define MAXJOYAXIS 16
+// if this is changed, the corresponding code in vid_shared.c must be updated
+#define MAXJOYBUTTON 36
+typedef struct vid_joystate_s
+{
+       float axis[MAXJOYAXIS]; // -1 to +1
+       unsigned char button[MAXJOYBUTTON]; // 0 or 1
+       qboolean is360; // indicates this joystick is a Microsoft Xbox 360 Controller For Windows
+}
+vid_joystate_t;
+
+extern vid_joystate_t vid_joystate;
+
+extern cvar_t joy_index;
+extern cvar_t joy_enable;
+extern cvar_t joy_detected;
+extern cvar_t joy_active;
+
+float VID_JoyState_GetAxis(const vid_joystate_t *joystate, int axis, float sensitivity, float deadzone);
+void VID_ApplyJoyState(vid_joystate_t *joystate);
+void VID_BuildJoyState(vid_joystate_t *joystate);
+void VID_Shared_BuildJoyState_Begin(vid_joystate_t *joystate);
+void VID_Shared_BuildJoyState_Finish(vid_joystate_t *joystate);
+int VID_Shared_SetJoystick(int index);
+qboolean VID_JoyBlockEmulatedKeys(int keycode);
+void VID_EnableJoystick(qboolean enable);
+
 extern qboolean vid_hidden;
 extern qboolean vid_activewindow;
 extern cvar_t vid_hardwaregammasupported;
index b0afdcf98126dfe3f99be8ffc4b12066e2facb3f..d21ffc063193ab1078fc0f3c9624fae4bf358e4f 100644 (file)
--- a/vid_agl.c
+++ b/vid_agl.c
@@ -396,6 +396,7 @@ void VID_Shutdown(void)
        if (context == NULL && window == NULL)
                return;
 
+       VID_EnableJoystick(false);
        VID_SetMouse(false, false, false);
        VID_RestoreSystemGamma();
 
@@ -1110,8 +1111,34 @@ void Sys_SendKeyEvents(void)
        }
 }
 
+void VID_BuildJoyState(vid_joystate_t *joystate)
+{
+       VID_Shared_BuildJoyState_Begin(joystate);
+       VID_Shared_BuildJoyState_Finish(joystate);
+}
+
+void VID_EnableJoystick(qboolean enable)
+{
+       int index = joy_enable.integer > 0 ? joy_index.integer : -1;
+       qboolean success = false;
+       int sharedcount = 0;
+       sharedcount = VID_Shared_SetJoystick(index);
+       if (index >= 0 && index < sharedcount)
+               success = true;
+
+       // update cvar containing count of XInput joysticks
+       if (joy_detected.integer != sharedcount)
+               Cvar_SetValueQuick(&joy_detected, sharedcount);
+
+       Cvar_SetValueQuick(&joy_active, success ? 1 : 0);
+}
+
 void IN_Move (void)
 {
+       vid_joystate_t joystate;
+       VID_EnableJoystick(true);
+       VID_BuildJoyState(&joystate);
+       VID_ApplyJoyState(&joystate);
 }
 
 static bool GetDictionaryBoolean(CFDictionaryRef d, const void *key)
index 293fdd459029f125da653b046079d4415aff6a40..9f142bb9a0caf34be92da7fe97f6611d3a111146 100644 (file)
--- a/vid_glx.c
+++ b/vid_glx.c
@@ -278,7 +278,9 @@ static int XLateKey(XKeyEvent *ev, Uchar *ascii)
                case XK_KP_Subtract: key = K_KP_MINUS; break;
                case XK_KP_Divide: key = K_KP_SLASH; break;
 
-               case XK_section:        key = '~'; break;
+               case XK_asciicircum:    *ascii = key = '^'; break; // for some reason, XLookupString returns "" on this one for Grunt|2
+
+               case XK_section:        *ascii = key = '~'; break;
 
                default:
                        if (keysym < 32)
@@ -832,6 +834,7 @@ void VID_Shutdown(void)
        if (!vidx11_display)
                return;
 
+       VID_EnableJoystick(false);
        VID_SetMouse(false, false, false);
        VID_RestoreSystemGamma();
 
@@ -1670,8 +1673,34 @@ void Sys_SendKeyEvents(void)
        HandleEvents();
 }
 
+void VID_BuildJoyState(vid_joystate_t *joystate)
+{
+       VID_Shared_BuildJoyState_Begin(joystate);
+       VID_Shared_BuildJoyState_Finish(joystate);
+}
+
+void VID_EnableJoystick(qboolean enable)
+{
+       int index = joy_enable.integer > 0 ? joy_index.integer : -1;
+       qboolean success = false;
+       int sharedcount = 0;
+       sharedcount = VID_Shared_SetJoystick(index);
+       if (index >= 0 && index < sharedcount)
+               success = true;
+
+       // update cvar containing count of XInput joysticks
+       if (joy_detected.integer != sharedcount)
+               Cvar_SetValueQuick(&joy_detected, sharedcount);
+
+       Cvar_SetValueQuick(&joy_active, success ? 1 : 0);
+}
+
 void IN_Move (void)
 {
+       vid_joystate_t joystate;
+       VID_EnableJoystick(true);
+       VID_BuildJoyState(&joystate);
+       VID_ApplyJoyState(&joystate);
 }
 
 size_t VID_ListModes(vid_mode_t *modes, size_t maxcount)
index 2be1bf272f44d8943a77460e44932618f874166b..4ac7ab11a9c336c573c14f8818c5ca5ae3eb1f70 100644 (file)
@@ -88,6 +88,10 @@ void Sys_SendKeyEvents(void)
 {
 }
 
+void VID_BuildJoyState(vid_joystate_t *joystate)
+{
+}
+
 void IN_Move(void)
 {
 }
index 76cc2ac44a38d2b745e578edaec742e5046b13ea..5eba5d05631bce31836ffd2a5c51d6b1d3b64dd6 100644 (file)
--- a/vid_sdl.c
+++ b/vid_sdl.c
@@ -66,42 +66,18 @@ int cl_available = true;
 
 qboolean vid_supportrefreshrate = false;
 
-cvar_t joy_detected = {CVAR_READONLY, "joy_detected", "0", "number of joysticks detected by engine"};
-cvar_t joy_enable = {CVAR_SAVE, "joy_enable", "0", "enables joystick support"};
-cvar_t joy_index = {0, "joy_index", "0", "selects which joystick to use if you have multiple"};
-cvar_t joy_axisforward = {0, "joy_axisforward", "1", "which joystick axis to query for forward/backward movement"};
-cvar_t joy_axisside = {0, "joy_axisside", "0", "which joystick axis to query for right/left movement"};
-cvar_t joy_axisup = {0, "joy_axisup", "-1", "which joystick axis to query for up/down movement"};
-cvar_t joy_axispitch = {0, "joy_axispitch", "3", "which joystick axis to query for looking up/down"};
-cvar_t joy_axisyaw = {0, "joy_axisyaw", "2", "which joystick axis to query for looking right/left"};
-cvar_t joy_axisroll = {0, "joy_axisroll", "-1", "which joystick axis to query for tilting head right/left"};
-cvar_t joy_deadzoneforward = {0, "joy_deadzoneforward", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
-cvar_t joy_deadzoneside = {0, "joy_deadzoneside", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
-cvar_t joy_deadzoneup = {0, "joy_deadzoneup", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
-cvar_t joy_deadzonepitch = {0, "joy_deadzonepitch", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
-cvar_t joy_deadzoneyaw = {0, "joy_deadzoneyaw", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
-cvar_t joy_deadzoneroll = {0, "joy_deadzoneroll", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
-cvar_t joy_sensitivityforward = {0, "joy_sensitivityforward", "-1", "movement multiplier"};
-cvar_t joy_sensitivityside = {0, "joy_sensitivityside", "1", "movement multiplier"};
-cvar_t joy_sensitivityup = {0, "joy_sensitivityup", "1", "movement multiplier"};
-cvar_t joy_sensitivitypitch = {0, "joy_sensitivitypitch", "1", "movement multiplier"};
-cvar_t joy_sensitivityyaw = {0, "joy_sensitivityyaw", "-1", "movement multiplier"};
-cvar_t joy_sensitivityroll = {0, "joy_sensitivityroll", "1", "movement multiplier"};
-cvar_t joy_axiskeyevents = {CVAR_SAVE, "joy_axiskeyevents", "0", "generate uparrow/leftarrow etc. keyevents for joystick axes, use if your joystick driver is not generating them"};
-cvar_t joy_axiskeyevents_deadzone = {CVAR_SAVE, "joy_axiskeyevents_deadzone", "0.5", "deadzone value for axes"};
-
-#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;
@@ -111,9 +87,7 @@ static qboolean vid_isfullscreen;
 #else
 static qboolean vid_usingvsync = false;
 #endif
-static int vid_numjoysticks = 0;
-#define MAX_JOYSTICKS 8
-static SDL_Joystick *vid_joysticks[MAX_JOYSTICKS];
+static SDL_Joystick *vid_sdljoystick = NULL;
 
 static int win_half_width = 50;
 static int win_half_height = 50;
@@ -129,20 +103,9 @@ static int window_flags;
 #endif
 static SDL_Surface *vid_softsurface;
 
-// joystick axes state
-#define MAX_JOYSTICK_AXES      16
-typedef struct
-{
-       float oldmove;
-       float move;
-       double keytime;
-}joy_axiscache_t;
-static joy_axiscache_t joy_axescache[MAX_JOYSTICK_AXES];
-
 /////////////////////////
 // Input handling
 ////
-//TODO: Add joystick support
 //TODO: Add error checking
 
 #ifndef SDLK_PERCENT
@@ -518,80 +481,6 @@ void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecurso
 #endif
 }
 
-static double IN_JoystickGetAxis(SDL_Joystick *joy, int axis, double sensitivity, double deadzone)
-{
-       double value;
-       if (axis < 0 || axis >= SDL_JoystickNumAxes(joy))
-               return 0; // no such axis on this joystick
-       value = SDL_JoystickGetAxis(joy, axis) * (1.0 / 32767.0);
-       value = bound(-1, value, 1);
-       if (fabs(value) < deadzone)
-               return 0; // within deadzone around center
-       return value * sensitivity;
-}
-
-/////////////////////
-// Joystick axis keyevents
-// a sort of hack emulating Arrow keys for joystick axises
-// as some drives dont send such keyevents for them
-// additionally we should block drivers that do send arrow keyevents to prevent double events
-////
-
-static void IN_JoystickKeyeventForAxis(SDL_Joystick *joy, int axis, int key_pos, int key_neg)
-{
-       double joytime;
-
-       if (axis < 0 || axis >= SDL_JoystickNumAxes(joy))
-               return; // no such axis on this joystick
-
-       joytime = Sys_DoubleTime();
-       // no key event, continuous keydown event
-       if (joy_axescache[axis].move == joy_axescache[axis].oldmove)
-       {
-               if (joy_axescache[axis].move != 0 && joytime > joy_axescache[axis].keytime)
-               {
-                       //Con_Printf("joy %s %i %f\n", Key_KeynumToString((joy_axescache[axis].move > 0) ? key_pos : key_neg), 1, cl.time);
-                       Key_Event((joy_axescache[axis].move > 0) ? key_pos : key_neg, 0, 1);
-                       joy_axescache[axis].keytime = joytime + 0.5 / 20;
-               }
-               return;
-       }
-       // generate key up event
-       if (joy_axescache[axis].oldmove)
-       {
-               //Con_Printf("joy %s %i %f\n", Key_KeynumToString((joy_axescache[axis].oldmove > 0) ? key_pos : key_neg), 1, cl.time);
-               Key_Event((joy_axescache[axis].oldmove > 0) ? key_pos : key_neg, 0, 0);
-       }
-       // generate key down event
-       if (joy_axescache[axis].move)
-       {
-               //Con_Printf("joy %s %i %f\n", Key_KeynumToString((joy_axescache[axis].move > 0) ? key_pos : key_neg), 1, cl.time);
-               Key_Event((joy_axescache[axis].move > 0) ? key_pos : key_neg, 0, 1);
-               joy_axescache[axis].keytime = joytime + 0.5;
-       }
-}
-
-static qboolean IN_JoystickBlockDoubledKeyEvents(int keycode)
-{
-       if (!joy_axiskeyevents.integer)
-               return false;
-
-       // block keyevent if it's going to be provided by joystick keyevent system
-       if (vid_numjoysticks && joy_enable.integer && joy_index.integer >= 0 && joy_index.integer < vid_numjoysticks)
-       {
-               SDL_Joystick *joy = vid_joysticks[joy_index.integer];
-
-               if (keycode == K_UPARROW || keycode == K_DOWNARROW)
-                       if (IN_JoystickGetAxis(joy, joy_axisforward.integer, 1, joy_axiskeyevents_deadzone.value) || joy_axescache[joy_axisforward.integer].move || joy_axescache[joy_axisforward.integer].oldmove)
-                               return true;
-               if (keycode == K_RIGHTARROW || keycode == K_LEFTARROW)
-                       if (IN_JoystickGetAxis(joy, joy_axisside.integer, 1, joy_axiskeyevents_deadzone.value) || joy_axescache[joy_axisside.integer].move || joy_axescache[joy_axisside.integer].oldmove)
-                               return true;
-       }
-
-       return false;
-}
-
 // multitouch[10][] represents the mouse pointer
 // X and Y coordinates are 0-32767 as per SDL spec
 #define MAXFINGERS 11
@@ -656,16 +545,37 @@ qboolean VID_TouchscreenArea(int corner, float px, float py, float pwidth, float
        return button;
 }
 
+void VID_BuildJoyState(vid_joystate_t *joystate)
+{
+       VID_Shared_BuildJoyState_Begin(joystate);
+
+       if (vid_sdljoystick)
+       {
+               SDL_Joystick *joy = vid_sdljoystick;
+               int j;
+               int numaxes;
+               int numbuttons;
+               numaxes = SDL_JoystickNumAxes(joy);
+               for (j = 0;j < numaxes;j++)
+                       joystate->axis[j] = SDL_JoystickGetAxis(joy, j) * (1.0f / 32767.0f);
+               numbuttons = SDL_JoystickNumButtons(joy);
+               for (j = 0;j < numbuttons;j++)
+                       joystate->button[j] = SDL_JoystickGetButton(joy, j);
+       }
+
+       VID_Shared_BuildJoyState_Finish(joystate);
+}
+
 /////////////////////
 // Movement handling
 ////
 
 void IN_Move( void )
 {
-       int j;
        static int old_x = 0, old_y = 0;
        static int stuck = 0;
-       int x, y, numaxes, numballs;
+       int x, y;
+       vid_joystate_t joystate;
 
        scr_numtouchscreenareas = 0;
        if (vid_touchscreen.integer)
@@ -798,42 +708,8 @@ void IN_Move( void )
                in_windowmouse_y = y;
        }
 
-       if (vid_numjoysticks && joy_enable.integer && joy_index.integer >= 0 && joy_index.integer < vid_numjoysticks)
-       {
-               SDL_Joystick *joy = vid_joysticks[joy_index.integer];
-
-               // balls convert to mousemove
-               numballs = SDL_JoystickNumBalls(joy);
-               for (j = 0;j < numballs;j++)
-               {
-                       SDL_JoystickGetBall(joy, j, &x, &y);
-                       in_mouse_x += x;
-                       in_mouse_y += y;
-               }
-
-               // axes
-               cl.cmd.forwardmove += IN_JoystickGetAxis(joy, joy_axisforward.integer, joy_sensitivityforward.value, joy_deadzoneforward.value) * cl_forwardspeed.value;
-               cl.cmd.sidemove    += IN_JoystickGetAxis(joy, joy_axisside.integer, joy_sensitivityside.value, joy_deadzoneside.value) * cl_sidespeed.value;
-               cl.cmd.upmove      += IN_JoystickGetAxis(joy, joy_axisup.integer, joy_sensitivityup.value, joy_deadzoneup.value) * cl_upspeed.value;
-               cl.viewangles[0]   += IN_JoystickGetAxis(joy, joy_axispitch.integer, joy_sensitivitypitch.value, joy_deadzonepitch.value) * cl.realframetime * cl_pitchspeed.value;
-               cl.viewangles[1]   += IN_JoystickGetAxis(joy, joy_axisyaw.integer, joy_sensitivityyaw.value, joy_deadzoneyaw.value) * cl.realframetime * cl_yawspeed.value;
-               //cl.viewangles[2]   += IN_JoystickGetAxis(joy, joy_axisroll.integer, joy_sensitivityroll.value, joy_deadzoneroll.value) * cl.realframetime * cl_rollspeed.value;
-       
-               // cache state of axes to emulate button events for them
-               numaxes = min(MAX_JOYSTICK_AXES, SDL_JoystickNumAxes(joy));
-               for (j = 0; j < numaxes; j++)
-               {
-                       joy_axescache[j].oldmove = joy_axescache[j].move;
-                       joy_axescache[j].move = IN_JoystickGetAxis(joy, j, 1, joy_axiskeyevents_deadzone.value);
-               }
-
-               // run keyevents
-               if (joy_axiskeyevents.integer)
-               {
-                       IN_JoystickKeyeventForAxis(joy, joy_axisforward.integer, K_DOWNARROW, K_UPARROW);
-                       IN_JoystickKeyeventForAxis(joy, joy_axisside.integer, K_RIGHTARROW, K_LEFTARROW);
-               }
-       }
+       VID_BuildJoyState(&joystate);
+       VID_ApplyJoyState(&joystate);
 }
 
 /////////////////////
@@ -886,6 +762,8 @@ void Sys_SendKeyEvents( void )
        int keycode;
        SDL_Event event;
 
+       VID_EnableJoystick(true);
+
        while( SDL_PollEvent( &event ) )
                switch( event.type ) {
                        case SDL_QUIT:
@@ -894,7 +772,7 @@ void Sys_SendKeyEvents( void )
                        case SDL_KEYDOWN:
                        case SDL_KEYUP:
                                keycode = MapKey(event.key.keysym.sym);
-                               if (!IN_JoystickBlockDoubledKeyEvents(keycode))
+                               if (!VID_JoyBlockEmulatedKeys(keycode))
                                        Key_Event(keycode, event.key.keysym.unicode, (event.key.state == SDL_PRESSED));
                                break;
                        case SDL_ACTIVEEVENT:
@@ -913,12 +791,7 @@ void Sys_SendKeyEvents( void )
                                        Key_Event( buttonremap[event.button.button - 1], 0, event.button.state == SDL_PRESSED );
                                break;
                        case SDL_JOYBUTTONDOWN:
-                               if (!joy_enable.integer)
-                                       break; // ignore down events if joystick has been disabled
                        case SDL_JOYBUTTONUP:
-                               if (event.jbutton.button < 48)
-                                       Key_Event( event.jbutton.button + (event.jbutton.button < 16 ? K_JOY1 : K_AUX1 - 16), 0, (event.jbutton.state == SDL_PRESSED) );
-                               break;
                        case SDL_JOYAXISMOTION:
                        case SDL_JOYBALLMOTION:
                        case SDL_JOYHATMOTION:
@@ -1000,6 +873,8 @@ void Sys_SendKeyEvents( void )
        int unicode;
        SDL_Event event;
 
+       VID_EnableJoystick(true);
+
        while( SDL_PollEvent( &event ) )
                switch( event.type ) {
                        case SDL_QUIT:
@@ -1008,16 +883,7 @@ void Sys_SendKeyEvents( void )
                        case SDL_KEYDOWN:
                        case SDL_KEYUP:
                                keycode = MapKey(event.key.keysym.sym);
-                               if (!IN_JoystickBlockDoubledKeyEvents(keycode))
-#ifdef __IPHONEOS__
-                               // the virtual keyboard seems to produce no unicode values...
-                               if (missingunicodehack && keycode >= ' ' && keycode < 0x7F && event.key.keysym.unicode == 0)
-                               {
-                                       Con_DPrintf("SDL hack: no unicode value reported, substituting ascii value %i\n", keycode);
-                                       Key_Event(keycode, keycode, (event.key.state == SDL_PRESSED));
-                               }
-                               else
-#endif
+                               if (!VID_JoyBlockEmulatedKeys(keycode))
                                        Key_Event(keycode, 0, (event.key.state == SDL_PRESSED));
                                break;
                        case SDL_MOUSEBUTTONDOWN:
@@ -1027,12 +893,7 @@ void Sys_SendKeyEvents( void )
                                        Key_Event( buttonremap[event.button.button - 1], 0, event.button.state == SDL_PRESSED );
                                break;
                        case SDL_JOYBUTTONDOWN:
-                               if (!joy_enable.integer)
-                                       break; // ignore down events if joystick has been disabled
                        case SDL_JOYBUTTONUP:
-                               if (event.jbutton.button < 48)
-                                       Key_Event( event.jbutton.button + (event.jbutton.button < 16 ? K_JOY1 : K_AUX1 - 16), 0, (event.jbutton.state == SDL_PRESSED) );
-                               break;
                        case SDL_JOYAXISMOTION:
                        case SDL_JOYBALLMOTION:
                        case SDL_JOYHATMOTION:
@@ -1182,15 +1043,6 @@ void Sys_SendKeyEvents( void )
                        case SDL_TOUCHBUTTONUP:
                                // not sure what to do with this...
                                break;
-                       case SDL_JOYAXISMOTION:
-                               // we poll the joystick instead
-                               break;
-                       case SDL_JOYBALLMOTION:
-                               // we poll the joystick instead
-                               break;
-                       case SDL_JOYHATMOTION:
-                               // we poll the joystick instead
-                               break;
                        default:
                                Con_DPrintf("Received unrecognized SDL_Event type 0x%x\n", event.type);
                                break;
@@ -1221,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;
@@ -1472,7 +1335,7 @@ void GLES_Init(void)
 //     qglBegin = wrapglBegin;
 //     qglBeginQueryARB = wrapglBeginQuery;
        qglBindAttribLocation = wrapglBindAttribLocation;
-       qglBindFragDataLocation = wrapglBindFragDataLocation;
+//     qglBindFragDataLocation = wrapglBindFragDataLocation;
        qglBindBufferARB = wrapglBindBuffer;
        qglBindFramebufferEXT = wrapglBindFramebuffer;
        qglBindRenderbufferEXT = wrapglBindRenderbuffer;
@@ -1508,7 +1371,7 @@ void GLES_Init(void)
        qglDeleteTextures = wrapglDeleteTextures;
        qglDepthFunc = wrapglDepthFunc;
        qglDepthMask = wrapglDepthMask;
-       qglDepthRange = wrapglDepthRange;
+       qglDepthRangef = wrapglDepthRangef;
        qglDetachShader = wrapglDetachShader;
        qglDisable = wrapglDisable;
        qglDisableClientState = wrapglDisableClientState;
@@ -1667,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);
@@ -1709,8 +1573,8 @@ void GLES_Init(void)
        vid.support.ext_draw_range_elements = true;
        vid.support.ext_framebuffer_object = false;//true;
        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;
@@ -1719,11 +1583,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)
@@ -1745,6 +1627,8 @@ void GLES_Init(void)
        Con_DPrintf("Using GLES2.0 rendering path - %i texture matrix, %i texture images, %i texcoords%s\n", vid.texunits, vid.teximageunits, vid.texarrayunits, vid.support.ext_framebuffer_object ? ", shadowmapping supported" : "");
        vid.renderpath = RENDERPATH_GLES2;
        vid.useinterleavedarrays = false;
+       vid.sRGBcapable2D = false;
+       vid.sRGBcapable3D = false;
 
        // VorteX: set other info (maybe place them in VID_InitMode?)
        extern cvar_t gl_info_vendor;
@@ -1776,29 +1660,6 @@ void VID_Init (void)
        Cvar_RegisterVariable(&apple_mouse_noaccel);
 #endif
 #endif
-       Cvar_RegisterVariable(&joy_detected);
-       Cvar_RegisterVariable(&joy_enable);
-       Cvar_RegisterVariable(&joy_index);
-       Cvar_RegisterVariable(&joy_axisforward);
-       Cvar_RegisterVariable(&joy_axisside);
-       Cvar_RegisterVariable(&joy_axisup);
-       Cvar_RegisterVariable(&joy_axispitch);
-       Cvar_RegisterVariable(&joy_axisyaw);
-       //Cvar_RegisterVariable(&joy_axisroll);
-       Cvar_RegisterVariable(&joy_deadzoneforward);
-       Cvar_RegisterVariable(&joy_deadzoneside);
-       Cvar_RegisterVariable(&joy_deadzoneup);
-       Cvar_RegisterVariable(&joy_deadzonepitch);
-       Cvar_RegisterVariable(&joy_deadzoneyaw);
-       //Cvar_RegisterVariable(&joy_deadzoneroll);
-       Cvar_RegisterVariable(&joy_sensitivityforward);
-       Cvar_RegisterVariable(&joy_sensitivityside);
-       Cvar_RegisterVariable(&joy_sensitivityup);
-       Cvar_RegisterVariable(&joy_sensitivitypitch);
-       Cvar_RegisterVariable(&joy_sensitivityyaw);
-       //Cvar_RegisterVariable(&joy_sensitivityroll);
-       Cvar_RegisterVariable(&joy_axiskeyevents);
-       Cvar_RegisterVariable(&joy_axiskeyevents_deadzone);
 #ifdef __IPHONEOS__
        Cvar_SetValueQuick(&vid_touchscreen, 1);
 #endif
@@ -1815,6 +1676,54 @@ void VID_Init (void)
        vid_isfullscreen = false;
 }
 
+static int vid_sdljoystickindex = -1;
+void VID_EnableJoystick(qboolean enable)
+{
+       int index = joy_enable.integer > 0 ? joy_index.integer : -1;
+       int numsdljoysticks;
+       qboolean success = false;
+       int sharedcount = 0;
+       int sdlindex = -1;
+       sharedcount = VID_Shared_SetJoystick(index);
+       if (index >= 0 && index < sharedcount)
+               success = true;
+       sdlindex = index - sharedcount;
+
+       numsdljoysticks = SDL_NumJoysticks();
+       if (sdlindex < 0 || sdlindex >= numsdljoysticks)
+               sdlindex = -1;
+
+       // update cvar containing count of XInput joysticks + SDL joysticks
+       if (joy_detected.integer != sharedcount + numsdljoysticks)
+               Cvar_SetValueQuick(&joy_detected, sharedcount + numsdljoysticks);
+
+       if (vid_sdljoystickindex != sdlindex)
+       {
+               vid_sdljoystickindex = sdlindex;
+               // close SDL joystick if active
+               if (vid_sdljoystick)
+                       SDL_JoystickClose(vid_sdljoystick);
+               vid_sdljoystick = NULL;
+               if (sdlindex >= 0)
+               {
+                       vid_sdljoystick = SDL_JoystickOpen(sdlindex);
+                       if (vid_sdljoystick)
+                               Con_Printf("Joystick %i opened (SDL_Joystick %i is \"%s\" with %i axes, %i buttons, %i balls)\n", index, sdlindex, SDL_JoystickName(sdlindex), (int)SDL_JoystickNumAxes(vid_sdljoystick), (int)SDL_JoystickNumButtons(vid_sdljoystick), (int)SDL_JoystickNumBalls(vid_sdljoystick));
+                       else
+                       {
+                               Con_Printf("Joystick %i failed (SDL_JoystickOpen(%i) returned: %s)\n", index, sdlindex, SDL_GetError());
+                               sdlindex = -1;
+                       }
+               }
+       }
+
+       if (sdlindex >= 0)
+               success = true;
+
+       if (joy_active.integer != (success ? 1 : 0))
+               Cvar_SetValueQuick(&joy_active, success ? 1 : 0);
+}
+
 #if SETVIDEOMODE
 // set the icon (we dont use SDL here since it would be too much a PITA)
 #ifdef WIN32
@@ -1850,6 +1759,15 @@ static SDL_Surface *VID_WrapSDL_SetVideoMode(int screenwidth, int screenheight,
        }
        return screen;
 }
+#elif defined(MACOSX)
+static SDL_Surface *VID_WrapSDL_SetVideoMode(int screenwidth, int screenheight, int screenbpp, int screenflags)
+{
+       SDL_Surface *screen = NULL;
+       SDL_WM_SetCaption( gamename, NULL );
+       screen = SDL_SetVideoMode(screenwidth, screenheight, screenbpp, screenflags);
+       // we don't use SDL_WM_SetIcon here because the icon in the .app should be used
+       return screen;
+}
 #else
 // Adding the OS independent XPM version --blub
 #include "darkplaces.xpm"
@@ -2127,6 +2045,7 @@ qboolean VID_InitModeGL(viddef_mode_t *mode)
        notfirstvideomode = true;
 #endif
 
+#ifndef USE_GLES2
        // SDL usually knows best
        drivername = NULL;
 
@@ -2139,6 +2058,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
@@ -2192,6 +2112,7 @@ qboolean VID_InitModeGL(viddef_mode_t *mode)
                SDL_GL_SetAttribute (SDL_GL_MULTISAMPLEBUFFERS, 1);
                SDL_GL_SetAttribute (SDL_GL_MULTISAMPLESAMPLES, mode->samples);
        }
+
 #if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION == 2
        if (vid_vsync.integer)
                SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 1);
@@ -2258,29 +2179,12 @@ qboolean VID_InitModeGL(viddef_mode_t *mode)
        GL_Init();
 #endif
 
-       vid_numjoysticks = SDL_NumJoysticks();
-       vid_numjoysticks = bound(0, vid_numjoysticks, MAX_JOYSTICKS);
-       Cvar_SetValueQuick(&joy_detected, vid_numjoysticks);
-       Con_Printf("%d SDL joystick(s) found:\n", vid_numjoysticks);
-       memset(vid_joysticks, 0, sizeof(vid_joysticks));
-       for (i = 0;i < vid_numjoysticks;i++)
-       {
-               SDL_Joystick *joy;
-               joy = vid_joysticks[i] = SDL_JoystickOpen(i);
-               if (!joy)
-               {
-                       Con_Printf("joystick #%i: open failed: %s\n", i, SDL_GetError());
-                       continue;
-               }
-               Con_Printf("joystick #%i: opened \"%s\" with %i axes, %i buttons, %i balls\n", i, SDL_JoystickName(i), (int)SDL_JoystickNumAxes(joy), (int)SDL_JoystickNumButtons(joy), (int)SDL_JoystickNumBalls(joy));
-       }
-
        vid_hidden = false;
        vid_activewindow = false;
        vid_hasfocus = true;
        vid_usingmouse = false;
        vid_usinghidecursor = false;
-
+               
 #if SETVIDEOMODE
        SDL_WM_GrabInput(SDL_GRAB_OFF);
 #endif
@@ -2296,7 +2200,6 @@ extern cvar_t gl_info_driver;
 
 qboolean VID_InitModeSoft(viddef_mode_t *mode)
 {
-       int i;
 #if SETVIDEOMODE
        int flags = SDL_HWSURFACE;
        if(!COM_CheckParm("-noasyncblit")) flags |= SDL_ASYNCBLIT;
@@ -2376,23 +2279,6 @@ qboolean VID_InitModeSoft(viddef_mode_t *mode)
 
        VID_Soft_SharedSetup();
 
-       vid_numjoysticks = SDL_NumJoysticks();
-       vid_numjoysticks = bound(0, vid_numjoysticks, MAX_JOYSTICKS);
-       Cvar_SetValueQuick(&joy_detected, vid_numjoysticks);
-       Con_Printf("%d SDL joystick(s) found:\n", vid_numjoysticks);
-       memset(vid_joysticks, 0, sizeof(vid_joysticks));
-       for (i = 0;i < vid_numjoysticks;i++)
-       {
-               SDL_Joystick *joy;
-               joy = vid_joysticks[i] = SDL_JoystickOpen(i);
-               if (!joy)
-               {
-                       Con_Printf("joystick #%i: open failed: %s\n", i, SDL_GetError());
-                       continue;
-               }
-               Con_Printf("joystick #%i: opened \"%s\" with %i axes, %i buttons, %i balls\n", i, SDL_JoystickName(i), (int)SDL_JoystickNumAxes(joy), (int)SDL_JoystickNumButtons(joy), (int)SDL_JoystickNumBalls(joy));
-       }
-
        vid_hidden = false;
        vid_activewindow = false;
        vid_hasfocus = true;
@@ -2419,15 +2305,18 @@ qboolean VID_InitMode(viddef_mode_t *mode)
 
 void VID_Shutdown (void)
 {
+       VID_EnableJoystick(false);
        VID_SetMouse(false, false, false);
        VID_RestoreSystemGamma();
 
 #if SETVIDEOMODE
 #ifndef WIN32
+#ifndef MACOSX
        if (icon)
                SDL_FreeSurface(icon);
        icon = NULL;
 #endif
+#endif
 #endif
 
        if (vid_softsurface)
@@ -2542,7 +2431,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 06e400d1b966dc54c8f9edb9d6c8199c1719e9cf..86aa75c7c4c68b8a85f6dcd90813e6c839e1c9ea 100644 (file)
 LPDIRECT3DDEVICE9 vid_d3d9dev;
 #endif
 
+#ifdef WIN32
+//#include <XInput.h>
+#define XINPUT_GAMEPAD_DPAD_UP          0x0001
+#define XINPUT_GAMEPAD_DPAD_DOWN        0x0002
+#define XINPUT_GAMEPAD_DPAD_LEFT        0x0004
+#define XINPUT_GAMEPAD_DPAD_RIGHT       0x0008
+#define XINPUT_GAMEPAD_START            0x0010
+#define XINPUT_GAMEPAD_BACK             0x0020
+#define XINPUT_GAMEPAD_LEFT_THUMB       0x0040
+#define XINPUT_GAMEPAD_RIGHT_THUMB      0x0080
+#define XINPUT_GAMEPAD_LEFT_SHOULDER    0x0100
+#define XINPUT_GAMEPAD_RIGHT_SHOULDER   0x0200
+#define XINPUT_GAMEPAD_A                0x1000
+#define XINPUT_GAMEPAD_B                0x2000
+#define XINPUT_GAMEPAD_X                0x4000
+#define XINPUT_GAMEPAD_Y                0x8000
+#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE  7849
+#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
+#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD    30
+#define XUSER_INDEX_ANY                 0x000000FF
+
+typedef struct xinput_gamepad_s
+{
+       WORD wButtons;
+       BYTE bLeftTrigger;
+       BYTE bRightTrigger;
+       SHORT sThumbLX;
+       SHORT sThumbLY;
+       SHORT sThumbRX;
+       SHORT sThumbRY;
+}
+xinput_gamepad_t;
+
+typedef struct xinput_state_s
+{
+       DWORD dwPacketNumber;
+       xinput_gamepad_t Gamepad;
+}
+xinput_state_t;
+
+typedef struct xinput_keystroke_s
+{
+    WORD    VirtualKey;
+    WCHAR   Unicode;
+    WORD    Flags;
+    BYTE    UserIndex;
+    BYTE    HidCode;
+}
+xinput_keystroke_t;
+
+DWORD (WINAPI *qXInputGetState)(DWORD index, xinput_state_t *state);
+DWORD (WINAPI *qXInputGetKeystroke)(DWORD index, DWORD reserved, xinput_keystroke_t *keystroke);
+
+qboolean vid_xinputinitialized = false;
+int vid_xinputindex = -1;
+#endif
+
 // global video state
 viddef_t vid;
 
@@ -31,6 +88,54 @@ qboolean vid_hidden = true;
 // let go of the mouse, turn off sound, and restore system gamma ramps...
 qboolean vid_activewindow = true;
 
+vid_joystate_t vid_joystate;
+
+#ifdef WIN32
+cvar_t joy_xinputavailable = {CVAR_READONLY, "joy_xinputavailable", "0", "indicates which devices are being reported by the Windows XInput API (first controller = 1, second = 2, third = 4, fourth = 8, added together)"};
+#endif
+cvar_t joy_active = {CVAR_READONLY, "joy_active", "0", "indicates that a joystick is active (detected and enabled)"};
+cvar_t joy_detected = {CVAR_READONLY, "joy_detected", "0", "number of joysticks detected by engine"};
+cvar_t joy_enable = {CVAR_SAVE, "joy_enable", "0", "enables joystick support"};
+cvar_t joy_index = {0, "joy_index", "0", "selects which joystick to use if you have multiple (0 uses the first controller, 1 uses the second, ...)"};
+cvar_t joy_axisforward = {0, "joy_axisforward", "1", "which joystick axis to query for forward/backward movement"};
+cvar_t joy_axisside = {0, "joy_axisside", "0", "which joystick axis to query for right/left movement"};
+cvar_t joy_axisup = {0, "joy_axisup", "-1", "which joystick axis to query for up/down movement"};
+cvar_t joy_axispitch = {0, "joy_axispitch", "3", "which joystick axis to query for looking up/down"};
+cvar_t joy_axisyaw = {0, "joy_axisyaw", "2", "which joystick axis to query for looking right/left"};
+cvar_t joy_axisroll = {0, "joy_axisroll", "-1", "which joystick axis to query for tilting head right/left"};
+cvar_t joy_deadzoneforward = {0, "joy_deadzoneforward", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
+cvar_t joy_deadzoneside = {0, "joy_deadzoneside", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
+cvar_t joy_deadzoneup = {0, "joy_deadzoneup", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
+cvar_t joy_deadzonepitch = {0, "joy_deadzonepitch", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
+cvar_t joy_deadzoneyaw = {0, "joy_deadzoneyaw", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
+cvar_t joy_deadzoneroll = {0, "joy_deadzoneroll", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
+cvar_t joy_sensitivityforward = {0, "joy_sensitivityforward", "-1", "movement multiplier"};
+cvar_t joy_sensitivityside = {0, "joy_sensitivityside", "1", "movement multiplier"};
+cvar_t joy_sensitivityup = {0, "joy_sensitivityup", "1", "movement multiplier"};
+cvar_t joy_sensitivitypitch = {0, "joy_sensitivitypitch", "1", "movement multiplier"};
+cvar_t joy_sensitivityyaw = {0, "joy_sensitivityyaw", "-1", "movement multiplier"};
+cvar_t joy_sensitivityroll = {0, "joy_sensitivityroll", "1", "movement multiplier"};
+cvar_t joy_axiskeyevents = {CVAR_SAVE, "joy_axiskeyevents", "0", "generate uparrow/leftarrow etc. keyevents for joystick axes, use if your joystick driver is not generating them"};
+cvar_t joy_axiskeyevents_deadzone = {CVAR_SAVE, "joy_axiskeyevents_deadzone", "0.5", "deadzone value for axes"};
+cvar_t joy_x360_axisforward = {0, "joy_x360_axisforward", "1", "which joystick axis to query for forward/backward movement"};
+cvar_t joy_x360_axisside = {0, "joy_x360_axisside", "0", "which joystick axis to query for right/left movement"};
+cvar_t joy_x360_axisup = {0, "joy_x360_axisup", "-1", "which joystick axis to query for up/down movement"};
+cvar_t joy_x360_axispitch = {0, "joy_x360_axispitch", "3", "which joystick axis to query for looking up/down"};
+cvar_t joy_x360_axisyaw = {0, "joy_x360_axisyaw", "2", "which joystick axis to query for looking right/left"};
+cvar_t joy_x360_axisroll = {0, "joy_x360_axisroll", "-1", "which joystick axis to query for tilting head right/left"};
+cvar_t joy_x360_deadzoneforward = {0, "joy_x360_deadzoneforward", "0.266", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
+cvar_t joy_x360_deadzoneside = {0, "joy_x360_deadzoneside", "0.266", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
+cvar_t joy_x360_deadzoneup = {0, "joy_x360_deadzoneup", "0.266", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
+cvar_t joy_x360_deadzonepitch = {0, "joy_x360_deadzonepitch", "0.266", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
+cvar_t joy_x360_deadzoneyaw = {0, "joy_x360_deadzoneyaw", "0.266", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
+cvar_t joy_x360_deadzoneroll = {0, "joy_x360_deadzoneroll", "0.266", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
+cvar_t joy_x360_sensitivityforward = {0, "joy_x360_sensitivityforward", "1", "movement multiplier"};
+cvar_t joy_x360_sensitivityside = {0, "joy_x360_sensitivityside", "1", "movement multiplier"};
+cvar_t joy_x360_sensitivityup = {0, "joy_x360_sensitivityup", "1", "movement multiplier"};
+cvar_t joy_x360_sensitivitypitch = {0, "joy_x360_sensitivitypitch", "-1", "movement multiplier"};
+cvar_t joy_x360_sensitivityyaw = {0, "joy_x360_sensitivityyaw", "-1", "movement multiplier"};
+cvar_t joy_x360_sensitivityroll = {0, "joy_x360_sensitivityroll", "1", "movement multiplier"};
+
 // cvars for DPSOFTRAST
 cvar_t vid_soft = {CVAR_SAVE, "vid_soft", "0", "enables use of the DarkPlaces Software Rasterizer rather than OpenGL or Direct3D"};
 cvar_t vid_soft_threads = {CVAR_SAVE, "vid_soft_threads", "2", "the number of threads the DarkPlaces Software Rasterizer should use"}; 
@@ -71,6 +176,7 @@ cvar_t vid_minheight = {0, "vid_minheight", "0", "minimum vid_height that is acc
 cvar_t vid_gl13 = {0, "vid_gl13", "1", "enables faster rendering using OpenGL 1.3 features (such as GL_ARB_texture_env_combine extension)"};
 cvar_t vid_gl20 = {0, "vid_gl20", "1", "enables faster rendering using OpenGL 2.0 features (such as GL_ARB_fragment_shader extension)"};
 cvar_t gl_finish = {0, "gl_finish", "0", "make the cpu wait for the graphics processor at the end of each rendered frame (can help with strange input or video lag problems on some machines)"};
+cvar_t vid_sRGB = {CVAR_SAVE, "vid_sRGB", "0", "if hardware is capable, modify rendering to be gamma corrected for the sRGB color standard (computer monitors, TVs), recommended"};
 
 cvar_t vid_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" };
@@ -90,8 +196,10 @@ cvar_t v_color_grey_b = {CVAR_SAVE, "v_color_grey_b", "0.5", "desired color of g
 cvar_t v_color_white_r = {CVAR_SAVE, "v_color_white_r", "1", "desired color of white"};
 cvar_t v_color_white_g = {CVAR_SAVE, "v_color_white_g", "1", "desired color of white"};
 cvar_t v_color_white_b = {CVAR_SAVE, "v_color_white_b", "1", "desired color of white"};
-cvar_t v_hwgamma = {CVAR_SAVE, "v_hwgamma", "1", "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", "0", "enables use of GLSL to apply gamma correction ramps if available (note: overrides v_hwgamma)"};
+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
@@ -110,6 +218,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);
@@ -151,6 +260,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);
@@ -396,6 +506,9 @@ void (GLAPIENTRY *qglGetQueryivARB)(GLenum target, GLenum pname, GLint *params);
 void (GLAPIENTRY *qglGetQueryObjectivARB)(GLuint qid, GLenum pname, GLint *params);
 void (GLAPIENTRY *qglGetQueryObjectuivARB)(GLuint qid, GLenum pname, GLuint *params);
 
+void (GLAPIENTRY *qglSampleCoverageARB)(GLclampf value, GLboolean invert);
+#endif
+
 #if _MSC_VER >= 1400
 #define sscanf sscanf_s
 #endif
@@ -475,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},
@@ -804,6 +918,13 @@ static dllfunction_t drawbuffersfuncs[] =
        {NULL, NULL}
 };
 
+static dllfunction_t multisamplefuncs[] =
+{
+       {"glSampleCoverageARB",          (void **) &qglSampleCoverageARB},
+       {NULL, NULL}
+};
+#endif
+
 void VID_ClearExtensions(void)
 {
        // VorteX: reset extensions info cvar, it got filled by GL_CheckExtension
@@ -812,6 +933,8 @@ void VID_ClearExtensions(void)
        // clear the extension flags
        memset(&vid.support, 0, sizeof(vid.support));
        vid.renderpath = RENDERPATH_GL11;
+       vid.sRGBcapable2D = false;
+       vid.sRGBcapable3D = false;
        vid.useinterleavedarrays = false;
        vid.forcevbo = false;
        vid.maxtexturesize_2d = 0;
@@ -823,6 +946,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;
@@ -832,30 +956,35 @@ void VID_ClearExtensions(void)
        qglGetCompressedTexImageARB = NULL;
        qglFramebufferTexture2DEXT = NULL;
        qglDrawBuffersARB = NULL;
+#endif
 }
 
+#ifndef USE_GLES2
 void VID_CheckExtensions(void)
 {
-       if (!GL_CheckExtension("1.1", opengl110funcs, NULL, false))
+       if (!GL_CheckExtension("glbase", opengl110funcs, NULL, false))
                Sys_Error("OpenGL 1.1.0 functions not found");
-       vid.support.gl20shaders = GL_CheckExtension("2.0", gl20shaderfuncs, "-noshaders", false);
+       vid.support.gl20shaders = GL_CheckExtension("2.0", gl20shaderfuncs, "-noshaders", true);
 
        CHECKGLERROR
 
        Con_DPrint("Checking OpenGL extensions...\n");
 
-       // this one is purely optional, needed for GLSL 1.3 support (#version 130), so we don't even check the return value of GL_CheckExtension
-       vid.support.gl20shaders130 = GL_CheckExtension("2.0", glsl130funcs, "-noglsl130", false);
-       if(vid.support.gl20shaders130)
+       if (vid.support.gl20shaders)
        {
-               char *s = (char *) qglGetString(GL_SHADING_LANGUAGE_VERSION);
-               if(!s || atof(s) < 1.30 - 0.00001)
-                       vid.support.gl20shaders130 = 0;
+               // this one is purely optional, needed for GLSL 1.3 support (#version 130), so we don't even check the return value of GL_CheckExtension
+               vid.support.gl20shaders130 = GL_CheckExtension("glshaders130", glsl130funcs, "-noglsl130", true);
+               if(vid.support.gl20shaders130)
+               {
+                       char *s = (char *) qglGetString(GL_SHADING_LANGUAGE_VERSION);
+                       if(!s || atof(s) < 1.30 - 0.00001)
+                               vid.support.gl20shaders130 = 0;
+               }
+               if(vid.support.gl20shaders130)
+                       Con_DPrintf("Using GLSL 1.30\n");
+               else
+                       Con_DPrintf("Using GLSL 1.00\n");
        }
-       if(vid.support.gl20shaders130)
-               Con_DPrintf("Using GLSL 1.30\n");
-       else
-               Con_DPrintf("Using GLSL 1.00\n");
 
        // GL drivers generally prefer GL_BGRA
        vid.forcetextype = GL_BGRA;
@@ -870,12 +999,15 @@ void VID_CheckExtensions(void)
        vid.support.arb_texture_cube_map = GL_CheckExtension("GL_ARB_texture_cube_map", NULL, "-nocubemap", false);
        vid.support.arb_texture_env_combine = GL_CheckExtension("GL_ARB_texture_env_combine", NULL, "-nocombine", false) || GL_CheckExtension("GL_EXT_texture_env_combine", NULL, "-nocombine", false);
        vid.support.arb_texture_gather = GL_CheckExtension("GL_ARB_texture_gather", NULL, "-notexturegather", false);
+#ifndef __APPLE__
+       // LordHavoc: too many bugs on OSX!
        vid.support.arb_texture_non_power_of_two = GL_CheckExtension("GL_ARB_texture_non_power_of_two", NULL, "-notexturenonpoweroftwo", false);
+#endif
        vid.support.arb_vertex_buffer_object = GL_CheckExtension("GL_ARB_vertex_buffer_object", vbofuncs, "-novbo", false);
-       vid.support.ati_separate_stencil = GL_CheckExtension("2.0", gl2separatestencilfuncs, "-noseparatestencil", true) || GL_CheckExtension("GL_ATI_separate_stencil", atiseparatestencilfuncs, "-noseparatestencil", false);
+       vid.support.ati_separate_stencil = GL_CheckExtension("separatestencil", gl2separatestencilfuncs, "-noseparatestencil", true) || GL_CheckExtension("GL_ATI_separate_stencil", atiseparatestencilfuncs, "-noseparatestencil", false);
        vid.support.ext_blend_minmax = GL_CheckExtension("GL_EXT_blend_minmax", blendequationfuncs, "-noblendminmax", false);
        vid.support.ext_blend_subtract = GL_CheckExtension("GL_EXT_blend_subtract", blendequationfuncs, "-noblendsubtract", false);
-       vid.support.ext_draw_range_elements = GL_CheckExtension("1.2", drawrangeelementsfuncs, "-nodrawrangeelements", true) || GL_CheckExtension("GL_EXT_draw_range_elements", drawrangeelementsextfuncs, "-nodrawrangeelements", 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.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);
@@ -883,6 +1015,9 @@ void VID_CheckExtensions(void)
        vid.support.ext_texture_edge_clamp = GL_CheckExtension("GL_EXT_texture_edge_clamp", NULL, "-noedgeclamp", false) || GL_CheckExtension("GL_SGIS_texture_edge_clamp", NULL, "-noedgeclamp", false);
        vid.support.ext_texture_filter_anisotropic = GL_CheckExtension("GL_EXT_texture_filter_anisotropic", NULL, "-noanisotropy", false);
        vid.support.ext_texture_srgb = GL_CheckExtension("GL_EXT_texture_sRGB", NULL, "-nosrgb", false);
+       vid.support.arb_multisample = GL_CheckExtension("GL_ARB_multisample", multisamplefuncs, "-nomultisample", false);
+       vid.allowalphatocoverage = false;
+
 // COMMANDLINEOPTION: GL: -noshaders disables use of OpenGL 2.0 shaders (which allow pixel shader effects, can improve per pixel lighting performance and capabilities)
 // COMMANDLINEOPTION: GL: -noanisotropy disables GL_EXT_texture_filter_anisotropic (allows higher quality texturing)
 // COMMANDLINEOPTION: GL: -noblendminmax disables GL_EXT_blend_minmax
@@ -907,6 +1042,7 @@ void VID_CheckExtensions(void)
 // COMMANDLINEOPTION: GL: -notexturenonpoweroftwo disables GL_ARB_texture_non_power_of_two (which saves video memory if it is supported, but crashes on some buggy drivers)
 // COMMANDLINEOPTION: GL: -novbo disables GL_ARB_vertex_buffer_object (which accelerates rendering)
 // COMMANDLINEOPTION: GL: -nosrgb disables GL_EXT_texture_sRGB (which is used for higher quality non-linear texture gamma)
+// COMMANDLINEOPTION: GL: -nomultisample disables GL_ARB_multisample
 
        if (vid.support.arb_draw_buffers)
                qglGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, (GLint*)&vid.maxdrawbuffers);
@@ -929,7 +1065,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);
 
@@ -942,10 +1078,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);
@@ -953,16 +1089,24 @@ void VID_CheckExtensions(void)
                vid.texarrayunits = bound(8, vid.texarrayunits, MAX_TEXTUREUNITS);
                Con_DPrintf("Using GL2.0 rendering path - %i texture matrix, %i texture images, %i texcoords%s\n", vid.texunits, vid.teximageunits, vid.texarrayunits, vid.support.ext_framebuffer_object ? ", shadowmapping supported" : "");
                vid.renderpath = RENDERPATH_GL20;
+               vid.sRGBcapable2D = false;
+               vid.sRGBcapable3D = true;
                vid.useinterleavedarrays = false;
+               Con_Printf("vid.support.arb_multisample %i\n", vid.support.arb_multisample);
+               Con_Printf("vid.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;
                Con_DPrintf("Using GL1.3 rendering path - %i texture units, single pass rendering\n", vid.texunits);
                vid.renderpath = RENDERPATH_GL13;
+               vid.sRGBcapable2D = false;
+               vid.sRGBcapable3D = false;
                vid.useinterleavedarrays = false;
        }
        else
@@ -972,9 +1116,24 @@ void VID_CheckExtensions(void)
                vid.texarrayunits = vid.texunits;
                Con_DPrintf("Using GL1.1 rendering path - %i texture units, two pass rendering\n", vid.texunits);
                vid.renderpath = RENDERPATH_GL11;
+               vid.sRGBcapable2D = false;
+               vid.sRGBcapable3D = false;
                vid.useinterleavedarrays = false;
        }
 
+       // enable multisample antialiasing if possible
+       if(vid.support.arb_multisample)
+       {
+               int samples = 0;
+               qglGetIntegerv(GL_SAMPLES_ARB, &samples);
+               if (samples > 1)
+                       qglEnable(GL_MULTISAMPLE_ARB);
+               else
+                       vid.allowalphatocoverage = false;
+       }
+       else
+               vid.allowalphatocoverage = false;
+
        // VorteX: set other info (maybe place them in VID_InitMode?)
        Cvar_SetQuick(&gl_info_vendor, gl_vendor);
        Cvar_SetQuick(&gl_info_renderer, gl_renderer);
@@ -982,6 +1141,244 @@ 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)
+{
+       float value;
+       value = (axis >= 0 && axis < MAXJOYAXIS) ? joystate->axis[axis] : 0.0f;
+       value = value > deadzone ? (value - deadzone) : (value < -deadzone ? (value + deadzone) : 0.0f);
+       value *= deadzone > 0 ? (1.0f / (1.0f - deadzone)) : 1.0f;
+       value = bound(-1, value, 1);
+       return value * sensitivity;
+}
+
+qboolean VID_JoyBlockEmulatedKeys(int keycode)
+{
+       int j;
+       vid_joystate_t joystate;
+
+       if (!joy_axiskeyevents.integer)
+               return false;
+       if (vid_joystate.is360)
+               return false;
+       if (keycode != K_UPARROW && keycode != K_DOWNARROW && keycode != K_RIGHTARROW && keycode != K_LEFTARROW)
+               return false;
+
+       // block system-generated key events for arrow keys if we're emulating the arrow keys ourselves
+       VID_BuildJoyState(&joystate);
+       for (j = 32;j < 36;j++)
+               if (vid_joystate.button[j] || joystate.button[j])
+                       return true;
+
+       return false;
+}
+
+void VID_Shared_BuildJoyState_Begin(vid_joystate_t *joystate)
+{
+#ifdef WIN32
+       xinput_state_t xinputstate;
+#endif
+       memset(joystate, 0, sizeof(*joystate));
+#ifdef WIN32
+       if (vid_xinputindex >= 0 && qXInputGetState && qXInputGetState(vid_xinputindex, &xinputstate) == S_OK)
+       {
+               joystate->is360 = true;
+               joystate->button[ 0] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) != 0;
+               joystate->button[ 1] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) != 0;
+               joystate->button[ 2] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) != 0;
+               joystate->button[ 3] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) != 0;
+               joystate->button[ 4] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_START) != 0;
+               joystate->button[ 5] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) != 0;
+               joystate->button[ 6] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) != 0;
+               joystate->button[ 7] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0;
+               joystate->button[ 8] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) != 0;
+               joystate->button[ 9] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0;
+               joystate->button[10] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_A) != 0;
+               joystate->button[11] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0;
+               joystate->button[12] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_X) != 0;
+               joystate->button[13] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_Y) != 0;
+               joystate->button[14] = xinputstate.Gamepad.bLeftTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD;
+               joystate->button[15] = xinputstate.Gamepad.bRightTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD;
+               joystate->button[16] = xinputstate.Gamepad.sThumbLY < -16384;
+               joystate->button[17] = xinputstate.Gamepad.sThumbLY >  16384;
+               joystate->button[18] = xinputstate.Gamepad.sThumbLX < -16384;
+               joystate->button[19] = xinputstate.Gamepad.sThumbLX >  16384;
+               joystate->button[20] = xinputstate.Gamepad.sThumbRY < -16384;
+               joystate->button[21] = xinputstate.Gamepad.sThumbRY >  16384;
+               joystate->button[22] = xinputstate.Gamepad.sThumbRX < -16384;
+               joystate->button[23] = xinputstate.Gamepad.sThumbRX >  16384;
+               joystate->axis[ 4] = xinputstate.Gamepad.bLeftTrigger * (1.0f / 255.0f);
+               joystate->axis[ 5] = xinputstate.Gamepad.bRightTrigger * (1.0f / 255.0f);
+               joystate->axis[ 0] = xinputstate.Gamepad.sThumbLX * (1.0f / 32767.0f);
+               joystate->axis[ 1] = xinputstate.Gamepad.sThumbLY * (1.0f / 32767.0f);
+               joystate->axis[ 2] = xinputstate.Gamepad.sThumbRX * (1.0f / 32767.0f);
+               joystate->axis[ 3] = xinputstate.Gamepad.sThumbRY * (1.0f / 32767.0f);
+       }
+#endif
+}
+
+void VID_Shared_BuildJoyState_Finish(vid_joystate_t *joystate)
+{
+       float f, r;
+       if (joystate->is360)
+               return;
+       // emulate key events for thumbstick
+       f = VID_JoyState_GetAxis(joystate, joy_axisforward.integer, 1, joy_axiskeyevents_deadzone.value) * joy_sensitivityforward.value;
+       r = VID_JoyState_GetAxis(joystate, joy_axisside.integer   , 1, joy_axiskeyevents_deadzone.value) * joy_sensitivityside.value;
+#if MAXJOYBUTTON != 36
+#error this code must be updated if MAXJOYBUTTON changes!
+#endif
+       joystate->button[32] = f > 0.0f;
+       joystate->button[33] = f < 0.0f;
+       joystate->button[34] = r > 0.0f;
+       joystate->button[35] = r < 0.0f;
+}
+
+void VID_KeyEventForButton(qboolean oldbutton, qboolean newbutton, int key, double *timer)
+{
+       if (oldbutton)
+       {
+               if (newbutton)
+               {
+                       if (realtime >= *timer)
+                       {
+                               Key_Event(key, 0, true);
+                               *timer = realtime + 0.1;
+                       }
+               }
+               else
+               {
+                       Key_Event(key, 0, false);
+                       *timer = 0;
+               }
+       }
+       else
+       {
+               if (newbutton)
+               {
+                       Key_Event(key, 0, true);
+                       *timer = realtime + 0.5;
+               }
+       }
+}
+
+#if MAXJOYBUTTON != 36
+#error this code must be updated if MAXJOYBUTTON changes!
+#endif
+static int joybuttonkey[MAXJOYBUTTON][2] =
+{
+       {K_JOY1, K_ENTER}, {K_JOY2, K_ESCAPE}, {K_JOY3, 0}, {K_JOY4, 0}, {K_JOY5, 0}, {K_JOY6, 0}, {K_JOY7, 0}, {K_JOY8, 0}, {K_JOY9, 0}, {K_JOY10, 0}, {K_JOY11, 0}, {K_JOY12, 0}, {K_JOY13, 0}, {K_JOY14, 0}, {K_JOY15, 0}, {K_JOY16, 0},
+       {K_AUX1, 0}, {K_AUX2, 0}, {K_AUX3, 0}, {K_AUX4, 0}, {K_AUX5, 0}, {K_AUX6, 0}, {K_AUX7, 0}, {K_AUX8, 0}, {K_AUX9, 0}, {K_AUX10, 0}, {K_AUX11, 0}, {K_AUX12, 0}, {K_AUX13, 0}, {K_AUX14, 0}, {K_AUX15, 0}, {K_AUX16, 0},
+       {K_JOY_UP, K_UPARROW}, {K_JOY_DOWN, K_DOWNARROW}, {K_JOY_RIGHT, K_RIGHTARROW}, {K_JOY_LEFT, K_LEFTARROW},
+};
+
+static int joybuttonkey360[][2] =
+{
+       {K_X360_DPAD_UP, K_UPARROW},
+       {K_X360_DPAD_DOWN, K_DOWNARROW},
+       {K_X360_DPAD_LEFT, K_LEFTARROW},
+       {K_X360_DPAD_RIGHT, K_RIGHTARROW},
+       {K_X360_START, K_ESCAPE},
+       {K_X360_BACK, K_ESCAPE},
+       {K_X360_LEFT_THUMB, 0},
+       {K_X360_RIGHT_THUMB, 0},
+       {K_X360_LEFT_SHOULDER, 0},
+       {K_X360_RIGHT_SHOULDER, 0},
+       {K_X360_A, K_ENTER},
+       {K_X360_B, K_ESCAPE},
+       {K_X360_X, 0},
+       {K_X360_Y, 0},
+       {K_X360_LEFT_TRIGGER, 0},
+       {K_X360_RIGHT_TRIGGER, 0},
+       {K_X360_LEFT_THUMB_DOWN, K_DOWNARROW},
+       {K_X360_LEFT_THUMB_UP, K_UPARROW},
+       {K_X360_LEFT_THUMB_LEFT, K_LEFTARROW},
+       {K_X360_LEFT_THUMB_RIGHT, K_RIGHTARROW},
+       {K_X360_RIGHT_THUMB_DOWN, 0},
+       {K_X360_RIGHT_THUMB_UP, 0},
+       {K_X360_RIGHT_THUMB_LEFT, 0},
+       {K_X360_RIGHT_THUMB_RIGHT, 0},
+};
+
+double vid_joybuttontimer[MAXJOYBUTTON];
+void VID_ApplyJoyState(vid_joystate_t *joystate)
+{
+       int j;
+       int c = joy_axiskeyevents.integer != 0;
+       if (joystate->is360)
+       {
+#if 0
+               // keystrokes (chatpad)
+               // DOES NOT WORK - no driver support in xinput1_3.dll :(
+               xinput_keystroke_t keystroke;
+               while (qXInputGetKeystroke && qXInputGetKeystroke(XUSER_INDEX_ANY, 0, &keystroke) == S_OK)
+                       Con_Printf("XInput KeyStroke: VirtualKey %i, Unicode %i, Flags %x, UserIndex %i, HidCode %i\n", keystroke.VirtualKey, keystroke.Unicode, keystroke.Flags, keystroke.UserIndex, keystroke.HidCode);
+#endif
+
+               // emit key events for buttons
+               for (j = 0;j < (int)(sizeof(joybuttonkey360)/sizeof(joybuttonkey360[0]));j++)
+                       VID_KeyEventForButton(vid_joystate.button[j] != 0, joystate->button[j] != 0, joybuttonkey360[j][c], &vid_joybuttontimer[j]);
+
+               // axes
+               cl.cmd.forwardmove += VID_JoyState_GetAxis(joystate, joy_x360_axisforward.integer, joy_x360_sensitivityforward.value, joy_x360_deadzoneforward.value) * cl_forwardspeed.value;
+               cl.cmd.sidemove    += VID_JoyState_GetAxis(joystate, joy_x360_axisside.integer, joy_x360_sensitivityside.value, joy_x360_deadzoneside.value) * cl_sidespeed.value;
+               cl.cmd.upmove      += VID_JoyState_GetAxis(joystate, joy_x360_axisup.integer, joy_x360_sensitivityup.value, joy_x360_deadzoneup.value) * cl_upspeed.value;
+               cl.viewangles[0]   += VID_JoyState_GetAxis(joystate, joy_x360_axispitch.integer, joy_x360_sensitivitypitch.value, joy_x360_deadzonepitch.value) * cl.realframetime * cl_pitchspeed.value;
+               cl.viewangles[1]   += VID_JoyState_GetAxis(joystate, joy_x360_axisyaw.integer, joy_x360_sensitivityyaw.value, joy_x360_deadzoneyaw.value) * cl.realframetime * cl_yawspeed.value;
+               //cl.viewangles[2]   += VID_JoyState_GetAxis(joystate, joy_x360_axisroll.integer, joy_x360_sensitivityroll.value, joy_x360_deadzoneroll.value) * cl.realframetime * cl_rollspeed.value;
+       }
+       else
+       {
+               // emit key events for buttons
+               for (j = 0;j < MAXJOYBUTTON;j++)
+                       VID_KeyEventForButton(vid_joystate.button[j] != 0, joystate->button[j] != 0, joybuttonkey[j][c], &vid_joybuttontimer[j]);
+
+               // axes
+               cl.cmd.forwardmove += VID_JoyState_GetAxis(joystate, joy_axisforward.integer, joy_sensitivityforward.value, joy_deadzoneforward.value) * cl_forwardspeed.value;
+               cl.cmd.sidemove    += VID_JoyState_GetAxis(joystate, joy_axisside.integer, joy_sensitivityside.value, joy_deadzoneside.value) * cl_sidespeed.value;
+               cl.cmd.upmove      += VID_JoyState_GetAxis(joystate, joy_axisup.integer, joy_sensitivityup.value, joy_deadzoneup.value) * cl_upspeed.value;
+               cl.viewangles[0]   += VID_JoyState_GetAxis(joystate, joy_axispitch.integer, joy_sensitivitypitch.value, joy_deadzonepitch.value) * cl.realframetime * cl_pitchspeed.value;
+               cl.viewangles[1]   += VID_JoyState_GetAxis(joystate, joy_axisyaw.integer, joy_sensitivityyaw.value, joy_deadzoneyaw.value) * cl.realframetime * cl_yawspeed.value;
+               //cl.viewangles[2]   += VID_JoyState_GetAxis(joystate, joy_axisroll.integer, joy_sensitivityroll.value, joy_deadzoneroll.value) * cl.realframetime * cl_rollspeed.value;
+       }
+
+       vid_joystate = *joystate;
+}
+
+int VID_Shared_SetJoystick(int index)
+{
+#ifdef WIN32
+       int i;
+       int xinputcount = 0;
+       int xinputindex = -1;
+       int xinputavailable = 0;
+       xinput_state_t state;
+       // detect available XInput controllers
+       for (i = 0;i < 4;i++)
+       {
+               if (qXInputGetState && qXInputGetState(i, &state) == S_OK)
+               {
+                       xinputavailable |= 1<<i;
+                       if (index == xinputcount)
+                               xinputindex = i;
+                       xinputcount++;
+               }
+       }
+       if (joy_xinputavailable.integer != xinputavailable)
+               Cvar_SetValueQuick(&joy_xinputavailable, xinputavailable);
+       if (vid_xinputindex != xinputindex)
+       {
+               vid_xinputindex = xinputindex;
+               if (xinputindex >= 0)
+                       Con_Printf("Joystick %i opened (XInput Device %i)\n", index, xinputindex);
+       }
+       return xinputcount;
+#else
+       return 0;
+#endif
+}
+
 
 void Force_CenterView_f (void)
 {
@@ -996,17 +1393,18 @@ 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]), 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);
+               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);
        }
        else
        {
-               BuildGammaTable16(1.0f, cachegamma, cachecontrast, cachebrightness, cachecontrastboost, ramps, rampsize);
-               BuildGammaTable16(1.0f, cachegamma, cachecontrast, cachebrightness, cachecontrastboost, ramps + rampsize, rampsize);
-               BuildGammaTable16(1.0f, cachegamma, cachecontrast, cachebrightness, cachecontrastboost, ramps + rampsize*2, rampsize);
+               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);
        }
 
        // LordHavoc: this code came from Ben Winslow and Zinx Verituse, I have
@@ -1081,8 +1479,8 @@ void VID_UpdateGamma(qboolean force, int rampsize)
                wantgamma = 0;
 #define BOUNDCVAR(cvar, m1, m2) c = &(cvar);f = bound(m1, c->value, m2);if (c->value != f) Cvar_SetValueQuick(c, f);
        BOUNDCVAR(v_gamma, 0.1, 5);
-       BOUNDCVAR(v_contrast, 1, 5);
-       BOUNDCVAR(v_brightness, 0, 0.8);
+       BOUNDCVAR(v_contrast, 0.2, 5);
+       BOUNDCVAR(v_brightness, -v_contrast.value * 0.8, 0.8);
        //BOUNDCVAR(v_contrastboost, 0.0625, 16);
        BOUNDCVAR(v_color_black_r, 0, 0.8);
        BOUNDCVAR(v_color_black_g, 0, 0.8);
@@ -1099,6 +1497,8 @@ void VID_UpdateGamma(qboolean force, int rampsize)
        vid_gammatables_trivial = false;
        if(v_psycho.integer == 0)
        if(v_contrastboost.value == 1)
+       if(!vid.sRGB2D)
+       if(!vid.sRGB3D)
        {
                if(v_color_enable.integer)
                {
@@ -1202,6 +1602,23 @@ void VID_RestoreSystemGamma(void)
        }
 }
 
+#ifdef WIN32
+static dllfunction_t xinputdllfuncs[] =
+{
+       {"XInputGetState", (void **) &qXInputGetState},
+       {"XInputGetKeystroke", (void **) &qXInputGetKeystroke},
+       {NULL, NULL}
+};
+static const char* xinputdllnames [] =
+{
+       "xinput1_3.dll",
+       "xinput1_2.dll",
+       "xinput1_1.dll",
+       NULL
+};
+static dllhandle_t xinputdll_dll = NULL;
+#endif
+
 void VID_Shared_Init(void)
 {
 #ifdef SSE_POSSIBLE
@@ -1243,6 +1660,7 @@ void VID_Shared_Init(void)
 
        Cvar_RegisterVariable(&v_hwgamma);
        Cvar_RegisterVariable(&v_glslgamma);
+       Cvar_RegisterVariable(&v_glslgamma_2d);
 
        Cvar_RegisterVariable(&v_psycho);
 
@@ -1265,6 +1683,58 @@ void VID_Shared_Init(void)
        Cvar_RegisterVariable(&vid_gl13);
        Cvar_RegisterVariable(&vid_gl20);
        Cvar_RegisterVariable(&gl_finish);
+       Cvar_RegisterVariable(&vid_sRGB);
+
+       Cvar_RegisterVariable(&joy_active);
+#ifdef WIN32
+       Cvar_RegisterVariable(&joy_xinputavailable);
+#endif
+       Cvar_RegisterVariable(&joy_detected);
+       Cvar_RegisterVariable(&joy_enable);
+       Cvar_RegisterVariable(&joy_index);
+       Cvar_RegisterVariable(&joy_axisforward);
+       Cvar_RegisterVariable(&joy_axisside);
+       Cvar_RegisterVariable(&joy_axisup);
+       Cvar_RegisterVariable(&joy_axispitch);
+       Cvar_RegisterVariable(&joy_axisyaw);
+       //Cvar_RegisterVariable(&joy_axisroll);
+       Cvar_RegisterVariable(&joy_deadzoneforward);
+       Cvar_RegisterVariable(&joy_deadzoneside);
+       Cvar_RegisterVariable(&joy_deadzoneup);
+       Cvar_RegisterVariable(&joy_deadzonepitch);
+       Cvar_RegisterVariable(&joy_deadzoneyaw);
+       //Cvar_RegisterVariable(&joy_deadzoneroll);
+       Cvar_RegisterVariable(&joy_sensitivityforward);
+       Cvar_RegisterVariable(&joy_sensitivityside);
+       Cvar_RegisterVariable(&joy_sensitivityup);
+       Cvar_RegisterVariable(&joy_sensitivitypitch);
+       Cvar_RegisterVariable(&joy_sensitivityyaw);
+       //Cvar_RegisterVariable(&joy_sensitivityroll);
+       Cvar_RegisterVariable(&joy_axiskeyevents);
+       Cvar_RegisterVariable(&joy_axiskeyevents_deadzone);
+       Cvar_RegisterVariable(&joy_x360_axisforward);
+       Cvar_RegisterVariable(&joy_x360_axisside);
+       Cvar_RegisterVariable(&joy_x360_axisup);
+       Cvar_RegisterVariable(&joy_x360_axispitch);
+       Cvar_RegisterVariable(&joy_x360_axisyaw);
+       //Cvar_RegisterVariable(&joy_x360_axisroll);
+       Cvar_RegisterVariable(&joy_x360_deadzoneforward);
+       Cvar_RegisterVariable(&joy_x360_deadzoneside);
+       Cvar_RegisterVariable(&joy_x360_deadzoneup);
+       Cvar_RegisterVariable(&joy_x360_deadzonepitch);
+       Cvar_RegisterVariable(&joy_x360_deadzoneyaw);
+       //Cvar_RegisterVariable(&joy_x360_deadzoneroll);
+       Cvar_RegisterVariable(&joy_x360_sensitivityforward);
+       Cvar_RegisterVariable(&joy_x360_sensitivityside);
+       Cvar_RegisterVariable(&joy_x360_sensitivityup);
+       Cvar_RegisterVariable(&joy_x360_sensitivitypitch);
+       Cvar_RegisterVariable(&joy_x360_sensitivityyaw);
+       //Cvar_RegisterVariable(&joy_x360_sensitivityroll);
+
+#ifdef WIN32
+       Sys_LoadLibrary(xinputdllnames, &xinputdll_dll, xinputdllfuncs);
+#endif
+
        Cmd_AddCommand("force_centerview", Force_CenterView_f, "recenters view (stops looking up/down)");
        Cmd_AddCommand("vid_restart", VID_Restart_f, "restarts video system (closes and reopens the window, restarts renderer)");
 }
@@ -1272,6 +1742,7 @@ void VID_Shared_Init(void)
 int VID_Mode(int fullscreen, int width, int height, int bpp, float refreshrate, int stereobuffer, int samples)
 {
        viddef_mode_t mode;
+
        memset(&mode, 0, sizeof(mode));
        mode.fullscreen = fullscreen != 0;
        mode.width = width;
@@ -1296,6 +1767,8 @@ int VID_Mode(int fullscreen, int width, int height, int bpp, float refreshrate,
                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) : "");
 
@@ -1534,6 +2007,8 @@ void VID_Soft_SharedSetup(void)
        vid.texarrayunits = bound(8, vid.texarrayunits, MAX_TEXTUREUNITS);
        Con_DPrintf("Using DarkPlaces Software Rasterizer rendering path\n");
        vid.renderpath = RENDERPATH_SOFT;
+       vid.sRGBcapable2D = false;
+       vid.sRGBcapable3D = false;
        vid.useinterleavedarrays = false;
 
        Cvar_SetQuick(&gl_info_vendor, gl_vendor);
@@ -1547,4 +2022,4 @@ void VID_Soft_SharedSetup(void)
 
        // clear to black (loading plaque will be seen over this)
        GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
-}
\ No newline at end of file
+}
index 960c14c085c8bfac0ceca0b82c7248e28793d2e0..d30c6a759f368321862876df7e02dfc8873ede85 100644 (file)
--- a/vid_wgl.c
+++ b/vid_wgl.c
@@ -204,90 +204,15 @@ static qboolean   dinput_acquired;
 static unsigned int            mstate_di;
 #endif
 
-// joystick defines and variables
-// where should defines be moved?
-#define JOY_ABSOLUTE_AXIS      0x00000000              // control like a joystick
-#define JOY_RELATIVE_AXIS      0x00000010              // control like a mouse, spinner, trackball
-#define        JOY_MAX_AXES            6                               // X, Y, Z, R, U, V
-#define JOY_AXIS_X                     0
-#define JOY_AXIS_Y                     1
-#define JOY_AXIS_Z                     2
-#define JOY_AXIS_R                     3
-#define JOY_AXIS_U                     4
-#define JOY_AXIS_V                     5
-
-// joystick axes state
-typedef struct
-{
-       float oldmove;
-       float move;
-       float mdelta;
-       double keytime;
-}joy_axiscache_t;
-static joy_axiscache_t joy_axescache[JOY_MAX_AXES];
-
-enum _ControlList
-{
-       AxisNada = 0, AxisForward, AxisLook, AxisSide, AxisTurn
-};
-
-static DWORD   dwAxisFlags[JOY_MAX_AXES] =
-{
-       JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ, JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
-};
-
-static DWORD   dwAxisMap[JOY_MAX_AXES];
-static DWORD   dwControlMap[JOY_MAX_AXES];
-static PDWORD  pdwRawValue[JOY_MAX_AXES];
-
-// none of these cvars are saved over a session
-// this means that advanced controller configuration needs to be executed
-// each time.  this avoids any problems with getting back to a default usage
-// or when changing from one controller to another.  this way at least something
-// works.
-static cvar_t in_joystick = {CVAR_SAVE, "joystick","0", "enables joysticks"};
-static cvar_t joy_name = {0, "joyname", "joystick", "name of joystick to use (informational only, used only by joyadvanced 1 mode)"};
-static cvar_t joy_advanced = {0, "joyadvanced", "0", "use more than 2 axis joysticks (configuring this is very technical)"};
-static cvar_t joy_advaxisx = {0, "joyadvaxisx", "0", "axis mapping for joyadvanced 1 mode"};
-static cvar_t joy_advaxisy = {0, "joyadvaxisy", "0", "axis mapping for joyadvanced 1 mode"};
-static cvar_t joy_advaxisz = {0, "joyadvaxisz", "0", "axis mapping for joyadvanced 1 mode"};
-static cvar_t joy_advaxisr = {0, "joyadvaxisr", "0", "axis mapping for joyadvanced 1 mode"};
-static cvar_t joy_advaxisu = {0, "joyadvaxisu", "0", "axis mapping for joyadvanced 1 mode"};
-static cvar_t joy_advaxisv = {0, "joyadvaxisv", "0", "axis mapping for joyadvanced 1 mode"};
-static cvar_t joy_forwardthreshold = {0, "joyforwardthreshold", "0.15", "minimum joystick movement necessary to move forward"};
-static cvar_t joy_sidethreshold = {0, "joysidethreshold", "0.15", "minimum joystick movement necessary to move sideways (strafing)"};
-static cvar_t joy_pitchthreshold = {0, "joypitchthreshold", "0.15", "minimum joystick movement necessary to look up/down"};
-static cvar_t joy_yawthreshold = {0, "joyyawthreshold", "0.15", "minimum joystick movement necessary to turn left/right"};
-static cvar_t joy_forwardsensitivity = {0, "joyforwardsensitivity", "-1.0", "how fast the joystick moves forward"};
-static cvar_t joy_sidesensitivity = {0, "joysidesensitivity", "-1.0", "how fast the joystick moves sideways (strafing)"};
-static cvar_t joy_pitchsensitivity = {0, "joypitchsensitivity", "1.0", "how fast the joystick looks up/down"};
-static cvar_t joy_yawsensitivity = {0, "joyyawsensitivity", "-1.0", "how fast the joystick turns left/right"};
-static cvar_t joy_wwhack1 = {0, "joywwhack1", "0.0", "special hack for wingman warrior"};
-static cvar_t joy_wwhack2 = {0, "joywwhack2", "0.0", "special hack for wingman warrior"};
-static cvar_t joy_axiskeyevents = {CVAR_SAVE, "joy_axiskeyevents", "0", "generate uparrow/leftarrow etc. keyevents for joystick axes, use if your joystick driver is not generating them"};
-static cvar_t joy_axiskeyevents_deadzone = {CVAR_SAVE, "joy_axiskeyevents_deadzone", "0.5", "deadzone value for axes"};
-
 static cvar_t vid_forcerefreshrate = {0, "vid_forcerefreshrate", "0", "try to set the given vid_refreshrate even if Windows doesn't list it as valid video mode"};
 
-static qboolean        joy_avail, joy_advancedinit, joy_haspov;
-static DWORD           joy_oldbuttonstate, joy_oldpovstate;
-
-static int                     joy_id;
-static DWORD           joy_flags;
-static DWORD           joy_numbuttons;
-
 #ifdef SUPPORTDIRECTX
 static LPDIRECTINPUT           g_pdi;
 static LPDIRECTINPUTDEVICE     g_pMouse;
 static HINSTANCE hInstDI;
 #endif
 
-static JOYINFOEX       ji;
-
 // forward-referenced functions
-static void IN_StartupJoystick (void);
-static void Joy_AdvancedUpdate_f (void);
-static void IN_JoyMove (void);
 static void IN_StartupMouse (void);
 
 
@@ -609,7 +534,6 @@ static keynum_t buttonremap[16] =
 };
 
 /* main window procedure */
-static qboolean IN_JoystickBlockDoubledKeyEvents(int keycode);
 LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM  wParam, LPARAM lParam)
 {
        LONG    lRet = 1;
@@ -654,7 +578,7 @@ LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM  wParam, LPARAM lParam)
                        else if( charlength == 2 ) {
                                asciichar[0] = asciichar[1];
                        }
-                       if (!IN_JoystickBlockDoubledKeyEvents(vkey))
+                       if (!VID_JoyBlockEmulatedKeys(vkey))
                                Key_Event (vkey, asciichar[0], down);
                        break;
 
@@ -1390,7 +1314,6 @@ qboolean VID_InitModeGL(viddef_mode_t *mode)
        vid_initialized = true;
 
        IN_StartupMouse ();
-       IN_StartupJoystick ();
 
        if (qwglSwapIntervalEXT)
        {
@@ -1605,6 +1528,8 @@ qboolean VID_InitModeDX(viddef_mode_t *mode, int version)
        vid.texarrayunits = bound(8, vid.texarrayunits, MAX_TEXTUREUNITS);
        Con_DPrintf("Using D3D9.0 rendering path - %i texture matrix, %i texture images, %i texcoords, shadowmapping supported%s\n", vid.texunits, vid.teximageunits, vid.texarrayunits, vid.maxdrawbuffers > 1 ? ", MRT detected (allows prepass deferred lighting)" : "");
        vid.renderpath = RENDERPATH_D3D9;
+       vid.sRGBcapable2D = false;
+       vid.sRGBcapable3D = true;
        vid.useinterleavedarrays = true;
 
        Cvar_SetQuick(&gl_info_vendor, gl_vendor);
@@ -1634,7 +1559,6 @@ qboolean VID_InitModeDX(viddef_mode_t *mode, int version)
        vid_initialized = true;
 
        IN_StartupMouse ();
-       IN_StartupJoystick ();
 
        return true;
 }
@@ -1916,7 +1840,6 @@ qboolean VID_InitModeSOFT(viddef_mode_t *mode)
        vid_initialized = true;
 
        IN_StartupMouse ();
-       IN_StartupJoystick ();
 
        return true;
 }
@@ -1946,6 +1869,7 @@ void VID_Shutdown (void)
        if(vid_initialized == false)
                return;
 
+       VID_EnableJoystick(false);
        VID_SetMouse(false, false, false);
        VID_RestoreSystemGamma();
 
@@ -2085,6 +2009,28 @@ void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecurso
        }
 }
 
+void VID_BuildJoyState(vid_joystate_t *joystate)
+{
+       VID_Shared_BuildJoyState_Begin(joystate);
+       VID_Shared_BuildJoyState_Finish(joystate);
+}
+
+void VID_EnableJoystick(qboolean enable)
+{
+       int index = joy_enable.integer > 0 ? joy_index.integer : -1;
+       qboolean success = false;
+       int sharedcount = 0;
+       sharedcount = VID_Shared_SetJoystick(index);
+       if (index >= 0 && index < sharedcount)
+               success = true;
+
+       // update cvar containing count of XInput joysticks
+       if (joy_detected.integer != sharedcount)
+               Cvar_SetValueQuick(&joy_detected, sharedcount);
+
+       if (joy_active.integer != (success ? 1 : 0))
+               Cvar_SetValueQuick(&joy_active, success ? 1 : 0);
+}
 
 #ifdef SUPPORTDIRECTX
 /*
@@ -2196,7 +2142,7 @@ static void IN_StartupMouse (void)
        mouseinitialized = true;
 
 #ifdef SUPPORTDIRECTX
-// COMMANDLINEOPTION: Windows Input: -dinput enables DirectInput for mouse/joystick input
+// COMMANDLINEOPTION: Windows Input: -dinput enables DirectInput for mouse input
        if (COM_CheckParm ("-dinput"))
                dinput = IN_InitDInput ();
 
@@ -2306,580 +2252,19 @@ IN_Move
 */
 void IN_Move (void)
 {
+       vid_joystate_t joystate;
        if (vid_activewindow && !vid_reallyhidden)
-       {
                IN_MouseMove ();
-               IN_JoyMove ();
-       }
+       VID_EnableJoystick(true);
+       VID_BuildJoyState(&joystate);
+       VID_ApplyJoyState(&joystate);
 }
 
 
-/*
-===============
-IN_StartupJoystick
-===============
-*/
-static void IN_StartupJoystick (void)
-{
-       int                     numdevs;
-       JOYCAPS         jc;
-       MMRESULT        mmr;
-       mmr = 0;
-
-       // assume no joystick
-       joy_avail = false;
-
-       // abort startup if user requests no joystick
-// COMMANDLINEOPTION: Windows Input: -nojoy disables joystick support, may be a small speed increase
-       if (COM_CheckParm ("-nojoy"))
-               return;
-
-       // verify joystick driver is present
-       if ((numdevs = joyGetNumDevs ()) == 0)
-       {
-               Con_Print("\njoystick not found -- driver not present\n\n");
-               return;
-       }
-
-       // cycle through the joystick ids for the first valid one
-       for (joy_id=0 ; joy_id<numdevs ; joy_id++)
-       {
-               memset (&ji, 0, sizeof(ji));
-               ji.dwSize = sizeof(ji);
-               ji.dwFlags = JOY_RETURNCENTERED;
-
-               if ((mmr = joyGetPosEx (joy_id, &ji)) == JOYERR_NOERROR)
-                       break;
-       }
-
-       // abort startup if we didn't find a valid joystick
-       if (mmr != JOYERR_NOERROR)
-       {
-               Con_Printf("\njoystick not found -- no valid joysticks (%x)\n\n", mmr);
-               return;
-       }
-
-       // get the capabilities of the selected joystick
-       // abort startup if command fails
-       memset (&jc, 0, sizeof(jc));
-       if ((mmr = joyGetDevCaps (joy_id, &jc, sizeof(jc))) != JOYERR_NOERROR)
-       {
-               Con_Printf("\njoystick not found -- invalid joystick capabilities (%x)\n\n", mmr);
-               return;
-       }
-
-       // save the joystick's number of buttons and POV status
-       joy_numbuttons = jc.wNumButtons;
-       joy_haspov = (jc.wCaps & JOYCAPS_HASPOV) != 0;
-
-       // old button and POV states default to no buttons pressed
-       joy_oldbuttonstate = joy_oldpovstate = 0;
-
-       // mark the joystick as available and advanced initialization not completed
-       // this is needed as cvars are not available during initialization
-
-       joy_avail = true;
-       joy_advancedinit = false;
-
-       Con_Print("\njoystick detected\n\n");
-}
-
-
-/*
-===========
-RawValuePointer
-===========
-*/
-static PDWORD RawValuePointer (int axis)
-{
-       switch (axis)
-       {
-       case JOY_AXIS_X:
-               return &ji.dwXpos;
-       case JOY_AXIS_Y:
-               return &ji.dwYpos;
-       case JOY_AXIS_Z:
-               return &ji.dwZpos;
-       case JOY_AXIS_R:
-               return &ji.dwRpos;
-       case JOY_AXIS_U:
-               return &ji.dwUpos;
-       case JOY_AXIS_V:
-               return &ji.dwVpos;
-       }
-       return NULL; // LordHavoc: hush compiler warning
-}
-
-
-/*
-===========
-Joy_AdvancedUpdate_f
-===========
-*/
-static void Joy_AdvancedUpdate_f (void)
-{
-
-       // called once by IN_ReadJoystick and by user whenever an update is needed
-       // cvars are now available
-       int     i;
-       DWORD dwTemp;
-
-       // initialize all the maps
-       for (i = 0; i < JOY_MAX_AXES; i++)
-       {
-               dwAxisMap[i] = AxisNada;
-               dwControlMap[i] = JOY_ABSOLUTE_AXIS;
-               pdwRawValue[i] = RawValuePointer(i);
-       }
-
-       if( joy_advanced.integer == 0)
-       {
-               // default joystick initialization
-               // 2 axes only with joystick control
-               dwAxisMap[JOY_AXIS_X] = AxisTurn;
-               // dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS;
-               dwAxisMap[JOY_AXIS_Y] = AxisForward;
-               // dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS;
-       }
-       else
-       {
-               if (strcmp (joy_name.string, "joystick") != 0)
-               {
-                       // notify user of advanced controller
-                       Con_Printf("\n%s configured\n\n", joy_name.string);
-               }
-
-               // advanced initialization here
-               // data supplied by user via joy_axisn cvars
-               dwTemp = (DWORD) joy_advaxisx.value;
-               dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f;
-               dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS;
-               dwTemp = (DWORD) joy_advaxisy.value;
-               dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f;
-               dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS;
-               dwTemp = (DWORD) joy_advaxisz.value;
-               dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f;
-               dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS;
-               dwTemp = (DWORD) joy_advaxisr.value;
-               dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f;
-               dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS;
-               dwTemp = (DWORD) joy_advaxisu.value;
-               dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f;
-               dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS;
-               dwTemp = (DWORD) joy_advaxisv.value;
-               dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f;
-               dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS;
-       }
-
-       // compute the axes to collect from DirectInput
-       joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV;
-       for (i = 0; i < JOY_MAX_AXES; i++)
-       {
-               if (dwAxisMap[i] != AxisNada)
-               {
-                       joy_flags |= dwAxisFlags[i];
-               }
-       }
-}
-
-/*
-===============
-IN_ReadJoystick
-===============
-*/
-static qboolean IN_ReadJoystick (void)
-{
-
-       memset (&ji, 0, sizeof(ji));
-       ji.dwSize = sizeof(ji);
-       ji.dwFlags = joy_flags;
-
-       if (joyGetPosEx (joy_id, &ji) == JOYERR_NOERROR)
-       {
-               // this is a hack -- there is a bug in the Logitech WingMan Warrior DirectInput Driver
-               // rather than having 32768 be the zero point, they have the zero point at 32668
-               // go figure -- anyway, now we get the full resolution out of the device
-               if (joy_wwhack1.integer != 0.0)
-               {
-                       ji.dwUpos += 100;
-               }
-               return true;
-       }
-       else
-       {
-               // read error occurred
-               // turning off the joystick seems too harsh for 1 read error,
-               // but what should be done?
-               return false;
-       }
-}
-
-/*
-===========
- IN_JoystickGetAxisNum
-===========
-*/
-
-int IN_JoystickGetAxisNum(int ControlListType)
-{
-       int i;
-
-       for (i = 0; i < JOY_MAX_AXES; i++)
-               if (dwAxisMap[i] == (DWORD) ControlListType)
-                       return i;
-       return -1;
-}
-
-/*
-===========
- IN_JoystickGetAxis
-===========
-*/
-static double IN_JoystickGetAxis(int axis, double sensitivity, double deadzone)
-{
-       float   fAxisValue, fTemp;
-
-       if (!joy_avail || axis < 0 || axis >= JOY_MAX_AXES)
-               return 0; // no such axis on this joystick
-
-       // get the floating point zero-centered, potentially-inverted data for the current axis
-       fAxisValue = (float) *pdwRawValue[axis];
-
-       // move centerpoint to zero
-       fAxisValue -= 32768.0;
-
-       if (joy_wwhack2.integer != 0.0)
-       {
-               if (dwAxisMap[axis] == AxisTurn)
-               {
-                       // this is a special formula for the Logitech WingMan Warrior
-                       // y=ax^b; where a = 300 and b = 1.3
-                       // also x values are in increments of 800 (so this is factored out)
-                       // then bounds check result to level out excessively high spin rates
-                       fTemp = 300.0 * pow(abs(fAxisValue) / 800.0, 1.3);
-                       if (fTemp > 14000.0)
-                               fTemp = 14000.0;
-                       // restore direction information
-                       fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp;
-               }
-       }
-
-       // convert range from -32768..32767 to -1..1
-       fAxisValue /= 32768.0;
-
-       // deadzone around center
-       if (fabs(fAxisValue) < deadzone)
-               return 0; 
-
-       // apply sensitivity
-       return fAxisValue * sensitivity;
-}
-
-/*
-===========
- IN_JoystickKeyeventForAxis
-===========
-*/
-
-static void IN_JoystickKeyeventForAxis(int axis, int key_pos, int key_neg)
-{
-       double joytime;
-
-       if (axis < 0 || axis >= JOY_MAX_AXES)
-               return; // no such axis on this joystick
-
-       joytime = Sys_DoubleTime();
-       // no key event, continuous keydown event
-       if (joy_axescache[axis].move == joy_axescache[axis].oldmove)
-       {
-               if (joy_axescache[axis].move != 0 && joytime > joy_axescache[axis].keytime)
-               {
-                       //Con_Printf("joy %s %i %f\n", Key_KeynumToString((joy_axescache[axis].move > 0) ? key_pos : key_neg), 1, cl.time);
-                       Key_Event((joy_axescache[axis].move > 0) ? key_pos : key_neg, 0, 1);
-                       joy_axescache[axis].keytime = joytime + 0.5 / 20;
-               }
-               return;
-       }
-       // generate key up event
-       if (joy_axescache[axis].oldmove)
-       {
-               //Con_Printf("joy %s %i %f\n", Key_KeynumToString((joy_axescache[axis].oldmove > 0) ? key_pos : key_neg), 1, cl.time);
-               Key_Event((joy_axescache[axis].oldmove > 0) ? key_pos : key_neg, 0, 0);
-       }
-       // generate key down event
-       if (joy_axescache[axis].move)
-       {
-               //Con_Printf("joy %s %i %f\n", Key_KeynumToString((joy_axescache[axis].move > 0) ? key_pos : key_neg), 1, cl.time);
-               Key_Event((joy_axescache[axis].move > 0) ? key_pos : key_neg, 0, 1);
-               joy_axescache[axis].keytime = joytime + 0.5;
-       }
-}
-
-/*
-===========
- IN_JoystickBlockDoubledKeyEvents
-===========
-*/
-
-static qboolean IN_ReadJoystick (void);
-static qboolean IN_JoystickBlockDoubledKeyEvents(int keycode)
-{
-       int axis;
-
-       if (!joy_axiskeyevents.integer)
-               return false;
-
-       // block keyevent if it's going to be provided by joystick keyevent system
-       if (joy_avail)
-       {
-               // collect the joystick data, if possible
-               if (IN_ReadJoystick() != true)
-                       return false;
-               axis = IN_JoystickGetAxisNum(AxisForward);
-               if (keycode == K_UPARROW || keycode == K_DOWNARROW)
-                       if (IN_JoystickGetAxis(axis, 1, joy_axiskeyevents_deadzone.value) || joy_axescache[axis].move || joy_axescache[axis].oldmove)
-                               return true;
-               axis = IN_JoystickGetAxisNum(AxisSide);
-               if (keycode == K_RIGHTARROW || keycode == K_LEFTARROW)
-                       if (IN_JoystickGetAxis(axis, 1, joy_axiskeyevents_deadzone.value) || joy_axescache[axis].move || joy_axescache[axis].oldmove)
-                               return true;
-       }
-
-       return false;
-}
-
-/*
-===========
- IN_JoyMove
-===========
-*/
-static void IN_JoyMove (void)
-{
-       float   speed, aspeed;
-       float   fAxisValue;
-       int             i, mouselook = (in_mlook.state & 1) || freelook.integer, AxisForwardIndex = -1, AxisSideIndex = -1;
-
-       // complete initialization if first time in
-       // this is needed as cvars are not available at initialization time
-       if( joy_advancedinit != true )
-       {
-               Joy_AdvancedUpdate_f();
-               joy_advancedinit = true;
-       }
-
-       if (joy_avail)
-       {
-               int             i, key_index;
-               DWORD   buttonstate, povstate;
-
-               // loop through the joystick buttons
-               // key a joystick event or auxillary event for higher number buttons for each state change
-               buttonstate = ji.dwButtons;
-               for (i=0 ; i < (int) joy_numbuttons ; i++)
-               {
-                       if ( (buttonstate & (1<<i)) && !(joy_oldbuttonstate & (1<<i)) )
-                       {
-                               key_index = (i < 16) ? K_JOY1 : K_AUX1;
-                               Key_Event (key_index + i, 0, true);
-                       }
-                       if ( !(buttonstate & (1<<i)) && (joy_oldbuttonstate & (1<<i)) )
-                       {
-                               key_index = (i < 16) ? K_JOY1 : K_AUX1;
-                               Key_Event (key_index + i, 0, false);
-                       }
-               }
-               joy_oldbuttonstate = buttonstate;
-
-               if (joy_haspov)
-               {
-                       // convert POV information into 4 bits of state information
-                       // this avoids any potential problems related to moving from one
-                       // direction to another without going through the center position
-                       povstate = 0;
-                       if(ji.dwPOV != JOY_POVCENTERED)
-                       {
-                               if (ji.dwPOV == JOY_POVFORWARD)
-                                       povstate |= 0x01;
-                               if (ji.dwPOV == JOY_POVRIGHT)
-                                       povstate |= 0x02;
-                               if (ji.dwPOV == JOY_POVBACKWARD)
-                                       povstate |= 0x04;
-                               if (ji.dwPOV == JOY_POVLEFT)
-                                       povstate |= 0x08;
-                       }
-                       // determine which bits have changed and key an auxillary event for each change
-                       for (i=0 ; i < 4 ; i++)
-                       {
-                               if ( (povstate & (1<<i)) && !(joy_oldpovstate & (1<<i)) )
-                               {
-                                       Key_Event (K_AUX29 + i, 0, true);
-                               }
-
-                               if ( !(povstate & (1<<i)) && (joy_oldpovstate & (1<<i)) )
-                               {
-                                       Key_Event (K_AUX29 + i, 0, false);
-                               }
-                       }
-                       joy_oldpovstate = povstate;
-               }
-       }
-
-       // verify joystick is available and that the user wants to use it
-       if (!joy_avail || !in_joystick.integer)
-       {
-               return;
-       }
-
-       // collect the joystick data, if possible
-       if (IN_ReadJoystick () != true)
-       {
-               return;
-       }
-
-       if (in_speed.state & 1)
-               speed = cl_movespeedkey.value;
-       else
-               speed = 1;
-       // LordHavoc: viewzoom affects sensitivity for sniping
-       aspeed = speed * cl.realframetime * cl.viewzoom;
-
-       // loop through the axes
-       for (i = 0; i < JOY_MAX_AXES; i++)
-       {
-               // convert axis to real move
-               switch (dwAxisMap[i])
-               {
-                       case AxisForward:
-                               if (AxisForwardIndex < 0)
-                                       AxisForwardIndex = i;
-                               if ((joy_advanced.integer == 0) && mouselook)
-                               {
-                                       // user wants forward control to become look control
-                                       fAxisValue = IN_JoystickGetAxis(i, joy_pitchsensitivity.value, joy_pitchthreshold.value);
-                                       if (fAxisValue != 0)
-                                       {
-                                               // if mouse invert is on, invert the joystick pitch value
-                                               // only absolute control support here (joy_advanced is false)
-                                               if (m_pitch.value < 0.0)
-                                                       cl.viewangles[PITCH] -= fAxisValue * aspeed * cl_pitchspeed.value;
-                                               else
-                                                       cl.viewangles[PITCH] += fAxisValue * aspeed * cl_pitchspeed.value;
-                                               V_StopPitchDrift();
-                                       }
-                                       else
-                                       {
-                                               // no pitch movement
-                                               // disable pitch return-to-center unless requested by user
-                                               // *** this code can be removed when the lookspring bug is fixed
-                                               // *** the bug always has the lookspring feature on
-                                               if (lookspring.value == 0.0)
-                                                       V_StopPitchDrift();
-                                       }
-                               }
-                               else
-                               {
-                                       // user wants forward control to be forward control
-                                       fAxisValue = IN_JoystickGetAxis(i, joy_forwardsensitivity.value, joy_forwardthreshold.value);
-                                       cl.cmd.forwardmove += fAxisValue * speed * cl_forwardspeed.value;
-                               }
-                               break;
-
-                       case AxisSide:
-                               if (AxisSideIndex < 0)
-                                       AxisSideIndex = i;
-                               fAxisValue = IN_JoystickGetAxis(i, joy_sidesensitivity.value, joy_sidethreshold.value);
-                               cl.cmd.sidemove += fAxisValue * speed * cl_sidespeed.value;
-                               break;
-
-                       case AxisTurn:
-                               if ((in_strafe.state & 1) || (lookstrafe.integer && mouselook))
-                               {
-                                       // user wants turn control to become side control
-                                       fAxisValue = IN_JoystickGetAxis(i, joy_sidesensitivity.value, joy_sidethreshold.value);
-                                       cl.cmd.sidemove -= fAxisValue * speed * cl_sidespeed.value;
-                               }
-                               else
-                               {
-                                       // user wants turn control to be turn control
-                                       fAxisValue = IN_JoystickGetAxis(i, joy_yawsensitivity.value, joy_yawthreshold.value);
-                                       if (dwControlMap[i] == JOY_ABSOLUTE_AXIS)
-                                               cl.viewangles[YAW] += fAxisValue * aspeed * cl_yawspeed.value;
-                                       else
-                                               cl.viewangles[YAW] += fAxisValue * speed * 180.0;
-                               }
-                               break;
-
-                       case AxisLook:
-                               fAxisValue = IN_JoystickGetAxis(i, joy_pitchsensitivity.value, joy_pitchthreshold.value);
-                               if (mouselook)
-                               {
-                                       if (fAxisValue != 0)
-                                       {
-                                               // pitch movement detected and pitch movement desired by user
-                                               if (dwControlMap[i] == JOY_ABSOLUTE_AXIS)
-                                                       cl.viewangles[PITCH] += fAxisValue * aspeed * cl_pitchspeed.value;
-                                               else
-                                                       cl.viewangles[PITCH] += fAxisValue * speed * 180.0;
-                                               V_StopPitchDrift();
-                                       }
-                                       else
-                                       {
-                                               // no pitch movement
-                                               // disable pitch return-to-center unless requested by user
-                                               // *** this code can be removed when the lookspring bug is fixed
-                                               // *** the bug always has the lookspring feature on
-                                               if(lookspring.integer == 0)
-                                                       V_StopPitchDrift();
-                                       }
-                               }
-                               break;
-
-                       default:
-                               fAxisValue = IN_JoystickGetAxis(i, 1, 0.01);
-                               break;
-               }
-       
-               // cache for keyevents
-               joy_axescache[i].oldmove = joy_axescache[i].move;
-               joy_axescache[i].move = IN_JoystickGetAxis(i, 1, joy_axiskeyevents_deadzone.value);
-       }
-
-       // run keyevents
-       if (joy_axiskeyevents.integer)
-       {
-               IN_JoystickKeyeventForAxis(AxisForwardIndex, K_DOWNARROW, K_UPARROW);
-               IN_JoystickKeyeventForAxis(AxisSideIndex, K_RIGHTARROW, K_LEFTARROW);
-       }
-}
-
 static void IN_Init(void)
 {
        uiWheelMessage = RegisterWindowMessage ( "MSWHEEL_ROLLMSG" );
-
-       // joystick variables
-       Cvar_RegisterVariable (&in_joystick);
-       Cvar_RegisterVariable (&joy_name);
-       Cvar_RegisterVariable (&joy_advanced);
-       Cvar_RegisterVariable (&joy_advaxisx);
-       Cvar_RegisterVariable (&joy_advaxisy);
-       Cvar_RegisterVariable (&joy_advaxisz);
-       Cvar_RegisterVariable (&joy_advaxisr);
-       Cvar_RegisterVariable (&joy_advaxisu);
-       Cvar_RegisterVariable (&joy_advaxisv);
-       Cvar_RegisterVariable (&joy_forwardthreshold);
-       Cvar_RegisterVariable (&joy_sidethreshold);
-       Cvar_RegisterVariable (&joy_pitchthreshold);
-       Cvar_RegisterVariable (&joy_yawthreshold);
-       Cvar_RegisterVariable (&joy_forwardsensitivity);
-       Cvar_RegisterVariable (&joy_sidesensitivity);
-       Cvar_RegisterVariable (&joy_pitchsensitivity);
-       Cvar_RegisterVariable (&joy_yawsensitivity);
-       Cvar_RegisterVariable (&joy_wwhack1);
-       Cvar_RegisterVariable (&joy_wwhack2);
-       Cvar_RegisterVariable (&joy_axiskeyevents);
-       Cvar_RegisterVariable (&joy_axiskeyevents_deadzone);
        Cvar_RegisterVariable (&vid_forcerefreshrate);
-       Cmd_AddCommand ("joyadvancedupdate", Joy_AdvancedUpdate_f, "applies current joyadv* cvar settings to the joystick driver");
 }
 
 static void IN_Shutdown(void)
diff --git a/view.c b/view.c
index 86902ad883337c126061f3a221f7059b7b1d10a7..3e0ccc57ebbf17154f9e4e8dd536fdc818222de5 100644 (file)
--- a/view.c
+++ b/view.c
@@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 #include "cl_collision.h"
+#include "image.h"
 
 void CL_VM_UpdateDmgGlobals (int dmg_take, int dmg_save, vec3_t dmg_origin);
 
@@ -369,7 +370,8 @@ static void V_BonusFlash_f (void)
 ==============================================================================
 */
 
-extern matrix4x4_t viewmodelmatrix;
+extern matrix4x4_t viewmodelmatrix_nobob;
+extern matrix4x4_t viewmodelmatrix_withbob;
 
 #include "cl_collision.h"
 #include "csprogs.h"
@@ -433,6 +435,7 @@ void V_CalcRefdef (void)
        entity_t *ent;
        float vieworg[3], viewangles[3], smoothtime;
        float gunorg[3], gunangles[3];
+       matrix4x4_t tmpmatrix;
        
        static float viewheightavg;
        float viewheight;       
@@ -444,7 +447,8 @@ void V_CalcRefdef (void)
 #endif
        trace_t trace;
        VectorClear(gunorg);
-       viewmodelmatrix = identitymatrix;
+       viewmodelmatrix_nobob = identitymatrix;
+       viewmodelmatrix_withbob = identitymatrix;
        r_refdef.view.matrix = identitymatrix;
        if (cls.state == ca_connected && cls.signon == SIGNONS)
        {
@@ -473,7 +477,9 @@ void V_CalcRefdef (void)
                                r_refdef.view.matrix = ent->render.matrix;
                                Matrix4x4_AdjustOrigin(&r_refdef.view.matrix, 0, 0, cl.stats[STAT_VIEWHEIGHT]);
                        }
-                       viewmodelmatrix = r_refdef.view.matrix;
+                       Matrix4x4_Copy(&viewmodelmatrix_nobob, &r_refdef.view.matrix);
+                       Matrix4x4_ConcatScale(&viewmodelmatrix_nobob, cl_viewmodel_scale.value);
+                       Matrix4x4_Copy(&viewmodelmatrix_withbob, &viewmodelmatrix_nobob);
                }
                else
                {
@@ -793,13 +799,23 @@ void V_CalcRefdef (void)
                        }
                        // calculate a view matrix for rendering the scene
                        if (v_idlescale.value)
-                               Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, vieworg[0], vieworg[1], vieworg[2], 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, 1);
-                       else
-                               Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, vieworg[0], vieworg[1], vieworg[2], viewangles[0], viewangles[1], viewangles[2], 1);
+                       {
+                               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_CreateFromQuakeEntity(&viewmodelmatrix, gunorg[0], gunorg[1], gunorg[2], gunangles[0], gunangles[1], gunangles[2], cl_viewmodel_scale.value);
-                       VectorCopy(vieworg, cl.csqc_origin);
-                       VectorCopy(viewangles, cl.csqc_angles);
+                       Matrix4x4_Copy(&viewmodelmatrix_nobob, &r_refdef.view.matrix);
+                       Matrix4x4_ConcatScale(&viewmodelmatrix_nobob, cl_viewmodel_scale.value);
+
+                       Matrix4x4_CreateFromQuakeEntity(&viewmodelmatrix_withbob, gunorg[0], gunorg[1], gunorg[2], gunangles[0], gunangles[1], gunangles[2], cl_viewmodel_scale.value);
+                       VectorCopy(vieworg, cl.csqc_vieworiginfromengine);
+                       VectorCopy(viewangles, cl.csqc_viewanglesfromengine);
+
+                       Matrix4x4_Invert_Simple(&tmpmatrix, &r_refdef.view.matrix);
+                       Matrix4x4_Concat(&cl.csqc_viewmodelmatrixfromengine, &tmpmatrix, &viewmodelmatrix_withbob);
                }
        }
 }
@@ -923,10 +939,22 @@ void V_CalcViewBlend(void)
                        a2 = 1 / r_refdef.viewblend[3];
                        VectorScale(r_refdef.viewblend, a2, r_refdef.viewblend);
                }
-               r_refdef.viewblend[0] = bound(0.0f, r_refdef.viewblend[0] * (1.0f/255.0f), 1.0f);
-               r_refdef.viewblend[1] = bound(0.0f, r_refdef.viewblend[1] * (1.0f/255.0f), 1.0f);
-               r_refdef.viewblend[2] = bound(0.0f, r_refdef.viewblend[2] * (1.0f/255.0f), 1.0f);
+               r_refdef.viewblend[0] = bound(0.0f, r_refdef.viewblend[0], 255.0f);
+               r_refdef.viewblend[1] = bound(0.0f, r_refdef.viewblend[1], 255.0f);
+               r_refdef.viewblend[2] = bound(0.0f, r_refdef.viewblend[2], 255.0f);
                r_refdef.viewblend[3] = bound(0.0f, r_refdef.viewblend[3] * gl_polyblend.value, 1.0f);
+               if (vid.sRGB3D)
+               {
+                       r_refdef.viewblend[0] = Image_LinearFloatFromsRGB(r_refdef.viewblend[0]);
+                       r_refdef.viewblend[1] = Image_LinearFloatFromsRGB(r_refdef.viewblend[1]);
+                       r_refdef.viewblend[2] = Image_LinearFloatFromsRGB(r_refdef.viewblend[2]);
+               }
+               else
+               {
+                       r_refdef.viewblend[0] *= (1.0f/256.0f);
+                       r_refdef.viewblend[1] *= (1.0f/256.0f);
+                       r_refdef.viewblend[2] *= (1.0f/256.0f);
+               }
                
                // Samual: Ugly hack, I know. But it's the best we can do since
                // there is no way to detect client states from the engine.
diff --git a/world.c b/world.c
index b5b1def2763aabc3851ccad259c014ee5e7db178..3a6503d702b0015110ab5877d42bdef1ba3b1cc9 100644 (file)
--- a/world.c
+++ b/world.c
@@ -341,6 +341,7 @@ 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_autodisable = {0, "physics_ode_autodisable", "1", "automatic disabling of objects which dont move for long period of time, makes object stacking a lot faster"};
@@ -1495,6 +1496,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);
@@ -1746,7 +1748,6 @@ static void World_Physics_Frame_BodyToEntity(world_t *world, prvm_edict_t *ed)
        int movetype;
        matrix4x4_t bodymatrix;
        matrix4x4_t entitymatrix;
-       prvm_eval_t *val;
        vec3_t angles;
        vec3_t avelocity;
        vec3_t forward, left, up;
@@ -1756,11 +1757,10 @@ static void World_Physics_Frame_BodyToEntity(world_t *world, prvm_edict_t *ed)
        int jointtype;
        if (!body)
                return;
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.movetype);
-       movetype = (int)val->_float;
+       movetype = (int)PRVM_gameedictfloat(ed, movetype);
        if (movetype != MOVETYPE_PHYSICS)
        {
-               jointtype = 0;val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.jointtype);if (val) jointtype = (int)val->_float;
+               jointtype = (int)PRVM_gameedictfloat(ed, jointtype);
                switch(jointtype)
                {
                        // TODO feed back data from physics
@@ -1817,14 +1817,14 @@ static void World_Physics_Frame_BodyToEntity(world_t *world, prvm_edict_t *ed)
                avelocity[PITCH] *= pitchsign;
        }
 
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.origin);if (val) VectorCopy(origin, val->vector);
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.velocity);if (val) VectorCopy(velocity, val->vector);
-       //val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.axis_forward);if (val) VectorCopy(forward, val->vector);
-       //val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.axis_left);if (val) VectorCopy(left, val->vector);
-       //val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.axis_up);if (val) VectorCopy(up, val->vector);
-       //val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.spinvelocity);if (val) VectorCopy(spinvelocity, val->vector);
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.angles);if (val) VectorCopy(angles, val->vector);
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.avelocity);if (val) VectorCopy(avelocity, val->vector);
+       VectorCopy(origin, PRVM_gameedictvector(ed, origin));
+       VectorCopy(velocity, PRVM_gameedictvector(ed, velocity));
+       //VectorCopy(forward, PRVM_gameedictvector(ed, axis_forward));
+       //VectorCopy(left, PRVM_gameedictvector(ed, axis_left));
+       //VectorCopy(up, PRVM_gameedictvector(ed, axis_up));
+       //VectorCopy(spinvelocity, PRVM_gameedictvector(ed, spinvelocity));
+       VectorCopy(angles, PRVM_gameedictvector(ed, angles));
+       VectorCopy(avelocity, PRVM_gameedictvector(ed, avelocity));
 
        // values for BodyFromEntity to check if the qc modified anything later
        VectorCopy(origin, ed->priv.server->ode_origin);
@@ -1850,19 +1850,18 @@ static void World_Physics_Frame_JointFromEntity(world_t *world, prvm_edict_t *ed
        int enemy = 0, aiment = 0;
        vec3_t origin, velocity, angles, forward, left, up, movedir;
        vec_t CFM, ERP, FMax, Stop, Vel;
-       prvm_eval_t *val;
        VectorClear(origin);
        VectorClear(velocity);
        VectorClear(angles);
        VectorClear(movedir);
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.movetype);if (val) movetype = (int)val->_float;
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.jointtype);if (val) jointtype = (int)val->_float;
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.enemy);if (val) enemy = val->_int;
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.aiment);if (val) aiment = val->_int;
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.origin);if (val) VectorCopy(val->vector, origin);
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.velocity);if (val) VectorCopy(val->vector, velocity);
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.angles);if (val) VectorCopy(val->vector, angles);
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.movedir);if (val) VectorCopy(val->vector, movedir);
+       movetype = (int)PRVM_gameedictfloat(ed, movetype);
+       jointtype = (int)PRVM_gameedictfloat(ed, jointtype);
+       enemy = PRVM_gameedictedict(ed, enemy);
+       aiment = PRVM_gameedictedict(ed, aiment);
+       VectorCopy(PRVM_gameedictvector(ed, origin), origin);
+       VectorCopy(PRVM_gameedictvector(ed, velocity), velocity);
+       VectorCopy(PRVM_gameedictvector(ed, angles), angles);
+       VectorCopy(PRVM_gameedictvector(ed, movedir), movedir);
        if(movetype == MOVETYPE_PHYSICS)
                jointtype = 0; // can't have both
        if(enemy <= 0 || enemy >= prog->num_edicts || prog->edicts[enemy].priv.required->free || prog->edicts[enemy].priv.server->ode_body == 0)
@@ -2044,7 +2043,6 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed)
        int triangleindex;
        int vertexindex;
        mempool_t *mempool;
-       prvm_eval_t *val;
        qboolean modified = false;
        vec3_t angles;
        vec3_t avelocity;
@@ -2074,9 +2072,9 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed)
 #endif
        VectorClear(entmins);
        VectorClear(entmaxs);
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.solid);if (val) solid = (int)val->_float;
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.movetype);if (val) movetype = (int)val->_float;
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.scale);if (val && val->_float) scale = val->_float;
+       solid = (int)PRVM_gameedictfloat(ed, solid);
+       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;
@@ -2088,9 +2086,8 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed)
        switch(solid)
        {
        case SOLID_BSP:
-               val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.modelindex);
-               if (val)
-                       modelindex = (int)val->_float;
+       case SOLID_PHYSICS_TRIMESH:
+               modelindex = (int)PRVM_gameedictfloat(ed, modelindex);
                if (world == &sv.world)
                        model = SV_GetModelByIndex(modelindex);
                else if (world == &cl.world)
@@ -2101,7 +2098,7 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed)
                {
                        VectorScale(model->normalmins, scale, entmins);
                        VectorScale(model->normalmaxs, scale, entmaxs);
-                       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.mass);if (val) massval = val->_float;
+                       massval = PRVM_gameedictfloat(ed, mass);
                }
                else
                {
@@ -2115,9 +2112,9 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed)
        case SOLID_PHYSICS_BOX:
        case SOLID_PHYSICS_SPHERE:
        case SOLID_PHYSICS_CAPSULE:
-               val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.mins);if (val) VectorCopy(val->vector, entmins);
-               val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.maxs);if (val) VectorCopy(val->vector, entmaxs);
-               val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.mass);if (val) massval = val->_float;
+               VectorCopy(PRVM_gameedictvector(ed, mins), entmins);
+               VectorCopy(PRVM_gameedictvector(ed, maxs), entmaxs);
+               massval = PRVM_gameedictfloat(ed, mass);
                break;
        default:
                if (ed->priv.server->ode_physics)
@@ -2157,7 +2154,7 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed)
                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_EDICTFIELDVALUE(ed, prog->fieldoffsets.classname)->string));
+                               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)));
                        massval = 1.0f;
                        VectorSet(geomsize, 1.0f, 1.0f, 1.0f);
                }
@@ -2165,10 +2162,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_EDICTFIELDVALUE(ed, prog->fieldoffsets.classname)->string));
+                               Con_Printf("entity %i (classname %s) has no model\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(PRVM_gameedictstring(ed, classname)));
                                goto treatasbox;
                        }
                        // add an optimized mesh to the model containing only the SUPERCONTENTS_SOLID surfaces
@@ -2176,7 +2174,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_EDICTFIELDVALUE(ed, prog->fieldoffsets.classname)->string));
+                               Con_Printf("entity %i (classname %s) has no geometry\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(PRVM_gameedictstring(ed, classname)));
                                goto treatasbox;
                        }
                        // ODE requires persistent mesh storage, so we need to copy out
@@ -2294,16 +2292,16 @@ treatasbox:
        VectorClear(angles);
        VectorClear(avelocity);
        gravity = true;
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.origin);if (val) VectorCopy(val->vector, origin);
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.velocity);if (val) VectorCopy(val->vector, velocity);
-       //val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.axis_forward);if (val) VectorCopy(val->vector, forward);
-       //val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.axis_left);if (val) VectorCopy(val->vector, left);
-       //val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.axis_up);if (val) VectorCopy(val->vector, up);
-       //val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.spinvelocity);if (val) VectorCopy(val->vector, spinvelocity);
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.angles);if (val) VectorCopy(val->vector, angles);
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.avelocity);if (val) VectorCopy(val->vector, avelocity);
-       val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.gravity);if (val) { if(val->_float != 0.0f && val->_float < 0.5f) gravity = false; }
-       if(ed == prog->edicts)
+       VectorCopy(PRVM_gameedictvector(ed, origin), origin);
+       VectorCopy(PRVM_gameedictvector(ed, velocity), velocity);
+       //VectorCopy(PRVM_gameedictvector(ed, axis_forward), forward);
+       //VectorCopy(PRVM_gameedictvector(ed, axis_left), left);
+       //VectorCopy(PRVM_gameedictvector(ed, axis_up), up);
+       //VectorCopy(PRVM_gameedictvector(ed, spinvelocity), spinvelocity);
+       VectorCopy(PRVM_gameedictvector(ed, angles), angles);
+       VectorCopy(PRVM_gameedictvector(ed, avelocity), avelocity);
+       if (PRVM_gameedictfloat(ed, gravity) != 0.0f && PRVM_gameedictfloat(ed, gravity) < 0.5f) gravity = false;
+       if (ed == prog->edicts)
                gravity = false;
 
        // compatibility for legacy entities
@@ -2352,9 +2350,9 @@ treatasbox:
                if (IS_NAN(test))
                {
                        modified = true;
-                       //Con_Printf("Fixing NAN values on entity %i : .classname = \"%s\" .origin = '%f %f %f' .velocity = '%f %f %f' .axis_forward = '%f %f %f' .axis_left = '%f %f %f' .axis_up = %f %f %f' .spinvelocity = '%f %f %f'\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.classname)->string), 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]);
+                       //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_EDICTFIELDVALUE(ed, prog->fieldoffsets.classname)->string), 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(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);
@@ -2506,7 +2504,6 @@ static void nearCallback (void *data, dGeomID o1, dGeomID o2)
        dJointID c;
        int i;
        int numcontacts;
-       prvm_eval_t *val;
        float bouncefactor1 = 0.0f;
        float bouncestop1 = 60.0f / 800.0f;
        float bouncefactor2 = 0.0f;
@@ -2541,13 +2538,10 @@ static void nearCallback (void *data, dGeomID o1, dGeomID o2)
                ed1 = NULL;
        if(ed1)
        {
-               val = PRVM_EDICTFIELDVALUE(ed1, prog->fieldoffsets.bouncefactor);
-               if (val!=0 && val->_float)
-                       bouncefactor1 = val->_float;
-
-               val = PRVM_EDICTFIELDVALUE(ed1, prog->fieldoffsets.bouncestop);
-               if (val!=0 && val->_float)
-                       bouncestop1 = val->_float;
+               bouncefactor1 = PRVM_gameedictfloat(ed1, bouncefactor);
+               bouncestop1 = PRVM_gameedictfloat(ed1, bouncestop);
+               if (!bouncestop1)
+                       bouncestop1 = 60.0f / 800.0f;
        }
 
        ed2 = (prvm_edict_t *) dGeomGetData(o2);
@@ -2555,22 +2549,19 @@ static void nearCallback (void *data, dGeomID o1, dGeomID o2)
                ed2 = NULL;
        if(ed2)
        {
-               val = PRVM_EDICTFIELDVALUE(ed2, prog->fieldoffsets.bouncefactor);
-               if (val!=0 && val->_float)
-                       bouncefactor2 = val->_float;
-
-               val = PRVM_EDICTFIELDVALUE(ed2, prog->fieldoffsets.bouncestop);
-               if (val!=0 && val->_float)
-                       bouncestop2 = val->_float;
+               bouncefactor2 = PRVM_gameedictfloat(ed2, bouncefactor);
+               bouncestop2 = PRVM_gameedictfloat(ed2, bouncestop);
+               if (!bouncestop2)
+                       bouncestop2 = 60.0f / 800.0f;
        }
 
        if(!strcmp(prog->name, "server"))
        {
-               if(ed1 && ed1->fields.server->touch)
+               if(ed1 && PRVM_serveredictfunction(ed1, touch))
                {
                        SV_LinkEdict_TouchAreaGrid_Call(ed1, ed2 ? ed2 : prog->edicts);
                }
-               if(ed2 && ed2->fields.server->touch)
+               if(ed2 && PRVM_serveredictfunction(ed2, touch))
                {
                        SV_LinkEdict_TouchAreaGrid_Call(ed2, ed1 ? ed1 : prog->edicts);
                }
@@ -2649,7 +2640,7 @@ void World_Physics_Frame(world_t *world, double frametime, double gravity)
                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));
 
diff --git a/zone.c b/zone.c
index 585c10396d03db32e726ccaef168d1eb32b52043..72432d551a9ef485df3eae579130225548f657ce 100644 (file)
--- a/zone.c
+++ b/zone.c
@@ -634,7 +634,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)
                {