#include "cl_collision.h"
#include "cl_video.h"
#include "image.h"
+#include "r_shadow.h"
// we need to declare some mouse variables here, because the menu system
// references them even when on a unix system.
cvar_t cl_prydoncursor = {0, "cl_prydoncursor", "0"};
+cvar_t cl_deathnoviewmodel = {0, "cl_deathnoviewmodel", "1"};
+
vec3_t cl_playerstandmins;
vec3_t cl_playerstandmaxs;
vec3_t cl_playercrouchmins;
int cl_max_dlights;
int cl_max_lightstyle;
int cl_max_brushmodel_entities;
+int cl_activedlights;
entity_t *cl_entities;
-qbyte *cl_entities_active;
+unsigned char *cl_entities_active;
entity_t *cl_static_entities;
entity_t *cl_temp_entities;
cl_effect_t *cl_effects;
int cl_num_temp_entities;
int cl_num_brushmodel_entities;
+// keep track of quake entities because they need to be killed if they get stale
+extern int cl_lastquakeentity;
+extern unsigned char cl_isquakeentity[MAX_EDICTS];
+
/*
=====================
CL_ClearState
cl_max_dlights = MAX_DLIGHTS;
cl_max_lightstyle = MAX_LIGHTSTYLES;
cl_max_brushmodel_entities = MAX_EDICTS;
+ cl_activedlights = 0;
- cl_entities = Mem_Alloc(cl_mempool, cl_max_entities * sizeof(entity_t));
- cl_entities_active = Mem_Alloc(cl_mempool, cl_max_brushmodel_entities * sizeof(qbyte));
- cl_static_entities = Mem_Alloc(cl_mempool, cl_max_static_entities * sizeof(entity_t));
- cl_temp_entities = Mem_Alloc(cl_mempool, cl_max_temp_entities * sizeof(entity_t));
- cl_effects = Mem_Alloc(cl_mempool, cl_max_effects * sizeof(cl_effect_t));
- cl_beams = Mem_Alloc(cl_mempool, cl_max_beams * sizeof(beam_t));
- cl_dlights = Mem_Alloc(cl_mempool, cl_max_dlights * sizeof(dlight_t));
- cl_lightstyle = Mem_Alloc(cl_mempool, cl_max_lightstyle * sizeof(lightstyle_t));
- cl_brushmodel_entities = Mem_Alloc(cl_mempool, cl_max_brushmodel_entities * sizeof(int));
+ cl_entities = (entity_t *)Mem_Alloc(cl_mempool, cl_max_entities * sizeof(entity_t));
+ cl_entities_active = (unsigned char *)Mem_Alloc(cl_mempool, cl_max_brushmodel_entities * sizeof(unsigned char));
+ cl_static_entities = (entity_t *)Mem_Alloc(cl_mempool, cl_max_static_entities * sizeof(entity_t));
+ cl_temp_entities = (entity_t *)Mem_Alloc(cl_mempool, cl_max_temp_entities * sizeof(entity_t));
+ cl_effects = (cl_effect_t *)Mem_Alloc(cl_mempool, cl_max_effects * sizeof(cl_effect_t));
+ cl_beams = (beam_t *)Mem_Alloc(cl_mempool, cl_max_beams * sizeof(beam_t));
+ cl_dlights = (dlight_t *)Mem_Alloc(cl_mempool, cl_max_dlights * sizeof(dlight_t));
+ cl_lightstyle = (lightstyle_t *)Mem_Alloc(cl_mempool, cl_max_lightstyle * sizeof(lightstyle_t));
+ cl_brushmodel_entities = (int *)Mem_Alloc(cl_mempool, cl_max_brushmodel_entities * sizeof(int));
+
+ cl_lastquakeentity = 0;
+ memset(cl_isquakeentity, 0, sizeof(cl_isquakeentity));
// LordHavoc: have to set up the baseline info for alpha and other stuff
for (i = 0;i < cl_max_entities;i++)
if (num >= cl_max_entities)
{
if (!cl_entities)
- Host_Error("CL_ExpandEntities: cl_entities not initialized\n");
+ Sys_Error("CL_ExpandEntities: cl_entities not initialized");
if (num >= MAX_EDICTS)
- Host_Error("CL_ExpandEntities: num %i >= %i\n", num, MAX_EDICTS);
+ Host_Error("CL_ExpandEntities: num %i >= %i", num, MAX_EDICTS);
oldmaxentities = cl_max_entities;
oldentities = cl_entities;
cl_max_entities = (num & ~255) + 256;
- cl_entities = Mem_Alloc(cl_mempool, cl_max_entities * sizeof(entity_t));
+ cl_entities = (entity_t *)Mem_Alloc(cl_mempool, cl_max_entities * sizeof(entity_t));
memcpy(cl_entities, oldentities, oldmaxentities * sizeof(entity_t));
Mem_Free(oldentities);
for (i = oldmaxentities;i < cl_max_entities;i++)
// stop demo loop in case this fails
CL_Disconnect();
- NetConn_ClientFrame();
- NetConn_ServerFrame();
+
+ // run a network frame
+ //NetConn_ClientFrame();SV_VM_Begin();NetConn_ServerFrame();SV_VM_End();
if (LHNETADDRESS_FromString(&cls.connect_address, host, 26000) && (cls.connect_mysocket = NetConn_ChooseClientSocketForAddress(&cls.connect_address)))
{
cls.connect_remainingtries = 3;
cls.connect_nextsendtime = 0;
M_Update_Return_Reason("Trying to connect...");
- if (sv.active)
- {
- NetConn_ClientFrame();
- NetConn_ServerFrame();
- NetConn_ClientFrame();
- NetConn_ServerFrame();
- NetConn_ClientFrame();
- NetConn_ServerFrame();
- NetConn_ClientFrame();
- NetConn_ServerFrame();
- }
+ // run several network frames to jump into the game quickly
+ //if (sv.active)
+ //{
+ // NetConn_ClientFrame();SV_VM_Begin();NetConn_ServerFrame();SV_VM_End();
+ // NetConn_ClientFrame();SV_VM_Begin();NetConn_ServerFrame();SV_VM_End();
+ // NetConn_ClientFrame();SV_VM_Begin();NetConn_ServerFrame();SV_VM_End();
+ // NetConn_ClientFrame();SV_VM_Begin();NetConn_ServerFrame();SV_VM_End();
+ //}
}
else
{
strlcpy (name, ent->render.model->name, 25);
else
strcpy(name, "--no model--");
- for (j = strlen(name);j < 25;j++)
+ for (j = (int)strlen(name);j < 25;j++)
name[j] = ' ';
- Con_Printf("%3i: %s:%04i (%5i %5i %5i) [%3i %3i %3i] %4.2f %5.3f\n", i, name, ent->render.frame, (int) ent->render.origin[0], (int) ent->render.origin[1], (int) ent->render.origin[2], (int) ent->render.angles[0] % 360, (int) ent->render.angles[1] % 360, (int) ent->render.angles[2] % 360, ent->render.scale, ent->render.alpha);
+ Con_Printf("%3i: %s:%4i (%5i %5i %5i) [%3i %3i %3i] %4.2f %5.3f\n", i, name, ent->render.frame, (int) ent->render.matrix.m[0][3], (int) ent->render.matrix.m[1][3], (int) ent->render.matrix.m[2][3], (int) ent->render.angles[0] % 360, (int) ent->render.angles[1] % 360, (int) ent->render.angles[2] % 360, ent->render.scale, ent->render.alpha);
}
}
// LordHavoc: lerp in listen games as the server is being capped below the client (usually)
f = cl.mtime[0] - cl.mtime[1];
- if (!f || cl_nolerp.integer || cls.timedemo || cl.islocalgame)
+ if (!f || cl_nolerp.integer || cls.timedemo || (cl.islocalgame && !sv_fixedframeratesingleplayer.integer))
{
cl.time = cl.mtime[0];
return 1;
if (ent)
{
dl = cl_dlights;
- for (i = 0;i < MAX_DLIGHTS;i++, dl++)
+ for (i = 0;i < cl_activedlights;i++, dl++)
if (dl->ent == ent)
goto dlightsetup;
}
// then look for anything else
dl = cl_dlights;
- for (i = 0;i < MAX_DLIGHTS;i++, dl++)
+ for (i = 0;i < cl_activedlights;i++, dl++)
if (!dl->radius)
goto dlightsetup;
+ // if we hit the end of the active dlights and found no gaps, add a new one
+ if (i < MAX_DLIGHTS)
+ {
+ cl_activedlights = i + 1;
+ goto dlightsetup;
+ }
// unable to find one
return;
dlightsetup:
//Con_Printf("dlight %i : %f %f %f : %f %f %f\n", i, org[0], org[1], org[2], red * radius, green * radius, blue * radius);
memset (dl, 0, sizeof(*dl));
- dl->matrix = *matrix;
+ Matrix4x4_Normalize(&dl->matrix, matrix);
dl->ent = ent;
dl->origin[0] = dl->matrix.m[0][3];
dl->origin[1] = dl->matrix.m[1][3];
dl->specularscale = specularscale;
}
+// called before entity relinking
void CL_DecayLights(void)
{
- int i;
+ int i, oldmax;
dlight_t *dl;
- float time;
+ float time, f;
time = cl.time - cl.oldtime;
- for (i = 0, dl = cl_dlights;i < MAX_DLIGHTS;i++, dl++)
+ oldmax = cl_activedlights;
+ cl_activedlights = 0;
+ for (i = 0, dl = cl_dlights;i < oldmax;i++, dl++)
+ {
if (dl->radius)
- dl->radius = (cl.time < dl->die) ? max(0, dl->radius - time * dl->decay) : 0;
+ {
+ f = dl->radius - time * dl->decay;
+ if (cl.time < dl->die && f > 0)
+ {
+ dl->radius = dl->radius - time * dl->decay;
+ cl_activedlights = i + 1;
+ }
+ else
+ dl->radius = 0;
+ }
+ }
+}
+
+// called after entity relinking
+void CL_UpdateLights(void)
+{
+ int i, j, k, l;
+ dlight_t *dl;
+ float frac, f;
+
+ r_refdef.numlights = 0;
+ if (r_dynamic.integer)
+ {
+ for (i = 0, dl = cl_dlights;i < cl_activedlights;i++, dl++)
+ {
+ if (dl->radius)
+ {
+ R_RTLight_Update(dl, false);
+ r_refdef.lights[r_refdef.numlights++] = dl;
+ }
+ }
+ }
+
+// light animations
+// 'm' is normal light, 'a' is no light, 'z' is double bright
+ f = cl.time * 10;
+ i = (int)floor(f);
+ frac = f - i;
+ for (j = 0;j < MAX_LIGHTSTYLES;j++)
+ {
+ if (!cl_lightstyle || !cl_lightstyle[j].length)
+ {
+ r_refdef.lightstylevalue[j] = 256;
+ continue;
+ }
+ k = i % cl_lightstyle[j].length;
+ l = (i-1) % cl_lightstyle[j].length;
+ k = cl_lightstyle[j].map[k] - 'a';
+ l = cl_lightstyle[j].map[l] - 'a';
+ r_refdef.lightstylevalue[j] = ((k*frac)+(l*(1-frac)))*22;
+ }
}
#define MAXVIEWMODELS 32
e->render.scale = e->state_current.scale * (1.0f / 16.0f); // FIXME: interpolate?
e->render.flags = e->state_current.flags;
e->render.effects = e->state_current.effects;
+ VectorScale(e->state_current.colormod, (1.0f / 32.0f), e->render.colormod);
if (e->state_current.flags & RENDER_COLORMAPPED)
+ {
+ int cb;
+ unsigned char *cbcolor;
e->render.colormap = e->state_current.colormap;
- else if (cl.scores != NULL && e->state_current.colormap)
+ cb = (e->render.colormap & 0xF) << 4;cb += (cb >= 128 && cb < 224) ? 4 : 12;
+ cbcolor = (unsigned char *) (&palette_complete[cb]);
+ e->render.colormap_pantscolor[0] = cbcolor[0] * (1.0f / 255.0f) * e->render.colormod[0];
+ e->render.colormap_pantscolor[1] = cbcolor[1] * (1.0f / 255.0f) * e->render.colormod[1];
+ e->render.colormap_pantscolor[2] = cbcolor[2] * (1.0f / 255.0f) * e->render.colormod[2];
+ cb = (e->render.colormap & 0xF0);cb += (cb >= 128 && cb < 224) ? 4 : 12;
+ cbcolor = (unsigned char *) (&palette_complete[cb]);
+ e->render.colormap_shirtcolor[0] = cbcolor[0] * (1.0f / 255.0f) * e->render.colormod[0];
+ e->render.colormap_shirtcolor[1] = cbcolor[1] * (1.0f / 255.0f) * e->render.colormod[1];
+ e->render.colormap_shirtcolor[2] = cbcolor[2] * (1.0f / 255.0f) * e->render.colormod[2];
+ }
+ else if (e->state_current.colormap && cl.scores != NULL)
+ {
+ int cb;
+ unsigned char *cbcolor;
e->render.colormap = cl.scores[e->state_current.colormap - 1].colors; // color it
+ cb = (e->render.colormap & 0xF) << 4;cb += (cb >= 128 && cb < 224) ? 4 : 12;
+ cbcolor = (unsigned char *) (&palette_complete[cb]);
+ e->render.colormap_pantscolor[0] = cbcolor[0] * (1.0f / 255.0f) * e->render.colormod[0];
+ e->render.colormap_pantscolor[1] = cbcolor[1] * (1.0f / 255.0f) * e->render.colormod[1];
+ e->render.colormap_pantscolor[2] = cbcolor[2] * (1.0f / 255.0f) * e->render.colormod[2];
+ cb = (e->render.colormap & 0xF0);cb += (cb >= 128 && cb < 224) ? 4 : 12;
+ cbcolor = (unsigned char *) (&palette_complete[cb]);
+ e->render.colormap_shirtcolor[0] = cbcolor[0] * (1.0f / 255.0f) * e->render.colormod[0];
+ e->render.colormap_shirtcolor[1] = cbcolor[1] * (1.0f / 255.0f) * e->render.colormod[1];
+ e->render.colormap_shirtcolor[2] = cbcolor[2] * (1.0f / 255.0f) * e->render.colormod[2];
+ }
else
+ {
e->render.colormap = -1; // no special coloring
+ VectorClear(e->render.colormap_pantscolor);
+ VectorClear(e->render.colormap_shirtcolor);
+ }
e->render.skinnum = e->state_current.skin;
- VectorScale(e->state_current.colormod, (1.0f / 32.0f), e->render.colormod);
- if (e->render.flags & RENDER_VIEWMODEL)
+ if (e->render.flags & RENDER_VIEWMODEL && !e->state_current.tagentity)
{
if (!r_drawviewmodel.integer || chase_active.integer || envmap)
return;
// if it's the player entity, update according to client movement
if (e == cl_entities + cl.playerentity && cl.movement)
{
- lerp = (cl.time - cl.mtime[0]) / (cl.mtime[0] - cl.mtime[1]);
+ lerp = (cl.time - cl.mtime[1]) / (cl.mtime[0] - cl.mtime[1]);
lerp = bound(0, lerp, 1);
VectorLerp(cl.movement_oldorigin, lerp, cl.movement_origin, origin);
VectorSet(angles, 0, cl.viewangles[1], 0);
e->render.model = cl.model_precache[e->state_current.modelindex];
if (e->render.model)
{
- Mod_CheckLoaded(e->render.model);
// if model is alias or this is a tenebrae-like dlight, reverse pitch direction
if (e->render.model->type == mod_alias || (e->state_current.lightpflags & PFLAGS_FULLDYNAMIC))
angles[0] = -angles[0];
CL_BoundingBoxForEntity(&e->render);
// handle effects now that we know where this entity is in the world...
- origin[0] = e->render.matrix.m[0][3];
- origin[1] = e->render.matrix.m[1][3];
- origin[2] = e->render.matrix.m[2][3];
+ if (e->render.model && e->render.model->soundfromcenter)
+ {
+ // bmodels are treated specially since their origin is usually '0 0 0'
+ vec3_t o;
+ VectorMAM(0.5f, e->render.model->normalmins, 0.5f, e->render.model->normalmaxs, o);
+ Matrix4x4_Transform(&e->render.matrix, o, origin);
+ }
+ else
+ {
+ origin[0] = e->render.matrix.m[0][3];
+ origin[1] = e->render.matrix.m[1][3];
+ origin[2] = e->render.matrix.m[2][3];
+ }
trailtype = -1;
dlightradius = 0;
dlightcolor[0] = 0;
else if (e->render.model->flags & EF_TRACER)
{
trailtype = 3;
- dlightradius = max(dlightradius, 100);
- dlightcolor[0] += 0.25f;
- dlightcolor[1] += 1.00f;
- dlightcolor[2] += 0.25f;
+ //dlightradius = max(dlightradius, 100);
+ //dlightcolor[0] += 0.25f;
+ //dlightcolor[1] += 1.00f;
+ //dlightcolor[2] += 0.25f;
}
else if (e->render.model->flags & EF_TRACER2)
{
trailtype = 5;
- dlightradius = max(dlightradius, 100);
- dlightcolor[0] += 1.00f;
- dlightcolor[1] += 0.60f;
- dlightcolor[2] += 0.20f;
+ //dlightradius = max(dlightradius, 100);
+ //dlightcolor[0] += 1.00f;
+ //dlightcolor[1] += 0.60f;
+ //dlightcolor[2] += 0.20f;
}
else if (e->render.model->flags & EF_ROCKET)
{
// * 4 for the expansion from 0-255 to 0-1023 range,
// / 255 to scale down byte colors
dlightradius = max(dlightradius, e->state_current.glowsize * 4);
- VectorMA(dlightcolor, (1.0f / 255.0f), (qbyte *)&palette_complete[e->state_current.glowcolor], dlightcolor);
+ VectorMA(dlightcolor, (1.0f / 255.0f), (unsigned char *)&palette_complete[e->state_current.glowcolor], dlightcolor);
}
// make the glow dlight
if (dlightradius > 0 && (dlightcolor[0] || dlightcolor[1] || dlightcolor[2]) && !(e->render.flags & RENDER_VIEWMODEL))
// 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;
entity_t *e;
for (i = 0, e = cl_static_entities;i < cl_num_static_entities && r_refdef.numentities < r_refdef.maxentities;i++, e++)
{
- Mod_CheckLoaded(e->render.model);
e->render.flags = 0;
// transparent stuff can't be lit during the opaque stage
if (e->render.effects & (EF_ADDITIVE | EF_NODEPTHTEST) || e->render.alpha < 1)
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.intermission)
+ 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 coming from the player, update the start position
//if (b->entity == cl.viewentity)
- // VectorCopy (cl_entities[cl.viewentity].render.origin, b->start);
- if (cl_beams_relative.integer && b->entity == cl.viewentity && b->entity && cl_entities[b->entity].state_current.active && b->relativestartvalid)
+ // Matrix4x4_OriginFromMatrix(&cl_entities[cl.viewentity].render.matrix, b->start);
+ if (cl_beams_relative.integer && b->entity && cl_entities[b->entity].state_current.active && b->relativestartvalid)
{
- entity_state_t *p = &cl_entities[b->entity].state_previous;
- //entity_state_t *c = &cl_entities[b->entity].state_current;
entity_render_t *r = &cl_entities[b->entity].render;
- matrix4x4_t matrix, imatrix;
- if (b->relativestartvalid == 2)
- {
- // not really valid yet, we need to get the orientation now
- // (ParseBeam flagged this because it is received before
- // entities are received, by now they have been received)
- // note: because players create lightning in their think
- // function (which occurs before movement), they actually
- // have some lag in it's location, so compare to the
- // previous player state, not the latest
- if (b->entity == cl.viewentity)
- Matrix4x4_CreateFromQuakeEntity(&matrix, p->origin[0], p->origin[1], p->origin[2] + 16, cl.viewangles[0], cl.viewangles[1], cl.viewangles[2], 1);
- else
- Matrix4x4_CreateFromQuakeEntity(&matrix, p->origin[0], p->origin[1], p->origin[2] + 16, p->angles[0], p->angles[1], p->angles[2], 1);
- Matrix4x4_Invert_Simple(&imatrix, &matrix);
- Matrix4x4_Transform(&imatrix, b->start, b->relativestart);
- Matrix4x4_Transform(&imatrix, b->end, b->relativeend);
- b->relativestartvalid = 1;
- }
- else
- {
- if (b->entity == cl.viewentity)
- Matrix4x4_CreateFromQuakeEntity(&matrix, r->origin[0], r->origin[1], r->origin[2] + 16, cl.viewangles[0], cl.viewangles[1], cl.viewangles[2], 1);
- else
- Matrix4x4_CreateFromQuakeEntity(&matrix, r->origin[0], r->origin[1], r->origin[2] + 16, r->angles[0], r->angles[1], r->angles[2], 1);
- Matrix4x4_Transform(&matrix, b->relativestart, b->start);
- Matrix4x4_Transform(&matrix, b->relativeend, b->end);
- }
+ //Matrix4x4_OriginFromMatrix(&r->matrix, origin);
+ //Matrix4x4_CreateFromQuakeEntity(&matrix, r->origin[0], r->origin[1], r->origin[2] + 16, r->angles[0], r->angles[1], r->angles[2], 1);
+ Matrix4x4_Transform(&r->matrix, b->relativestart, b->start);
+ Matrix4x4_Transform(&r->matrix, b->relativeend, b->end);
}
if (b->lightning)
Read all incoming data from the server
===============
*/
+extern void CL_ClientMovement_Replay();
int CL_ReadFromServer(void)
{
CL_ReadDemoMessage();
V_FadeViewFlashs();
// relink network entities (note: this sets up the view!)
+ CL_ClientMovement_Replay();
CL_RelinkNetworkEntities();
// move particles
// run cgame code (which can add more entities)
CL_CGVM_Frame();
+ CL_UpdateLights();
+
// update view blend
V_CalcViewBlend();
}
void CL_UpdatePrydonCursor(void);
void CL_SendCmd(void)
{
- if (cls.signon == SIGNONS)
- CL_UpdatePrydonCursor();
-
if (cls.demoplayback)
{
SZ_Clear(&cls.message);
memset(&r_refdef, 0, sizeof(r_refdef));
// max entities sent to renderer per frame
r_refdef.maxentities = MAX_EDICTS + 256 + 512;
- r_refdef.entities = Mem_Alloc(cl_mempool, sizeof(entity_render_t *) * r_refdef.maxentities);
+ r_refdef.entities = (entity_render_t **)Mem_Alloc(cl_mempool, sizeof(entity_render_t *) * r_refdef.maxentities);
// 256k drawqueue buffer
+ // TODO: make dynamic
r_refdef.maxdrawqueuesize = 256 * 1024;
- r_refdef.drawqueue = Mem_Alloc(cl_mempool, r_refdef.maxdrawqueuesize);
+ r_refdef.drawqueue = (unsigned char *)Mem_Alloc(cl_mempool, r_refdef.maxdrawqueuesize);
cls.message.data = cls.message_buf;
cls.message.maxsize = sizeof(cls.message_buf);
Cvar_RegisterVariable(&cl_prydoncursor);
+ Cvar_RegisterVariable(&cl_deathnoviewmodel);
+
Cmd_AddCommand("timerefresh", CL_TimeRefresh_f);
CL_Parse_Init();