From: havoc Date: Sat, 26 Aug 2006 07:02:49 +0000 (+0000) Subject: CSQC fixes (less broken, still not spec compliant) X-Git-Tag: xonotic-v0.1.0preview~3818 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=commitdiff_plain;h=757a7dcbb67fcbeac0275a072dd984fd15a96b93 CSQC fixes (less broken, still not spec compliant) CSQC can now link the same entity multiple times (each time modified differently) as per the CSQC spec (this is mainly useful for rendering multi-model players based on one csqc entity, like Quake3's cgame does) changed DrawQ functions to automatically set up 2D rendering if previous rendering was of a 3D view (necessary change for proper CSQC support) changed QuakeC rint builtin implementation to handle very large values (outside of int range) and possibly run a little bit faster, note that it still rounds toward the nearest integer, away from zero (as intended) refactored gun bob, damage kick fade, and stair smoothing code to eliminate a 'multiple fade steps per frame' bug renamed the misnamed VM_ftoi function to VM_ftoe, in accordance with the menu QC builtin ftoe git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6568 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/cl_main.c b/cl_main.c index 363bdcee..fae786c0 100644 --- a/cl_main.c +++ b/cl_main.c @@ -796,7 +796,7 @@ extern void V_CalcViewBlend(void); extern void V_CalcRefdef(void); // note this is a recursive function, but it can never get in a runaway loop (because of the delayedlink flags) -void CL_LinkNetworkEntity(entity_t *e) +void CL_UpdateNetworkEntity(entity_t *e) { matrix4x4_t *matrix, blendmatrix, tempmatrix, matrix2; //matrix4x4_t dlightmatrix; @@ -865,7 +865,7 @@ void CL_LinkNetworkEntity(entity_t *e) if (!e->csqc) { if (cl.viewentity) - CL_LinkNetworkEntity(cl.entities + cl.viewentity); + CL_UpdateNetworkEntity(cl.entities + cl.viewentity); if (e == &cl.viewent && cl.entities[cl.viewentity].state_current.active) { e->state_current.alpha = cl.entities[cl.viewentity].state_current.alpha; @@ -893,7 +893,7 @@ void CL_LinkNetworkEntity(entity_t *e) if (!t->state_current.active) return; // note: this can link to world - CL_LinkNetworkEntity(t); + CL_UpdateNetworkEntity(t); // make relative to the entity matrix = &t->render.matrix; // some properties of the tag entity carry over @@ -1175,12 +1175,108 @@ void CL_LinkNetworkEntity(entity_t *e) && !(e->render.flags & (RENDER_VIEWMODEL | RENDER_TRANSPARENT)) && (!(e->render.flags & RENDER_EXTERIORMODEL) || (!cl.intermission && cls.protocol != PROTOCOL_NEHAHRAMOVIE && !cl_noplayershadow.integer))) e->render.flags |= RENDER_SHADOW; - // as soon as player is known we can call V_CalcRefDef - if (!csqc_loaded) - if (e->state_current.number == cl.viewentity) - V_CalcRefdef(); if (e->render.model && e->render.model->name[0] == '*' && e->render.model->TraceBox) cl.brushmodel_entities[cl.num_brushmodel_entities++] = e->state_current.number; + // because the player may be attached to another entity, V_CalcRefdef must be deferred until here... + if (e->state_current.number == cl.viewentity) + V_CalcRefdef(); + } +} + + +/* +=============== +CL_UpdateEntities +=============== +*/ +static void CL_UpdateEntities(void) +{ + entity_t *ent; + int i; + + ent = &cl.viewent; + ent->state_previous = ent->state_current; + ent->state_current = defaultstate; + ent->state_current.time = cl.time; + ent->state_current.number = -1; + ent->state_current.active = true; + ent->state_current.modelindex = cl.stats[STAT_WEAPON]; + ent->state_current.frame = cl.stats[STAT_WEAPONFRAME]; + ent->state_current.flags = RENDER_VIEWMODEL; + if ((cl.stats[STAT_HEALTH] <= 0 && cl_deathnoviewmodel.integer) || cl.intermission) + ent->state_current.modelindex = 0; + else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY) + { + if (gamemode == GAME_TRANSFUSION) + ent->state_current.alpha = 128; + else + ent->state_current.modelindex = 0; + } + + // reset animation interpolation on weaponmodel if model changed + if (ent->state_previous.modelindex != ent->state_current.modelindex) + { + ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_current.frame; + ent->render.frame1time = ent->render.frame2time = cl.time; + ent->render.framelerp = 1; + } + + // start on the entity after the world + entitylinkframenumber++; + for (i = 1;i < cl.num_entities;i++) + { + if (cl.entities_active[i]) + { + ent = cl.entities + i; + if (ent->state_current.active) + CL_UpdateNetworkEntity(ent); + else + cl.entities_active[i] = false; + } + } + CL_UpdateNetworkEntity(&cl.viewent); +} + +// note this is a recursive function, but it can never get in a runaway loop (because of the delayedlink flags) +void CL_LinkNetworkEntity(entity_t *e) +{ + entity_t *t; + if (e->persistent.linkframe != entitylinkframenumber) + { + e->persistent.linkframe = entitylinkframenumber; + // skip inactive entities and world + if (!e->state_current.active || e == cl.entities || e == cl.csqcentities) + return; + if (e->render.flags & RENDER_VIEWMODEL && !e->state_current.tagentity) + { + if (!r_drawviewmodel.integer || chase_active.integer || r_refdef.envmap) + return; + if (!e->csqc) + if (cl.viewentity) + CL_LinkNetworkEntity(cl.entities + cl.viewentity); + } + else + { + // if the tag entity is currently impossible, skip it + if (!e->csqc) + { + if (e->state_current.tagentity >= cl.num_entities) + return; + t = cl.entities + e->state_current.tagentity; + } + else + { + if (e->state_current.tagentity >= cl.num_csqcentities) + return; + t = cl.csqcentities + e->state_current.tagentity; + } + // if the tag entity is inactive, skip it + if (!t->state_current.active) + return; + // note: this can link to world + CL_LinkNetworkEntity(t); + } + // don't show entities with no modelindex (note: this still shows // entities which have a modelindex that resolved to a NULL model) if (e->render.model && !(e->render.effects & EF_NODRAW) && r_refdef.numentities < r_refdef.maxentities) @@ -1207,25 +1303,6 @@ void CL_RelinkWorld(void) r_refdef.worldmodel = cl.worldmodel; } -void CL_RelinkCSQCWorld(void) //[515]: csqc -{ - entity_t *ent = &cl.csqcentities[0]; - if(!csqc_loaded) - return; -// cl.brushmodel_entities[cl.num_brushmodel_entities++] = 0; - // FIXME: this should be done at load - ent->render.matrix = identitymatrix; - ent->render.inversematrix = identitymatrix; - R_LerpAnimation(&ent->render); - CL_BoundingBoxForEntity(&ent->render); - ent->render.flags = RENDER_SHADOW; - if (!r_fullbright.integer) - ent->render.flags |= RENDER_LIGHT; - VectorSet(ent->render.colormod, 1, 1, 1); -// r_refdef.worldentity = &ent->render; -// r_refdef.worldmodel = cl.worldmodel; -} - static void CL_RelinkStaticEntities(void) { int i; @@ -1253,82 +1330,23 @@ static void CL_RelinkStaticEntities(void) CL_RelinkEntities =============== */ -static void CL_RelinkNetworkEntities(int drawmask) +static void CL_RelinkNetworkEntities(void) { entity_t *ent; - int i, k; - - if(!csqc_loaded) - { - ent = &cl.viewent; - ent->state_previous = ent->state_current; - ent->state_current = defaultstate; - ent->state_current.time = cl.time; - ent->state_current.number = -1; - ent->state_current.active = true; - ent->state_current.modelindex = cl.stats[STAT_WEAPON]; - ent->state_current.frame = cl.stats[STAT_WEAPONFRAME]; - ent->state_current.flags = RENDER_VIEWMODEL; - if ((cl.stats[STAT_HEALTH] <= 0 && cl_deathnoviewmodel.integer) || cl.intermission) - ent->state_current.modelindex = 0; - else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY) - { - if (gamemode == GAME_TRANSFUSION) - ent->state_current.alpha = 128; - else - ent->state_current.modelindex = 0; - } - - // reset animation interpolation on weaponmodel if model changed - if (ent->state_previous.modelindex != ent->state_current.modelindex) - { - ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_current.frame; - ent->render.frame1time = ent->render.frame2time = cl.time; - ent->render.framelerp = 1; - } - } + int i; // start on the entity after the world - entitylinkframenumber++; - if(drawmask & ENTMASK_ENGINE || !csqc_loaded) - { - for (i = 1;i < cl.num_entities;i++) - { - if (cl.entities_active[i]) - { - ent = cl.entities + i; - if (!(drawmask & ENTMASK_ENGINEVIEWMODELS)) - if (ent->state_current.flags & RENDER_VIEWMODEL) //[515]: csqc drawmask - { - cl.entities_active[i] = false; - continue; - } - if (ent->state_current.active) - CL_LinkNetworkEntity(ent); - else - cl.entities_active[i] = false; - } - } - } - - //[515]: csqc - if(csqc_loaded) + for (i = 1;i < cl.num_entities;i++) { - for (i=1,k=cl.num_csqcentities;k;i++) + if (cl.entities_active[i]) { - if (cl.csqcentities_active[i]) - { - --k; - ent = cl.csqcentities + i; - if (ent->state_current.active) - CL_LinkNetworkEntity(ent); - else - cl.csqcentities_active[i] = false; - } + ent = cl.entities + i; + if (ent->state_current.active) + CL_LinkNetworkEntity(ent); + else + cl.entities_active[i] = false; } } - else - CL_LinkNetworkEntity(&cl.viewent); } static void CL_RelinkEffects(void) @@ -1552,25 +1570,15 @@ void CL_LerpPlayer(float frac) void CSQC_RelinkAllEntities (int drawmask) { - cl.num_brushmodel_entities = 0; - CL_RelinkNetworkEntities(drawmask); - if(drawmask & ENTMASK_ENGINE) - { - // move particles - CL_MoveParticles(); - R_MoveExplosions(); - } - // link stuff - CL_RelinkWorld(); - CL_RelinkCSQCWorld(); //[515]: csqc - if(drawmask & ENTMASK_ENGINE) + if (drawmask & ENTMASK_ENGINE) { - CL_RelinkStaticEntities(); - CL_RelinkBeams(); - CL_RelinkEffects(); + CL_RelinkNetworkEntities(); CL_RelinkQWNails(); } + + if (drawmask & ENTMASK_ENGINEVIEWMODELS) + CL_LinkNetworkEntity(&cl.viewent); // link gun model } /* @@ -1580,7 +1588,8 @@ CL_ReadFromServer Read all incoming data from the server =============== */ -extern void CL_ClientMovement_Replay(); +extern void CL_ClientMovement_Replay(void); +extern void CL_StairSmoothing(void);//view.c int CL_ReadFromServer(void) { @@ -1601,33 +1610,39 @@ int CL_ReadFromServer(void) V_DriftPitch(); V_FadeViewFlashs(); - // relink network entities (note: this sets up the view!) + // move particles + CL_MoveParticles(); + R_MoveExplosions(); + + // process network entities (note: this sets up the view!) CL_ClientMovement_Replay(); + cl.num_brushmodel_entities = 0; + // now that the player entity has been updated we can call V_CalcRefdef + V_CalcRefdef(); + CL_UpdateEntities(); + + entitylinkframenumber++; + // link stuff + CL_RelinkWorld(); + CL_RelinkStaticEntities(); + CL_RelinkBeams(); + CL_RelinkEffects(); + if(!csqc_loaded) //[515]: csqc { - cl.num_brushmodel_entities = 0; - CL_RelinkNetworkEntities(65535); - - // move particles - CL_MoveParticles(); - R_MoveExplosions(); - - // link stuff - CL_RelinkWorld(); - CL_RelinkCSQCWorld(); //[515]: csqc - CL_RelinkStaticEntities(); - CL_RelinkBeams(); - CL_RelinkEffects(); + CL_RelinkNetworkEntities(); + CL_LinkNetworkEntity(&cl.viewent); // link gun model CL_RelinkQWNails(); } else csqc_frame = true; - CL_UpdateLights(); - // update view blend V_CalcViewBlend(); + CL_UpdateLights(); + CL_StairSmoothing(); + // update the r_refdef time again because cl.time may have changed r_refdef.time = cl.time; } diff --git a/cl_screen.c b/cl_screen.c index 4a05b5d1..33ef4eca 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -1318,7 +1318,6 @@ void SCR_DrawScreen (void) } // draw 2D stuff - DrawQ_Begin(); //FIXME: force menu if nothing else to look at? //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected) diff --git a/client.h b/client.h index ce30abb5..0bd5eb90 100644 --- a/client.h +++ b/client.h @@ -637,6 +637,8 @@ typedef struct client_state_s float weapontime; // use pain anim frame if cl.time < this float faceanimtime; + // for stair smoothing + float stairoffset; // color shifts for damage, powerups cshift_t cshifts[NUM_CSHIFTS]; @@ -926,9 +928,6 @@ extern cvar_t cl_anglespeedkey; extern cvar_t cl_autofire; -extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat -extern cvar_t csqc_progcrc; - extern cvar_t cl_shownet; extern cvar_t cl_nolerp; diff --git a/clvm_cmds.c b/clvm_cmds.c index 4bd60f2c..5239a08d 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -760,15 +760,12 @@ void VM_CL_getlight (void) //============================================================================ //[515]: SCENE MANAGER builtins -void V_CalcRefdef (void);//view.c -void CSQC_R_ClearScreen (void);//gl_rmain.c -void CSQC_R_RenderScene (void);//gl_rmain.c -void CSQC_AddEntity (int n);//csprogs.c -void CSQC_ClearCSQCEntities (void); +extern void V_CalcRefdef (void);//view.c +extern qboolean CSQC_AddRenderEdict (prvm_edict_t *ed);//csprogs.c +extern void CSQC_ClearCSQCEntities (void);//csprogs.c matrix4x4_t csqc_listenermatrix; qboolean csqc_usecsqclistener = false, csqc_frame = false;//[515]: per-frame -qboolean csqc_onground; static void CSQC_R_RecalcView (void) { @@ -784,23 +781,46 @@ void VM_R_ClearScene (void) { VM_SAFEPARMCOUNT(0, VM_R_ClearScene); // CSQC_R_RecalcView(); - if(csqc_frame) - CSQC_ClearCSQCEntities(); - CSQC_R_ClearScreen(); + CSQC_ClearCSQCEntities(); } //#301 void(float mask) addentities (EXT_CSQC) +extern void CSQC_Predraw (prvm_edict_t *ed);//csprogs.c +extern void CSQC_Think (prvm_edict_t *ed);//csprogs.c void VM_R_AddEntities (void) { + int i, drawmask; + prvm_edict_t *ed; VM_SAFEPARMCOUNT(1, VM_R_AddEntities); - csqc_drawmask = (int)PRVM_G_FLOAT(OFS_PARM0); + drawmask = (int)PRVM_G_FLOAT(OFS_PARM0); + CSQC_RelinkAllEntities(drawmask); + + *prog->time = cl.time; + for(i=1;inum_edicts;i++) + { + ed = &prog->edicts[i]; + if(ed->priv.required->free) + continue; + VectorAdd(ed->fields.client->origin, ed->fields.client->mins, ed->fields.client->absmin); + VectorAdd(ed->fields.client->origin, ed->fields.client->maxs, ed->fields.client->absmax); + CSQC_Think(ed); + if(ed->priv.required->free) + continue; + // note that for RF_USEAXIS entities, Predraw sets v_forward/v_right/v_up globals that are read by CSQC_AddRenderEdict + CSQC_Predraw(ed); + if(ed->priv.required->free) + continue; + if(!((int)ed->fields.client->drawmask & drawmask)) + continue; + CSQC_AddRenderEdict(ed); + } } //#302 void(entity ent) addentity (EXT_CSQC) void VM_R_AddEntity (void) { VM_SAFEPARMCOUNT(1, VM_R_AddEntity); - CSQC_AddEntity(PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0))); + CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0)); } //#303 float(float property, ...) setproperty (EXT_CSQC) @@ -900,14 +920,7 @@ void VM_R_SetView (void) void VM_R_RenderScene (void) //#134 { VM_SAFEPARMCOUNT(0, VM_R_RenderScene); - - if(csqc_frame) - { - CSQC_RelinkCSQCEntities(); - CSQC_RelinkAllEntities(csqc_drawmask); - } - - CSQC_R_RenderScene(); + R_RenderView(); } //#305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC) @@ -1296,7 +1309,7 @@ void VM_CL_playernum (void) //#355 float() cl_onground (EXT_CSQC) void VM_CL_onground (void) { - PRVM_G_FLOAT(OFS_RETURN) = csqc_onground; + PRVM_G_FLOAT(OFS_RETURN) = cl.onground; } //#360 float() readbyte (EXT_CSQC) diff --git a/csprogs.c b/csprogs.c index 3309a5f4..bc01a0a9 100644 --- a/csprogs.c +++ b/csprogs.c @@ -43,7 +43,6 @@ static char *cl_required_func[] = static int cl_numrequiredfunc = sizeof(cl_required_func) / sizeof(char*); -unsigned int csqc_drawmask = 0; static char *csqc_printtextbuf = NULL; static unsigned short *csqc_sv2csqcents; //[515]: server entities numbers on client side. FIXME : make pointers instead of numbers ? @@ -141,7 +140,7 @@ static void CSQC_SetGlobals (void) CSQC_END } -static void CSQC_Predraw (prvm_edict_t *ed) +void CSQC_Predraw (prvm_edict_t *ed) { int b; if(!ed->fields.client->predraw) @@ -152,7 +151,7 @@ static void CSQC_Predraw (prvm_edict_t *ed) prog->globals.client->self = b; } -static void CSQC_Think (prvm_edict_t *ed) +void CSQC_Think (prvm_edict_t *ed) { int b; if(ed->fields.client->think) @@ -166,59 +165,113 @@ static void CSQC_Think (prvm_edict_t *ed) } } -//[515]: weird too -static qboolean CSQC_EdictToEntity (prvm_edict_t *ed, entity_t *e) +extern cvar_t cl_noplayershadow; +qboolean CSQC_AddRenderEdict(prvm_edict_t *ed) { int i; prvm_eval_t *val; + entity_t *e; + matrix4x4_t tagmatrix, matrix2; + + e = CL_NewTempEntity(); + if (!e) + return false; i = (int)ed->fields.client->modelindex; - e->state_current.modelindex = 0; if(i >= MAX_MODELS || i <= -MAX_MODELS) //[515]: make work as error ? { - Con_Print("CSQC_EdictToEntity: modelindex >= MAX_MODELS\n"); - ed->fields.client->modelindex = 0; + Con_Print("CSQC_AddRenderEdict: modelindex >= MAX_MODELS\n"); + ed->fields.client->modelindex = i = 0; } + + // model setup and some modelflags + if (i < MAX_MODELS) + e->render.model = cl.model_precache[e->state_current.modelindex]; else - e->state_current.modelindex = i; - if(!e->state_current.modelindex) + e->render.model = cl.csqc_model_precache[65536-e->state_current.modelindex]; + + if (!e->render.model) return false; - e->state_current.time = cl.time; + e->render.colormap = (int)ed->fields.client->colormap; + e->render.frame = (int)ed->fields.client->frame; + e->render.skinnum = (int)ed->fields.client->skin; + e->render.effects |= e->render.model->flags2 & (EF_FULLBRIGHT | EF_ADDITIVE); - i = 0; - if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_renderflags)) && val->_float) + if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_alpha)) && val->_float) e->render.alpha = val->_float; + if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_scale)) && val->_float) e->render.scale = val->_float; + if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, e->render.colormod); + if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_effects)) && val->_float) e->render.effects = (int)val->_float; + if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_tag_entity)) && val->edict) { - i = (int)val->_float; - if(i & RF_VIEWMODEL) e->state_current.flags |= RENDER_VIEWMODEL; - if(i & RF_EXTERNALMODEL)e->state_current.flags |= RENDER_EXTERIORMODEL; - if(i & RF_DEPTHHACK) e->state_current.effects |= EF_NODEPTHTEST; - if(i & RF_ADDITIVE) e->state_current.effects |= EF_ADDITIVE; + int tagentity; + int tagindex; + tagentity = val->edict; + if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_tag_index)) && val->_float) + tagindex = (int)val->_float; + // FIXME: calculate tag matrix + Matrix4x4_CreateIdentity(&tagmatrix); } + else + Matrix4x4_CreateIdentity(&tagmatrix); if(i & RF_USEAXIS) //FIXME!!! - VectorCopy(ed->fields.client->angles, e->persistent.newangles); + { + vec3_t left; + VectorNegate(prog->globals.client->v_right, left); + Matrix4x4_FromVectors(&matrix2, prog->globals.client->v_forward, left, prog->globals.client->v_up, ed->fields.client->origin); + } else - VectorCopy(ed->fields.client->angles, e->persistent.newangles); - - VectorCopy(ed->fields.client->origin, e->persistent.neworigin); - VectorCopy(ed->fields.client->origin, e->state_current.origin); - e->state_current.colormap = (int)ed->fields.client->colormap; - e->state_current.effects = (int)ed->fields.client->effects; - e->state_current.frame = (int)ed->fields.client->frame; - e->state_current.skin = (int)ed->fields.client->skin; - - if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_alpha)) && val->_float) e->state_current.alpha = (int)(val->_float*255); - if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_scale)) && val->_float) e->state_current.scale = (int)(val->_float*16); - if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_colormod)) && VectorLength2(val->vector)) {int j;for (j = 0;j < 3;j++) e->state_current.colormod[j] = (unsigned char)bound(0, val->vector[j] * 32.0f, 255);} - if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_effects)) && val->_float) e->state_current.effects = (int)val->_float; - if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_tag_entity)) && val->edict) { - e->state_current.tagentity = val->edict; - if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_tag_index)) && val->_float) - e->state_current.tagindex = (int)val->_float; + vec3_t angles; + VectorCopy(ed->fields.client->angles, angles); + // if model is alias, reverse pitch direction + if (e->render.model->type == mod_alias) + angles[0] = -angles[0]; + + // set up the render matrix + // FIXME: e->render.scale should go away + Matrix4x4_CreateFromQuakeEntity(&matrix2, ed->fields.client->origin[0], ed->fields.client->origin[1], ed->fields.client->origin[2], angles[0], angles[1], angles[2], e->render.scale); } + // concat the matrices to make the entity relative to its tag + Matrix4x4_Concat(&e->render.matrix, &tagmatrix, &matrix2); + // make the other useful stuff + Matrix4x4_Invert_Simple(&e->render.inversematrix, &e->render.matrix); + CL_BoundingBoxForEntity(&e->render); + + // FIXME: csqc has frame1/frame2/frame1time/frame2time/lerpfrac but this implementation's cl_entvars_t lacks those fields + e->render.frame1 = e->render.frame = ed->fields.client->frame; + e->render.frame1time = e->render.frame2time = 0; + e->render.framelerp = 0; + R_LerpAnimation(&e->render); + + i = 0; + if((val = PRVM_GETEDICTFIELDVALUE(ed, csqc_fieldoff_renderflags)) && val->_float) + { + i = (int)val->_float; + if(i & RF_VIEWMODEL) e->render.flags |= RENDER_VIEWMODEL; + if(i & RF_EXTERNALMODEL)e->render.flags |= RENDER_EXTERIORMODEL; + if(i & RF_DEPTHHACK) e->render.effects |= EF_NODEPTHTEST; + if(i & RF_ADDITIVE) e->render.effects |= EF_ADDITIVE; + } + + // transparent stuff can't be lit during the opaque stage + if (e->render.effects & (EF_ADDITIVE | EF_NODEPTHTEST) || e->render.alpha < 1) + e->render.flags |= RENDER_TRANSPARENT; + // double sided rendering mode causes backfaces to be visible + // (mostly useful on transparent stuff) + if (e->render.effects & EF_DOUBLESIDED) + e->render.flags |= RENDER_NOCULLFACE; + // either fullbright or lit + if (!(e->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer) + e->render.flags |= RENDER_LIGHT; + // hide player shadow during intermission or nehahra movie + if (!(e->render.effects & EF_NOSHADOW) + && !(e->render.flags & (RENDER_VIEWMODEL | RENDER_TRANSPARENT)) + && (!(e->render.flags & RENDER_EXTERIORMODEL) || (!cl.intermission && cls.protocol != PROTOCOL_NEHAHRAMOVIE && !cl_noplayershadow.integer))) + e->render.flags |= RENDER_SHADOW; + return true; } @@ -226,74 +279,10 @@ void CSQC_ClearCSQCEntities (void) { memset(cl.csqcentities_active, 0, sizeof(cl.csqcentities_active)); cl.num_csqcentities = 0; - csqc_drawmask = 0; } void CL_ExpandCSQCEntities (int num); -void CSQC_RelinkCSQCEntities (void) -{ - int i; - entity_t *e; - prvm_edict_t *ed; - - *prog->time = cl.time; - for(i=1;inum_edicts;i++) - { - if(i >= cl.max_csqcentities) - CL_ExpandCSQCEntities(i); - - e = &cl.csqcentities[i]; - ed = &prog->edicts[i]; - if(ed->priv.required->free) - { - e->state_current.active = false; - cl.csqcentities_active[i] = false; - continue; - } - VectorAdd(ed->fields.client->origin, ed->fields.client->mins, ed->fields.client->absmin); - VectorAdd(ed->fields.client->origin, ed->fields.client->maxs, ed->fields.client->absmax); - CSQC_Think(ed); - if(ed->priv.required->free) - { - e->state_current.active = false; - cl.csqcentities_active[i] = false; - continue; - } - CSQC_Predraw(ed); - if(ed->priv.required->free) - { - e->state_current.active = false; - cl.csqcentities_active[i] = false; - continue; - } - if(!cl.csqcentities_active[i]) - if(!((int)ed->fields.client->drawmask & csqc_drawmask)) - continue; - - e->state_previous = e->state_current; - e->state_current = defaultstate; - if((cl.csqcentities_active[i] = CSQC_EdictToEntity(ed, e))) - { - if(!e->state_current.active) - { - if(!e->state_previous.active) - VectorCopy(ed->fields.client->origin, e->persistent.trail_origin);//[515]: hack to make good gibs =/ - e->state_previous = e->state_current; - e->state_current.active = true; - } - e->persistent.lerpdeltatime = 0;//prog->globals.client->frametime; - cl.num_csqcentities++; - } - } -} - -//[515]: omfg... it's all weird =/ -void CSQC_AddEntity (int n) -{ - cl.csqcentities_active[n] = true; -} - qboolean CL_VM_InputEvent (qboolean pressed, int key) { qboolean r; @@ -318,7 +307,6 @@ qboolean CL_VM_UpdateView (void) //VectorCopy(cl.viewangles, oldangles); *prog->time = cl.time; CSQC_SetGlobals(); - csqc_drawmask = 0; cl.num_csqcentities = 0; PRVM_ExecuteProgram (prog->globals.client->CSQC_UpdateView, CL_F_UPDATEVIEW); //VectorCopy(oldangles, cl.viewangles); @@ -546,7 +534,7 @@ void CL_VM_Init (void) if(!sv.active && !cls.demoplayback && prog->filecrc != (unsigned short)csqc_progcrc.integer) { - Con_Printf("^1Your CSQC version differs from server's one (%i!=%i)\n", prog->filecrc, csqc_progcrc.integer); + Con_Printf("^1Your %s is not the same version as the server (CRC is %i but should be %i)\n", prog->filecrc, csqc_progcrc.integer); PRVM_ResetProg(); CL_Disconnect(); return; diff --git a/csprogs.h b/csprogs.h index e67578ff..7d53c7ee 100644 --- a/csprogs.h +++ b/csprogs.h @@ -45,18 +45,16 @@ // Note that to use this properly, you'll NEED to use the predraw function to set the globals. //#define RF_DOUBLESIDED 32 -extern unsigned int csqc_drawmask; extern qboolean csqc_frame; extern int csqc_buttons; extern qboolean csqc_loaded; -extern qboolean csqc_onground; extern vec3_t csqc_origin, csqc_angles; -extern unsigned int csqc_drawmask; extern int csqc_fieldoff_scale; extern int csqc_fieldoff_renderflags; extern int csqc_fieldoff_tag_entity; extern int csqc_fieldoff_tag_index; extern int csqc_fieldoff_dphitcontentsmask; +extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat extern cvar_t csqc_progcrc; extern qboolean csqc_usecsqclistener; extern matrix4x4_t csqc_listenermatrix; diff --git a/draw.h b/draw.h index e185a69b..62e9d585 100644 --- a/draw.h +++ b/draw.h @@ -74,8 +74,8 @@ DRAWFLAG_NUMFLAGS #define STRING_COLOR_DEFAULT 7 #define STRING_COLOR_DEFAULT_STR "^7" -// sets r_defdef.draw2dstage and prepares for 2D rendering -void DrawQ_Begin(void); +// all of these functions will set r_defdef.draw2dstage if not in 2D rendering mode (and of course prepare for 2D rendering in that case) + // draw an image (or a filled rectangle if pic == NULL) void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags); // draw a text string diff --git a/gl_draw.c b/gl_draw.c index 17f1224e..5f966912 100644 --- a/gl_draw.c +++ b/gl_draw.c @@ -529,14 +529,17 @@ void GL_Draw_Init (void) R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap); } -void DrawQ_Begin(void) +static void _DrawQ_Setup(void) { - GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1); - + if (r_refdef.draw2dstage) + return; + r_refdef.draw2dstage = true; CHECKGLERROR qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR + GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1); GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100); qglDepthFunc(GL_LEQUAL);CHECKGLERROR + qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR R_Mesh_Matrix(&identitymatrix); GL_DepthMask(true); @@ -545,11 +548,15 @@ void DrawQ_Begin(void) GL_AlphaTest(false); GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - r_refdef.draw2dstage = true; + if (gl_support_fragment_shader) + { + qglUseProgramObjectARB(0);CHECKGLERROR + } } static void _DrawQ_ProcessDrawFlag(int flags) { + _DrawQ_Setup(); CHECKGLERROR if(flags == DRAWFLAG_ADDITIVE) GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); @@ -563,11 +570,6 @@ static void _DrawQ_ProcessDrawFlag(int flags) void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags) { - if (!r_refdef.draw2dstage) - { - Con_Printf("DrawQ_Pic: not in 2d rendering stage!\n"); - return; - } DrawQ_SuperPic(x,y,pic,width,height,0,0,red,green,blue,alpha,1,0,red,green,blue,alpha,0,1,red,green,blue,alpha,1,1,red,green,blue,alpha,flags); } @@ -579,12 +581,6 @@ void DrawQ_String_Real(float x, float y, const char *string, int maxlen, float w float vertex3f[QUADELEMENTS_MAXQUADS*4*3]; float texcoord2f[QUADELEMENTS_MAXQUADS*4*2]; - if (!r_refdef.draw2dstage) - { - Con_Printf("DrawQ_String: not in 2d rendering stage!\n"); - return; - } - if (alpha < (1.0f / 255.0f)) return; @@ -644,12 +640,6 @@ void DrawQ_String_Real(float x, float y, const char *string, int maxlen, float w void DrawQ_String(float x, float y, const char *string, int maxlen, float scalex, float scaley, float red, float green, float blue, float alpha, int flags) { - if (!r_refdef.draw2dstage) - { - Con_Printf("DrawQ_String: not in 2d rendering stage!\n"); - return; - } - if (r_textshadow.integer) DrawQ_String_Real(x+scalex*0.25,y+scaley*0.25,string,maxlen,scalex,scaley,0,0,0,alpha*0.8,flags); @@ -694,11 +684,6 @@ void DrawQ_ColoredString( float x, float y, const char *text, int maxlen, float int colorindex; const char *start, *current; - if (!r_refdef.draw2dstage) - { - Con_Printf("DrawQ_ColoredString: not in 2d rendering stage!\n"); - return; - } if( !outcolor || *outcolor == -1 ) { colorindex = STRING_COLOR_DEFAULT; } else { @@ -773,12 +758,6 @@ void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height { float floats[36]; - if (!r_refdef.draw2dstage) - { - Con_Printf("DrawQ_SuperPic: not in 2d rendering stage!\n"); - return; - } - _DrawQ_ProcessDrawFlag(flags); R_Mesh_VertexPointer(floats); @@ -813,12 +792,6 @@ void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags) { - if (!r_refdef.draw2dstage) - { - Con_Printf("DrawQ_Mesh: not in 2d rendering stage!\n"); - return; - } - _DrawQ_ProcessDrawFlag(flags); R_Mesh_VertexPointer(mesh->data_vertex3f); @@ -836,12 +809,6 @@ void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags) { int num; - if (!r_refdef.draw2dstage) - { - Con_Printf("DrawQ_LineLoop: not in 2d rendering stage!\n"); - return; - } - _DrawQ_ProcessDrawFlag(flags); GL_Color(1,1,1,1); @@ -857,32 +824,13 @@ void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags) CHECKGLERROR } -//LordHavoc: FIXME: this is nasty! -void DrawQ_LineWidth (float width) -{ - if (!r_refdef.draw2dstage) - { - Con_Printf("DrawQ_LineWidth: not in 2d rendering stage!\n"); - return; - } - CHECKGLERROR - qglLineWidth(width);CHECKGLERROR -} - //[515]: this is old, delete void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags) { - if (!r_refdef.draw2dstage) - { - Con_Printf("DrawQ_Line: not in 2d rendering stage!\n"); - return; - } + _DrawQ_ProcessDrawFlag(flags); CHECKGLERROR - if(width > 0) - DrawQ_LineWidth(width); - - _DrawQ_ProcessDrawFlag(flags); + qglLineWidth(width);CHECKGLERROR GL_Color(r,g,b,alpha); CHECKGLERROR @@ -895,11 +843,7 @@ void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, f void DrawQ_SetClipArea(float x, float y, float width, float height) { - if (!r_refdef.draw2dstage) - { - Con_Printf("DrawQ_SetClipArea: not in 2d rendering stage!\n"); - return; - } + _DrawQ_Setup(); // We have to convert the con coords into real coords // OGL uses top to bottom @@ -910,22 +854,12 @@ void DrawQ_SetClipArea(float x, float y, float width, float height) void DrawQ_ResetClipArea(void) { - if (!r_refdef.draw2dstage) - { - Con_Printf("DrawQ_ResetClipArea: not in 2d rendering stage!\n"); - return; - } + _DrawQ_Setup(); GL_ScissorTest(false); } void DrawQ_Finish(void) { - if (!r_refdef.draw2dstage) - { - Con_Printf("R_DrawQueue: not in 2d rendering stage!\n"); - return; - } - r_refdef.draw2dstage = false; } diff --git a/gl_rmain.c b/gl_rmain.c index 596f9c36..8022dcc8 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -1794,43 +1794,6 @@ R_RenderView ================ */ void R_RenderView(void) -{ - if (!r_refdef.entities/* || !r_refdef.worldmodel*/) - return; //Host_Error ("R_RenderView: NULL worldmodel"); - - CHECKGLERROR - if (r_timereport_active) - R_TimeReport("setup"); - - R_View_Update(); - if (r_timereport_active) - R_TimeReport("visibility"); - - // GL is weird because it's bottom to top, r_view.y is top to bottom - R_ResetViewRendering(); - - R_ClearScreen(); - if (r_timereport_active) - R_TimeReport("clear"); - - // this produces a bloom texture to be used in R_BlendView() later - if (r_hdr.integer) - R_HDR_RenderBloomTexture(); - - r_view.colorscale = r_hdr_scenebrightness.value; - R_RenderScene(); - - R_BlendView(); - if (r_timereport_active) - R_TimeReport("blendview"); - - GL_Scissor(0, 0, vid.width, vid.height); - GL_ScissorTest(false); - CHECKGLERROR -} - -//[515]: csqc -void CSQC_R_ClearScreen (void) { if (!r_refdef.entities/* || !r_refdef.worldmodel*/) return; //Host_Error ("R_RenderView: NULL worldmodel"); @@ -1847,17 +1810,6 @@ void CSQC_R_ClearScreen (void) R_ResetViewRendering(); - R_ClearScreen(); - if (r_timereport_active) - R_TimeReport("clear"); - CHECKGLERROR -} - -//[515]: csqc -void CSQC_R_RenderScene (void) -{ - R_ResetViewRendering(); - R_ClearScreen(); if (r_timereport_active) R_TimeReport("clear"); @@ -1883,6 +1835,8 @@ extern void VM_AddPolygonsToMeshQueue (void); extern void R_DrawPortals (void); void R_RenderScene(void) { + DrawQ_Finish(); + // don't let sound skip if going slow if (r_refdef.extraupdate) S_ExtraUpdate (); diff --git a/mvm_cmds.c b/mvm_cmds.c index cdba429f..504760a4 100644 --- a/mvm_cmds.c +++ b/mvm_cmds.c @@ -862,7 +862,7 @@ prvm_builtin_t vm_m_builtins[] = { VM_search_getfilename, // 77 VM_chr, VM_itof, - VM_ftoi, // 80 + VM_ftoe, // 80 VM_itof, // isString VM_altstr_count, VM_altstr_prepare, diff --git a/prvm_cmds.c b/prvm_cmds.c index 811cdf67..7d43ad99 100644 --- a/prvm_cmds.c +++ b/prvm_cmds.c @@ -715,19 +715,19 @@ void VM_itof(void) /* ======================== -VM_itoe +VM_ftoe -intt ftoi(float num) +entity ftoe(float num) ======================== */ -void VM_ftoi(void) +void VM_ftoe(void) { int ent; - VM_SAFEPARMCOUNT(1, VM_ftoi); + VM_SAFEPARMCOUNT(1, VM_ftoe); ent = (int)PRVM_G_FLOAT(OFS_PARM0); - if(PRVM_PROG_TO_EDICT(ent)->priv.required->free) - PRVM_ERROR ("VM_ftoe: %s tried to access a freed entity (entity %i)!", PRVM_NAME, ent); + if (ent < 0 || ent >= MAX_EDICTS || PRVM_PROG_TO_EDICT(ent)->priv.required->free) + ent = 0; // return world instead of a free or invalid entity PRVM_G_INT(OFS_RETURN) = ent; } @@ -1150,15 +1150,14 @@ float rint(float) */ void VM_rint (void) { - float f; - + float f; VM_SAFEPARMCOUNT(1,VM_rint); f = PRVM_G_FLOAT(OFS_PARM0); if (f > 0) - PRVM_G_FLOAT(OFS_RETURN) = (int)(f + 0.5); + PRVM_G_FLOAT(OFS_RETURN) = floor(f + 0.5); else - PRVM_G_FLOAT(OFS_RETURN) = (int)(f - 0.5); + PRVM_G_FLOAT(OFS_RETURN) = ceil(f - 0.5); } /* @@ -3011,7 +3010,7 @@ void VM_R_PolygonBegin (void) if(picname[0]) p->tex = Draw_CachePic(picname, true)->tex; else - p->tex = r_texture_notexture; + p->tex = r_texture_white; p->flags = (unsigned char)PRVM_G_FLOAT(OFS_PARM1); vm_current_vertices = 0; vm_polygonbegin = true; @@ -3053,8 +3052,7 @@ void VM_R_PolygonVertex (void) p->data[vm_current_vertices*3] = coords[0]; p->data[1+vm_current_vertices*3] = coords[1]; - if(!(p->flags & VM_POLYGON_FL2D)) - p->data[2+vm_current_vertices*3] = coords[2]; + p->data[2+vm_current_vertices*3] = coords[2]; p->data[12+vm_current_vertices*2] = tx[0]; if(!(p->flags & VM_POLYGON_FLLINES)) diff --git a/prvm_cmds.h b/prvm_cmds.h index 5c9673f0..0404e760 100644 --- a/prvm_cmds.h +++ b/prvm_cmds.h @@ -99,7 +99,7 @@ string search_getfilename(float handle, float num) string chr(float ascii) float itof(intt ent) -intt ftoi(float num) +entity ftoe(float num) -------will be removed soon---------- float altstr_count(string) @@ -235,7 +235,7 @@ void VM_vtos (void); void VM_etos (void); void VM_stof(void); void VM_itof(void); -void VM_ftoi(void); +void VM_ftoe(void); void VM_spawn (void); void VM_remove (void); void VM_find (void); diff --git a/todo b/todo index 50de8e66..e6a8fd47 100644 --- a/todo +++ b/todo @@ -34,9 +34,11 @@ -f (James D) bug darkplaces server: losing runes on episode completion, completing episode 1 then 2 then 3 causes it to forget 1, then 4 causes it to forget 2 and 3, making it impossible to open the boss gate (James D) -f (Wazat) bug darkplaces: client's slowmo detection (measuring packet times and comparing to game time changes) may be making the game unpleasant (Wazat) 0 bug darkplaces client: GAME_NEHAHRA: make sure cutscenes and movies work, got a report of seeing a black screen (NightFright) +0 bug darkplaces client: hipnotic: health is one character to the right on the sbar, covering up the key icons (M`Shacron) 0 bug darkplaces client: it has been reported that sometimes level changes on quakeworld servers don't load a map, this may be related to downloading? (Baker) 0 bug darkplaces client: svc_effect should post a warning and do nothing if given a framerate below 1 (Willis) 0 bug darkplaces console: commandline history won't scroll back past a blank line - the blank line should not be entered into history (Elric) +0 bug darkplaces console: when cursoring up and down through command history, shorter lines sometimes contain some text from the previous line 0 bug darkplaces csqc: after the drawqueue was eliminated, the CSQC probably can't draw 2D polygons the same way, so it may need fixing ([515]) 0 bug darkplaces csqc: engine-based rocket entities have a trail but they don't glow if csqc is used 0 bug darkplaces csqc: it's broken! diff --git a/view.c b/view.c index 9fab2676..f1f66e55 100644 --- a/view.c +++ b/view.c @@ -311,6 +311,32 @@ extern matrix4x4_t viewmodelmatrix; #include "cl_collision.h" #include "csprogs.h" +/* +================== +CL_StairSmoothing + +================== +*/ +void CL_StairSmoothing (void) +{ + if (v_dmg_time > 0) + v_dmg_time -= (cl.time - cl.oldtime); + + // stair smoothing + if (cl.onground && cl.stairoffset < 0) + { + cl.stairoffset += (cl.time - cl.oldtime) * cl_stairsmoothspeed.value; + cl.stairoffset = bound(-16, cl.stairoffset, 0); + } + else if (cl.onground && cl.stairoffset > 0) + { + cl.stairoffset -= (cl.time - cl.oldtime) * cl_stairsmoothspeed.value; + cl.stairoffset = bound(0, cl.stairoffset, 16); + } + else + cl.stairoffset = 0; +} + /* ================== V_CalcRefdef @@ -336,6 +362,13 @@ void V_CalcRefdef (void) // and the angles from the input system Matrix4x4_OriginFromMatrix(&ent->render.matrix, vieworg); VectorCopy(cl.viewangles, viewangles); + + // update the stairoffset if the player entity has gone up or down without leaving the ground + //Con_Printf("cl.onground %i oldz %f newz %f\n", cl.onground, oldz, vieworg[2]); + cl.stairoffset -= vieworg[2] - oldz; + oldz = vieworg[2]; + cl.stairoffset = bound(-16, cl.stairoffset, 16); + // interpolate the angles if playing a demo or spectating someone if (cls.demoplayback || cl.fixangle[0]) { @@ -369,28 +402,8 @@ void V_CalcRefdef (void) // TODO: add a cvar to disable this viewangles[PITCH] += cl.qw_weaponkick; - if (cl.onground) - { - if (!cl.oldonground) - cl.hitgroundtime = cl.time; - cl.lastongroundtime = cl.time; - } - cl.oldonground = cl.onground; - - // stair smoothing - //Con_Printf("cl.onground %i oldz %f newz %f\n", cl.onground, oldz, vieworg[2]); - if (cl.onground && oldz < vieworg[2]) - { - oldz += (cl.time - cl.oldtime) * cl_stairsmoothspeed.value; - oldz = vieworg[2] = bound(vieworg[2] - 16, oldz, vieworg[2]); - } - else if (cl.onground && oldz > vieworg[2]) - { - oldz -= (cl.time - cl.oldtime) * cl_stairsmoothspeed.value; - oldz = vieworg[2] = bound(vieworg[2], oldz, vieworg[2] + 16); - } - else - oldz = vieworg[2]; + // bias by stair smoothing offset + vieworg[2] += cl.stairoffset; if (chase_active.value) { @@ -435,7 +448,6 @@ void V_CalcRefdef (void) { viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll; viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch; - v_dmg_time -= cl.realframetime; } // origin VectorAdd(vieworg, cl.punchvector, vieworg);