]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - clvm_cmds.c
patch from esteel making the findkeysforcommand builtin available in
[xonotic/darkplaces.git] / clvm_cmds.c
index 8ce9adaa9fc6e95200eb1c37256cb5adfacc11fd..289e531eed039e9391c2aed589f1c2581128603d 100644 (file)
@@ -4,6 +4,8 @@
 #include "csprogs.h"
 #include "cl_collision.h"
 #include "r_shadow.h"
+#include "jpeg.h"
+#include "image.h"
 
 //============================================================================
 // Client
 //4 feature darkplaces csqc: add builtins to clientside qc for gl calls
 
 sfx_t *S_FindName(const char *name);
-int Sbar_GetPlayer (int index);
+int Sbar_GetSortedPlayerIndex (int index);
 void Sbar_SortFrags (void);
 void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius);
 void CSQC_RelinkAllEntities (int drawmask);
 void CSQC_RelinkCSQCEntities (void);
 const char *Key_GetBind (int key);
 
-
-
-
-
-
 // #1 void(vector ang) makevectors
 static void VM_CL_makevectors (void)
 {
@@ -39,7 +36,7 @@ static void VM_CL_makevectors (void)
 }
 
 // #2 void(entity e, vector o) setorigin
-static void VM_CL_setorigin (void)
+void VM_CL_setorigin (void)
 {
        prvm_edict_t    *e;
        float   *org;
@@ -61,41 +58,71 @@ static void VM_CL_setorigin (void)
        CL_LinkEdict(e);
 }
 
+static void SetMinMaxSize (prvm_edict_t *e, float *min, float *max)
+{
+       int             i;
+
+       for (i=0 ; i<3 ; i++)
+               if (min[i] > max[i])
+                       PRVM_ERROR("SetMinMaxSize: backwards mins/maxs");
+
+       // set derived values
+       VectorCopy (min, e->fields.client->mins);
+       VectorCopy (max, e->fields.client->maxs);
+       VectorSubtract (max, min, e->fields.client->size);
+
+       CL_LinkEdict (e);
+}
+
 // #3 void(entity e, string m) setmodel
