//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_GetSortedPlayerIndex (int index);
void Sbar_SortFrags (void);
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_Move(v1, vec3_origin, vec3_origin, 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_Move(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;
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);
}
}
}
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++)
vec3_t org, eorg, mins, maxs;
int i, numtouchedicts;
prvm_edict_t *touchedicts[MAX_EDICTS];
+ int chainfield;
- VM_SAFEPARMCOUNT(2, VM_CL_findradius);
+ VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_findradius);
+
+ if(prog->argc == 3)
+ chainfield = PRVM_G_INT(OFS_PARM2);
+ else
+ chainfield = prog->fieldoffsets.chain;
+ if(chainfield < 0)
+ 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;
}
}
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);
+ 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++];
}
//============================================================================
VM_SAFEPARMCOUNT(1, VM_CL_unproject);
f = PRVM_G_VECTOR(OFS_PARM0);
+ if(v_flipped.integer)
+ f[0] = r_refdef.view.x + r_refdef.view.width - f[0];
VectorSet(temp, f[2], (-1.0 + 2.0 * (f[0] - r_refdef.view.x)) / r_refdef.view.width * f[2] * -r_refdef.view.frustum_x, (-1.0 + 2.0 * (f[1] - 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);
+ if(v_flipped.integer)
+ v[1] = -v[1];
VectorSet(PRVM_G_VECTOR(OFS_RETURN), r_refdef.view.x + r_refdef.view.width*0.5*(1.0+v[1]/v[0]/-r_refdef.view.frustum_x), r_refdef.view.y + r_refdef.view.height*0.5*(1.0+v[2]/v[0]/-r_refdef.view.frustum_y), v[0]);
}
int i, frame;
VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
frame = (int)PRVM_G_FLOAT(OFS_PARM0);
+ PRVM_G_FLOAT(OFS_RETURN) = false;
for (i = 0;i < CL_MAX_USERCMDS;i++)
{
if (cl.movecmd[i].sequence == frame)
VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
}
+ PRVM_G_FLOAT(OFS_RETURN) = true;
}
}
}
{
// texture not found
// use the attached jpeg as texture
- buf = Mem_Alloc(tempmempool, size);
+ buf = (unsigned char *) Mem_Alloc(tempmempool, size);
MSG_ReadBytes(size, buf);
data = JPEG_LoadImage_BGRA(buf, size);
Mem_Free(buf);
// 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;
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;
+ 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
+ {
+ pitchsign = 1;
+ 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)
// 1 - world entity
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;
dp_model_t *model;
- float scale;
*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);
/*
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)
{
{
mempool_t *pool;
qboolean initialized;
+ double progstarttime;
int max_vertices;
int num_vertices;
R_RenderView();
polys->num_vertices = polys->num_triangles = 0;
+ polys->progstarttime = prog->starttime;
}
static void VM_ResizePolygons(vmpolygons_t *polys)
{
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);
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(drawflag == DRAWFLAG_MODULATE)
GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
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(tex));
void VM_CL_R_PolygonBegin (void)
{
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_SAFEPARMCOUNT(2, VM_CL_R_PolygonBegin);
if (!polys->initialized)
VM_InitPolygons(polys);
+ if(polys->progstarttime != prog->starttime)
+ {
+ // from another progs? then reset the polys first (fixes crashes on map change, because that can make skinframe textures invalid)
+ polys->num_vertices = polys->num_triangles = 0;
+ polys->progstarttime = prog->starttime;
+ }
if (polys->begin_active)
{
VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonBegin after first\n");
return;
}
picname = PRVM_G_STRING(OFS_PARM0);
- polys->begin_texture = picname[0] ? Draw_CachePic_Flags (picname, CACHEPICFLAG_NOCLAMP)->tex : r_texture_white;
- polys->begin_drawflag = (int)PRVM_G_FLOAT(OFS_PARM1);
+
+ sf = NULL;
+ if(*picname)
+ {
+ tf = TEXF_ALPHA;
+ if((int)PRVM_G_FLOAT(OFS_PARM1) & DRAWFLAG_MIPMAP)
+ tf |= TEXF_MIPMAP;
+
+ do
+ {
+ sf = R_SkinFrame_FindNextByName(sf, picname);
+ }
+ while(sf && sf->textureflags != tf);
+
+ if(!sf || !sf->base)
+ sf = R_SkinFrame_LoadExternal(picname, tf, true);
+
+ if(sf)
+ R_SkinFrame_MarkUsed(sf);
+ }
+
+ polys->begin_texture = (sf && sf->base) ? sf->base : r_texture_white;
+ polys->begin_drawflag = (int)PRVM_G_FLOAT(OFS_PARM1) & DRAWFLAG_MASK;
polys->begin_vertices = 0;
polys->begin_active = true;
}
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_Move (start, vec3_origin, vec3_origin, 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_Move (start, vec3_origin, vec3_origin, 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_Move (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_Move (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_Move (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:
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_drawcolorcodedstring, // #326 float drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) (EXT_CSQC)
VM_stringwidth, // #327 // FIXME is this okay?
VM_drawsubpic, // #328 // FIXME is this okay?
-NULL, // #329
+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_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_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)
+NULL, // #522
+NULL, // #523
+NULL, // #524
+NULL, // #525
+NULL, // #526
+NULL, // #527
+NULL, // #528
+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);