#include "csprogs.h"
#include "cl_collision.h"
#include "r_shadow.h"
+#include "jpeg.h"
+#include "image.h"
//============================================================================
// Client
//4 feature darkplaces csqc: add builtin to clientside qc for reading triangles of model meshes (useful to orient a ui along a triangle of a model mesh)
//4 feature darkplaces csqc: add builtins to clientside qc for gl calls
+extern cvar_t v_flipped;
+
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);
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
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;
- VM_Warning ("setmodel: model '%s' not precached\n", m);
+ 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
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);
}
{
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);
}
-// #16 float(vector v1, vector v2, float movetype, entity ignore) traceline
+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;
+}
+
+#define CL_HitNetworkBrushModels(move) !((move) == MOVE_WORLDONLY)
+#define CL_HitNetworkPlayers(move) !((move) == MOVE_WORLDONLY || (move) == MOVE_NOMONSTERS)
+
+// #16 void(vector v1, vector v2, float movetype, entity ignore) traceline
static void VM_CL_traceline (void)
{
float *v1, *v2;
trace_t trace;
- int move;
+ int move, svent;
prvm_edict_t *ent;
VM_SAFEPARMCOUNTRANGE(4, 4, VM_CL_traceline);
move = (int)PRVM_G_FLOAT(OFS_PARM2);
ent = PRVM_G_EDICT(OFS_PARM3);
- if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v1[2]) || IS_NAN(v2[2]))
+ if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v2[1]) || IS_NAN(v2[2]))
PRVM_ERROR("%s: NAN errors detected in traceline('%f %f %f', '%f %f %f', %i, entity %i)\n", PRVM_NAME, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
- trace = CL_Move(v1, vec3_origin, vec3_origin, v2, move, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+ trace = CL_TraceLine(v1, v2, move, ent, CL_GenericHitSuperContentsMask(ent), CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true);
- VM_SetTraceGlobals(&trace);
+ CL_VM_SetTraceGlobals(&trace, svent);
}
/*
{
float *v1, *v2, *m1, *m2;
trace_t trace;
- int move;
+ int move, svent;
prvm_edict_t *ent;
VM_SAFEPARMCOUNTRANGE(6, 8, VM_CL_tracebox); // allow more parameters for future expansion
move = (int)PRVM_G_FLOAT(OFS_PARM4);
ent = PRVM_G_EDICT(OFS_PARM5);
- if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v1[2]) || IS_NAN(v2[2]))
+ if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v2[1]) || IS_NAN(v2[2]))
PRVM_ERROR("%s: NAN errors detected in tracebox('%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', %i, entity %i)\n", PRVM_NAME, v1[0], v1[1], v1[2], m1[0], m1[1], m1[2], m2[0], m2[1], m2[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
- trace = CL_Move(v1, m1, m2, v2, move, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+ trace = CL_TraceBox(v1, m1, m2, v2, move, ent, CL_GenericHitSuperContentsMask(ent), CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true);
- VM_SetTraceGlobals(&trace);
+ CL_VM_SetTraceGlobals(&trace, svent);
}
-trace_t CL_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
+trace_t CL_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore, int *svent)
{
int i;
float 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_Move (tossent->fields.client->origin, tossent->fields.client->mins, tossent->fields.client->maxs, end, MOVE_NORMAL, tossent, CL_GenericHitSuperContentsMask(tossent), true, true, NULL, true);
+ 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);
if (trace.fraction < 1)
trace_t trace;
prvm_edict_t *ent;
prvm_edict_t *ignore;
+ int svent;
prog->xfunction->builtinsprofile += 600;
}
ignore = PRVM_G_EDICT(OFS_PARM1);
- trace = CL_Trace_Toss (ent, ignore);
+ trace = CL_Trace_Toss (ent, ignore, &svent);
- VM_SetTraceGlobals(&trace);
+ CL_VM_SetTraceGlobals(&trace, svent);
}
{
const char *name;
int i;
- model_t *m;
+ dp_model_t *m;
VM_SAFEPARMCOUNT(1, VM_CL_precache_model);
}
}
PRVM_G_FLOAT(OFS_RETURN) = 0;
- m = Mod_ForName(name, false, false, false);
+ m = Mod_ForName(name, false, false, name[0] == '*' ? cl.model_name[1] : NULL);
if(m && m->loaded)
{
for (i = 0;i < MAX_MODELS;i++)
{
if (!cl.csqc_model_precache[i])
{
- cl.csqc_model_precache[i] = (model_t*)m;
+ cl.csqc_model_precache[i] = (dp_model_t*)m;
PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
return;
}
vec3_t org, eorg, mins, maxs;
int i, numtouchedicts;
prvm_edict_t *touchedicts[MAX_EDICTS];
+ int chainfield;
+
+ VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_findradius);
- VM_SAFEPARMCOUNT(2, VM_CL_findradius);
+ if(prog->argc == 3)
+ chainfield = PRVM_G_INT(OFS_PARM2);
+ else
+ chainfield = prog->fieldoffsets.chain;
+ if(chainfield < 0)
+ PRVM_ERROR("VM_findchain: %s doesnt have the specified chain field !", PRVM_NAME);
chain = (prvm_edict_t *)prog->edicts;
VectorMAMAM(1, eorg, -0.5f, ent->fields.client->mins, -0.5f, ent->fields.client->maxs, eorg);
if (DotProduct(eorg, eorg) < radius2)
{
- ent->fields.client->chain = PRVM_EDICT_TO_PROG(chain);
+ PRVM_EDICTFIELDVALUE(ent, chainfield)->edict = PRVM_EDICT_TO_PROG(chain);
chain = ent;
}
}
VectorCopy (ent->fields.client->origin, end);
end[2] -= 256;
- trace = CL_Move(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(ent->fields.client->origin, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
if (trace.fraction != 1)
{
VM_Warning("VM_CL_lightstyle >= MAX_LIGHTSTYLES\n");
return;
}
- strlcpy (cl.lightstyle[i].map, MSG_ReadString(), sizeof (cl.lightstyle[i].map));
+ strlcpy (cl.lightstyle[i].map, c, sizeof (cl.lightstyle[i].map));
cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map);
}
start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
stop[2] = start[2] - 2*sv_stepheight.value;
- trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+ trace = CL_TraceLine(start, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
if (trace.fraction == 1.0)
return;
start[0] = stop[0] = x ? maxs[0] : mins[0];
start[1] = stop[1] = y ? maxs[1] : mins[1];
- trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+ trace = CL_TraceLine(start, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
bottom = trace.endpos[2];
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;
extern void CSQC_Think (prvm_edict_t *ed);//csprogs.c
void VM_CL_R_AddEntities (void)
{
+ double t = Sys_DoubleTime();
int i, drawmask;
prvm_edict_t *ed;
VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities);
continue;
CSQC_AddRenderEdict(ed);
}
+
+ // 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;
}
//#302 void(entity ent) addentity (EXT_CSQC)
void VM_CL_R_AddEntity (void)
{
+ double t = Sys_DoubleTime();
VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0));
+ prog->functions[prog->funcoffsets.CSQC_UpdateView].totaltime -= Sys_DoubleTime() - t;
}
//#303 float(float property, ...) setproperty (EXT_CSQC)
switch(c)
{
case VF_MIN:
- r_refdef.view.x = (int)(f[0] * vid.width / vid_conwidth.value);
- r_refdef.view.y = (int)(f[1] * vid.height / vid_conheight.value);
+ r_refdef.view.x = (int)(f[0]);
+ r_refdef.view.y = (int)(f[1]);
break;
case VF_MIN_X:
- r_refdef.view.x = (int)(k * vid.width / vid_conwidth.value);
+ r_refdef.view.x = (int)(k);
break;
case VF_MIN_Y:
- r_refdef.view.y = (int)(k * vid.height / vid_conheight.value);
+ r_refdef.view.y = (int)(k);
break;
case VF_SIZE:
- 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_Y:
- r_refdef.view.width = (int)(k * vid.width / vid_conwidth.value);
+ r_refdef.view.width = (int)(f[0]);
+ r_refdef.view.height = (int)(f[1]);
break;
case VF_SIZE_X:
- r_refdef.view.height = (int)(k * vid.height / vid_conheight.value);
+ r_refdef.view.width = (int)(k);
+ break;
+ case VF_SIZE_Y:
+ r_refdef.view.height = (int)(k);
break;
case VF_VIEWPORT:
- r_refdef.view.x = (int)(f[0] * vid.width / vid_conwidth.value);
- r_refdef.view.y = (int)(f[1] * vid.height / vid_conheight.value);
+ r_refdef.view.x = (int)(f[0]);
+ r_refdef.view.y = (int)(f[1]);
f = PRVM_G_VECTOR(OFS_PARM2);
- r_refdef.view.width = (int)(f[0] * vid.width / vid_conwidth.value);
- r_refdef.view.height = (int)(f[1] * vid.height / vid_conheight.value);
+ r_refdef.view.width = (int)(f[0]);
+ r_refdef.view.height = (int)(f[1]);
break;
case VF_FOV:
r_refdef.view.frustum_x = tan(f[0] * M_PI / 360.0);r_refdef.view.ortho_x = f[0];
CSQC_R_RecalcView();
break;
case VF_DRAWWORLD:
- cl.csqc_vidvars.drawworld = k;
+ cl.csqc_vidvars.drawworld = k != 0;
break;
case VF_DRAWENGINESBAR:
- cl.csqc_vidvars.drawenginesbar = k;
+ cl.csqc_vidvars.drawenginesbar = k != 0;
break;
case VF_DRAWCROSSHAIR:
- cl.csqc_vidvars.drawcrosshair = k;
+ cl.csqc_vidvars.drawcrosshair = k != 0;
break;
case VF_CL_VIEWANGLES:
VectorCopy(f, cl.viewangles);
case VF_PERSPECTIVE:
r_refdef.view.useperspective = k != 0;
break;
+ case VF_CLEARSCREEN:
+ r_refdef.view.isoverlay = !k;
+ break;
default:
PRVM_G_FLOAT(OFS_RETURN) = 0;
VM_Warning("VM_CL_R_SetView : unknown parm %i\n", c);
PRVM_G_FLOAT(OFS_RETURN) = 1;
}
-//#304 void() renderscene (EXT_CSQC)
-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)
+//#305 void(vector org, float radius, vector lightcolours[, float style, string cubemapname, float pflags]) adddynamiclight (EXT_CSQC)
void VM_CL_R_AddDynamicLight (void)
{
- float *pos, *col;
- matrix4x4_t matrix;
- VM_SAFEPARMCOUNTRANGE(3, 3, VM_CL_R_AddDynamicLight);
+ double t = Sys_DoubleTime();
+ 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.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.scene.lights[r_refdef.scene.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.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++];
+ prog->functions[prog->funcoffsets.CSQC_UpdateView].totaltime -= Sys_DoubleTime() - t;
}
//============================================================================
VM_SAFEPARMCOUNT(1, VM_CL_unproject);
f = PRVM_G_VECTOR(OFS_PARM0);
- 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);
+ if(v_flipped.integer)
+ f[0] = (2 * r_refdef.view.x + r_refdef.view.width) * (vid_conwidth.integer / (float) vid.width) - f[0];
+ VectorSet(temp,
+ f[2],
+ (-1.0 + 2.0 * (f[0] / (vid_conwidth.integer / (float) vid.width) - r_refdef.view.x) / r_refdef.view.width) * f[2] * -r_refdef.view.frustum_x,
+ (-1.0 + 2.0 * (f[1] / (vid_conheight.integer / (float) vid.height) - r_refdef.view.y) / r_refdef.view.height) * f[2] * -r_refdef.view.frustum_y);
Matrix4x4_Transform(&r_refdef.view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN));
}
f = PRVM_G_VECTOR(OFS_PARM0);
Matrix4x4_Invert_Simple(&m, &r_refdef.view.matrix);
Matrix4x4_Transform(&m, f, v);
- 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]);
+ if(v_flipped.integer)
+ v[1] = -v[1];
+ VectorSet(PRVM_G_VECTOR(OFS_RETURN),
+ (vid_conwidth.integer / (float) vid.width) * (r_refdef.view.x + r_refdef.view.width*0.5*(1.0+v[1]/v[0]/-r_refdef.view.frustum_x)),
+ (vid_conheight.integer / (float) vid.height) * (r_refdef.view.y + r_refdef.view.height*0.5*(1.0+v[2]/v[0]/-r_refdef.view.frustum_y)),
+ v[0]);
}
//#330 float(float stnum) getstatf (EXT_CSQC)
}
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);
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);
}
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);
}
static void VM_CL_setcursormode (void)
{
VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
- cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0);
+ cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0) != 0;
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)
+ PRVM_G_FLOAT(OFS_RETURN) = false;
+ 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);
VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
}
+ PRVM_G_FLOAT(OFS_RETURN) = true;
}
+ }
}
//#346 void(float sens) setsensitivityscaler (EXT_CSQC)
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;
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);
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 = (unsigned char *) 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)
// copy it to the current state
memset(staticent, 0, sizeof(*staticent));
staticent->render.model = CL_GetModelByIndex((int)ent->fields.client->modelindex);
- staticent->render.frame1 = staticent->render.frame2 = (int)ent->fields.client->frame;
- staticent->render.framelerp = 0;
+ staticent->render.framegroupblend[0].frame = (int)ent->fields.client->frame;
+ staticent->render.framegroupblend[0].lerp = 1;
// make torchs play out of sync
- staticent->render.frame1time = staticent->render.frame2time = lhrandom(-10, -1);
+ 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;
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);
+ 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;
//====================================================================
//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;
// #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
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);
//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;
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))))
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;
// 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 );
// #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);
// #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;
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);
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);
}
// #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);
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
return -1;
-};
+}
+
+int CL_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
+{
+ int r;
+ dp_model_t *model;
+ int frame;
+
+ *tagname = NULL;
+ *parentindex = 0;
+ Matrix4x4_CreateIdentity(tag_localmatrix);
+
+ if (tagindex >= 0
+ && (model = CL_GetModelFromEdict(e))
+ && model->animscenes)
+ {
+ frame = (int)e->fields.client->frame;
+ if (frame < 0 || frame >= model->numframes)
+ frame = 0;
+
+ r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)e->fields.client->skin, model->animscenes[frame].firstframe, tagindex - 1, parentindex, tagname, tag_localmatrix);
+
+ if(!r) // success?
+ *parentindex += 1;
+
+ return r;
+ }
+
+ return 1;
+}
+
+void CL_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
+{
+ prvm_eval_t *val;
+ float scale;
+ float pitchsign = 1;
+ dp_model_t *model;
+
+ scale = 1;
+ val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
+ if (val && val->_float != 0)
+ scale = val->_float;
+
+ // 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);
+ else
+ {
+ if ((model = CL_GetModelFromEdict(ent)) && model->type == mod_alias)
+ pitchsign = -1;
+ 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);
+ }
+}
+
+
+int CL_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
+{
+ int frame;
+ dp_model_t *model;
+ if (tagindex >= 0
+ && (model = CL_GetModelFromEdict(ent))
+ && model->animscenes)
+ {
+ // if model has wrong frame, engine automatically switches to model first frame
+ frame = (int)ent->fields.client->frame;
+ if (frame < 0 || frame >= model->numframes)
+ frame = 0;
+ return Mod_Alias_GetTagMatrix(model, model->animscenes[frame].firstframe, tagindex, out);
+ }
+ *out = identitymatrix;
+ return 0;
+}
// Warnings/errors code:
// 0 - normal (everything all-right)
extern cvar_t cl_bobup;
int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
{
+ int ret;
prvm_eval_t *val;
- int reqframe, attachloop;
+ int attachloop;
matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
- prvm_edict_t *attachent;
- model_t *model;
- float scale;
+ dp_model_t *model;
*out = identitymatrix; // warnings and errors return identical matrix
return 2;
model = CL_GetModelFromEdict(ent);
-
if(!model)
return 3;
- if (ent->fields.client->frame >= 0 && ent->fields.client->frame < model->numframes && model->animscenes)
- reqframe = model->animscenes[(int)ent->fields.client->frame].firstframe;
- else
- reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
-
- // get initial tag matrix
- if (tagindex)
+ tagmatrix = identitymatrix;
+ attachloop = 0;
+ for(;;)
{
- int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
- if (ret)
+ if(attachloop >= 256)
+ return 5;
+ // apply transformation by child's tagindex on parent entity and then
+ // by parent entity itself
+ ret = CL_GetEntityLocalTagMatrix(ent, tagindex - 1, &attachmatrix);
+ if(ret && attachloop == 0)
return ret;
- }
- else
- tagmatrix = identitymatrix;
-
- if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
- { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
- attachloop = 0;
- do
+ CL_GetEntityMatrix(ent, &entitymatrix, false);
+ 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)
{
- attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
- val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index);
-
- model = CL_GetModelFromEdict(attachent);
-
- if (model && val->_float >= 1 && model->animscenes && attachent->fields.client->frame >= 0 && attachent->fields.client->frame < model->numframes)
- Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.client->frame].firstframe, (int)val->_float - 1, &attachmatrix);
- else
- attachmatrix = identitymatrix;
-
- // apply transformation by child entity matrix
- scale = 1;
- val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
- 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);
-
- // finally transformate by matrix of tag on parent entity
- Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
- Matrix4x4_Copy(&tagmatrix, out);
-
- ent = attachent;
- attachloop += 1;
- if (attachloop > 255) // prevent runaway looping
- return 5;
+ tagindex = (int)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
+ ent = PRVM_EDICT_NUM(val->edict);
}
- while ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict);
+ else
+ break;
+ attachloop++;
}
- // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
- scale = 1;
- val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
- 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], scale);
- Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
-
+ // RENDER_VIEWMODEL magic
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 && 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], scale);
+ CL_GetEntityMatrix(prog->edicts, &entitymatrix, true);
Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
/*
}
// #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;
}
// #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;
matrix4x4_t tag_matrix;
+ matrix4x4_t tag_localmatrix;
+ int parentindex;
+ const char *tagname;
int returncode;
+ prvm_eval_t *val;
+ vec3_t fo, le, up, trans;
VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
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, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
+ 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);
+ 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);
switch(returncode)
{
//============================================================================
+//====================
+// DP_CSQC_SPAWNPARTICLE
+// a QC hook to engine's CL_NewParticle
+//====================
+
+// particle theme struct
+typedef struct vmparticletheme_s
+{
+ unsigned short typeindex;
+ qboolean initialized;
+ pblend_t blendmode;
+ porientation_t orientation;
+ int color1;
+ int color2;
+ int tex;
+ float size;
+ float sizeincrease;
+ int alpha;
+ int alphafade;
+ float gravity;
+ float bounce;
+ float airfriction;
+ float liquidfriction;
+ float originjitter;
+ float velocityjitter;
+ qboolean qualityreduction;
+ float lifetime;
+ float stretch;
+ int staincolor1;
+ int staincolor2;
+ int staintex;
+ float delayspawn;
+ float delaycollision;
+}vmparticletheme_t;
+
+// particle spawner
+typedef struct vmparticlespawner_s
+{
+ mempool_t *pool;
+ qboolean initialized;
+ qboolean verified;
+ vmparticletheme_t *themes;
+ int max_themes;
+ // global addresses
+ float *particle_type;
+ float *particle_blendmode;
+ float *particle_orientation;
+ float *particle_color1;
+ float *particle_color2;
+ float *particle_tex;
+ float *particle_size;
+ float *particle_sizeincrease;
+ float *particle_alpha;
+ float *particle_alphafade;
+ float *particle_time;
+ float *particle_gravity;
+ float *particle_bounce;
+ float *particle_airfriction;
+ float *particle_liquidfriction;
+ float *particle_originjitter;
+ float *particle_velocityjitter;
+ float *particle_qualityreduction;
+ float *particle_stretch;
+ float *particle_staincolor1;
+ float *particle_staincolor2;
+ float *particle_staintex;
+ float *particle_delayspawn;
+ float *particle_delaycollision;
+}vmparticlespawner_t;
+
+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;
+ if (maxthemes > 2048)
+ maxthemes = 2048;
+ // allocate and set up structure
+ if (vmpartspawner.initialized) // reallocate
+ {
+ Mem_FreePool(&vmpartspawner.pool);
+ memset(&vmpartspawner, 0, sizeof(vmparticlespawner_t));
+ }
+ vmpartspawner.pool = Mem_AllocPool("VMPARTICLESPAWNER", 0, NULL);
+ vmpartspawner.themes = (vmparticletheme_t *)Mem_Alloc(vmpartspawner.pool, sizeof(vmparticletheme_t)*maxthemes);
+ vmpartspawner.max_themes = maxthemes;
+ vmpartspawner.initialized = true;
+ vmpartspawner.verified = true;
+ // 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_staintex, "particle_staintex");
+ getglobal(particle_delayspawn, "particle_delayspawn");
+ getglobal(particle_delaycollision, "particle_delaycollision");
+ #undef getglobal
+ #undef getglobalvector
+}
+
+// reset particle theme to default values
+static void VM_ResetParticleTheme (vmparticletheme_t *theme)
+{
+ theme->initialized = true;
+ theme->typeindex = pt_static;
+ theme->blendmode = PBLEND_ADD;
+ theme->orientation = PARTICLE_BILLBOARD;
+ theme->color1 = 0x808080;
+ theme->color2 = 0xFFFFFF;
+ theme->tex = 63;
+ theme->size = 2;
+ theme->sizeincrease = 0;
+ theme->alpha = 256;
+ theme->alphafade = 512;
+ theme->gravity = 0.0f;
+ theme->bounce = 0.0f;
+ theme->airfriction = 1.0f;
+ theme->liquidfriction = 4.0f;
+ theme->originjitter = 0.0f;
+ theme->velocityjitter = 0.0f;
+ theme->qualityreduction = false;
+ theme->lifetime = 4;
+ theme->stretch = 1;
+ theme->staincolor1 = -1;
+ theme->staincolor2 = -1;
+ theme->staintex = -1;
+ theme->delayspawn = 0.0f;
+ theme->delaycollision = 0.0f;
+}
+
+// particle theme -> QC globals
+void VM_CL_ParticleThemeToGlobals(vmparticletheme_t *theme)
+{
+ *vmpartspawner.particle_type = theme->typeindex;
+ *vmpartspawner.particle_blendmode = theme->blendmode;
+ *vmpartspawner.particle_orientation = theme->orientation;
+ vmpartspawner.particle_color1[0] = (theme->color1 >> 16) & 0xFF; // VorteX: int only can store 0-255, not 0-256 which means 0 - 0,99609375...
+ vmpartspawner.particle_color1[1] = (theme->color1 >> 8) & 0xFF;
+ vmpartspawner.particle_color1[2] = (theme->color1 >> 0) & 0xFF;
+ vmpartspawner.particle_color2[0] = (theme->color2 >> 16) & 0xFF;
+ vmpartspawner.particle_color2[1] = (theme->color2 >> 8) & 0xFF;
+ vmpartspawner.particle_color2[2] = (theme->color2 >> 0) & 0xFF;
+ *vmpartspawner.particle_tex = (float)theme->tex;
+ *vmpartspawner.particle_size = theme->size;
+ *vmpartspawner.particle_sizeincrease = theme->sizeincrease;
+ *vmpartspawner.particle_alpha = (float)theme->alpha/256;
+ *vmpartspawner.particle_alphafade = (float)theme->alphafade/256;
+ *vmpartspawner.particle_time = theme->lifetime;
+ *vmpartspawner.particle_gravity = theme->gravity;
+ *vmpartspawner.particle_bounce = theme->bounce;
+ *vmpartspawner.particle_airfriction = theme->airfriction;
+ *vmpartspawner.particle_liquidfriction = theme->liquidfriction;
+ *vmpartspawner.particle_originjitter = theme->originjitter;
+ *vmpartspawner.particle_velocityjitter = theme->velocityjitter;
+ *vmpartspawner.particle_qualityreduction = theme->qualityreduction;
+ *vmpartspawner.particle_stretch = theme->stretch;
+ vmpartspawner.particle_staincolor1[0] = (theme->staincolor1 >> 16) & 0xFF;
+ vmpartspawner.particle_staincolor1[1] = (theme->staincolor1 >> 8) & 0xFF;
+ vmpartspawner.particle_staincolor1[2] = (theme->staincolor1 >> 0) & 0xFF;
+ vmpartspawner.particle_staincolor2[0] = (theme->staincolor2 >> 16) & 0xFF;
+ vmpartspawner.particle_staincolor2[1] = (theme->staincolor2 >> 8) & 0xFF;
+ vmpartspawner.particle_staincolor2[2] = (theme->staincolor2 >> 0) & 0xFF;
+ *vmpartspawner.particle_staintex = (float)theme->staintex;
+ *vmpartspawner.particle_delayspawn = theme->delayspawn;
+ *vmpartspawner.particle_delaycollision = theme->delaycollision;
+}
+
+// QC globals -> particle theme
+void VM_CL_ParticleThemeFromGlobals(vmparticletheme_t *theme)
+{
+ theme->typeindex = (unsigned short)*vmpartspawner.particle_type;
+ theme->blendmode = (pblend_t)*vmpartspawner.particle_blendmode;
+ theme->orientation = (porientation_t)*vmpartspawner.particle_orientation;
+ theme->color1 = ((int)vmpartspawner.particle_color1[0] << 16) + ((int)vmpartspawner.particle_color1[1] << 8) + ((int)vmpartspawner.particle_color1[2]);
+ theme->color2 = ((int)vmpartspawner.particle_color2[0] << 16) + ((int)vmpartspawner.particle_color2[1] << 8) + ((int)vmpartspawner.particle_color2[2]);
+ theme->tex = (int)*vmpartspawner.particle_tex;
+ theme->size = *vmpartspawner.particle_size;
+ theme->sizeincrease = *vmpartspawner.particle_sizeincrease;
+ theme->alpha = (int)(*vmpartspawner.particle_alpha*256);
+ theme->alphafade = (int)(*vmpartspawner.particle_alphafade*256);
+ theme->lifetime = *vmpartspawner.particle_time;
+ theme->gravity = *vmpartspawner.particle_gravity;
+ theme->bounce = *vmpartspawner.particle_bounce;
+ theme->airfriction = *vmpartspawner.particle_airfriction;
+ theme->liquidfriction = *vmpartspawner.particle_liquidfriction;
+ theme->originjitter = *vmpartspawner.particle_originjitter;
+ theme->velocityjitter = *vmpartspawner.particle_velocityjitter;
+ theme->qualityreduction = (*vmpartspawner.particle_qualityreduction) ? true : false;
+ theme->stretch = *vmpartspawner.particle_stretch;
+ theme->staincolor1 = vmpartspawner.particle_staincolor1[0]*65536 + vmpartspawner.particle_staincolor1[1]*256 + vmpartspawner.particle_staincolor1[2];
+ theme->staincolor2 = vmpartspawner.particle_staincolor2[0]*65536 + vmpartspawner.particle_staincolor2[1]*256 + vmpartspawner.particle_staincolor2[2];
+ theme->staintex =(int)*vmpartspawner.particle_staintex;
+ theme->delayspawn = *vmpartspawner.particle_delayspawn;
+ theme->delaycollision = *vmpartspawner.particle_delaycollision;
+}
+
+// init particle spawner interface
+// # float(float max_themes) initparticlespawner
+void VM_CL_InitParticleSpawner (void)
+{
+ VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_InitParticleSpawner);
+ VM_InitParticleSpawner((int)PRVM_G_FLOAT(OFS_PARM0));
+ vmpartspawner.themes[0].initialized = true;
+ VM_ResetParticleTheme(&vmpartspawner.themes[0]);
+ PRVM_G_FLOAT(OFS_RETURN) = (vmpartspawner.verified == true) ? 1 : 0;
+}
+
+// void() resetparticle
+void VM_CL_ResetParticle (void)
+{
+ VM_SAFEPARMCOUNT(0, VM_CL_ResetParticle);
+ if (vmpartspawner.verified == false)
+ {
+ VM_Warning("VM_CL_ResetParticle: particle spawner not initialized\n");
+ return;
+ }
+ VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]);
+}
+
+// void(float themenum) particletheme
+void VM_CL_ParticleTheme (void)
+{
+ int themenum;
+
+ VM_SAFEPARMCOUNT(1, VM_CL_ParticleTheme);
+ if (vmpartspawner.verified == false)
+ {
+ VM_Warning("VM_CL_ParticleTheme: particle spawner not initialized\n");
+ return;
+ }
+ themenum = (int)PRVM_G_FLOAT(OFS_PARM0);
+ if (themenum < 0 || themenum >= vmpartspawner.max_themes)
+ {
+ VM_Warning("VM_CL_ParticleTheme: bad theme number %i\n", themenum);
+ VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]);
+ return;
+ }
+ if (vmpartspawner.themes[themenum].initialized == false)
+ {
+ VM_Warning("VM_CL_ParticleTheme: theme #%i not exists\n", themenum);
+ VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]);
+ return;
+ }
+ // load particle theme into globals
+ VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[themenum]);
+}
+
+// float() saveparticletheme
+// void(float themenum) updateparticletheme
+void VM_CL_ParticleThemeSave (void)
+{
+ int themenum;
+
+ VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_ParticleThemeSave);
+ if (vmpartspawner.verified == false)
+ {
+ VM_Warning("VM_CL_ParticleThemeSave: particle spawner not initialized\n");
+ return;
+ }
+ // allocate new theme, save it and return
+ if (prog->argc < 1)
+ {
+ for (themenum = 0; themenum < vmpartspawner.max_themes; themenum++)
+ if (vmpartspawner.themes[themenum].initialized == false)
+ break;
+ if (themenum >= vmpartspawner.max_themes)
+ {
+ if (vmpartspawner.max_themes == 2048)
+ VM_Warning("VM_CL_ParticleThemeSave: no free theme slots\n");
+ else
+ VM_Warning("VM_CL_ParticleThemeSave: no free theme slots, try initparticlespawner() with highter max_themes\n");
+ PRVM_G_FLOAT(OFS_RETURN) = -1;
+ return;
+ }
+ vmpartspawner.themes[themenum].initialized = true;
+ VM_CL_ParticleThemeFromGlobals(&vmpartspawner.themes[themenum]);
+ PRVM_G_FLOAT(OFS_RETURN) = themenum;
+ return;
+ }
+ // update existing theme
+ themenum = (int)PRVM_G_FLOAT(OFS_PARM0);
+ if (themenum < 0 || themenum >= vmpartspawner.max_themes)
+ {
+ VM_Warning("VM_CL_ParticleThemeSave: bad theme number %i\n", themenum);
+ return;
+ }
+ vmpartspawner.themes[themenum].initialized = true;
+ VM_CL_ParticleThemeFromGlobals(&vmpartspawner.themes[themenum]);
+}
+
+// void(float themenum) freeparticletheme
+void VM_CL_ParticleThemeFree (void)
+{
+ int themenum;
+
+ VM_SAFEPARMCOUNT(1, VM_CL_ParticleThemeFree);
+ if (vmpartspawner.verified == false)
+ {
+ VM_Warning("VM_CL_ParticleThemeFree: particle spawner not initialized\n");
+ return;
+ }
+ themenum = (int)PRVM_G_FLOAT(OFS_PARM0);
+ // check parms
+ if (themenum <= 0 || themenum >= vmpartspawner.max_themes)
+ {
+ VM_Warning("VM_CL_ParticleThemeFree: bad theme number %i\n", themenum);
+ return;
+ }
+ if (vmpartspawner.themes[themenum].initialized == false)
+ {
+ VM_Warning("VM_CL_ParticleThemeFree: theme #%i already freed\n", themenum);
+ VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0]);
+ return;
+ }
+ // free theme
+ VM_ResetParticleTheme(&vmpartspawner.themes[themenum]);
+ vmpartspawner.themes[themenum].initialized = false;
+}
+
+// float(vector org, vector dir, [float theme]) particle
+// returns 0 if failed, 1 if succesful
+void VM_CL_SpawnParticle (void)
+{
+ float *org, *dir;
+ vmparticletheme_t *theme;
+ particle_t *part;
+ int themenum;
+
+ VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_SpawnParticle2);
+ if (vmpartspawner.verified == false)
+ {
+ VM_Warning("VM_CL_SpawnParticle: particle spawner not initialized\n");
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+ org = PRVM_G_VECTOR(OFS_PARM0);
+ dir = PRVM_G_VECTOR(OFS_PARM1);
+
+ if (prog->argc < 3) // global-set particle
+ {
+ part = CL_NewParticle((unsigned short)*vmpartspawner.particle_type, ((int)vmpartspawner.particle_color1[0] << 16) + ((int)vmpartspawner.particle_color1[1] << 8) + ((int)vmpartspawner.particle_color1[2]), ((int)vmpartspawner.particle_color2[0] << 16) + ((int)vmpartspawner.particle_color2[1] << 8) + ((int)vmpartspawner.particle_color2[2]), (int)*vmpartspawner.particle_tex, *vmpartspawner.particle_size, *vmpartspawner.particle_sizeincrease, (int)(*vmpartspawner.particle_alpha*256), (int)(*vmpartspawner.particle_alphafade*256), *vmpartspawner.particle_gravity, *vmpartspawner.particle_bounce, org[0], org[1], org[2], dir[0], dir[1], dir[2], *vmpartspawner.particle_airfriction, *vmpartspawner.particle_liquidfriction, *vmpartspawner.particle_originjitter, *vmpartspawner.particle_velocityjitter, (*vmpartspawner.particle_qualityreduction) ? true : false, *vmpartspawner.particle_time, *vmpartspawner.particle_stretch, (pblend_t)*vmpartspawner.particle_blendmode, (porientation_t)*vmpartspawner.particle_orientation, ((int)vmpartspawner.particle_staincolor1[0] << 16) + ((int)vmpartspawner.particle_staincolor1[1] << 8) + ((int)vmpartspawner.particle_staincolor1[2]), ((int)vmpartspawner.particle_staincolor2[0] << 16) + ((int)vmpartspawner.particle_staincolor2[1] << 8) + ((int)vmpartspawner.particle_staincolor2[2]), (int)*vmpartspawner.particle_staintex);
+ if (!part)
+ {
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+ if (*vmpartspawner.particle_delayspawn)
+ part->delayedspawn = cl.time + *vmpartspawner.particle_delayspawn;
+ if (*vmpartspawner.particle_delaycollision)
+ part->delayedcollisions = cl.time + *vmpartspawner.particle_delaycollision;
+ }
+ else // quick themed particle
+ {
+ themenum = (int)PRVM_G_FLOAT(OFS_PARM2);
+ if (themenum <= 0 || themenum >= vmpartspawner.max_themes)
+ {
+ VM_Warning("VM_CL_SpawnParticle: bad theme number %i\n", themenum);
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+ theme = &vmpartspawner.themes[themenum];
+ part = CL_NewParticle(theme->typeindex, theme->color1, theme->color2, theme->tex, theme->size, theme->sizeincrease, theme->alpha, theme->alphafade, theme->gravity, theme->bounce, org[0], org[1], org[2], dir[0], dir[1], dir[2], theme->airfriction, theme->liquidfriction, theme->originjitter, theme->velocityjitter, theme->qualityreduction, theme->lifetime, theme->stretch, theme->blendmode, theme->orientation, theme->staincolor1, theme->staincolor2, theme->staintex);
+ if (!part)
+ {
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+ if (theme->delayspawn)
+ part->delayedspawn = cl.time + theme->delayspawn;
+ if (theme->delaycollision)
+ part->delayedcollisions = cl.time + theme->delaycollision;
+ }
+ PRVM_G_FLOAT(OFS_RETURN) = 1;
+}
+
+// float(vector org, vector dir, float spawndelay, float collisiondelay, [float theme]) delayedparticle
+// returns 0 if failed, 1 if success
+void VM_CL_SpawnParticleDelayed (void)
+{
+ float *org, *dir;
+ vmparticletheme_t *theme;
+ particle_t *part;
+ int themenum;
+
+ VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_SpawnParticle2);
+ if (vmpartspawner.verified == false)
+ {
+ VM_Warning("VM_CL_SpawnParticle: particle spawner not initialized\n");
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+ org = PRVM_G_VECTOR(OFS_PARM0);
+ dir = PRVM_G_VECTOR(OFS_PARM1);
+ if (prog->argc < 5) // global-set particle
+ part = CL_NewParticle((unsigned short)*vmpartspawner.particle_type, ((int)vmpartspawner.particle_color1[0] << 16) + ((int)vmpartspawner.particle_color1[1] << 8) + ((int)vmpartspawner.particle_color1[2]), ((int)vmpartspawner.particle_color2[0] << 16) + ((int)vmpartspawner.particle_color2[1] << 8) + ((int)vmpartspawner.particle_color2[2]), (int)*vmpartspawner.particle_tex, *vmpartspawner.particle_size, *vmpartspawner.particle_sizeincrease, (int)(*vmpartspawner.particle_alpha*256), (int)(*vmpartspawner.particle_alphafade*256), *vmpartspawner.particle_gravity, *vmpartspawner.particle_bounce, org[0], org[1], org[2], dir[0], dir[1], dir[2], *vmpartspawner.particle_airfriction, *vmpartspawner.particle_liquidfriction, *vmpartspawner.particle_originjitter, *vmpartspawner.particle_velocityjitter, (*vmpartspawner.particle_qualityreduction) ? true : false, *vmpartspawner.particle_time, *vmpartspawner.particle_stretch, (pblend_t)*vmpartspawner.particle_blendmode, (porientation_t)*vmpartspawner.particle_orientation, ((int)vmpartspawner.particle_staincolor1[0] << 16) + ((int)vmpartspawner.particle_staincolor1[1] << 8) + ((int)vmpartspawner.particle_staincolor1[2]), ((int)vmpartspawner.particle_staincolor2[0] << 16) + ((int)vmpartspawner.particle_staincolor2[1] << 8) + ((int)vmpartspawner.particle_staincolor2[2]), (int)*vmpartspawner.particle_staintex);
+ else // themed particle
+ {
+ themenum = (int)PRVM_G_FLOAT(OFS_PARM4);
+ if (themenum <= 0 || themenum >= vmpartspawner.max_themes)
+ {
+ VM_Warning("VM_CL_SpawnParticle: bad theme number %i\n", themenum);
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+ theme = &vmpartspawner.themes[themenum];
+ part = CL_NewParticle(theme->typeindex, theme->color1, theme->color2, theme->tex, theme->size, theme->sizeincrease, theme->alpha, theme->alphafade, theme->gravity, theme->bounce, org[0], org[1], org[2], dir[0], dir[1], dir[2], theme->airfriction, theme->liquidfriction, theme->originjitter, theme->velocityjitter, theme->qualityreduction, theme->lifetime, theme->stretch, theme->blendmode, theme->orientation, theme->staincolor1, theme->staincolor2, theme->staintex);
+ }
+ if (!part)
+ {
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+ part->delayedspawn = cl.time + PRVM_G_FLOAT(OFS_PARM2);
+ part->delayedcollisions = cl.time + PRVM_G_FLOAT(OFS_PARM3);
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+}
+
+//
//====================
//QC POLYGON functions
//====================
-typedef struct
+#define VMPOLYGONS_MAXPOINTS 64
+
+typedef struct vmpolygons_triangle_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;
+ rtexture_t *texture;
+ int drawflag;
+ unsigned short elements[3];
+}vmpolygons_triangle_t;
typedef struct vmpolygons_s
{
- //static float vm_polygon_linewidth = 1;
mempool_t *pool;
- unsigned char current_vertices;
qboolean initialized;
- vm_polygon_t *polygons;
- unsigned long polygons_num, drawpolygons_num; //[515]: ok long on 64bit ?
- qboolean polygonbegin; //[515]: for "no-crap-on-the-screen" check
+ double progstarttime;
+
+ int max_vertices;
+ int num_vertices;
+ float *data_vertex3f;
+ float *data_color4f;
+ float *data_texcoord2f;
+
+ int max_triangles;
+ int num_triangles;
+ vmpolygons_triangle_t *data_triangles;
+ unsigned short *data_sortedelement3s;
+
+ qboolean begin_active;
+ 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;
+
+// FIXME: make VM_CL_R_Polygon functions use Debug_Polygon functions?
vmpolygons_t vmpolygons[PRVM_MAXPROGS];
-#define VM_DEFPOLYNUM 64 //[515]: enough for default ?
-#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
+//#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)
+{
+ double t = Sys_DoubleTime();
+ 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;
+ 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;
+}
+
+static void VM_ResizePolygons(vmpolygons_t *polys)
+{
+ float *oldvertex3f = polys->data_vertex3f;
+ float *oldcolor4f = polys->data_color4f;
+ float *oldtexcoord2f = polys->data_texcoord2f;
+ vmpolygons_triangle_t *oldtriangles = polys->data_triangles;
+ unsigned short *oldsortedelement3s = polys->data_sortedelement3s;
+ polys->max_vertices = min(polys->max_triangles*3, 65536);
+ polys->data_vertex3f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[3]));
+ polys->data_color4f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[4]));
+ polys->data_texcoord2f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[2]));
+ polys->data_triangles = (vmpolygons_triangle_t *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(vmpolygons_triangle_t));
+ polys->data_sortedelement3s = (unsigned short *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(unsigned short[3]));
+ if (polys->num_vertices)
+ {
+ memcpy(polys->data_vertex3f, oldvertex3f, polys->num_vertices*sizeof(float[3]));
+ memcpy(polys->data_color4f, oldcolor4f, polys->num_vertices*sizeof(float[4]));
+ memcpy(polys->data_texcoord2f, oldtexcoord2f, polys->num_vertices*sizeof(float[2]));
+ }
+ if (polys->num_triangles)
+ {
+ memcpy(polys->data_triangles, oldtriangles, polys->num_triangles*sizeof(vmpolygons_triangle_t));
+ memcpy(polys->data_sortedelement3s, oldsortedelement3s, polys->num_triangles*sizeof(unsigned short[3]));
+ }
+ if (oldvertex3f)
+ Mem_Free(oldvertex3f);
+ if (oldcolor4f)
+ Mem_Free(oldcolor4f);
+ if (oldtexcoord2f)
+ Mem_Free(oldtexcoord2f);
+ if (oldtriangles)
+ Mem_Free(oldtriangles);
+ if (oldsortedelement3s)
+ Mem_Free(oldsortedelement3s);
+}
static void VM_InitPolygons (vmpolygons_t* polys)
{
+ memset(polys, 0, sizeof(*polys));
polys->pool = Mem_AllocPool("VMPOLY", 0, NULL);
- polys->polygons = (vm_polygon_t *)Mem_Alloc(polys->pool, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
- memset(polys->polygons, 0, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
- polys->polygons_num = VM_DEFPOLYNUM;
- polys->drawpolygons_num = 0;
- polys->polygonbegin = false;
+ polys->max_triangles = 1024;
+ VM_ResizePolygons(polys);
polys->initialized = true;
}
{
int surfacelistindex;
vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
+ if(polys->progstarttime != prog->starttime) // from other progs? won't draw these (this can cause crashes!)
+ return;
+ 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);
- // LordHavoc: FIXME: this is stupid code
- for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+ for (surfacelistindex = 0;surfacelistindex < numsurfaces;)
{
- const vm_polygon_t *p = &polys->polygons[surfacelist[surfacelistindex]];
- int flags = p->flags & 0x0f;
-
- if(flags == DRAWFLAG_ADDITIVE)
+ int numtriangles = 0;
+ rtexture_t *tex = polys->data_triangles[surfacelist[surfacelistindex]].texture;
+ int drawflag = polys->data_triangles[surfacelist[surfacelistindex]].drawflag;
+ // this can't call _DrawQ_ProcessDrawFlag, but should be in sync with it
+ // FIXME factor this out
+ 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 if(drawflag == DRAWFLAG_SCREEN)
+ GL_BlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ONE);
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;
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;
- if(!polys->drawpolygons_num)
+ if (!polys->num_triangles)
return;
- R_Mesh_Matrix(&identitymatrix);
- GL_CullFace(GL_NONE);
- for(i = 0;i < (int)polys->drawpolygons_num;i++)
- VM_DrawPolygonCallback(NULL, NULL, 1, &i);
- polys->drawpolygons_num = 0;
+
+ 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
+//void(string texturename, float flag) R_BeginPolygon
void VM_CL_R_PolygonBegin (void)
{
- vm_polygon_t *p;
const char *picname;
+ skinframe_t *sf;
vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
+ int tf;
+
+ // TODO instead of using skinframes here (which provides the benefit of
+ // better management of flags, and is more suited for 3D rendering), what
+ // about supporting Q3 shaders?
- VM_SAFEPARMCOUNTRANGE(2, 4, VM_CL_R_PolygonBegin);
+ VM_SAFEPARMCOUNT(2, VM_CL_R_PolygonBegin);
- if(!polys->initialized)
+ if (!polys->initialized)
VM_InitPolygons(polys);
- if(polys->polygonbegin)
+ if(polys->progstarttime != prog->starttime)
{
- VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonEnd after first\n");
- return;
+ // from another progs? then reset the polys first (fixes crashes on map change, because that can make skinframe textures invalid)
+ polys->num_vertices = polys->num_triangles = 0;
+ polys->progstarttime = prog->starttime;
}
- if(polys->drawpolygons_num >= polys->polygons_num)
+ if (polys->begin_active)
{
- p = (vm_polygon_t *)Mem_Alloc(polys->pool, 2 * polys->polygons_num * sizeof(vm_polygon_t));
- memset(p, 0, 2 * polys->polygons_num * sizeof(vm_polygon_t));
- memcpy(p, polys->polygons, polys->polygons_num * sizeof(vm_polygon_t));
- Mem_Free(polys->polygons);
- polys->polygons = p;
- polys->polygons_num *= 2;
+ VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonBegin after first\n");
+ return;
}
- p = &polys->polygons[polys->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);
- polys->current_vertices = 0;
- polys->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))
+
+ sf = NULL;
+ if(*picname)
+ {
+ tf = TEXF_ALPHA;
+ if((int)PRVM_G_FLOAT(OFS_PARM1) & DRAWFLAG_MIPMAP)
+ tf |= TEXF_MIPMAP;
+
+ do
{
- p->data[13] = PRVM_G_FLOAT(OFS_PARM3); //[515]: linewidth
- p->flags |= VM_POLYGON_FLLINES;
+ sf = R_SkinFrame_FindNextByName(sf, picname);
}
+ while(sf && sf->textureflags != tf);
+
+ if(!sf || !sf->base)
+ sf = R_SkinFrame_LoadExternal(picname, tf, true);
+
+ if(sf)
+ R_SkinFrame_MarkUsed(sf);
}
+
+ polys->begin_texture = (sf && sf->base) ? sf->base : r_texture_white;
+ polys->begin_drawflag = (int)PRVM_G_FLOAT(OFS_PARM1) & DRAWFLAG_MASK;
+ polys->begin_vertices = 0;
+ polys->begin_active = true;
}
//void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
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(!polys->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 = &polys->polygons[polys->drawpolygons_num];
- if(polys->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[polys->current_vertices*3] = coords[0];
- p->data[1+polys->current_vertices*3] = coords[1];
- p->data[2+polys->current_vertices*3] = coords[2];
-
- p->data[12+polys->current_vertices*2] = tx[0];
- if(!(p->flags & VM_POLYGON_FLLINES))
- p->data[13+polys->current_vertices*2] = tx[1];
-
- p->data[20+polys->current_vertices*4] = rgb[0];
- p->data[21+polys->current_vertices*4] = rgb[1];
- p->data[22+polys->current_vertices*4] = rgb[2];
- p->data[23+polys->current_vertices*4] = alpha;
-
- polys->current_vertices++;
- if(polys->current_vertices == 4)
- p->flags |= VM_POLYGON_FL4V;
- else
- if(polys->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
vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
- if(!polys->polygonbegin)
+ if (!polys->begin_active)
{
VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
return;
}
- polys->polygonbegin = false;
- if(polys->current_vertices > 2 || (polys->current_vertices >= 2 && polys->polygons[polys->drawpolygons_num].flags & VM_POLYGON_FLLINES))
- {
- if(polys->polygons[polys->drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
- VM_CL_AddPolygonTo2DScene(&polys->polygons[polys->drawpolygons_num]);
- else
- polys->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", polys->current_vertices);
+ VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", polys->begin_vertices);
}
static vmpolygons_t debugPolys;
-void Debug_PolygonBegin(const char *picname, int flags, qboolean draw2d, float linewidth)
+void Debug_PolygonBegin(const char *picname, int drawflag)
{
- vm_polygon_t *p;
-
if(!debugPolys.initialized)
VM_InitPolygons(&debugPolys);
- if(debugPolys.polygonbegin)
+ 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
- debugPolys.drawpolygons_num = min(debugPolys.drawpolygons_num, (1<<20)-1);
- if(debugPolys.drawpolygons_num >= debugPolys.polygons_num)
- {
- p = (vm_polygon_t *)Mem_Alloc(debugPolys.pool, 2 * debugPolys.polygons_num * sizeof(vm_polygon_t));
- memset(p, 0, 2 * debugPolys.polygons_num * sizeof(vm_polygon_t));
- memcpy(p, debugPolys.polygons, debugPolys.polygons_num * sizeof(vm_polygon_t));
- Mem_Free(debugPolys.polygons);
- debugPolys.polygons = p;
- debugPolys.polygons_num *= 2;
- }
- p = &debugPolys.polygons[debugPolys.drawpolygons_num];
- if(picname && picname[0])
- p->tex = Draw_CachePic(picname, true)->tex;
- else
- p->tex = r_texture_white;
- p->flags = flags;
- debugPolys.current_vertices = 0;
- debugPolys.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(!debugPolys.polygonbegin)
+ if(!debugPolys.begin_active)
{
Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
return;
}
- p = &debugPolys.polygons[debugPolys.drawpolygons_num];
- if(debugPolys.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[debugPolys.current_vertices*3] = x;
- p->data[1+debugPolys.current_vertices*3] = y;
- p->data[2+debugPolys.current_vertices*3] = z;
-
- p->data[12+debugPolys.current_vertices*2] = s;
- if(!(p->flags & VM_POLYGON_FLLINES))
- p->data[13+debugPolys.current_vertices*2] = t;
-
- p->data[20+debugPolys.current_vertices*4] = r;
- p->data[21+debugPolys.current_vertices*4] = g;
- p->data[22+debugPolys.current_vertices*4] = b;
- p->data[23+debugPolys.current_vertices*4] = a;
-
- debugPolys.current_vertices++;
- if(debugPolys.current_vertices == 4)
- p->flags |= VM_POLYGON_FL4V;
- else
- if(debugPolys.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(!debugPolys.polygonbegin)
+ if (!debugPolys.begin_active)
{
Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
return;
}
- debugPolys.polygonbegin = false;
- if(debugPolys.current_vertices > 2 || (debugPolys.current_vertices >= 2 && debugPolys.polygons[debugPolys.drawpolygons_num].flags & VM_POLYGON_FLLINES))
- {
- if(debugPolys.polygons[debugPolys.drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
- VM_CL_AddPolygonTo2DScene(&debugPolys.polygons[debugPolys.drawpolygons_num]);
- else
- debugPolys.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", debugPolys.current_vertices);
+ Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", debugPolys.begin_vertices);
}
/*
start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
stop[2] = start[2] - 2*sv_stepheight.value;
- trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+ trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true);
if (trace.fraction == 1.0)
return false;
start[0] = stop[0] = x ? maxs[0] : mins[0];
start[1] = stop[1] = y ? maxs[1] : mins[1];
- trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+ trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true);
if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
bottom = trace.endpos[2];
float dz;
vec3_t oldorg, neworg, end, traceendpos;
trace_t trace;
- int i;
+ int i, svent;
prvm_edict_t *enemy;
prvm_eval_t *val;
if (dz < 30)
neworg[2] += 8;
}
- trace = CL_Move (ent->fields.client->origin, ent->fields.client->mins, ent->fields.client->maxs, neworg, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+ 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);
if (settrace)
- VM_SetTraceGlobals(&trace);
+ CL_VM_SetTraceGlobals(&trace, svent);
if (trace.fraction == 1)
{
VectorCopy (neworg, end);
end[2] -= sv_stepheight.value*2;
- trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+ trace = CL_TraceBox(neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
if (settrace)
- VM_SetTraceGlobals(&trace);
+ CL_VM_SetTraceGlobals(&trace, svent);
if (trace.startsolid)
{
neworg[2] -= sv_stepheight.value;
- trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+ trace = CL_TraceBox(neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
if (settrace)
- VM_SetTraceGlobals(&trace);
+ CL_VM_SetTraceGlobals(&trace, svent);
if (trace.startsolid)
return false;
}
PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
}
+/*
+=================
+VM_CL_checkpvs
+
+Checks if an entity is in a point's PVS.
+Should be fast but can be inexact.
+
+float checkpvs(vector viewpos, entity viewee) = #240;
+=================
+*/
+static void VM_CL_checkpvs (void)
+{
+ vec3_t viewpos;
+ prvm_edict_t *viewee;
+ vec3_t mi, ma;
+#if 1
+ unsigned char *pvs;
+#else
+ static int fatpvsbytes;
+ static unsigned char fatpvs[MAX_MAP_LEAFS/8];
+#endif
+
+ VM_SAFEPARMCOUNT(2, VM_SV_checkpvs);
+ VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
+ viewee = PRVM_G_EDICT(OFS_PARM1);
+
+ if(viewee->priv.required->free)
+ {
+ VM_Warning("checkpvs: can not check free entity\n");
+ PRVM_G_FLOAT(OFS_RETURN) = 4;
+ return;
+ }
+
+ VectorAdd(viewee->fields.server->origin, viewee->fields.server->mins, mi);
+ VectorAdd(viewee->fields.server->origin, viewee->fields.server->maxs, ma);
+
+#if 1
+ if(!sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS)
+ {
+ // no PVS support on this worldmodel... darn
+ PRVM_G_FLOAT(OFS_RETURN) = 3;
+ return;
+ }
+ pvs = sv.worldmodel->brush.GetPVS(sv.worldmodel, viewpos);
+ if(!pvs)
+ {
+ // viewpos isn't in any PVS... darn
+ PRVM_G_FLOAT(OFS_RETURN) = 2;
+ return;
+ }
+ PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, mi, ma);
+#else
+ // using fat PVS like FTEQW does (slow)
+ if(!sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
+ {
+ // no PVS support on this worldmodel... darn
+ PRVM_G_FLOAT(OFS_RETURN) = 3;
+ return;
+ }
+ fatpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false);
+ if(!fatpvsbytes)
+ {
+ // viewpos isn't in any PVS... darn
+ PRVM_G_FLOAT(OFS_RETURN) = 2;
+ return;
+ }
+ PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, mi, ma);
+#endif
+}
//============================================================================
// To create a almost working builtin file from this replace:
-// "^NULL,.*" with ""
-// "^{.*//.*}:Wh\(.*)" with ""
+// "^NULL.*" with ""
+// "^{.*//.*}:Wh\(.*\)" with "\1"
// "\:" with "//"
-// ".*//:Wh{\#:d*}:Wh{.*}" with "\2 = \1;"
+// "^.*//:Wh{\#:d*}:Wh{.*}" with "\2 = \1;"
// "\n\n+" with "\n\n"
prvm_builtin_t vm_cl_builtins[] = {
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, entity ignoreentity) traceline (QUAKE)
+VM_CL_traceline, // #16 void(vector v1, vector v2, float tryents, entity ignoreentity) traceline (QUAKE)
NULL, // #17 entity() checkclient (QUAKE)
VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
VM_precache_sound, // #19 void(string s) precache_sound (QUAKE)
NULL, // #237
NULL, // #238
NULL, // #239
-NULL, // #240
+VM_CL_checkpvs, // #240
NULL, // #241
NULL, // #242
NULL, // #243
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?
-NULL, // #329
+VM_stringwidth, // #327 // FIXME is this okay?
+VM_drawsubpic, // #328 // FIXME is this okay?
+VM_drawrotpic, // #329 // FIXME is this okay?
VM_CL_getstatf, // #330 float(float stnum) getstatf (EXT_CSQC)
VM_CL_getstati, // #331 float(float stnum) getstati (EXT_CSQC)
VM_CL_getstats, // #332 string(float firststnum) getstats (EXT_CSQC)
VM_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) setsensitivityscale (EXT_CSQC)
VM_CL_runplayerphysics, // #347 void() runstandardplayerphysics (EXT_CSQC)
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
-#ifdef SUPPORT_GECKO
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_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 )
-#else
-NULL, // #487
-NULL, // #488
-NULL, // #489
-NULL, // #490
-NULL, // #491
-NULL, // #492
-NULL, // #493
-#endif
-NULL, // #494
-NULL, // #495
-NULL, // #496
-NULL, // #497
-NULL, // #498
-NULL, // #499
+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)
+VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
+VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
+VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
+VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
+VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
+VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
+VM_keynumtostring, // #520 string keynumtostring(float keynum)
+VM_findkeysforcommand, // #521 string findkeysforcommand(string command)
+VM_CL_InitParticleSpawner, // #522 void(float max_themes) initparticlespawner (DP_CSQC_SPAWNPARTICLE)
+VM_CL_ResetParticle, // #523 void() resetparticle (DP_CSQC_SPAWNPARTICLE)
+VM_CL_ParticleTheme, // #524 void(float theme) particletheme (DP_CSQC_SPAWNPARTICLE)
+VM_CL_ParticleThemeSave, // #525 void() particlethemesave, void(float theme) particlethemeupdate (DP_CSQC_SPAWNPARTICLE)
+VM_CL_ParticleThemeFree, // #526 void() particlethemefree (DP_CSQC_SPAWNPARTICLE)
+VM_CL_SpawnParticle, // #527 float(vector org, vector vel, [float theme]) particle (DP_CSQC_SPAWNPARTICLE)
+VM_CL_SpawnParticleDelayed, // #528 float(vector org, vector vel, float delay, float collisiondelay, [float theme]) delayedparticle (DP_CSQC_SPAWNPARTICLE)
+NULL, // #529
+NULL, // #530
+NULL, // #531
+NULL, // #532
+NULL, // #533
+NULL, // #534
+NULL, // #535
+NULL, // #536
+NULL, // #537
+NULL, // #538
+NULL, // #539
+NULL, // #540
+NULL, // #541
+NULL, // #542
+NULL, // #543
+NULL, // #544
+NULL, // #545
+NULL, // #546
+NULL, // #547
+NULL, // #548
+NULL, // #549
+NULL, // #550
+NULL, // #551
+NULL, // #552
+NULL, // #553
+NULL, // #554
+NULL, // #555
+NULL, // #556
+NULL, // #557
+NULL, // #558
+NULL, // #559
+NULL, // #560
+NULL, // #561
+NULL, // #562
+NULL, // #563
+NULL, // #564
+NULL, // #565
+NULL, // #566
+NULL, // #567
+NULL, // #568
+NULL, // #569
+NULL, // #570
+NULL, // #571
+NULL, // #572
+NULL, // #573
+NULL, // #574
+NULL, // #575
+NULL, // #576
+NULL, // #577
+NULL, // #578
+NULL, // #579
+NULL, // #580
+NULL, // #581
+NULL, // #582
+NULL, // #583
+NULL, // #584
+NULL, // #585
+NULL, // #586
+NULL, // #587
+NULL, // #588
+NULL, // #589
+NULL, // #590
+NULL, // #591
+NULL, // #592
+NULL, // #593
+NULL, // #594
+NULL, // #595
+NULL, // #596
+NULL, // #597
+NULL, // #598
+NULL, // #599
+NULL, // #600
+NULL, // #601
+NULL, // #602
+NULL, // #603
+NULL, // #604
+NULL, // #605
+NULL, // #606
+NULL, // #607
+NULL, // #608
+NULL, // #609
+NULL, // #610
+NULL, // #611
+NULL, // #612
+NULL, // #613
+NULL, // #614
+NULL, // #615
+NULL, // #616
+NULL, // #617
+NULL, // #618
+NULL, // #619
+NULL, // #620
+NULL, // #621
+NULL, // #622
+NULL, // #623
+VM_getextresponse, // #624 string getextresponse(void)
+NULL, // #625
};
const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);