-static void VM_CL_setmodel (void)
+void VM_CL_setmodel (void)
 {
        prvm_edict_t    *e;
        const char              *m;
-       struct model_s  *mod;
+       dp_model_t *mod;
        int                             i;
 
        VM_SAFEPARMCOUNT(2, VM_CL_setmodel);
 
        e = PRVM_G_EDICT(OFS_PARM0);
+       e->fields.client->modelindex = 0;
+       e->fields.client->model = 0;
+
        m = PRVM_G_STRING(OFS_PARM1);
+       mod = NULL;
        for (i = 0;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
        {
                if (!strcmp(cl.csqc_model_precache[i]->name, m))
                {
-                       e->fields.client->model = PRVM_SetEngineString(cl.csqc_model_precache[i]->name);
+                       mod = cl.csqc_model_precache[i];
+                       e->fields.client->model = PRVM_SetEngineString(mod->name);
                        e->fields.client->modelindex = -(i+1);
-                       return;
+                       break;
                }
        }
 
-       for (i = 0;i < MAX_MODELS;i++)
-       {
-               mod = cl.model_precache[i];
-               if (mod && !strcmp(mod->name, m))
+       if( !mod ) {
+               for (i = 0;i < MAX_MODELS;i++)
                {
-                       e->fields.client->model = PRVM_SetEngineString(mod->name);
-                       e->fields.client->modelindex = i;
-                       return;
+                       mod = cl.model_precache[i];
+                       if (mod && !strcmp(mod->name, m))
+                       {
+                               e->fields.client->model = PRVM_SetEngineString(mod->name);
+                               e->fields.client->modelindex = i;
+                               break;
+                       }
                }
        }
 
-       e->fields.client->modelindex = 0;
-       e->fields.client->model = 0;
+       if( mod ) {
+               // TODO: check if this breaks needed consistency and maybe add a cvar for it too?? [1/10/2008 Black]
+               //SetMinMaxSize (e, mod->normalmins, mod->normalmaxs);
+       }
+       else
+       {
+               SetMinMaxSize (e, vec3_origin, vec3_origin);
+               VM_Warning ("setmodel: model '%s' not precached\n", m);
+       }
 }
 
 // #4 void(entity e, vector min, vector max) setsize
@@ -119,9 +146,7 @@ static void VM_CL_setsize (void)
        min = PRVM_G_VECTOR(OFS_PARM1);
        max = PRVM_G_VECTOR(OFS_PARM2);
 
-       VectorCopy (min, e->fields.client->mins);
-       VectorCopy (max, e->fields.client->maxs);
-       VectorSubtract (max, min, e->fields.client->size);
+       SetMinMaxSize( e, min, max );
 
        CL_LinkEdict(e);
 }
@@ -200,8 +225,6 @@ static void VM_CL_spawn (void)
 {
        prvm_edict_t *ed;
        ed = PRVM_ED_Alloc();
-       // FIXME: WTF.. this should be removed imo.. entnum points to the server.. [12/17/2007 Black]
-       ed->fields.client->entnum = PRVM_NUM_FOR_EDICT(ed);     //[515]: not needed any more ?
        VM_RETURN_EDICT(ed);
 }
 
@@ -338,11 +361,11 @@ static void VM_CL_tracetoss (void)
 
 
 // #20 void(string s) precache_model
-static void VM_CL_precache_model (void)
+void VM_CL_precache_model (void)
 {
        const char      *name;
        int                     i;
-       model_t         *m;
+       dp_model_t              *m;
 
        VM_SAFEPARMCOUNT(1, VM_CL_precache_model);
 
@@ -363,7 +386,7 @@ static void VM_CL_precache_model (void)
                {
                        if (!cl.csqc_model_precache[i])
                        {
-                               cl.csqc_model_precache[i] = (model_t*)m;
+                               cl.csqc_model_precache[i] = (dp_model_t*)m;
                                PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
                                return;
                        }
@@ -640,33 +663,35 @@ extern qboolean CSQC_AddRenderEdict (prvm_edict_t *ed);//csprogs.c
 static void CSQC_R_RecalcView (void)
 {
        extern matrix4x4_t viewmodelmatrix;
-       Matrix4x4_CreateFromQuakeEntity(&r_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(&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);
 }
 
 void CL_RelinkLightFlashes(void);
 //#300 void() clearscene (EXT_CSQC)
-static void VM_CL_R_ClearScene (void)
+void VM_CL_R_ClearScene (void)
 {
        VM_SAFEPARMCOUNT(0, VM_CL_R_ClearScene);
        // clear renderable entity and light lists
-       r_refdef.numentities = 0;
-       r_refdef.numlights = 0;
+       r_refdef.scene.numentities = 0;
+       r_refdef.scene.numlights = 0;
        // FIXME: restore these to the values from VM_CL_UpdateView
-       r_view.x = 0;
-       r_view.y = 0;
-       r_view.z = 0;
-       r_view.width = vid.width;
-       r_view.height = vid.height;
-       r_view.depth = 1;
+       r_refdef.view.x = 0;
+       r_refdef.view.y = 0;
+       r_refdef.view.z = 0;
+       r_refdef.view.width = vid.width;
+       r_refdef.view.height = vid.height;
+       r_refdef.view.depth = 1;
        // FIXME: restore frustum_x/frustum_y
-       r_view.useperspective = true;
-       r_view.frustum_y = tan(scr_fov.value * M_PI / 360.0) * (3.0/4.0) * cl.viewzoom;
-       r_view.frustum_x = r_view.frustum_y * (float)r_view.width / (float)r_view.height / vid_pixelheight.value;
-       r_view.frustum_x *= r_refdef.frustumscale_x;
-       r_view.frustum_y *= r_refdef.frustumscale_y;
-       r_view.ortho_x = scr_fov.value * (3.0 / 4.0) * (float)r_view.width / (float)r_view.height / vid_pixelheight.value;
-       r_view.ortho_y = scr_fov.value * (3.0 / 4.0);
+       r_refdef.view.useperspective = true;
+       r_refdef.view.frustum_y = tan(scr_fov.value * M_PI / 360.0) * (3.0/4.0) * cl.viewzoom;
+       r_refdef.view.frustum_x = r_refdef.view.frustum_y * (float)r_refdef.view.width / (float)r_refdef.view.height / vid_pixelheight.value;
+       r_refdef.view.frustum_x *= r_refdef.frustumscale_x;
+       r_refdef.view.frustum_y *= r_refdef.frustumscale_y;
+       r_refdef.view.ortho_x = scr_fov.value * (3.0 / 4.0) * (float)r_refdef.view.width / (float)r_refdef.view.height / vid_pixelheight.value;
+       r_refdef.view.ortho_y = scr_fov.value * (3.0 / 4.0);
+       r_refdef.view.clear = true;
+       r_refdef.view.isoverlay = false;
        // FIXME: restore cl.csqc_origin
        // FIXME: restore cl.csqc_angles
        cl.csqc_vidvars.drawworld = true;
@@ -677,7 +702,7 @@ static void VM_CL_R_ClearScene (void)
 //#301 void(float mask) addentities (EXT_CSQC)
 extern void CSQC_Predraw (prvm_edict_t *ed);//csprogs.c
 extern void CSQC_Think (prvm_edict_t *ed);//csprogs.c
-static void VM_CL_R_AddEntities (void)
+void VM_CL_R_AddEntities (void)
 {
        int                     i, drawmask;
        prvm_edict_t *ed;
@@ -706,14 +731,14 @@ static void VM_CL_R_AddEntities (void)
 }
 
 //#302 void(entity ent) addentity (EXT_CSQC)
-static void VM_CL_R_AddEntity (void)
+void VM_CL_R_AddEntity (void)
 {
        VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
        CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0));
 }
 
 //#303 float(float property, ...) setproperty (EXT_CSQC)
-static void VM_CL_R_SetView (void)
+void VM_CL_R_SetView (void)
 {
        int             c;
        float   *f;
@@ -728,41 +753,41 @@ static void VM_CL_R_SetView (void)
        switch(c)
        {
        case VF_MIN:
-               r_view.x = (int)(f[0] * vid.width / vid_conwidth.value);
-               r_view.y = (int)(f[1] * vid.height / vid_conheight.value);
+               r_refdef.view.x = (int)(f[0] * vid.width / vid_conwidth.value);
+               r_refdef.view.y = (int)(f[1] * vid.height / vid_conheight.value);
                break;
        case VF_MIN_X:
-               r_view.x = (int)(k * vid.width / vid_conwidth.value);
+               r_refdef.view.x = (int)(k * vid.width / vid_conwidth.value);
                break;
        case VF_MIN_Y:
-               r_view.y = (int)(k * vid.height / vid_conheight.value);
+               r_refdef.view.y = (int)(k * vid.height / vid_conheight.value);
                break;
        case VF_SIZE:
-               r_view.width = (int)(f[0] * vid.width / vid_conwidth.value);
-               r_view.height = (int)(f[1] * vid.height / vid_conheight.value);
-               break;
-       case VF_SIZE_Y:
-               r_view.width = (int)(k * vid.width / vid_conwidth.value);
+               r_refdef.view.width = (int)(f[0] * vid.width / vid_conwidth.value);
+               r_refdef.view.height = (int)(f[1] * vid.height / vid_conheight.value);
                break;
        case VF_SIZE_X:
-               r_view.height = (int)(k * vid.height / vid_conheight.value);
+               r_refdef.view.width = (int)(k * vid.width / vid_conwidth.value);
+               break;
+       case VF_SIZE_Y:
+               r_refdef.view.height = (int)(k * vid.height / vid_conheight.value);
                break;
        case VF_VIEWPORT:
-               r_view.x = (int)(f[0] * vid.width / vid_conwidth.value);
-               r_view.y = (int)(f[1] * vid.height / vid_conheight.value);
+               r_refdef.view.x = (int)(f[0] * vid.width / vid_conwidth.value);
+               r_refdef.view.y = (int)(f[1] * vid.height / vid_conheight.value);
                f = PRVM_G_VECTOR(OFS_PARM2);
-               r_view.width = (int)(f[0] * vid.width / vid_conwidth.value);
-               r_view.height = (int)(f[1] * vid.height / vid_conheight.value);
+               r_refdef.view.width = (int)(f[0] * vid.width / vid_conwidth.value);
+               r_refdef.view.height = (int)(f[1] * vid.height / vid_conheight.value);
                break;
        case VF_FOV:
-               r_view.frustum_x = tan(f[0] * M_PI / 360.0);r_view.ortho_x = f[0];
-               r_view.frustum_y = tan(f[1] * M_PI / 360.0);r_view.ortho_y = f[1];
+               r_refdef.view.frustum_x = tan(f[0] * M_PI / 360.0);r_refdef.view.ortho_x = f[0];
+               r_refdef.view.frustum_y = tan(f[1] * M_PI / 360.0);r_refdef.view.ortho_y = f[1];
                break;
        case VF_FOVX:
-               r_view.frustum_x = tan(k * M_PI / 360.0);r_view.ortho_x = k;
+               r_refdef.view.frustum_x = tan(k * M_PI / 360.0);r_refdef.view.ortho_x = k;
                break;
        case VF_FOVY:
-               r_view.frustum_y = tan(k * M_PI / 360.0);r_view.ortho_y = k;
+               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);
@@ -818,7 +843,10 @@ static void VM_CL_R_SetView (void)
                cl.viewangles[2] = k;
                break;
        case VF_PERSPECTIVE:
-               r_view.useperspective = k != 0;
+               r_refdef.view.useperspective = k != 0;
+               break;
+       case VF_CLEARSCREEN:
+               r_refdef.view.isoverlay = !k;
                break;
        default:
                PRVM_G_FLOAT(OFS_RETURN) = 0;
@@ -828,32 +856,54 @@ static void VM_CL_R_SetView (void)
        PRVM_G_FLOAT(OFS_RETURN) = 1;
 }
 
-//#304 void() renderscene (EXT_CSQC)
-static void VM_CL_R_RenderScene (void)
-{
-       VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
-       // we need to update any RENDER_VIEWMODEL entities at this point because
-       // csqc supplies its own view matrix
-       CL_UpdateViewEntities();
-       // now draw stuff!
-       R_RenderView();
-}
-
-//#305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
-static void VM_CL_R_AddDynamicLight (void)
-{
-       float           *pos, *col;
-       matrix4x4_t     matrix;
-       VM_SAFEPARMCOUNTRANGE(3, 3, VM_CL_R_AddDynamicLight);
+//#305 void(vector org, float radius, vector lightcolours[, float style, string cubemapname, float pflags]) adddynamiclight (EXT_CSQC)
+void VM_CL_R_AddDynamicLight (void)
+{
+       vec_t *org;
+       float radius = 300;
+       vec_t *col;
+       int style = -1;
+       const char *cubemapname = NULL;
+       int pflags = PFLAGS_CORONA | PFLAGS_FULLDYNAMIC;
+       float coronaintensity = 1;
+       float coronasizescale = 0.25;
+       qboolean castshadow = true;
+       float ambientscale = 0;
+       float diffusescale = 1;
+       float specularscale = 1;
+       matrix4x4_t matrix;
+       vec3_t forward, left, up;
+       VM_SAFEPARMCOUNTRANGE(3, 8, VM_CL_R_AddDynamicLight);
 
        // if we've run out of dlights, just return
-       if (r_refdef.numlights >= MAX_DLIGHTS)
+       if (r_refdef.scene.numlights >= MAX_DLIGHTS)
                return;
 
-       pos = PRVM_G_VECTOR(OFS_PARM0);
+       org = PRVM_G_VECTOR(OFS_PARM0);
+       radius = PRVM_G_FLOAT(OFS_PARM1);
        col = PRVM_G_VECTOR(OFS_PARM2);
-       Matrix4x4_CreateFromQuakeEntity(&matrix, pos[0], pos[1], pos[2], 0, 0, 0, PRVM_G_FLOAT(OFS_PARM1));
-       R_RTLight_Update(&r_refdef.lights[r_refdef.numlights++], false, &matrix, col, -1, NULL, true, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+       if (prog->argc >= 4)
+       {
+               style = (int)PRVM_G_FLOAT(OFS_PARM3);
+               if (style >= MAX_LIGHTSTYLES)
+               {
+                       Con_DPrintf("VM_CL_R_AddDynamicLight: out of bounds lightstyle index %i\n", style);
+                       style = -1;
+               }
+       }
+       if (prog->argc >= 5)
+               cubemapname = PRVM_G_STRING(OFS_PARM4);
+       if (prog->argc >= 6)
+               pflags = (int)PRVM_G_FLOAT(OFS_PARM5);
+       coronaintensity = (pflags & PFLAGS_CORONA) != 0;
+       castshadow = (pflags & PFLAGS_NOSHADOW) == 0;
+
+       VectorScale(prog->globals.client->v_forward, radius, forward);
+       VectorScale(prog->globals.client->v_right, -radius, left);
+       VectorScale(prog->globals.client->v_up, radius, up);
+       Matrix4x4_FromVectors(&matrix, forward, left, up, org);
+
+       R_RTLight_Update(&r_refdef.scene.lights[r_refdef.scene.numlights++], false, &matrix, col, style, cubemapname, castshadow, coronaintensity, coronasizescale, ambientscale, diffusescale, specularscale, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
 }
 
 //============================================================================
@@ -866,8 +916,8 @@ static void VM_CL_unproject (void)
 
        VM_SAFEPARMCOUNT(1, VM_CL_unproject);
        f = PRVM_G_VECTOR(OFS_PARM0);
-       VectorSet(temp, f[2], f[0] * f[2] * -r_view.frustum_x * 2.0 / r_view.width, f[1] * f[2] * -r_view.frustum_y * 2.0 / r_view.height);
-       Matrix4x4_Transform(&r_view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN));
+       VectorSet(temp, f[2], f[0] * f[2] * -r_refdef.view.frustum_x * 2.0 / r_refdef.view.width, f[1] * f[2] * -r_refdef.view.frustum_y * 2.0 / r_refdef.view.height);
+       Matrix4x4_Transform(&r_refdef.view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN));
 }
 
 //#311 vector (vector v) cs_project (EXT_CSQC)
@@ -879,9 +929,9 @@ static void VM_CL_project (void)
 
        VM_SAFEPARMCOUNT(1, VM_CL_project);
        f = PRVM_G_VECTOR(OFS_PARM0);
-       Matrix4x4_Invert_Simple(&m, &r_view.matrix);
+       Matrix4x4_Invert_Simple(&m, &r_refdef.view.matrix);
        Matrix4x4_Transform(&m, f, v);
-       VectorSet(PRVM_G_VECTOR(OFS_RETURN), v[1]/v[0]/-r_view.frustum_x*0.5*r_view.width, v[2]/v[0]/-r_view.frustum_y*r_view.height*0.5, v[0]);
+       VectorSet(PRVM_G_VECTOR(OFS_RETURN), v[1]/v[0]/-r_refdef.view.frustum_x*0.5*r_refdef.view.width, v[2]/v[0]/-r_refdef.view.frustum_y*r_refdef.view.height*0.5, v[0]);
 }
 
 //#330 float(float stnum) getstatf (EXT_CSQC)
@@ -982,12 +1032,20 @@ static void VM_CL_setmodelindex (void)
        }
        t->fields.client->model = PRVM_SetEngineString(model->name);
        t->fields.client->modelindex = i;
+
+       // TODO: check if this breaks needed consistency and maybe add a cvar for it too?? [1/10/2008 Black]
+       if (model)
+       {
+               SetMinMaxSize (t, model->normalmins, model->normalmaxs);
+       }
+       else
+               SetMinMaxSize (t, vec3_origin, vec3_origin);
 }
 
 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
 static void VM_CL_modelnameforindex (void)
 {
-       model_t *model;
+       dp_model_t *model;
 
        VM_SAFEPARMCOUNT(1, VM_CL_modelnameforindex);
 
@@ -1020,6 +1078,8 @@ static void VM_CL_trailparticles (void)
        start   = PRVM_G_VECTOR(OFS_PARM2);
        end             = PRVM_G_VECTOR(OFS_PARM3);
 
+       if (i < 0)
+               return;
        CL_ParticleEffect(i, VectorDistance(start, end), start, end, t->fields.client->velocity, t->fields.client->velocity, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
 }
 
@@ -1033,6 +1093,8 @@ static void VM_CL_pointparticles (void)
        f = PRVM_G_VECTOR(OFS_PARM1);
        v = PRVM_G_VECTOR(OFS_PARM2);
        n = (int)PRVM_G_FLOAT(OFS_PARM3);
+       if (i < 0)
+               return;
        CL_ParticleEffect(i, n, f, f, v, v, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
 }
 
@@ -1051,20 +1113,36 @@ static void VM_CL_setcursormode (void)
        cl_ignoremousemoves = 2;
 }
 
