X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=clvm_cmds.c;h=87ee706a4c3376e0e7547a231736b4e495ebe240;hb=9e0b57e36ca8bb835c2f49901b4493b1f3b5625a;hp=cd2588ed7d814bfce50049a78fc33ecfb34d8aa1;hpb=861c406b589acf1252ddc231e02f94557a15e2bc;p=xonotic%2Fdarkplaces.git diff --git a/clvm_cmds.c b/clvm_cmds.c index cd2588ed..87ee706a 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -234,10 +234,8 @@ static void VM_CL_spawn (void) void CL_VM_SetTraceGlobals(const trace_t *trace, int svent) { - prvm_eval_t *val; VM_SetTraceGlobals(trace); - if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_networkentity))) - val->_float = svent; + PRVM_GLOBALFIELDFLOAT(prog->globaloffsets.trace_networkentity) = svent; } #define CL_HitNetworkBrushModels(move) !((move) == MOVE_WORLDONLY) @@ -265,7 +263,7 @@ static void VM_CL_traceline (void) 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_TraceLine(v1, v2, move, ent, CL_GenericHitSuperContentsMask(ent), CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true); + trace = CL_TraceLine(v1, v2, move, ent, CL_GenericHitSuperContentsMask(ent), CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true, false); CL_VM_SetTraceGlobals(&trace, svent); // R_TimeReport("traceline"); @@ -320,7 +318,6 @@ trace_t CL_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore, int *svent) vec3_t original_velocity; vec3_t original_angles; vec3_t original_avelocity; - prvm_eval_t *val; trace_t trace; VectorCopy(tossent->fields.client->origin , original_origin ); @@ -328,11 +325,9 @@ trace_t CL_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore, int *svent) VectorCopy(tossent->fields.client->angles , original_angles ); VectorCopy(tossent->fields.client->avelocity, original_avelocity); - val = PRVM_EDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity); - if (val != NULL && val->_float != 0) - gravity = val->_float; - else - gravity = 1.0; + gravity = PRVM_EDICTFIELDFLOAT(tossent, prog->fieldoffsets.gravity); + if (!gravity) + gravity = 1.0f; gravity *= cl.movevars_gravity * 0.05; for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds @@ -493,7 +488,7 @@ static void VM_CL_findradius (void) VectorMAMAM(1, eorg, -0.5f, ent->fields.client->mins, -0.5f, ent->fields.client->maxs, eorg); if (DotProduct(eorg, eorg) < radius2) { - PRVM_EDICTFIELDVALUE(ent, chainfield)->edict = PRVM_EDICT_TO_PROG(chain); + PRVM_EDICTFIELDEDICT(ent, chainfield) = PRVM_EDICT_TO_PROG(chain); chain = ent; } } @@ -505,7 +500,6 @@ static void VM_CL_findradius (void) static void VM_CL_droptofloor (void) { prvm_edict_t *ent; - prvm_eval_t *val; vec3_t end; trace_t trace; @@ -535,8 +529,7 @@ static void VM_CL_droptofloor (void) { VectorCopy (trace.endpos, ent->fields.client->origin); ent->fields.client->flags = (int)ent->fields.client->flags | FL_ONGROUND; - if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity))) - val->edict = PRVM_EDICT_TO_PROG(trace.ent); + PRVM_EDICTFIELDEDICT(ent, prog->fieldoffsets.groundentity) = PRVM_EDICT_TO_PROG(trace.ent); PRVM_G_FLOAT(OFS_RETURN) = 1; // if support is destroyed, keep suspended (gross hack for floating items in various maps) // ent->priv.server->suspendedinairflag = true; @@ -608,7 +601,7 @@ realcheck: 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_TraceLine(start, 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, false); if (trace.fraction == 1.0) return; @@ -622,7 +615,7 @@ realcheck: start[0] = stop[0] = x ? maxs[0] : mins[0]; start[1] = stop[1] = y ? maxs[1] : mins[1]; - trace = CL_TraceLine(start, 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, false); if (trace.fraction != 1.0 && trace.endpos[2] > bottom) bottom = trace.endpos[2]; @@ -667,24 +660,25 @@ static void VM_CL_ambientsound (void) S_StaticSound (s, f, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3)*64); } -// #92 vector(vector org) getlight (DP_QC_GETLIGHT) +// #92 vector(vector org[, float lpflag]) getlight (DP_QC_GETLIGHT) static void VM_CL_getlight (void) { vec3_t ambientcolor, diffusecolor, diffusenormal; vec_t *p; - VM_SAFEPARMCOUNT(1, VM_CL_getlight); + VM_SAFEPARMCOUNTRANGE(1, 2, VM_CL_getlight); p = PRVM_G_VECTOR(OFS_PARM0); VectorClear(ambientcolor); VectorClear(diffusecolor); VectorClear(diffusenormal); - if (cl.worldmodel && cl.worldmodel->brush.LightPoint) + if (prog->argc >= 2) + R_CompleteLightPoint(ambientcolor, diffusecolor, diffusenormal, p, PRVM_G_FLOAT(OFS_PARM1)); + else if (cl.worldmodel && cl.worldmodel->brush.LightPoint) cl.worldmodel->brush.LightPoint(cl.worldmodel, p, ambientcolor, diffusecolor, diffusenormal); VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN)); } - //============================================================================ //[515]: SCENE MANAGER builtins extern qboolean CSQC_AddRenderEdict (prvm_edict_t *ed, int edictnum);//csprogs.c @@ -692,8 +686,8 @@ extern qboolean CSQC_AddRenderEdict (prvm_edict_t *ed, int edictnum);//csprogs.c static void CSQC_R_RecalcView (void) { extern matrix4x4_t viewmodelmatrix; - Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], 1); - Matrix4x4_CreateFromQuakeEntity(&viewmodelmatrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], cl_viewmodel_scale.value); + Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, cl.csqc_vieworigin[0], cl.csqc_vieworigin[1], cl.csqc_vieworigin[2], cl.csqc_viewangles[0], cl.csqc_viewangles[1], cl.csqc_viewangles[2], 1); + Matrix4x4_CreateFromQuakeEntity(&viewmodelmatrix, cl.csqc_vieworigin[0], cl.csqc_vieworigin[1], cl.csqc_vieworigin[2], cl.csqc_viewangles[0], cl.csqc_viewangles[1], cl.csqc_viewangles[2], cl_viewmodel_scale.value); } void CL_RelinkLightFlashes(void); @@ -721,8 +715,8 @@ void VM_CL_R_ClearScene (void) r_refdef.view.ortho_y = scr_fov.value * (3.0 / 4.0); r_refdef.view.clear = true; r_refdef.view.isoverlay = false; - // FIXME: restore cl.csqc_origin - // FIXME: restore cl.csqc_angles + VectorCopy(cl.csqc_vieworiginfromengine, cl.csqc_vieworigin); + VectorCopy(cl.csqc_viewanglesfromengine, cl.csqc_viewangles); cl.csqc_vidvars.drawworld = r_drawworld.integer != 0; cl.csqc_vidvars.drawenginesbar = false; cl.csqc_vidvars.drawcrosshair = false; @@ -744,6 +738,8 @@ void VM_CL_R_AddEntities (void) prog->globals.client->time = cl.time; for(i=1;inum_edicts;i++) { + // so we can easily check if CSQC entity #edictnum is currently drawn + cl.csqcrenderentities[i].entitynumber = 0; ed = &prog->edicts[i]; if(ed->priv.required->free) continue; @@ -822,28 +818,28 @@ void VM_CL_R_SetView (void) PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.ortho_y; break; case VF_ORIGIN: - VectorCopy(cl.csqc_origin, PRVM_G_VECTOR(OFS_RETURN)); + VectorCopy(cl.csqc_vieworigin, PRVM_G_VECTOR(OFS_RETURN)); break; case VF_ORIGIN_X: - PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_origin[0]; + PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vieworigin[0]; break; case VF_ORIGIN_Y: - PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_origin[1]; + PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vieworigin[1]; break; case VF_ORIGIN_Z: - PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_origin[2]; + PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vieworigin[2]; break; case VF_ANGLES: - VectorCopy(cl.csqc_angles, PRVM_G_VECTOR(OFS_RETURN)); + VectorCopy(cl.csqc_viewangles, PRVM_G_VECTOR(OFS_RETURN)); break; case VF_ANGLES_X: - PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_angles[0]; + PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_viewangles[0]; break; case VF_ANGLES_Y: - PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_angles[1]; + PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_viewangles[1]; break; case VF_ANGLES_Z: - PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_angles[2]; + PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_viewangles[2]; break; case VF_DRAWWORLD: PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vidvars.drawworld; @@ -887,22 +883,28 @@ void VM_CL_R_SetView (void) case VF_MIN: r_refdef.view.x = (int)(f[0]); r_refdef.view.y = (int)(f[1]); + DrawQ_RecalcView(); break; case VF_MIN_X: r_refdef.view.x = (int)(k); + DrawQ_RecalcView(); break; case VF_MIN_Y: r_refdef.view.y = (int)(k); + DrawQ_RecalcView(); break; case VF_SIZE: r_refdef.view.width = (int)(f[0]); r_refdef.view.height = (int)(f[1]); + DrawQ_RecalcView(); break; case VF_SIZE_X: r_refdef.view.width = (int)(k); + DrawQ_RecalcView(); break; case VF_SIZE_Y: r_refdef.view.height = (int)(k); + DrawQ_RecalcView(); break; case VF_VIEWPORT: r_refdef.view.x = (int)(f[0]); @@ -910,6 +912,7 @@ void VM_CL_R_SetView (void) f = PRVM_G_VECTOR(OFS_PARM2); r_refdef.view.width = (int)(f[0]); r_refdef.view.height = (int)(f[1]); + DrawQ_RecalcView(); break; case VF_FOV: r_refdef.view.frustum_x = tan(f[0] * M_PI / 360.0);r_refdef.view.ortho_x = f[0]; @@ -922,35 +925,35 @@ void VM_CL_R_SetView (void) r_refdef.view.frustum_y = tan(k * M_PI / 360.0);r_refdef.view.ortho_y = k; break; case VF_ORIGIN: - VectorCopy(f, cl.csqc_origin); + VectorCopy(f, cl.csqc_vieworigin); CSQC_R_RecalcView(); break; case VF_ORIGIN_X: - cl.csqc_origin[0] = k; + cl.csqc_vieworigin[0] = k; CSQC_R_RecalcView(); break; case VF_ORIGIN_Y: - cl.csqc_origin[1] = k; + cl.csqc_vieworigin[1] = k; CSQC_R_RecalcView(); break; case VF_ORIGIN_Z: - cl.csqc_origin[2] = k; + cl.csqc_vieworigin[2] = k; CSQC_R_RecalcView(); break; case VF_ANGLES: - VectorCopy(f, cl.csqc_angles); + VectorCopy(f, cl.csqc_viewangles); CSQC_R_RecalcView(); break; case VF_ANGLES_X: - cl.csqc_angles[0] = k; + cl.csqc_viewangles[0] = k; CSQC_R_RecalcView(); break; case VF_ANGLES_Y: - cl.csqc_angles[1] = k; + cl.csqc_viewangles[1] = k; CSQC_R_RecalcView(); break; case VF_ANGLES_Z: - cl.csqc_angles[2] = k; + cl.csqc_viewangles[2] = k; CSQC_R_RecalcView(); break; case VF_DRAWWORLD: @@ -1051,12 +1054,12 @@ static void VM_CL_unproject (void) VM_SAFEPARMCOUNT(1, VM_CL_unproject); f = PRVM_G_VECTOR(OFS_PARM0); - 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); + (-1.0 + 2.0 * (f[0] / vid_conwidth.integer)) * f[2] * -r_refdef.view.frustum_x, + (-1.0 + 2.0 * (f[1] / vid_conheight.integer)) * f[2] * -r_refdef.view.frustum_y); + if(v_flipped.integer) + temp[1] = -temp[1]; Matrix4x4_Transform(&r_refdef.view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN)); } @@ -1074,9 +1077,12 @@ static void VM_CL_project (void) 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)), + vid_conwidth.integer * (0.5*(1.0+v[1]/v[0]/-r_refdef.view.frustum_x)), + vid_conheight.integer * (0.5*(1.0+v[2]/v[0]/-r_refdef.view.frustum_y)), v[0]); + // explanation: + // after transforming, relative position to viewport (0..1) = 0.5 * (1 + v[2]/v[0]/-frustum_{x \or y}) + // as 2D drawing honors the viewport too, to get the same pixel, we simply multiply this by conwidth/height } //#330 float(float stnum) getstatf (EXT_CSQC) @@ -1248,16 +1254,15 @@ static void VM_CL_pointparticles (void) static void VM_CL_boxparticles (void) { int effectnum; - prvm_edict_t *own; + // prvm_edict_t *own; float *origin_from, *origin_to, *dir_from, *dir_to; float count; int flags; float tintmins[4], tintmaxs[4]; - prvm_eval_t *val; VM_SAFEPARMCOUNTRANGE(7, 8, VM_CL_boxparticles); effectnum = (int)PRVM_G_FLOAT(OFS_PARM0); - own = PRVM_G_EDICT(OFS_PARM1); // TODO find use for this + // own = PRVM_G_EDICT(OFS_PARM1); // TODO find use for this origin_from = PRVM_G_VECTOR(OFS_PARM2); origin_to = PRVM_G_VECTOR(OFS_PARM3); dir_from = PRVM_G_VECTOR(OFS_PARM4); @@ -1271,17 +1276,13 @@ static void VM_CL_boxparticles (void) Vector4Set(tintmaxs, 1, 1, 1, 1); if(flags & 1) // read alpha { - if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.particles_alphamin))) - tintmins[3] = val->_float; - if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.particles_alphamax))) - tintmaxs[3] = val->_float; + tintmins[3] = PRVM_GLOBALFIELDFLOAT(prog->globaloffsets.particles_alphamin); + tintmaxs[3] = PRVM_GLOBALFIELDFLOAT(prog->globaloffsets.particles_alphamax); } if(flags & 2) // read color { - if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.particles_colormin))) - VectorCopy(val->vector, tintmins); - if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.particles_colormax))) - VectorCopy(val->vector, tintmaxs); + VectorCopy(PRVM_GLOBALFIELDVECTOR(prog->globaloffsets.particles_colormin), tintmins); + VectorCopy(PRVM_GLOBALFIELDVECTOR(prog->globaloffsets.particles_colormax), tintmaxs); } if (effectnum < 0) return; @@ -1532,7 +1533,7 @@ static void VM_CL_ReadPicture (void) // texture found and loaded // skip over the jpeg as we don't need it for(i = 0; i < size; ++i) - MSG_ReadByte(); + (void) MSG_ReadByte(); } else { @@ -1573,7 +1574,6 @@ static void VM_CL_makestatic (void) if (cl.num_static_entities < cl.max_static_entities) { int renderflags; - prvm_eval_t *val; entity_t *staticent = &cl.static_entities[cl.num_static_entities++]; // copy it to the current state @@ -1585,19 +1585,22 @@ static void VM_CL_makestatic (void) staticent->render.framegroupblend[0].start = lhrandom(-10, -1); staticent->render.skinnum = (int)ent->fields.client->skin; staticent->render.effects = (int)ent->fields.client->effects; - staticent->render.alpha = 1; - if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)) && val->_float) staticent->render.alpha = val->_float; - staticent->render.scale = 1; - if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)) && val->_float) staticent->render.scale = val->_float; - if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.colormod); - if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glowmod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.glowmod); + staticent->render.alpha = PRVM_EDICTFIELDFLOAT(ent, prog->fieldoffsets.alpha); + staticent->render.scale = PRVM_EDICTFIELDFLOAT(ent, prog->fieldoffsets.scale); + VectorCopy(PRVM_EDICTFIELDVECTOR(ent, prog->fieldoffsets.colormod), staticent->render.colormod); + VectorCopy(PRVM_EDICTFIELDVECTOR(ent, prog->fieldoffsets.glowmod), staticent->render.glowmod); + + // sanitize values + if (!staticent->render.alpha) + staticent->render.alpha = 1.0f; + if (!staticent->render.scale) + staticent->render.scale = 1.0f; if (!VectorLength2(staticent->render.colormod)) VectorSet(staticent->render.colormod, 1, 1, 1); if (!VectorLength2(staticent->render.glowmod)) VectorSet(staticent->render.glowmod, 1, 1, 1); - renderflags = 0; - if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && val->_float) renderflags = (int)val->_float; + renderflags = (int)PRVM_EDICTFIELDFLOAT(ent, prog->fieldoffsets.renderflags); if (renderflags & RF_USEAXIS) { vec3_t left; @@ -1673,7 +1676,7 @@ static void VM_CL_copyentity (void) VM_Warning("copyentity: can not modify free entity\n"); return; } - memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4); + memcpy(out->fields.vp, in->fields.vp, prog->entityfields * 4); CL_LinkEdict(out); } @@ -2087,8 +2090,8 @@ void VM_CL_setattachment (void) prvm_edict_t *e; prvm_edict_t *tagentity; const char *tagname; - prvm_eval_t *v; int modelindex; + int tagindex; dp_model_t *model; VM_SAFEPARMCOUNT(3, VM_CL_setattachment); @@ -2110,26 +2113,23 @@ void VM_CL_setattachment (void) if (tagentity == NULL) tagentity = prog->edicts; - v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity); - if (v) - v->edict = PRVM_EDICT_TO_PROG(tagentity); - - v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index); - if (v) - v->_float = 0; + tagindex = 0; if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0]) { modelindex = (int)tagentity->fields.client->modelindex; model = CL_GetModelByIndex(modelindex); if (model) { - v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.client->skin, tagname); - if (v->_float == 0) + tagindex = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.client->skin, tagname); + if (tagindex == 0) Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity), model->name); } else Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity)); } + + PRVM_EDICTFIELDEDICT(e, prog->fieldoffsets.tag_entity) = PRVM_EDICT_TO_PROG(tagentity); + PRVM_EDICTFIELDFLOAT(e, prog->fieldoffsets.tag_index) = tagindex; } ///////////////////////////////////////// @@ -2178,18 +2178,27 @@ int CL_GetPitchSign(prvm_edict_t *ent) void CL_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix) { - prvm_eval_t *val; float scale; float pitchsign = 1; - scale = 1; - val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale); - if (val && val->_float != 0) - scale = val->_float; + scale = PRVM_EDICTFIELDFLOAT(ent, prog->fieldoffsets.scale); + if (!scale) + scale = 1.0f; - // TODO do we need the same weird angle inverting logic here as in the server side case? if(viewmatrix) - Matrix4x4_CreateFromQuakeEntity(out, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], scale * cl_viewmodel_scale.value); + *out = r_refdef.view.matrix; + else if ((int)PRVM_EDICTFIELDFLOAT(ent, prog->fieldoffsets.renderflags) & RF_USEAXIS) + { + vec3_t forward; + vec3_t left; + vec3_t up; + vec3_t origin; + VectorScale(prog->globals.client->v_forward, scale, forward); + VectorScale(prog->globals.client->v_right, -scale, left); + VectorScale(prog->globals.client->v_up, scale, up); + VectorCopy(ent->fields.client->origin, origin); + Matrix4x4_FromVectors(out, forward, left, up, origin); + } else { pitchsign = CL_GetPitchSign(ent); @@ -2226,7 +2235,6 @@ extern cvar_t cl_bobup; int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex) { int ret; - prvm_eval_t *val; int attachloop; matrix4x4_t entitymatrix, tagmatrix, attachmatrix; dp_model_t *model; @@ -2257,10 +2265,10 @@ int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex) Matrix4x4_Concat(&tagmatrix, &attachmatrix, out); Matrix4x4_Concat(out, &entitymatrix, &tagmatrix); // next iteration we process the parent entity - if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict) + if (PRVM_EDICTFIELDEDICT(ent, prog->fieldoffsets.tag_entity)) { - tagindex = (int)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float; - ent = PRVM_EDICT_NUM(val->edict); + tagindex = (int)PRVM_EDICTFIELDFLOAT(ent, prog->fieldoffsets.tag_index); + ent = PRVM_EDICT_NUM(PRVM_EDICTFIELDEDICT(ent, prog->fieldoffsets.tag_entity)); } else break; @@ -2268,7 +2276,7 @@ int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex) } // RENDER_VIEWMODEL magic - if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float)) + if ((int)PRVM_EDICTFIELDFLOAT(ent, prog->fieldoffsets.renderflags) & RF_VIEWMODEL) { Matrix4x4_Copy(&tagmatrix, out); @@ -2345,7 +2353,6 @@ void VM_CL_gettaginfo (void) int parentindex; const char *tagname; int returncode; - prvm_eval_t *val; vec3_t fo, le, up, trans; const dp_model_t *model; @@ -2363,18 +2370,12 @@ void VM_CL_gettaginfo (void) CL_GetExtendedTagInfo(e, tagindex, &parentindex, &tagname, &tag_localmatrix); Matrix4x4_ToVectors(&tag_localmatrix, fo, le, up, trans); - if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_parent))) - val->_float = parentindex; - if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_name))) - val->string = tagname ? PRVM_SetTempString(tagname) : 0; - if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_offset))) - VectorCopy(trans, val->vector); - if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_forward))) - VectorCopy(fo, val->vector); - if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_right))) - VectorScale(le, -1, val->vector); - if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_up))) - VectorCopy(up, val->vector); + PRVM_GLOBALFIELDFLOAT(prog->globaloffsets.gettaginfo_parent) = parentindex; + PRVM_GLOBALFIELDSTRING(prog->globaloffsets.gettaginfo_name) = tagname ? PRVM_SetTempString(tagname) : 0; + VectorCopy(trans, PRVM_GLOBALFIELDVECTOR(prog->globaloffsets.gettaginfo_offset)); + VectorCopy(fo, PRVM_GLOBALFIELDVECTOR(prog->globaloffsets.gettaginfo_forward)); + VectorScale(le, -1, PRVM_GLOBALFIELDVECTOR(prog->globaloffsets.gettaginfo_right)); + VectorCopy(up, PRVM_GLOBALFIELDVECTOR(prog->globaloffsets.gettaginfo_up)); switch(returncode) { @@ -2481,8 +2482,6 @@ vmparticlespawner_t vmpartspawner; // TODO: automatic max_themes grow static void VM_InitParticleSpawner (int maxthemes) { - prvm_eval_t *val; - // bound max themes to not be an insane value if (maxthemes < 4) maxthemes = 4; @@ -2500,8 +2499,8 @@ static void VM_InitParticleSpawner (int maxthemes) vmpartspawner.initialized = true; vmpartspawner.verified = true; // get field addresses for fast querying (we can do 1000 calls of spawnparticle in a frame) - #define getglobal(v,s) val = PRVM_GLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset(s)); if (val) { vmpartspawner.v = &val->_float; } else { VM_Warning("VM_InitParticleSpawner: missing global '%s', spawner cannot work\n", s); vmpartspawner.verified = false; } - #define getglobalvector(v,s) val = PRVM_GLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset(s)); if (val) { vmpartspawner.v = (float *)val->vector; } else { VM_Warning("VM_InitParticleSpawner: missing global '%s', spawner cannot work\n", s); vmpartspawner.verified = false; } + #define getglobal(v,s) vmpartspawner.v = &PRVM_GLOBALFIELDFLOAT(PRVM_ED_FindGlobalOffset(s)) + #define getglobalvector(v,s) vmpartspawner.v = PRVM_GLOBALFIELDVECTOR(PRVM_ED_FindGlobalOffset(s)) getglobal(particle_type, "particle_type"); getglobal(particle_blendmode, "particle_blendmode"); getglobal(particle_orientation, "particle_orientation"); @@ -2954,6 +2953,7 @@ typedef struct vmpolygons_triangle_s { rtexture_t *texture; int drawflag; + qboolean hasalpha; unsigned short elements[3]; }vmpolygons_triangle_t; @@ -2975,12 +2975,14 @@ typedef struct vmpolygons_s unsigned short *data_sortedelement3s; qboolean begin_active; + int begin_draw2d; rtexture_t *begin_texture; int begin_drawflag; int begin_vertices; float begin_vertex[VMPOLYGONS_MAXPOINTS][3]; float begin_color[VMPOLYGONS_MAXPOINTS][4]; float begin_texcoord[VMPOLYGONS_MAXPOINTS][2]; + qboolean begin_texture_hasalpha; } vmpolygons_t; // FIXME: make VM_CL_R_Polygon functions use Debug_Polygon functions? @@ -3060,9 +3062,11 @@ static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t 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_ResetTextureState(); R_EntityMatrix(&identitymatrix); GL_CullFace(GL_NONE); + GL_DepthTest(true); // polys in 3D space shall always have depth test + GL_DepthRange(0, 1); R_Mesh_PrepareVertices_Generic_Arrays(polys->num_vertices, polys->data_vertex3f, polys->data_color4f, polys->data_texcoord2f); for (surfacelistindex = 0;surfacelistindex < numsurfaces;) @@ -3070,18 +3074,7 @@ static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t 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); + DrawQ_ProcessDrawFlag(drawflag, polys->data_triangles[surfacelist[surfacelistindex]].hasalpha); R_SetupShader_Generic(tex, NULL, GL_MODULATE, 1); numtriangles = 0; for (;surfacelistindex < numsurfaces;surfacelistindex++) @@ -3097,7 +3090,16 @@ static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t void VMPolygons_Store(vmpolygons_t *polys) { - if (r_refdef.draw2dstage) + qboolean hasalpha; + int i; + + // detect if we have alpha + hasalpha = polys->begin_texture_hasalpha; + for(i = 0; !hasalpha && (i < polys->begin_vertices); ++i) + if(polys->begin_color[i][3] < 1) + hasalpha = true; + + if (polys->begin_draw2d) { // draw the polygon as 2D immediately drawqueuemesh_t mesh; @@ -3109,7 +3111,7 @@ void VMPolygons_Store(vmpolygons_t *polys) 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); + DrawQ_Mesh(&mesh, polys->begin_drawflag, hasalpha); } else { @@ -3117,7 +3119,8 @@ void VMPolygons_Store(vmpolygons_t *polys) int i; if (polys->max_triangles < polys->num_triangles + polys->begin_vertices-2) { - polys->max_triangles *= 2; + while (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) @@ -3136,6 +3139,7 @@ void VMPolygons_Store(vmpolygons_t *polys) 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->data_triangles[polys->num_triangles].hasalpha = hasalpha; polys->num_triangles++; } polys->num_vertices += polys->begin_vertices; @@ -3169,7 +3173,7 @@ void VM_CL_AddPolygonsToMeshQueue (void) polys->num_vertices = 0; // otherwise it's not rendered at all and prints an error message --blub */ } -//void(string texturename, float flag) R_BeginPolygon +//void(string texturename, float flag[, float is2d]) R_BeginPolygon void VM_CL_R_PolygonBegin (void) { const char *picname; @@ -3181,7 +3185,7 @@ void VM_CL_R_PolygonBegin (void) // better management of flags, and is more suited for 3D rendering), what // about supporting Q3 shaders? - VM_SAFEPARMCOUNT(2, VM_CL_R_PolygonBegin); + VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_R_PolygonBegin); if (!polys->initialized) VM_InitPolygons(polys); @@ -3219,9 +3223,11 @@ void VM_CL_R_PolygonBegin (void) } polys->begin_texture = (sf && sf->base) ? sf->base : r_texture_white; + polys->begin_texture_hasalpha = (sf && sf->base) ? sf->hasalpha : false; polys->begin_drawflag = (int)PRVM_G_FLOAT(OFS_PARM1) & DRAWFLAG_MASK; polys->begin_vertices = 0; polys->begin_active = true; + polys->begin_draw2d = (prog->argc >= 3 ? (int)PRVM_G_FLOAT(OFS_PARM2) : r_refdef.draw2dstage); } //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex @@ -3284,7 +3290,7 @@ void Debug_PolygonBegin(const char *picname, int drawflag) Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n"); return; } - debugPolys.begin_texture = picname[0] ? Draw_CachePic (picname)->tex : r_texture_white; + debugPolys.begin_texture = picname[0] ? Draw_CachePic_Flags (picname, CACHEPICFLAG_NOTPERSISTENT)->tex : r_texture_white; debugPolys.begin_drawflag = drawflag; debugPolys.begin_vertices = 0; debugPolys.begin_active = true; @@ -3374,7 +3380,7 @@ realcheck: 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_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true); + trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true, false); if (trace.fraction == 1.0) return false; @@ -3387,7 +3393,7 @@ realcheck: start[0] = stop[0] = x ? maxs[0] : mins[0]; start[1] = stop[1] = y ? maxs[1] : mins[1]; - trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true); + trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true, false); if (trace.fraction != 1.0 && trace.endpos[2] > bottom) bottom = trace.endpos[2]; @@ -3414,7 +3420,6 @@ qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean trace_t trace; int i, svent; prvm_edict_t *enemy; - prvm_eval_t *val; // try the move VectorCopy (ent->fields.client->origin, oldorg); @@ -3511,8 +3516,7 @@ qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean if ( (int)ent->fields.client->flags & FL_PARTIALGROUND ) ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND; - if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity))) - val->edict = PRVM_EDICT_TO_PROG(trace.ent); + PRVM_EDICTFIELDEDICT(ent, prog->fieldoffsets.groundentity) = PRVM_EDICT_TO_PROG(trace.ent); // the move is ok if (relink) @@ -3970,6 +3974,44 @@ static void VM_CL_frameduration(void) PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate; } +void VM_CL_RotateMoves(void) +{ + /* + * Obscure builtin used by GAME_XONOTIC. + * + * Edits the input history of cl_movement by rotating all move commands + * currently in the queue using the given transform. + * + * The vector passed is an "angles transform" as used by warpzonelib, i.e. + * v_angle-like (non-inverted) euler angles that perform the rotation + * of the space that is to be done. + * + * This is meant to be used as a fixangle replacement after passing + * through a warpzone/portal: the client is told about the warp transform, + * and calls this function in the same frame as the one on which the + * client's origin got changed by the serverside teleport. Then this code + * transforms the pre-warp input (which matches the empty space behind + * the warp plane) into post-warp input (which matches the target area + * of the warp). Also, at the same time, the client has to use + * R_SetView to adjust VF_CL_VIEWANGLES according to the same transform. + * + * This together allows warpzone motion to be perfectly predicted by + * the client! + * + * Furthermore, for perfect warpzone behaviour, the server side also + * has to detect input the client sent before it received the origin + * update, but after the warp occurred on the server, and has to adjust + * input appropriately. + */ + matrix4x4_t m; + vec3_t v = {0, 0, 0}; + vec3_t x, y, z; + VM_SAFEPARMCOUNT(1, VM_CL_RotateMoves); + AngleVectorsFLU(PRVM_G_VECTOR(OFS_PARM0), x, y, z); + Matrix4x4_FromVectors(&m, x, y, z, v); + CL_RotateMoves(&m); +} + //============================================================================ // To create a almost working builtin file from this replace: @@ -4289,7 +4331,7 @@ VM_CL_R_AddEntity, // #302 void(entity ent) addentity (EXT_CSQC) VM_CL_R_SetView, // #303 float(float property, ...) setproperty (EXT_CSQC) VM_CL_R_RenderScene, // #304 void() renderscene (EXT_CSQC) VM_CL_R_AddDynamicLight, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC) -VM_CL_R_PolygonBegin, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon +VM_CL_R_PolygonBegin, // #306 void(string texturename, float flag, float is2d[NYI: , float lines]) R_BeginPolygon VM_CL_R_PolygonVertex, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex VM_CL_R_PolygonEnd, // #308 void() R_EndPolygon NULL /* R_LoadWorldModel in menu VM, should stay unassigned in client*/, // #309 @@ -4325,7 +4367,7 @@ VM_centerprint, // #338 void(string s, ...) centerprint (EXT_CSQC) VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT) VM_keynumtostring, // #340 string(float keynum) keynumtostring (EXT_CSQC) VM_stringtokeynum, // #341 float(string keyname) stringtokeynum (EXT_CSQC) -VM_getkeybind, // #342 string(float keynum) getkeybind (EXT_CSQC) +VM_getkeybind, // #342 string(float keynum[, float bindmap]) getkeybind (EXT_CSQC) VM_CL_setcursormode, // #343 void(float usecursor) setcursormode (EXT_CSQC) VM_CL_getmousepos, // #344 vector() getmousepos (EXT_CSQC) VM_CL_getinputstate, // #345 float(float framenum) getinputstate (EXT_CSQC) @@ -4497,7 +4539,7 @@ 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_uri_get, // #513 float(string uri, float id, [string post_contenttype, string post_delim, [float buf]]) uri_get = #513; (DP_QC_URI_GET, DP_QC_URI_POST) 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) @@ -4505,7 +4547,7 @@ VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) 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_findkeysforcommand, // #521 string findkeysforcommand(string command[, float bindmap]) 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) @@ -4524,9 +4566,9 @@ NULL, // #536 NULL, // #537 NULL, // #538 NULL, // #539 -NULL, // #540 -NULL, // #541 -NULL, // #542 +VM_physics_enable, // #540 void(entity e, float physics_enabled) physics_enable = #540; (DP_PHYSICS_ODE) +VM_physics_addforce, // #541 void(entity e, vector force, vector relative_ofs) physics_addforce = #541; (DP_PHYSICS_ODE) +VM_physics_addtorque, // #542 void(entity e, vector torque) physics_addtorque = #542; (DP_PHYSICS_ODE) NULL, // #543 NULL, // #544 NULL, // #545 @@ -4594,7 +4636,7 @@ VM_writetofile, // #606 VM_isfunction, // #607 NULL, // #608 NULL, // #609 -NULL, // #610 +VM_findkeysforcommand, // #610 string findkeysforcommand(string command[, float bindmap]) NULL, // #611 NULL, // #612 VM_parseentitydata, // #613 @@ -4614,7 +4656,16 @@ NULL, // #626 VM_sprintf, // #627 string sprintf(string format, ...) VM_getsurfacenumtriangles, // #628 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACETRIANGLE) VM_getsurfacetriangle, // #629 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACETRIANGLE) -NULL, // #630 +VM_setkeybind, // #630 float(float key, string bind[, float bindmap]) setkeybind +VM_getbindmaps, // #631 vector(void) getbindmap +VM_setbindmaps, // #632 float(vector bm) setbindmap +NULL, // #633 +NULL, // #634 +NULL, // #635 +NULL, // #636 +NULL, // #637 +VM_CL_RotateMoves, // #638 +NULL, // #639 }; const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);