X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=csprogs.c;h=5791e9ea44ebf616618e26186bd955b624c38f75;hb=e941f7fbf97a98b3c0796ed834f580e0138c31b1;hp=2bf194178b004845dfa98f8a192d5ca041344deb;hpb=5d924fbc6125aa04fd9eae6c93af8f6bc04f7cf6;p=xonotic%2Fdarkplaces.git diff --git a/csprogs.c b/csprogs.c index 2bf19417..5791e9ea 100644 --- a/csprogs.c +++ b/csprogs.c @@ -5,6 +5,7 @@ #include "cl_collision.h" #include "snd_main.h" #include "clvm_cmds.h" +#include "prvm_cmds.h" //============================================================================ // Client prog handling @@ -13,8 +14,21 @@ #define CSQC_RETURNVAL prog->globals.generic[OFS_RETURN] #define CSQC_BEGIN csqc_tmpprog=prog;prog=0;PRVM_SetProg(PRVM_CLIENTPROG); #define CSQC_END prog=csqc_tmpprog; + static prvm_prog_t *csqc_tmpprog; +void CL_VM_PreventInformationLeaks(void) +{ + prvm_eval_t *val; + if(!cl.csqc_loaded) + return; + CSQC_BEGIN + VM_ClearTraceGlobals(); + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_networkentity))) + val->_float = 0; + CSQC_END +} + //[515]: these are required funcs static char *cl_required_func[] = { @@ -68,6 +82,22 @@ void CL_VM_UpdateDmgGlobals (int dmg_take, int dmg_save, vec3_t dmg_origin) CSQC_END } } + +void CSQC_UpdateNetworkTimes(double newtime, double oldtime) +{ + prvm_eval_t *val; + if(!cl.csqc_loaded) + return; + CSQC_BEGIN + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.servertime))) + val->_float = newtime; + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.serverprevtime))) + val->_float = oldtime; + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.serverdeltatime))) + val->_float = newtime - oldtime; + CSQC_END +} + //[515]: set globals before calling R_UpdateView, WEIRD CRAP static void CSQC_SetGlobals (void) { @@ -89,7 +119,7 @@ static void CSQC_SetGlobals (void) // CSQC is useless as it can't alter the view origin without // completely replacing it VectorCopy(cl.csqc_origin, prog->globals.client->pmove_org); - VectorCopy(cl.velocity, prog->globals.client->pmove_vel); + VectorCopy(cl.movement_velocity, prog->globals.client->pmove_vel); if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.view_angles))) VectorCopy(cl.viewangles, val->vector); @@ -123,6 +153,7 @@ void CSQC_Think (prvm_edict_t *ed) } extern cvar_t cl_noplayershadow; +extern cvar_t r_equalize_entities_fullbright; qboolean CSQC_AddRenderEdict(prvm_edict_t *ed) { int renderflags; @@ -137,7 +168,7 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed) if (!model) return false; - entrender = CL_NewTempEntity(); + entrender = CL_NewTempEntity(0); if (!entrender) return false; @@ -150,6 +181,7 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed) if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.alpha)) && val->_float) entrender->alpha = val->_float; if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.scale)) && val->_float) entrender->scale = scale = val->_float; if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, entrender->colormod); + if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.glowmod)) && VectorLength2(val->vector)) VectorCopy(val->vector, entrender->glowmod); if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.effects)) && val->_float) entrender->effects |= (int)val->_float; if((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.tag_entity)) && val->edict) { @@ -162,6 +194,10 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed) } else Matrix4x4_CreateIdentity(&tagmatrix); + if (!VectorLength2(entrender->colormod)) + VectorSet(entrender->colormod, 1, 1, 1); + if (!VectorLength2(entrender->glowmod)) + VectorSet(entrender->glowmod, 1, 1, 1); if (renderflags & RF_USEAXIS) { @@ -183,25 +219,23 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed) } // set up the animation data - // self.frame is the interpolation target (new frame) - // self.frame1time is the animation base time for the interpolation target - // self.frame2 is the interpolation start (previous frame) - // self.frame2time is the animation base time for the interpolation start - entrender->frame1 = entrender->frame2 = ed->fields.client->frame; - if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2))) entrender->frame2 = val->_float; - if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame1time))) entrender->frame2time = val->_float; - if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2time))) entrender->frame1time = val->_float; - if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac))) entrender->framelerp = val->_float; + CL_LoadFrameGroupBlend(ed, entrender); // concat the matrices to make the entity relative to its tag Matrix4x4_Concat(&entrender->matrix, &tagmatrix, &matrix2); + // transparent offset + if ((renderflags & RF_USETRANSPARENTOFFSET) && (val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.transparent_offset))) + entrender->transparent_offset = val->_float; + if(renderflags) { - if(renderflags & RF_VIEWMODEL) entrender->flags |= RENDER_VIEWMODEL; + if(renderflags & RF_VIEWMODEL) entrender->flags |= RENDER_VIEWMODEL | RENDER_NODEPTHTEST; if(renderflags & RF_EXTERNALMODEL)entrender->flags |= RENDER_EXTERIORMODEL; - if(renderflags & RF_DEPTHHACK) entrender->effects |= EF_NODEPTHTEST; - if(renderflags & RF_ADDITIVE) entrender->effects |= EF_ADDITIVE; + if(renderflags & RF_NOCULL) entrender->flags |= RENDER_NOCULL; + if(renderflags & RF_DEPTHHACK) entrender->flags |= RENDER_NODEPTHTEST; + if(renderflags & RF_ADDITIVE) entrender->flags |= RENDER_ADDITIVE; + } c = (int)ed->fields.client->colormap; @@ -214,8 +248,13 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed) entrender->flags &= ~(RENDER_SHADOW | RENDER_LIGHT | RENDER_NOSELFSHADOW); // either fullbright or lit - if (!(entrender->effects & EF_FULLBRIGHT) && !r_fullbright.integer) - entrender->flags |= RENDER_LIGHT; + if(!r_fullbright.integer) + { + if (!(entrender->effects & EF_FULLBRIGHT)) + entrender->flags |= RENDER_LIGHT; + else if(r_equalize_entities_fullbright.integer) + entrender->flags |= RENDER_LIGHT | RENDER_EQUALIZE; + } // hide player shadow during intermission or nehahra movie if (!(entrender->effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (entrender->alpha >= 1) @@ -226,6 +265,12 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed) entrender->flags |= RENDER_NOSELFSHADOW; if (entrender->effects & EF_NOSELFSHADOW) entrender->flags |= RENDER_NOSELFSHADOW; + if (entrender->effects & EF_NODEPTHTEST) + entrender->flags |= RENDER_NODEPTHTEST; + if (entrender->effects & EF_ADDITIVE) + entrender->flags |= RENDER_ADDITIVE; + if (entrender->effects & EF_DOUBLESIDED) + entrender->flags |= RENDER_DOUBLESIDED; // make the other useful stuff CL_UpdateRenderEntity(entrender); @@ -251,7 +296,7 @@ qboolean CL_VM_InputEvent (qboolean down, int key, int ascii) PRVM_G_FLOAT(OFS_PARM1) = key; PRVM_G_FLOAT(OFS_PARM2) = ascii; PRVM_ExecuteProgram(prog->funcoffsets.CSQC_InputEvent, "QC function CSQC_InputEvent is missing"); - r = CSQC_RETURNVAL; + r = CSQC_RETURNVAL != 0; } CSQC_END return r; @@ -302,7 +347,7 @@ qboolean CL_VM_ConsoleCommand (const char *cmd) PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(cmd); PRVM_ExecuteProgram(prog->funcoffsets.CSQC_ConsoleCommand, "QC function CSQC_ConsoleCommand is missing"); vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; - r = CSQC_RETURNVAL; + r = CSQC_RETURNVAL != 0; } CSQC_END return r; @@ -321,7 +366,7 @@ qboolean CL_VM_Parse_TempEntity (void) prog->globals.client->time = cl.time; prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity]; PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Parse_TempEntity, "QC function CSQC_Parse_TempEntity is missing"); - r = CSQC_RETURNVAL; + r = CSQC_RETURNVAL != 0; if(!r) { msg_readcount = t; @@ -503,7 +548,7 @@ void CL_VM_UpdateShowingScoresState (int showingscores) CSQC_END } } -qboolean CL_VM_Event_Sound(int sound_num, int volume, int channel, float attenuation, int ent, vec3_t pos) +qboolean CL_VM_Event_Sound(int sound_num, float volume, int channel, float attenuation, int ent, vec3_t pos) { qboolean r = false; if(cl.csqc_loaded) @@ -520,7 +565,7 @@ qboolean CL_VM_Event_Sound(int sound_num, int volume, int channel, float attenua PRVM_G_FLOAT(OFS_PARM4) = attenuation; VectorCopy(pos, PRVM_G_VECTOR(OFS_PARM5) ); PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Event_Sound, "QC function CSQC_Event_Sound is missing"); - r = CSQC_RETURNVAL; + r = CSQC_RETURNVAL != 0; } CSQC_END } @@ -677,6 +722,8 @@ void CL_VM_CB_FreeEdict(prvm_edict_t *ed) { World_UnlinkEdict(ed); memset(ed->fields.client, 0, sizeof(*ed->fields.client)); + World_Physics_RemoveFromEntity(&cl.world, ed); + World_Physics_RemoveJointFromEntity(&cl.world, ed); } void CL_VM_CB_CountEdicts(void) @@ -840,6 +887,7 @@ void CL_VM_Init (void) prog->init_cmd = VM_CL_Cmd_Init; prog->reset_cmd = VM_CL_Cmd_Reset; prog->error_cmd = CL_VM_Error; + prog->ExecuteProgram = CLVM_ExecuteProgram; PRVM_LoadProgs(csprogsfn, cl_numrequiredfunc, cl_required_func, 0, NULL, 0, NULL); @@ -863,7 +911,7 @@ void CL_VM_Init (void) sizebuf_t sb; unsigned char *demobuf; fs_offset_t demofilesize; - sb.data = (void *) buf; + sb.data = (unsigned char *) buf; sb.maxsize = sizeof(buf); i = 0; @@ -926,3 +974,81 @@ void CL_VM_ShutDown (void) Con_Print("CSQC ^1unloaded\n"); cl.csqc_loaded = false; } + +qboolean CL_VM_GetEntitySoundOrigin(int entnum, vec3_t out) +{ + prvm_edict_t *ed; + dp_model_t *mod; + matrix4x4_t matrix; + qboolean r = 0; + + CSQC_BEGIN; + + // FIXME consider attachments here! + + ed = PRVM_EDICT_NUM(entnum - 32768); + + if(!ed->priv.required->free) + { + mod = CL_GetModelFromEdict(ed); + VectorCopy(ed->fields.client->origin, out); + if(CL_GetTagMatrix (&matrix, ed, 0) == 0) + Matrix4x4_OriginFromMatrix(&matrix, out); + if (mod && mod->soundfromcenter) + VectorMAMAM(1.0f, out, 0.5f, mod->normalmins, 0.5f, mod->normalmaxs, out); + r = 1; + } + + CSQC_END; + + return r; +} + +void CL_LoadFrameGroupBlend(prvm_edict_t *ed, entity_render_t *entrender) +{ + prvm_eval_t *val; + // self.frame is the interpolation target (new frame) + // self.frame1time is the animation base time for the interpolation target + // self.frame2 is the interpolation start (previous frame) + // self.frame2time is the animation base time for the interpolation start + // self.lerpfrac is the interpolation strength for self.frame + // 3+ are for additional blends (the main use for this feature is lerping + // pitch angle on a player model where the animator set up 5 sets of + // animations and the csqc simply lerps between sets) + entrender->framegroupblend[0].frame = entrender->framegroupblend[1].frame = (int) ed->fields.client->frame; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2))) entrender->framegroupblend[1].frame = (int) val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame3))) entrender->framegroupblend[2].frame = (int) val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame4))) entrender->framegroupblend[3].frame = (int) val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame1time))) entrender->framegroupblend[0].start = val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2time))) entrender->framegroupblend[1].start = val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame3time))) entrender->framegroupblend[2].start = val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame4time))) entrender->framegroupblend[3].start = val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac))) entrender->framegroupblend[0].lerp = val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac3))) entrender->framegroupblend[2].lerp = val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac4))) entrender->framegroupblend[3].lerp = val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.shadertime))) entrender->shadertime = val->_float; + // assume that the (missing) lerpfrac2 is whatever remains after lerpfrac+lerpfrac3+lerpfrac4 are summed + entrender->framegroupblend[1].lerp = 1 - entrender->framegroupblend[0].lerp - entrender->framegroupblend[2].lerp - entrender->framegroupblend[3].lerp; +} + +qboolean CL_BlendTagMatrix(entity_render_t *entrender, int tagindex, matrix4x4_t *blendmatrix) +{ + int j, l, k; + float d; + dp_model_t *model = entrender->model; + if(!model) + return false; + // blend the matrices + memset(&blendmatrix, 0, sizeof(blendmatrix)); + for (j = 0;j < MAX_FRAMEBLENDS && entrender->frameblend[j].lerp > 0;j++) + { + matrix4x4_t tagmatrix; + if(!Mod_Alias_GetTagMatrix(model, entrender->frameblend[j].subframe, tagindex, &tagmatrix)) + return false; + d = entrender->frameblend[j].lerp; + for (l = 0;l < 4;l++) + for (k = 0;k < 4;k++) + blendmatrix->m[l][k] += d * tagmatrix.m[l][k]; + } + return true; +}