+//#344 vector() getmousepos (EXT_CSQC)
+static void VM_CL_getmousepos(void)
+{
+       VM_SAFEPARMCOUNT(0,VM_CL_getmousepos);
+
+       if (key_consoleactive || key_dest != key_game)
+               VectorSet(PRVM_G_VECTOR(OFS_RETURN), 0, 0, 0);
+       else if (cl.csqc_wantsmousemove)
+               VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_windowmouse_x * vid_conwidth.integer / vid.width, in_windowmouse_y * vid_conheight.integer / vid.height, 0);
+       else
+               VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_mouse_x * vid_conwidth.integer / vid.width, in_mouse_y * vid_conheight.integer / vid.height, 0);
+}
+
 //#345 float(float framenum) getinputstate (EXT_CSQC)
 static void VM_CL_getinputstate (void)
 {
        int i, frame;
        VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
        frame = (int)PRVM_G_FLOAT(OFS_PARM0);
-       for (i = 0;i < cl.movement_numqueue;i++)
-               if (cl.movement_queue[i].sequence == frame)
+       for (i = 0;i < CL_MAX_USERCMDS;i++)
+       {
+               if (cl.movecmd[i].sequence == frame)
                {
-                       VectorCopy(cl.movement_queue[i].viewangles, prog->globals.client->input_angles);
-                       //prog->globals.client->input_buttons = cl.movement_queue[i].//FIXME
-                       VectorCopy(cl.movement_queue[i].move, prog->globals.client->input_movevalues);
-                       prog->globals.client->input_timelength = cl.movement_queue[i].frametime;
-                       if(cl.movement_queue[i].crouch)
+                       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;
+                       if(cl.movecmd[i].crouch)
                        {
                                VectorCopy(cl.playercrouchmins, prog->globals.client->pmove_mins);
                                VectorCopy(cl.playercrouchmaxs, prog->globals.client->pmove_maxs);
@@ -1075,6 +1153,7 @@ static void VM_CL_getinputstate (void)
                                VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
                        }
                }
+       }
 }
 
 //#346 void(float sens) setsensitivityscaler (EXT_CSQC)
@@ -1103,8 +1182,9 @@ static void VM_CL_getplayerkey (void)
        PRVM_G_INT(OFS_RETURN) = OFS_NULL;
        Sbar_SortFrags();
 
-       i = Sbar_GetPlayer(i);
-       if(i < 0)
+       if (i < 0)
+               i = Sbar_GetSortedPlayerIndex(-1-i);
+       if(i < 0 || i >= cl.maxclients)
                return;
 
        t[0] = 0;
@@ -1113,28 +1193,28 @@ static void VM_CL_getplayerkey (void)
                strlcpy(t, cl.scores[i].name, sizeof(t));
        else
                if(!strcasecmp(c, "frags"))
-                       sprintf(t, "%i", cl.scores[i].frags);
+                       dpsnprintf(t, sizeof(t), "%i", cl.scores[i].frags);
        else
                if(!strcasecmp(c, "ping"))
-                       sprintf(t, "%i", cl.scores[i].qw_ping);
+                       dpsnprintf(t, sizeof(t), "%i", cl.scores[i].qw_ping);
        else
                if(!strcasecmp(c, "pl"))
-                       sprintf(t, "%i", cl.scores[i].qw_packetloss);
+                       dpsnprintf(t, sizeof(t), "%i", cl.scores[i].qw_packetloss);
        else
                if(!strcasecmp(c, "entertime"))
-                       sprintf(t, "%f", cl.scores[i].qw_entertime);
+                       dpsnprintf(t, sizeof(t), "%f", cl.scores[i].qw_entertime);
        else
                if(!strcasecmp(c, "colors"))
-                       sprintf(t, "%i", cl.scores[i].colors);
+                       dpsnprintf(t, sizeof(t), "%i", cl.scores[i].colors);
        else
                if(!strcasecmp(c, "topcolor"))
-                       sprintf(t, "%i", cl.scores[i].colors & 0xf0);
+                       dpsnprintf(t, sizeof(t), "%i", cl.scores[i].colors & 0xf0);
        else
                if(!strcasecmp(c, "bottomcolor"))
-                       sprintf(t, "%i", (cl.scores[i].colors &15)<<4);
+                       dpsnprintf(t, sizeof(t), "%i", (cl.scores[i].colors &15)<<4);
        else
                if(!strcasecmp(c, "viewentity"))
-                       sprintf(t, "%i", i+1);
+                       dpsnprintf(t, sizeof(t), "%i", i+1);
        if(!t[0])
                return;
        PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
@@ -1230,6 +1310,55 @@ static void VM_CL_ReadFloat (void)
        PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat();
 }
 
+//#501 string() readpicture (DP_CSQC_READWRITEPICTURE)
+extern cvar_t cl_readpicture_force;
+static void VM_CL_ReadPicture (void)
+{
+       const char *name;
+       unsigned char *data;
+       unsigned char *buf;
+       int size;
+       int i;
+       cachepic_t *pic;
+
+       VM_SAFEPARMCOUNT(0, VM_CL_ReadPicture);
+
+       name = MSG_ReadString();
+       size = MSG_ReadShort();
+
+       // check if a texture of that name exists
+       // if yes, it is used and the data is discarded
+       // if not, the (low quality) data is used to build a new texture, whose name will get returned
+
+       pic = Draw_CachePic_Flags (name, CACHEPICFLAG_NOTPERSISTENT);
+
+       if(size)
+       {
+               if(pic->tex == r_texture_notexture)
+                       pic->tex = NULL; // don't overwrite the notexture by Draw_NewPic
+               if(pic->tex && !cl_readpicture_force.integer)
+               {
+                       // texture found and loaded
+                       // skip over the jpeg as we don't need it
+                       for(i = 0; i < size; ++i)
+                               MSG_ReadByte();
+               }
+               else
+               {
+                       // texture not found
+                       // use the attached jpeg as texture
+                       buf = Mem_Alloc(tempmempool, size);
+                       MSG_ReadBytes(size, buf);
+                       data = JPEG_LoadImage_BGRA(buf, size);
+                       Mem_Free(buf);
+                       Draw_NewPic(name, image_width, image_height, false, data);
+                       Mem_Free(data);
+               }
+       }
+
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(name);
+}
+
 //////////////////////////////////////////////////////////
 
 static void VM_CL_makestatic (void)
@@ -1747,9 +1876,9 @@ static void VM_CL_te_flamejet (void)
 //====================================================================
 //DP_QC_GETSURFACE
 
-extern void clippointtosurface(model_t *model, msurface_t *surface, vec3_t p, vec3_t out);
+extern void clippointtosurface(dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t out);
 
-static msurface_t *cl_getsurface(model_t *model, int surfacenum)
+static msurface_t *cl_getsurface(dp_model_t *model, int surfacenum)
 {
        if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
                return NULL;
@@ -1759,7 +1888,7 @@ static msurface_t *cl_getsurface(model_t *model, int surfacenum)
 // #434 float(entity e, float s) getsurfacenumpoints
 static void VM_CL_getsurfacenumpoints(void)
 {
-       model_t *model;
+       dp_model_t *model;
        msurface_t *surface;
        VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenumpoints);
        // return 0 if no such surface
@@ -1777,7 +1906,7 @@ static void VM_CL_getsurfacenumpoints(void)
 static void VM_CL_getsurfacepoint(void)
 {
        prvm_edict_t *ed;
-       model_t *model;
+       dp_model_t *model;
        msurface_t *surface;
        int pointnum;
        VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints);
@@ -1795,8 +1924,8 @@ static void VM_CL_getsurfacepoint(void)
 //PF_getsurfacepointattribute,     // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
 // float SPA_POSITION = 0;
 // float SPA_S_AXIS = 1;
-// float SPA_R_AXIS = 2;
-// float SPA_T_AXIS = 3; // same as SPA_NORMAL
+// float SPA_T_AXIS = 2;
+// float SPA_R_AXIS = 3; // same as SPA_NORMAL
 // float SPA_TEXCOORDS0 = 4;
 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
 // float SPA_LIGHTMAP0_COLOR = 6;
@@ -1804,12 +1933,12 @@ static void VM_CL_getsurfacepoint(void)
 static void VM_CL_getsurfacepointattribute(void)
 {
        prvm_edict_t *ed;
-       model_t *model;
+       dp_model_t *model;
        msurface_t *surface;
        int pointnum;
        int attributetype;
 
-       VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints);
+       VM_SAFEPARMCOUNT(4, VM_CL_getsurfacenumpoints);
        VectorClear(PRVM_G_VECTOR(OFS_RETURN));
        ed = PRVM_G_EDICT(OFS_PARM0);
        if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
@@ -1825,17 +1954,17 @@ static void VM_CL_getsurfacepointattribute(void)
        switch( attributetype ) {
                // float SPA_POSITION = 0;
                case 0:
-                       VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
+                       VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
                        break;
                // float SPA_S_AXIS = 1;
                case 1:
                        VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
                        break;
-               // float SPA_R_AXIS = 2;
+               // float SPA_T_AXIS = 2;
                case 2:
                        VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
                        break;
-               // float SPA_T_AXIS = 3; // same as SPA_NORMAL
+               // float SPA_R_AXIS = 3; // same as SPA_NORMAL
                case 3:
                        VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
                        break;
@@ -1860,7 +1989,7 @@ static void VM_CL_getsurfacepointattribute(void)
                // float SPA_LIGHTMAP0_COLOR = 6;
                case 6:
                        // ignore alpha for now..
-                       VectorCopy( &(model->surfmesh.data_normal3f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
+                       VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
                        break;
                default:
                        VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
@@ -1870,7 +1999,7 @@ static void VM_CL_getsurfacepointattribute(void)
 // #436 vector(entity e, float s) getsurfacenormal
 static void VM_CL_getsurfacenormal(void)
 {
-       model_t *model;
+       dp_model_t *model;
        msurface_t *surface;
        vec3_t normal;
        VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenormal);
@@ -1889,7 +2018,7 @@ static void VM_CL_getsurfacenormal(void)
 // #437 string(entity e, float s) getsurfacetexture
 static void VM_CL_getsurfacetexture(void)
 {
-       model_t *model;
+       dp_model_t *model;
        msurface_t *surface;
        VM_SAFEPARMCOUNT(2, VM_CL_getsurfacetexture);
        PRVM_G_INT(OFS_RETURN) = OFS_NULL;
@@ -1905,7 +2034,7 @@ static void VM_CL_getsurfacenearpoint(void)
        vec3_t clipped, p;
        vec_t dist, bestdist;
        prvm_edict_t *ed;
-       model_t *model = NULL;
+       dp_model_t *model = NULL;
        msurface_t *surface;
        vec_t *point;
        VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenearpoint);
@@ -1948,7 +2077,7 @@ static void VM_CL_getsurfacenearpoint(void)
 static void VM_CL_getsurfaceclippedpoint(void)
 {
        prvm_edict_t *ed;
-       model_t *model;
+       dp_model_t *model;
        msurface_t *surface;
        vec3_t p, out;
        VM_SAFEPARMCOUNT(3, VM_CL_getsurfaceclippedpoint);
@@ -1964,14 +2093,14 @@ static void VM_CL_getsurfaceclippedpoint(void)
 }
 
 // #443 void(entity e, entity tagentity, string tagname) setattachment
-static void VM_CL_setattachment (void)
+void VM_CL_setattachment (void)
 {
        prvm_edict_t *e;
        prvm_edict_t *tagentity;
        const char *tagname;
        prvm_eval_t *v;
        int modelindex;
-       model_t *model;
+       dp_model_t *model;
        VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
 
        e = PRVM_G_EDICT(OFS_PARM0);
@@ -2019,7 +2148,7 @@ static void VM_CL_setattachment (void)
 
 int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
 {
-       model_t *model = CL_GetModelFromEdict(e);
+       dp_model_t *model = CL_GetModelFromEdict(e);
        if (model)
                return Mod_Alias_GetTagIndexForName(model, (int)e->fields.client->skin, tagname);
        else
@@ -2042,7 +2171,8 @@ int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
        int reqframe, attachloop;
        matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
        prvm_edict_t *attachent;
-       model_t *model;
+       dp_model_t *model;
+       float scale;
 
        *out = identitymatrix; // warnings and errors return identical matrix
 
@@ -2087,10 +2217,11 @@ int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
                                attachmatrix = identitymatrix;
 
                        // apply transformation by child entity matrix
+                       scale = 1;
                        val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
-                       if (val->_float == 0)
-                               val->_float = 1;
-                       Matrix4x4_CreateFromQuakeEntity(&entitymatrix, 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], val->_float);
+                       if (val && val->_float != 0)
+                               scale = val->_float;
+                       Matrix4x4_CreateFromQuakeEntity(&entitymatrix, 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], scale);
                        Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
                        Matrix4x4_Copy(&tagmatrix, out);
 
@@ -2107,22 +2238,24 @@ int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
        }
 
        // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
+       scale = 1;
        val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
-       if (val->_float == 0)
-               val->_float = 1;
+       if (val && val->_float != 0)
+               scale = val->_float;
        // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
-       Matrix4x4_CreateFromQuakeEntity(&entitymatrix, 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], val->_float);
+       Matrix4x4_CreateFromQuakeEntity(&entitymatrix, 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], scale);
        Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
 
        if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float))
        {// RENDER_VIEWMODEL magic
                Matrix4x4_Copy(&tagmatrix, out);
 
+               scale = 1;
                val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
-               if (val->_float == 0)
-                       val->_float = 1;
+               if (val && val->_float != 0)
+                       scale = val->_float;
 
-               Matrix4x4_CreateFromQuakeEntity(&entitymatrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], val->_float);
+               Matrix4x4_CreateFromQuakeEntity(&entitymatrix, 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);
                Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
 
                /*
@@ -2152,7 +2285,7 @@ int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
 }
 
 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
-static void VM_CL_gettagindex (void)
+void VM_CL_gettagindex (void)
 {
        prvm_edict_t *ent;
        const char *tag_name;
@@ -2174,10 +2307,8 @@ static void VM_CL_gettagindex (void)
        }
 
        modelindex = (int)ent->fields.client->modelindex;
-       if(modelindex < 0)
-               modelindex = -(modelindex+1);
        tag_index = 0;
-       if (modelindex <= 0 || modelindex >= MAX_MODELS)
+       if (modelindex >= MAX_MODELS || (modelindex <= -MAX_MODELS /* client models */))
                Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
        else
        {
@@ -2189,7 +2320,7 @@ static void VM_CL_gettagindex (void)
 }
 
 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
-static void VM_CL_gettaginfo (void)
+void VM_CL_gettaginfo (void)
 {
        prvm_edict_t *e;
        int tagindex;
@@ -2229,358 +2360,342 @@ static void VM_CL_gettaginfo (void)
 //QC POLYGON functions
 //====================
 
-typedef struct
+#define VMPOLYGONS_MAXPOINTS 64
+
+typedef struct vmpolygons_triangle_s
+{
+       rtexture_t              *texture;
+       int                             drawflag;
+       unsigned short  elements[3];
+}vmpolygons_triangle_t;
+
+typedef struct vmpolygons_s
 {
-       rtexture_t              *tex;
-       float                   data[36];       //[515]: enough for polygons
-       unsigned char                   flags;  //[515]: + VM_POLYGON_2D and VM_POLYGON_FL4V flags
-}vm_polygon_t;
+       mempool_t               *pool;
+       qboolean                initialized;
+
+       int                             max_vertices;
+       int                             num_vertices;
+       float                   *data_vertex3f;
+       float                   *data_color4f;
+       float                   *data_texcoord2f;
+
+       int                             max_triangles;
+       int                             num_triangles;
+       vmpolygons_triangle_t *data_triangles;
+       unsigned short  *data_sortedelement3s;
 
-//static float                 vm_polygon_linewidth = 1;
-static mempool_t               *vm_polygons_pool = NULL;
-static unsigned char                   vm_current_vertices = 0;
-static qboolean                        vm_polygons_initialized = false;
-static vm_polygon_t            *vm_polygons = NULL;
-static unsigned long   vm_polygons_num = 0, vm_drawpolygons_num = 0;   //[515]: ok long on 64bit ?
-static qboolean                        vm_polygonbegin = false;        //[515]: for "no-crap-on-the-screen" check
-#define VM_DEFPOLYNUM 64       //[515]: enough for default ?
+       qboolean                begin_active;
+       rtexture_t              *begin_texture;
+       int                             begin_drawflag;
+       int                             begin_vertices;
+       float                   begin_vertex[VMPOLYGONS_MAXPOINTS][3];
+       float                   begin_color[VMPOLYGONS_MAXPOINTS][4];
+       float                   begin_texcoord[VMPOLYGONS_MAXPOINTS][2];
+} vmpolygons_t;
 
-#define VM_POLYGON_FL3V                16      //more than 2 vertices (used only for lines)
-#define VM_POLYGON_FLLINES     32
-#define VM_POLYGON_FL2D                64
-#define VM_POLYGON_FL4V                128     //4 vertices
+// FIXME: make VM_CL_R_Polygon functions use Debug_Polygon functions?
+vmpolygons_t vmpolygons[PRVM_MAXPROGS];
+
+//#304 void() renderscene (EXT_CSQC)
+// moved that here to reset the polygons,
+// resetting them earlier causes R_Mesh_Draw to be called with numvertices = 0
+// --blub
+void VM_CL_R_RenderScene (void)
+{
+       vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
+       VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
+       // we need to update any RENDER_VIEWMODEL entities at this point because
+       // csqc supplies its own view matrix
+       CL_UpdateViewEntities();
+       // now draw stuff!
+       R_RenderView();
+
+       polys->num_vertices = polys->num_triangles = 0;
+}
+
+static void VM_ResizePolygons(vmpolygons_t *polys)
+{
+       float *oldvertex3f = polys->data_vertex3f;
+       float *oldcolor4f = polys->data_color4f;
+       float *oldtexcoord2f = polys->data_texcoord2f;
+       vmpolygons_triangle_t *oldtriangles = polys->data_triangles;
+       unsigned short *oldsortedelement3s = polys->data_sortedelement3s;
+       polys->max_vertices = min(polys->max_triangles*3, 65536);
+       polys->data_vertex3f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[3]));
+       polys->data_color4f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[4]));
+       polys->data_texcoord2f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[2]));
+       polys->data_triangles = (vmpolygons_triangle_t *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(vmpolygons_triangle_t));
+       polys->data_sortedelement3s = (unsigned short *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(unsigned short[3]));
+       if (polys->num_vertices)
+       {
+               memcpy(polys->data_vertex3f, oldvertex3f, polys->num_vertices*sizeof(float[3]));
+               memcpy(polys->data_color4f, oldcolor4f, polys->num_vertices*sizeof(float[4]));
+               memcpy(polys->data_texcoord2f, oldtexcoord2f, polys->num_vertices*sizeof(float[2]));
+       }
+       if (polys->num_triangles)
+       {
+               memcpy(polys->data_triangles, oldtriangles, polys->num_triangles*sizeof(vmpolygons_triangle_t));
+               memcpy(polys->data_sortedelement3s, oldsortedelement3s, polys->num_triangles*sizeof(unsigned short[3]));
+       }
+       if (oldvertex3f)
+               Mem_Free(oldvertex3f);
+       if (oldcolor4f)
+               Mem_Free(oldcolor4f);
+       if (oldtexcoord2f)
+               Mem_Free(oldtexcoord2f);
+       if (oldtriangles)
+               Mem_Free(oldtriangles);
+       if (oldsortedelement3s)
+               Mem_Free(oldsortedelement3s);
+}
 
-static void VM_InitPolygons (void)
+static void VM_InitPolygons (vmpolygons_t* polys)
 {
-       vm_polygons_pool = Mem_AllocPool("VMPOLY", 0, NULL);
-       vm_polygons = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
-       memset(vm_polygons, 0, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
-       vm_polygons_num = VM_DEFPOLYNUM;
-       vm_drawpolygons_num = 0;
-       vm_polygonbegin = false;
-       vm_polygons_initialized = true;
+       memset(polys, 0, sizeof(*polys));
+       polys->pool = Mem_AllocPool("VMPOLY", 0, NULL);
+       polys->max_triangles = 1024;
+       VM_ResizePolygons(polys);
+       polys->initialized = true;
 }
 
 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
 {
        int surfacelistindex;
-       // LordHavoc: FIXME: this is stupid code
-       for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
-       {
-               const vm_polygon_t      *p = &vm_polygons[surfacelist[surfacelistindex]];
-               int                                     flags = p->flags & 0x0f;
+       vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
+       R_Mesh_ResetTextureState();
+       R_Mesh_Matrix(&identitymatrix);
+       GL_CullFace(GL_NONE);
+       R_Mesh_VertexPointer(polys->data_vertex3f, 0, 0);
+       R_Mesh_ColorPointer(polys->data_color4f, 0, 0);
+       R_Mesh_TexCoordPointer(0, 2, polys->data_texcoord2f, 0, 0);
+       R_SetupGenericShader(true);
 
-               if(flags == DRAWFLAG_ADDITIVE)
+       for (surfacelistindex = 0;surfacelistindex < numsurfaces;)
+       {
+               int numtriangles = 0;
+               rtexture_t *tex = polys->data_triangles[surfacelist[surfacelistindex]].texture;
+               int drawflag = polys->data_triangles[surfacelist[surfacelistindex]].drawflag;
+               if(drawflag == DRAWFLAG_ADDITIVE)
                        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
-               else if(flags == DRAWFLAG_MODULATE)
+               else if(drawflag == DRAWFLAG_MODULATE)
                        GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
-               else if(flags == DRAWFLAG_2XMODULATE)
+               else if(drawflag == DRAWFLAG_2XMODULATE)
                        GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
                else
                        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-               R_Mesh_TexBind(0, R_GetTexture(p->tex));
-
-               CHECKGLERROR
-               //[515]: is speed is max ?
-               if(p->flags & VM_POLYGON_FLLINES)       //[515]: lines
-               {
-                       qglLineWidth(p->data[13]);CHECKGLERROR
-                       qglBegin(GL_LINE_LOOP);
-                               qglTexCoord1f   (p->data[12]);
-                               qglColor4f              (p->data[20], p->data[21], p->data[22], p->data[23]);
-                               qglVertex3f             (p->data[0] , p->data[1],  p->data[2]);
-
-                               qglTexCoord1f   (p->data[14]);
-                               qglColor4f              (p->data[24], p->data[25], p->data[26], p->data[27]);
-                               qglVertex3f             (p->data[3] , p->data[4],  p->data[5]);
-
-                               if(p->flags & VM_POLYGON_FL3V)
-                               {
-                                       qglTexCoord1f   (p->data[16]);
-                                       qglColor4f              (p->data[28], p->data[29], p->data[30], p->data[31]);
-                                       qglVertex3f             (p->data[6] , p->data[7],  p->data[8]);
-
-                                       if(p->flags & VM_POLYGON_FL4V)
-                                       {
-                                               qglTexCoord1f   (p->data[18]);
-                                               qglColor4f              (p->data[32], p->data[33], p->data[34], p->data[35]);
-                                               qglVertex3f             (p->data[9] , p->data[10],  p->data[11]);
-                                       }
-                               }
-                       qglEnd();
-                       CHECKGLERROR
-               }
-               else
+               R_Mesh_TexBind(0, R_GetTexture(tex));
+               numtriangles = 0;
+               for (;surfacelistindex < numsurfaces;surfacelistindex++)
                {
-                       qglBegin(GL_POLYGON);
-                               qglTexCoord2f   (p->data[12], p->data[13]);
-                               qglColor4f              (p->data[20], p->data[21], p->data[22], p->data[23]);
-                               qglVertex3f             (p->data[0] , p->data[1],  p->data[2]);
-
-                               qglTexCoord2f   (p->data[14], p->data[15]);
-                               qglColor4f              (p->data[24], p->data[25], p->data[26], p->data[27]);
-                               qglVertex3f             (p->data[3] , p->data[4],  p->data[5]);
-
-                               qglTexCoord2f   (p->data[16], p->data[17]);
-                               qglColor4f              (p->data[28], p->data[29], p->data[30], p->data[31]);
-                               qglVertex3f             (p->data[6] , p->data[7],  p->data[8]);
-
-                               if(p->flags & VM_POLYGON_FL4V)
-                               {
-                                       qglTexCoord2f   (p->data[18], p->data[19]);
-                                       qglColor4f              (p->data[32], p->data[33], p->data[34], p->data[35]);
-                                       qglVertex3f             (p->data[9] , p->data[10],  p->data[11]);
-                               }
-                       qglEnd();
-                       CHECKGLERROR
+                       if (polys->data_triangles[surfacelist[surfacelistindex]].texture != tex || polys->data_triangles[surfacelist[surfacelistindex]].drawflag != drawflag)
+                               break;
+                       VectorCopy(polys->data_triangles[surfacelist[surfacelistindex]].elements, polys->data_sortedelement3s + 3*numtriangles);
+                       numtriangles++;
                }
+               R_Mesh_Draw(0, polys->num_vertices, 0, numtriangles, NULL, polys->data_sortedelement3s, 0, 0);
        }
 }
 
-static void VM_CL_AddPolygonTo2DScene (vm_polygon_t *p)
+void VMPolygons_Store(vmpolygons_t *polys)
 {
-       drawqueuemesh_t mesh;
-       static int              picelements[6] = {0, 1, 2, 0, 2, 3};
-
-       mesh.texture = p->tex;
-       mesh.data_element3i = picelements;
-       mesh.data_vertex3f = p->data;
-       mesh.data_texcoord2f = p->data + 12;
-       mesh.data_color4f = p->data + 20;
-       if(p->flags & VM_POLYGON_FL4V)
+       if (r_refdef.draw2dstage)
        {
-               mesh.num_vertices = 4;
-               mesh.num_triangles = 2;
+               // draw the polygon as 2D immediately
+               drawqueuemesh_t mesh;
+               mesh.texture = polys->begin_texture;
+               mesh.num_vertices = polys->begin_vertices;
+               mesh.num_triangles = polys->begin_vertices-2;
+               mesh.data_element3s = polygonelements;
+               mesh.data_vertex3f = polys->begin_vertex[0];
+               mesh.data_color4f = polys->begin_color[0];
+               mesh.data_texcoord2f = polys->begin_texcoord[0];
+               DrawQ_Mesh(&mesh, polys->begin_drawflag);
        }
        else
        {
-               mesh.num_vertices = 3;
-               mesh.num_triangles = 1;
+               // queue the polygon as 3D for sorted transparent rendering later
+               int i;
+               if (polys->max_triangles < polys->num_triangles + polys->begin_vertices-2)
+               {
+                       polys->max_triangles *= 2;
+                       VM_ResizePolygons(polys);
+               }
+               if (polys->num_vertices + polys->begin_vertices <= polys->max_vertices)
+               {
+                       // needle in a haystack!
+                       // polys->num_vertices was used for copying where we actually want to copy begin_vertices
+                       // that also caused it to not render the first polygon that is added
+                       // --blub
+                       memcpy(polys->data_vertex3f + polys->num_vertices * 3, polys->begin_vertex[0], polys->begin_vertices * sizeof(float[3]));
+                       memcpy(polys->data_color4f + polys->num_vertices * 4, polys->begin_color[0], polys->begin_vertices * sizeof(float[4]));
+                       memcpy(polys->data_texcoord2f + polys->num_vertices * 2, polys->begin_texcoord[0], polys->begin_vertices * sizeof(float[2]));
+                       for (i = 0;i < polys->begin_vertices-2;i++)
+                       {
+                               polys->data_triangles[polys->num_triangles].texture = polys->begin_texture;
+                               polys->data_triangles[polys->num_triangles].drawflag = polys->begin_drawflag;
+                               polys->data_triangles[polys->num_triangles].elements[0] = polys->num_vertices;
+                               polys->data_triangles[polys->num_triangles].elements[1] = polys->num_vertices + i+1;
+                               polys->data_triangles[polys->num_triangles].elements[2] = polys->num_vertices + i+2;
+                               polys->num_triangles++;
+                       }
+                       polys->num_vertices += polys->begin_vertices;
+               }
        }
-       if(p->flags & VM_POLYGON_FLLINES)       //[515]: lines
-               DrawQ_LineLoop (&mesh, (p->flags&0x0f));
-       else
-               DrawQ_Mesh (&mesh, (p->flags&0x0f));
+       polys->begin_active = false;
 }
 
+// TODO: move this into the client code and clean-up everything else, too! [1/6/2008 Black]
+// LordHavoc: agreed, this is a mess
 void VM_CL_AddPolygonsToMeshQueue (void)
 {
        int i;
-       if(!vm_drawpolygons_num)
+       vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
+       vec3_t center;
+
+       // only add polygons of the currently active prog to the queue - if there is none, we're done
+       if( !prog )
                return;
-       R_Mesh_Matrix(&identitymatrix);
-       GL_CullFace(GL_NONE);
-       for(i = 0;i < (int)vm_drawpolygons_num;i++)
-               VM_DrawPolygonCallback(NULL, NULL, 1, &i);
-       vm_drawpolygons_num = 0;
+
+       if (!polys->num_triangles)
+               return;
+
+       for (i = 0;i < polys->num_triangles;i++)
+       {
+               VectorMAMAM(1.0f / 3.0f, polys->data_vertex3f + 3*polys->data_triangles[i].elements[0], 1.0f / 3.0f, polys->data_vertex3f + 3*polys->data_triangles[i].elements[1], 1.0f / 3.0f, polys->data_vertex3f + 3*polys->data_triangles[i].elements[2], center);
+               R_MeshQueue_AddTransparent(center, VM_DrawPolygonCallback, NULL, i, NULL);
+       }
+
+       /*polys->num_triangles = 0; // now done after rendering the scene,
+         polys->num_vertices = 0;  // otherwise it's not rendered at all and prints an error message --blub */
 }
 
-//void(string texturename, float flag[, float 2d[, float lines]]) R_BeginPolygon
-static void VM_CL_R_PolygonBegin (void)
+//void(string texturename, float flag) R_BeginPolygon
+void VM_CL_R_PolygonBegin (void)
 {
-       vm_polygon_t    *p;
        const char              *picname;
-       VM_SAFEPARMCOUNTRANGE(2, 4, VM_CL_R_PolygonBegin);
+       vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
+
+       VM_SAFEPARMCOUNT(2, VM_CL_R_PolygonBegin);
 
-       if(!vm_polygons_initialized)
-               VM_InitPolygons();
-       if(vm_polygonbegin)
+       if (!polys->initialized)
+               VM_InitPolygons(polys);
+       if (polys->begin_active)
        {
-               VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonEnd after first\n");
+               VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonBegin after first\n");
                return;
        }
-       if(vm_drawpolygons_num >= vm_polygons_num)
-       {
-               p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
-               memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
-               memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
-               Mem_Free(vm_polygons);
-               vm_polygons = p;
-               vm_polygons_num *= 2;
-       }
-       p = &vm_polygons[vm_drawpolygons_num];
        picname = PRVM_G_STRING(OFS_PARM0);
-       if(picname[0])
-               p->tex = Draw_CachePic(picname, true)->tex;
-       else
-               p->tex = r_texture_white;
-       p->flags = (unsigned char)PRVM_G_FLOAT(OFS_PARM1);
-       vm_current_vertices = 0;
-       vm_polygonbegin = true;
-       if(prog->argc >= 3)
-       {
-               if(PRVM_G_FLOAT(OFS_PARM2))
-                       p->flags |= VM_POLYGON_FL2D;
-               if(prog->argc >= 4 && PRVM_G_FLOAT(OFS_PARM3))
-               {
-                       p->data[13] = PRVM_G_FLOAT(OFS_PARM3);  //[515]: linewidth
-                       p->flags |= VM_POLYGON_FLLINES;
-               }
-       }
+       polys->begin_texture = picname[0] ? Draw_CachePic_Flags (picname, CACHEPICFLAG_NOCLAMP)->tex : r_texture_white;
+       polys->begin_drawflag = (int)PRVM_G_FLOAT(OFS_PARM1);
+       polys->begin_vertices = 0;
+       polys->begin_active = true;
 }
 
 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
-static void VM_CL_R_PolygonVertex (void)
+void VM_CL_R_PolygonVertex (void)
 {
-       float                   *coords, *tx, *rgb, alpha;
-       vm_polygon_t    *p;
+       vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
+
        VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
 
-       if(!vm_polygonbegin)
+       if (!polys->begin_active)
        {
                VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
                return;
        }
-       coords  = PRVM_G_VECTOR(OFS_PARM0);
-       tx              = PRVM_G_VECTOR(OFS_PARM1);
-       rgb             = PRVM_G_VECTOR(OFS_PARM2);
-       alpha = PRVM_G_FLOAT(OFS_PARM3);
 
-       p = &vm_polygons[vm_drawpolygons_num];
-       if(vm_current_vertices > 4)
+       if (polys->begin_vertices >= VMPOLYGONS_MAXPOINTS)
        {
-               VM_Warning("VM_CL_R_PolygonVertex: may have 4 vertices max\n");
+               VM_Warning("VM_CL_R_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS);
                return;
        }
 
-       p->data[vm_current_vertices*3]          = coords[0];
-       p->data[1+vm_current_vertices*3]        = coords[1];
-       p->data[2+vm_current_vertices*3]        = coords[2];
-
-       p->data[12+vm_current_vertices*2]       = tx[0];
-       if(!(p->flags & VM_POLYGON_FLLINES))
-               p->data[13+vm_current_vertices*2]       = tx[1];
-
-       p->data[20+vm_current_vertices*4]       = rgb[0];
-       p->data[21+vm_current_vertices*4]       = rgb[1];
-       p->data[22+vm_current_vertices*4]       = rgb[2];
-       p->data[23+vm_current_vertices*4]       = alpha;
-
-       vm_current_vertices++;
-       if(vm_current_vertices == 4)
-               p->flags |= VM_POLYGON_FL4V;
-       else
-               if(vm_current_vertices == 3)
-                       p->flags |= VM_POLYGON_FL3V;
+       polys->begin_vertex[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM0)[0];
+       polys->begin_vertex[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM0)[1];
+       polys->begin_vertex[polys->begin_vertices][2] = PRVM_G_VECTOR(OFS_PARM0)[2];
+       polys->begin_texcoord[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM1)[0];
+       polys->begin_texcoord[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM1)[1];
+       polys->begin_color[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM2)[0];
+       polys->begin_color[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM2)[1];
+       polys->begin_color[polys->begin_vertices][2] = PRVM_G_VECTOR(OFS_PARM2)[2];
+       polys->begin_color[polys->begin_vertices][3] = PRVM_G_FLOAT(OFS_PARM3);
+       polys->begin_vertices++;
 }
 
 //void() R_EndPolygon
-static void VM_CL_R_PolygonEnd (void)
+void VM_CL_R_PolygonEnd (void)
 {
+       vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
+
        VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
-       if(!vm_polygonbegin)
+       if (!polys->begin_active)
        {
                VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
                return;
        }
-       vm_polygonbegin = false;
-       if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
-       {
-               if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D)    //[515]: don't use qcpolygons memory if 2D
-                       VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
-               else
-                       vm_drawpolygons_num++;
-       }
+       polys->begin_active = false;
+       if (polys->begin_vertices >= 3)
+               VMPolygons_Store(polys);
        else
-               VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
+               VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", polys->begin_vertices);
 }
 
-void Debug_PolygonBegin(const char *picname, int flags, qboolean draw2d, float linewidth)
-{
-       vm_polygon_t    *p;
+static vmpolygons_t debugPolys;
 
-       if(!vm_polygons_initialized)
-               VM_InitPolygons();
-       if(vm_polygonbegin)
+void Debug_PolygonBegin(const char *picname, int drawflag)
+{
+       if(!debugPolys.initialized)
+               VM_InitPolygons(&debugPolys);
+       if(debugPolys.begin_active)
        {
                Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n");
                return;
        }
-       // limit polygons to a vaguely sane amount, beyond this each one just
-       // replaces the last one
-       vm_drawpolygons_num = min(vm_drawpolygons_num, (1<<20)-1);
-       if(vm_drawpolygons_num >= vm_polygons_num)
-       {
-               p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
-               memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
-               memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
-               Mem_Free(vm_polygons);
-               vm_polygons = p;
-               vm_polygons_num *= 2;
-       }
-       p = &vm_polygons[vm_drawpolygons_num];
-       if(picname && picname[0])
-               p->tex = Draw_CachePic(picname, true)->tex;
-       else
-               p->tex = r_texture_white;
-       p->flags = flags;
-       vm_current_vertices = 0;
-       vm_polygonbegin = true;
-       if(draw2d)
-               p->flags |= VM_POLYGON_FL2D;
-       if(linewidth)
-       {
-               p->data[13] = linewidth;        //[515]: linewidth
-               p->flags |= VM_POLYGON_FLLINES;
-       }
+       debugPolys.begin_texture = picname[0] ? Draw_CachePic (picname)->tex : r_texture_white;
+       debugPolys.begin_drawflag = drawflag;
+       debugPolys.begin_vertices = 0;
+       debugPolys.begin_active = true;
 }
 
 void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a)
 {
-       vm_polygon_t    *p;
-
-       if(!vm_polygonbegin)
+       if(!debugPolys.begin_active)
        {
                Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
                return;
        }
 
-       p = &vm_polygons[vm_drawpolygons_num];
-       if(vm_current_vertices > 4)
+       if(debugPolys.begin_vertices > VMPOLYGONS_MAXPOINTS)
        {
-               Con_Printf("Debug_PolygonVertex: may have 4 vertices max\n");
+               Con_Printf("Debug_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS);
                return;
        }
 
-       p->data[vm_current_vertices*3]          = x;
-       p->data[1+vm_current_vertices*3]        = y;
-       p->data[2+vm_current_vertices*3]        = z;
-
-       p->data[12+vm_current_vertices*2]       = s;
-       if(!(p->flags & VM_POLYGON_FLLINES))
-               p->data[13+vm_current_vertices*2]       = t;
-
-       p->data[20+vm_current_vertices*4]       = r;
-       p->data[21+vm_current_vertices*4]       = g;
-       p->data[22+vm_current_vertices*4]       = b;
-       p->data[23+vm_current_vertices*4]       = a;
-
-       vm_current_vertices++;
-       if(vm_current_vertices == 4)
-               p->flags |= VM_POLYGON_FL4V;
-       else
-               if(vm_current_vertices == 3)
-                       p->flags |= VM_POLYGON_FL3V;
+       debugPolys.begin_vertex[debugPolys.begin_vertices][0] = x;
+       debugPolys.begin_vertex[debugPolys.begin_vertices][1] = y;
+       debugPolys.begin_vertex[debugPolys.begin_vertices][2] = z;
+       debugPolys.begin_texcoord[debugPolys.begin_vertices][0] = s;
+       debugPolys.begin_texcoord[debugPolys.begin_vertices][1] = t;
+       debugPolys.begin_color[debugPolys.begin_vertices][0] = r;
+       debugPolys.begin_color[debugPolys.begin_vertices][1] = g;
+       debugPolys.begin_color[debugPolys.begin_vertices][2] = b;
+       debugPolys.begin_color[debugPolys.begin_vertices][3] = a;
+       debugPolys.begin_vertices++;
 }
 
 void Debug_PolygonEnd(void)
 {
-       if(!vm_polygonbegin)
+       if (!debugPolys.begin_active)
        {
                Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
                return;
        }
-       vm_polygonbegin = false;
-       if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
-       {
-               if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D)    //[515]: don't use qcpolygons memory if 2D
-                       VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
-               else
-                       vm_drawpolygons_num++;
-       }
+       debugPolys.begin_active = false;
+       if (debugPolys.begin_vertices >= 3)
+               VMPolygons_Store(&debugPolys);
        else
-               Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
+               Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", debugPolys.begin_vertices);
 }
 
 /*
@@ -2847,6 +2962,13 @@ void VM_CL_serverkey(void)
 
 //============================================================================
 
+// To create a almost working builtin file from this replace:
+// "^NULL.*" with ""
+// "^{.*//.*}:Wh\(.*\)" with "\1"
+// "\:" with "//"
+// "^.*//:Wh{\#:d*}:Wh{.*}" with "\2 = \1;"
+// "\n\n+" with "\n\n"
+
 prvm_builtin_t vm_cl_builtins[] = {
 NULL,                                                  // #0 NULL function (not callable) (QUAKE)
 VM_CL_makevectors,                             // #1 void(vector ang) makevectors (QUAKE)
@@ -2864,7 +2986,7 @@ VM_vlen,                                          // #12 float(vector v) vlen (QUAKE)
 VM_vectoyaw,                                   // #13 float(vector v) vectoyaw (QUAKE)
 VM_CL_spawn,                                   // #14 entity() spawn (QUAKE)
 VM_remove,                                             // #15 void(entity e) remove (QUAKE)
-VM_CL_traceline,                               // #16 float(vector v1, vector v2, float tryents) traceline (QUAKE)
+VM_CL_traceline,                               // #16 float(vector v1, vector v2, float tryents, entity ignoreentity) traceline (QUAKE)
 NULL,                                                  // #17 entity() checkclient (QUAKE)
 VM_find,                                               // #18 entity(entity start, .string fld, string match) find (QUAKE)
 VM_precache_sound,                             // #19 void(string s) precache_sound (QUAKE)
@@ -2880,7 +3002,7 @@ VM_coredump,                                      // #28 void() coredump (QUAKE)
 VM_traceon,                                            // #29 void() traceon (QUAKE)
 VM_traceoff,                                   // #30 void() traceoff (QUAKE)
 VM_eprint,                                             // #31 void(entity e) eprint (QUAKE)
-VM_CL_walkmove,                                        // #32 float(float yaw, float dist) walkmove (QUAKE)
+VM_CL_walkmove,                                        // #32 float(float yaw, float dist[, float settrace]) walkmove (QUAKE)
 NULL,                                                  // #33 (QUAKE)
 VM_CL_droptofloor,                             // #34 float() droptofloor (QUAKE)
 VM_CL_lightstyle,                              // #35 void(float style, string value) lightstyle (QUAKE)
@@ -3160,7 +3282,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, 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,                                                  // #309
+NULL /* R_LoadWorldModel in menu VM, should stay unassigned in client*/, // #309
 VM_CL_unproject,                               // #310 vector (vector v) cs_unproject (EXT_CSQC)
 VM_CL_project,                                 // #311 vector (vector v) cs_project (EXT_CSQC)
 NULL,                                                  // #312
@@ -3178,8 +3300,8 @@ VM_drawfill,                                      // #323 float(vector position, vector size, vector rgb, float a
 VM_drawsetcliparea,                            // #324 void(float x, float y, float width, float height) drawsetcliparea
 VM_drawresetcliparea,                  // #325 void(void) drawresetcliparea
 VM_drawcolorcodedstring,               // #326 float drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) (EXT_CSQC)
-NULL,                                                  // #327 // FIXME add stringwidth() here?
-NULL,                                                  // #328 // FIXME add drawsubpic() here?
+VM_stringwidth,                 // #327 // FIXME is this okay?
+VM_drawsubpic,                                 // #328 // FIXME is this okay?
 NULL,                                                  // #329
 VM_CL_getstatf,                                        // #330 float(float stnum) getstatf (EXT_CSQC)
 VM_CL_getstati,                                        // #331 float(float stnum) getstati (EXT_CSQC)
@@ -3195,9 +3317,9 @@ VM_keynumtostring,                                // #340 string(float keynum) keynumtostring (EXT_CSQC)
 VM_stringtokeynum,                             // #341 float(string keyname) stringtokeynum (EXT_CSQC)
 VM_CL_getkeybind,                              // #342 string(float keynum) getkeybind (EXT_CSQC)
 VM_CL_setcursormode,                   // #343 void(float usecursor) setcursormode (EXT_CSQC)
-VM_getmousepos,                                        // #344 vector() getmousepos (EXT_CSQC)
+VM_CL_getmousepos,                             // #344 vector() getmousepos (EXT_CSQC)
 VM_CL_getinputstate,                   // #345 float(float framenum) getinputstate (EXT_CSQC)
-VM_CL_setsensitivityscale,             // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
+VM_CL_setsensitivityscale,             // #346 void(float sens) setsensitivityscale (EXT_CSQC)
 VM_CL_runplayerphysics,                        // #347 void() runstandardplayerphysics (EXT_CSQC)
 VM_CL_getplayerkey,                            // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
 VM_CL_isdemo,                                  // #349 float() isdemo (EXT_CSQC)
@@ -3219,7 +3341,7 @@ VM_CL_ReadCoord,                          // #364 float() readcoord (EXT_CSQC)
 VM_CL_ReadAngle,                               // #365 float() readangle (EXT_CSQC)
 VM_CL_ReadString,                              // #366 string() readstring (EXT_CSQC)
 VM_CL_ReadFloat,                               // #367 float() readfloat (EXT_CSQC)
-NULL,                                                  // #368
+NULL,                                          // #368
 NULL,                                                  // #369
 NULL,                                                  // #370
 NULL,                                                  // #371
@@ -3309,7 +3431,7 @@ NULL,                                                     // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
 NULL,                                                  // #454 entity() spawnclient (DP_SV_BOTCLIENT)
 NULL,                                                  // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
 NULL,                                                  // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
-VM_CL_te_flamejet,                             // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
+VM_CL_te_flamejet,                             // #457 void(vector org, vector vel, float howmany) te_flamejet (DP_TE_FLAMEJET)
 NULL,                                                  // #458
 VM_ftoe,                                               // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
 VM_buf_create,                                 // #460 float() buf_create (DP_QC_STRINGBUFFERS)
@@ -3335,53 +3457,71 @@ VM_tokenizebyseparator,                 // #479 float(string s) tokenizebyseparator (DP_QC_TOK
 VM_strtolower,                                 // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
 VM_strtoupper,                                 // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
 VM_cvar_defstring,                             // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
-VM_CL_pointsound,                              // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND)
+VM_CL_pointsound,                              // #483 void(vector origin, string sample, float volume, float attenuation) pointsound (DP_SV_POINTSOUND)
 VM_strreplace,                                 // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
 VM_strireplace,                                        // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
-VM_CL_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
-#ifdef SUPPORT_GECKO
-VM_gecko_create,                                       // #487
-VM_gecko_destroy,                                      // #488
-VM_gecko_navigate,                             // #489
-VM_gecko_keyevent,                             // #490
-VM_gecko_movemouse,                            // #491
-#else
-NULL,                                                                  // #487
-NULL,                                                                  // #488
-NULL,                                                                  // #489
-NULL,                                                                  // #490
-NULL,                                                                  // #491
-#endif
-NULL,                                                  // #492
-NULL,                                                  // #493
-NULL,                                                  // #494
-NULL,                                                  // #495
-NULL,                                                  // #496
-NULL,                                                  // #497
-NULL,                                                  // #498
-NULL,                                                  // #499
+VM_CL_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute
+VM_gecko_create,                                       // #487 float gecko_create( string name )
+VM_gecko_destroy,                                      // #488 void gecko_destroy( string name )
+VM_gecko_navigate,                             // #489 void gecko_navigate( string name, string URI )
+VM_gecko_keyevent,                             // #490 float gecko_keyevent( string name, float key, float eventtype )
+VM_gecko_movemouse,                            // #491 void gecko_mousemove( string name, float x, float y )
+VM_gecko_resize,                                       // #492 void gecko_resize( string name, float w, float h )
+VM_gecko_get_texture_extent,   // #493 vector gecko_get_texture_extent( string name )
+VM_crc16,                                              // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
+VM_cvar_type,                                  // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
+VM_numentityfields,                            // #496 float() numentityfields = #496; (QP_QC_ENTITYDATA)
+VM_entityfieldname,                            // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
+VM_entityfieldtype,                            // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
+VM_getentityfieldstring,               // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
+VM_putentityfieldstring,               // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
+VM_CL_ReadPicture,                             // #501 string() ReadPicture = #501;
+NULL,                                                  // #502
+VM_whichpack,                                  // #503 string(string) whichpack = #503;
+NULL,                                                  // #504
+NULL,                                                  // #505
+NULL,                                                  // #506
+NULL,                                                  // #507
+NULL,                                                  // #508
+NULL,                                                  // #509
+VM_uri_escape,                                 // #510 string(string in) uri_escape = #510;
+VM_uri_unescape,                               // #511 string(string in) uri_unescape = #511;
+VM_etof,                                       // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
+VM_uri_get,                                            // #513 float(string uril, float id) uri_get = #512; (DP_QC_URI_GET)
+NULL,                                                  // #514
+NULL,                                                  // #515
+NULL,                                                  // #516
+NULL,                                                  // #517
+NULL,                                                  // #518
+NULL,                                                  // #519
+VM_keynumtostring,                             // #520 string keynumtostring(float keynum)
+VM_findkeysforcommand,         // #521 string findkeysforcommand(string command)
 };
 
 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
 
-void VM_CL_Cmd_Init(void)
+void VM_Polygons_Reset(void)
 {
-       VM_Cmd_Init();
+       vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
+
        // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system
-       if(vm_polygons_initialized)
+       if(polys->initialized)
        {
-               Mem_FreePool(&vm_polygons_pool);
-               vm_polygons_initialized = false;
+               Mem_FreePool(&polys->pool);
+               polys->initialized = false;
        }
 }
 
+void VM_CL_Cmd_Init(void)
+{
+       VM_Cmd_Init();
+       VM_Polygons_Reset();
+}
+
 void VM_CL_Cmd_Reset(void)
 {
        VM_Cmd_Reset();
-       if(vm_polygons_initialized)
-       {
-               Mem_FreePool(&vm_polygons_pool);
-               vm_polygons_initialized = false;
-       }
+       VM_Polygons_Reset();
 }
 
+