X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=cl_main.c;h=d47902f83721e474bf024d65c85a4599797f13a1;hb=15d6d05dd61474b483f78c871bff5b1acba6e337;hp=a938d12db96d4228b71409cfcd705770650c0856;hpb=c055bc8b788bf9990755cf1b5e5d38c6d78b7e80;p=xonotic%2Fdarkplaces.git diff --git a/cl_main.c b/cl_main.c index a938d12d..d47902f8 100644 --- a/cl_main.c +++ b/cl_main.c @@ -20,39 +20,70 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // cl_main.c -- client main loop #include "quakedef.h" +#include "cl_collision.h" +#include "cl_video.h" +#include "image.h" // we need to declare some mouse variables here, because the menu system // references them even when on a unix system. -// these two are not intended to be set directly -cvar_t cl_name = {CVAR_SAVE, "_cl_name", "player"}; -cvar_t cl_color = {CVAR_SAVE, "_cl_color", "0"}; -cvar_t cl_pmodel = {CVAR_SAVE, "_cl_pmodel", "0"}; +cvar_t cl_shownet = {0, "cl_shownet","0"}; +cvar_t cl_nolerp = {0, "cl_nolerp", "0"}; -cvar_t cl_shownet = {0, "cl_shownet","0"}; -cvar_t cl_nolerp = {0, "cl_nolerp", "0"}; +cvar_t cl_itembobheight = {0, "cl_itembobheight", "8"}; +cvar_t cl_itembobspeed = {0, "cl_itembobspeed", "0.5"}; -cvar_t lookspring = {CVAR_SAVE, "lookspring","0"}; -cvar_t lookstrafe = {CVAR_SAVE, "lookstrafe","0"}; -cvar_t sensitivity = {CVAR_SAVE, "sensitivity","3", 1, 30}; +cvar_t lookspring = {CVAR_SAVE, "lookspring","0"}; +cvar_t lookstrafe = {CVAR_SAVE, "lookstrafe","0"}; +cvar_t sensitivity = {CVAR_SAVE, "sensitivity","3", 1, 30}; -cvar_t m_pitch = {CVAR_SAVE, "m_pitch","0.022"}; -cvar_t m_yaw = {CVAR_SAVE, "m_yaw","0.022"}; -cvar_t m_forward = {CVAR_SAVE, "m_forward","1"}; -cvar_t m_side = {CVAR_SAVE, "m_side","0.8"}; +cvar_t m_pitch = {CVAR_SAVE, "m_pitch","0.022"}; +cvar_t m_yaw = {CVAR_SAVE, "m_yaw","0.022"}; +cvar_t m_forward = {CVAR_SAVE, "m_forward","1"}; +cvar_t m_side = {CVAR_SAVE, "m_side","0.8"}; cvar_t freelook = {CVAR_SAVE, "freelook", "1"}; +cvar_t r_draweffects = {0, "r_draweffects", "1"}; + +cvar_t cl_explosions = {CVAR_SAVE, "cl_explosions", "1"}; +cvar_t cl_stainmaps = {CVAR_SAVE, "cl_stainmaps", "1"}; + +cvar_t cl_beams_polygons = {CVAR_SAVE, "cl_beams_polygons", "1"}; +cvar_t cl_beams_relative = {CVAR_SAVE, "cl_beams_relative", "1"}; +cvar_t cl_beams_lightatend = {CVAR_SAVE, "cl_beams_lightatend", "0"}; + +cvar_t cl_noplayershadow = {CVAR_SAVE, "cl_noplayershadow", "0"}; + +mempool_t *cl_refdef_mempool; +mempool_t *cl_entities_mempool; + client_static_t cls; client_state_t cl; -// FIXME: put these on hunk? -entity_t cl_entities[MAX_EDICTS]; -entity_t cl_static_entities[MAX_STATIC_ENTITIES]; -lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES]; -dlight_t cl_dlights[MAX_DLIGHTS]; -int cl_numvisedicts; -entity_t *cl_visedicts[MAX_VISEDICTS]; +int cl_max_entities; +int cl_max_static_entities; +int cl_max_temp_entities; +int cl_max_effects; +int cl_max_beams; +int cl_max_dlights; +int cl_max_lightstyle; +int cl_max_brushmodel_entities; + +entity_t *cl_entities; +qbyte *cl_entities_active; +entity_t *cl_static_entities; +entity_t *cl_temp_entities; +cl_effect_t *cl_effects; +beam_t *cl_beams; +dlight_t *cl_dlights; +lightstyle_t *cl_lightstyle; +entity_render_t **cl_brushmodel_entities; + +int cl_num_entities; +int cl_num_static_entities; +int cl_num_temp_entities; +int cl_num_brushmodel_entities; /* ===================== @@ -60,31 +91,58 @@ CL_ClearState ===================== */ -void CL_ClearState (void) +void CL_ClearState(void) { - int i; + int i; if (!sv.active) Host_ClearMemory (); + Mem_EmptyPool(cl_entities_mempool); + // wipe the entire cl structure memset (&cl, 0, sizeof(cl)); SZ_Clear (&cls.message); -// clear other arrays - memset (cl_entities, 0, sizeof(cl_entities)); - memset (cl_dlights, 0, sizeof(cl_dlights)); - memset (cl_lightstyle, 0, sizeof(cl_lightstyle)); - memset (cl_temp_entities, 0, sizeof(cl_temp_entities)); - memset (cl_beams, 0, sizeof(cl_beams)); + cl_num_entities = 0; + cl_num_static_entities = 0; + cl_num_temp_entities = 0; + cl_num_brushmodel_entities = 0; + + // tweak these if the game runs out + cl_max_entities = MAX_EDICTS; + cl_max_static_entities = 256; + cl_max_temp_entities = 512; + cl_max_effects = 256; + cl_max_beams = 24; + cl_max_dlights = MAX_DLIGHTS; + cl_max_lightstyle = MAX_LIGHTSTYLES; + cl_max_brushmodel_entities = MAX_EDICTS; + + cl_entities = Mem_Alloc(cl_entities_mempool, cl_max_entities * sizeof(entity_t)); + cl_entities_active = Mem_Alloc(cl_entities_mempool, cl_max_entities * sizeof(qbyte)); + cl_static_entities = Mem_Alloc(cl_entities_mempool, cl_max_static_entities * sizeof(entity_t)); + cl_temp_entities = Mem_Alloc(cl_entities_mempool, cl_max_temp_entities * sizeof(entity_t)); + cl_effects = Mem_Alloc(cl_entities_mempool, cl_max_effects * sizeof(cl_effect_t)); + cl_beams = Mem_Alloc(cl_entities_mempool, cl_max_beams * sizeof(beam_t)); + cl_dlights = Mem_Alloc(cl_entities_mempool, cl_max_dlights * sizeof(dlight_t)); + cl_lightstyle = Mem_Alloc(cl_entities_mempool, cl_max_lightstyle * sizeof(lightstyle_t)); + cl_brushmodel_entities = Mem_Alloc(cl_entities_mempool, cl_max_brushmodel_entities * sizeof(entity_render_t *)); + + CL_Screen_NewMap(); + + CL_Particles_Clear(); + // LordHavoc: have to set up the baseline info for alpha and other stuff - for (i = 0;i < MAX_EDICTS;i++) + for (i = 0;i < cl_max_entities;i++) { ClearStateToDefault(&cl_entities[i].state_baseline); ClearStateToDefault(&cl_entities[i].state_previous); ClearStateToDefault(&cl_entities[i].state_current); } + + CL_CGVM_Clear(); } /* @@ -95,8 +153,11 @@ Sends a disconnect message to the server This is also called on Host_Error, so it shouldn't cause any errors ===================== */ -void CL_Disconnect (void) +void CL_Disconnect(void) { + if (cls.state == ca_dedicated) + return; + // stop sounds (especially looping!) S_StopAllSounds (true); @@ -106,31 +167,37 @@ void CL_Disconnect (void) cl.cshifts[2].percent = 0; cl.cshifts[3].percent = 0; -// if running a local server, shut it down + cl.worldmodel = NULL; + if (cls.demoplayback) - CL_StopPlayback (); - else if (cls.state == ca_connected) + CL_StopPlayback(); + else if (cls.netcon) { if (cls.demorecording) - CL_Stop_f (); - - Con_DPrintf ("Sending clc_disconnect\n"); - SZ_Clear (&cls.message); - MSG_WriteByte (&cls.message, clc_disconnect); - NET_SendUnreliableMessage (cls.netcon, &cls.message); - SZ_Clear (&cls.message); - NET_Close (cls.netcon); - - cls.state = ca_disconnected; + CL_Stop_f(); + + Con_DPrintf("Sending clc_disconnect\n"); + SZ_Clear(&cls.message); + MSG_WriteByte(&cls.message, clc_disconnect); + NetConn_SendUnreliableMessage(cls.netcon, &cls.message); + SZ_Clear(&cls.message); + NetConn_Close(cls.netcon); + cls.netcon = NULL; + // if running a local server, shut it down if (sv.active) + { + // prevent this code from executing again during Host_ShutdownServer + cls.state = ca_disconnected; Host_ShutdownServer(false); + } } + cls.state = ca_disconnected; cls.demoplayback = cls.timedemo = false; cls.signon = 0; } -void CL_Disconnect_f (void) +void CL_Disconnect_f(void) { CL_Disconnect (); if (sv.active) @@ -144,156 +211,208 @@ void CL_Disconnect_f (void) ===================== CL_EstablishConnection -Host should be either "local" or a net address to be passed on +Host should be either "local" or a net address ===================== */ -void CL_EstablishConnection (char *host) +void CL_EstablishConnection(const char *host) { if (cls.state == ca_dedicated) return; - if (cls.demoplayback) - return; + // clear menu's connect error message + m_return_reason[0] = 0; - CL_Disconnect (); + // stop demo loop in case this fails + cls.demonum = -1; + CL_Disconnect(); - cls.netcon = NET_Connect (host); - if (!cls.netcon) - Host_Error ("CL_Connect: connect failed\n"); - Con_DPrintf ("CL_EstablishConnection: connected to %s\n", host); - - cls.demonum = -1; // not in the demo loop now - cls.state = ca_connected; - cls.signon = 0; // need all the signon messages before playing + if (LHNETADDRESS_FromString(&cls.connect_address, host, 26000) && (cls.connect_mysocket = NetConn_ChooseClientSocketForAddress(&cls.connect_address))) + { + cls.connect_trying = true; + cls.connect_remainingtries = 3; + cls.connect_nextsendtime = 0; + if (sv.active) + { + NetConn_ClientFrame(); + NetConn_ServerFrame(); + NetConn_ClientFrame(); + NetConn_ServerFrame(); + NetConn_ClientFrame(); + NetConn_ServerFrame(); + NetConn_ClientFrame(); + NetConn_ServerFrame(); + } + } } /* -===================== -CL_SignonReply - -An svc_signonnum has been received, perform a client side setup -===================== +============== +CL_PrintEntities_f +============== */ -void CL_SignonReply (void) +static void CL_PrintEntities_f(void) { - char str[8192]; - -Con_DPrintf ("CL_SignonReply: %i\n", cls.signon); + entity_t *ent; + int i, j; + char name[32]; - switch (cls.signon) + for (i = 0, ent = cl_entities;i < cl_num_entities;i++, ent++) { - case 1: - MSG_WriteByte (&cls.message, clc_stringcmd); - MSG_WriteString (&cls.message, "prespawn"); - break; - - case 2: - MSG_WriteByte (&cls.message, clc_stringcmd); - MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string)); + if (!ent->state_current.active) + continue; + + if (ent->render.model) + strncpy(name, ent->render.model->name, 25); + else + strcpy(name, "--no model--"); + name[25] = 0; + for (j = 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); + } +} - MSG_WriteByte (&cls.message, clc_stringcmd); - MSG_WriteString (&cls.message, va("color %i %i\n", ((int)cl_color.value)>>4, ((int)cl_color.value)&15)); - - if (cl_pmodel.value) +//static const vec3_t nomodelmins = {-16, -16, -16}; +//static const vec3_t nomodelmaxs = {16, 16, 16}; +void CL_BoundingBoxForEntity(entity_render_t *ent) +{ + if (ent->model) + { + //if (ent->angles[0] || ent->angles[2]) + if (ent->matrix.m[2][0] != 0 || ent->matrix.m[2][1] != 0) { - MSG_WriteByte (&cls.message, clc_stringcmd); - MSG_WriteString (&cls.message, va("pmodel %f\n", cl_pmodel.value)); + // pitch or roll + ent->mins[0] = ent->matrix.m[0][3] + ent->model->rotatedmins[0]; + ent->mins[1] = ent->matrix.m[1][3] + ent->model->rotatedmins[1]; + ent->mins[2] = ent->matrix.m[2][3] + ent->model->rotatedmins[2]; + ent->maxs[0] = ent->matrix.m[0][3] + ent->model->rotatedmaxs[0]; + ent->maxs[1] = ent->matrix.m[1][3] + ent->model->rotatedmaxs[1]; + ent->maxs[2] = ent->matrix.m[2][3] + ent->model->rotatedmaxs[2]; + //VectorAdd(ent->origin, ent->model->rotatedmins, ent->mins); + //VectorAdd(ent->origin, ent->model->rotatedmaxs, ent->maxs); + } + //else if (ent->angles[1]) + else if (ent->matrix.m[0][1] != 0 || ent->matrix.m[1][0] != 0) + { + // yaw + ent->mins[0] = ent->matrix.m[0][3] + ent->model->yawmins[0]; + ent->mins[1] = ent->matrix.m[1][3] + ent->model->yawmins[1]; + ent->mins[2] = ent->matrix.m[2][3] + ent->model->yawmins[2]; + ent->maxs[0] = ent->matrix.m[0][3] + ent->model->yawmaxs[0]; + ent->maxs[1] = ent->matrix.m[1][3] + ent->model->yawmaxs[1]; + ent->maxs[2] = ent->matrix.m[2][3] + ent->model->yawmaxs[2]; + //VectorAdd(ent->origin, ent->model->yawmins, ent->mins); + //VectorAdd(ent->origin, ent->model->yawmaxs, ent->maxs); + } + else + { + ent->mins[0] = ent->matrix.m[0][3] + ent->model->normalmins[0]; + ent->mins[1] = ent->matrix.m[1][3] + ent->model->normalmins[1]; + ent->mins[2] = ent->matrix.m[2][3] + ent->model->normalmins[2]; + ent->maxs[0] = ent->matrix.m[0][3] + ent->model->normalmaxs[0]; + ent->maxs[1] = ent->matrix.m[1][3] + ent->model->normalmaxs[1]; + ent->maxs[2] = ent->matrix.m[2][3] + ent->model->normalmaxs[2]; + //VectorAdd(ent->origin, ent->model->normalmins, ent->mins); + //VectorAdd(ent->origin, ent->model->normalmaxs, ent->maxs); } - - MSG_WriteByte (&cls.message, clc_stringcmd); - sprintf (str, "spawn %s", cls.spawnparms); - MSG_WriteString (&cls.message, str); - break; - - case 3: - MSG_WriteByte (&cls.message, clc_stringcmd); - MSG_WriteString (&cls.message, "begin"); - Cache_Report (); // print remaining memory - break; - - case 4: -// SCR_EndLoadingPlaque (); // allow normal screen updates - Con_ClearNotify(); - break; + } + else + { + ent->mins[0] = ent->matrix.m[0][3] - 16; + ent->mins[1] = ent->matrix.m[1][3] - 16; + ent->mins[2] = ent->matrix.m[2][3] - 16; + ent->maxs[0] = ent->matrix.m[0][3] + 16; + ent->maxs[1] = ent->matrix.m[1][3] + 16; + ent->maxs[2] = ent->matrix.m[2][3] + 16; + //VectorAdd(ent->origin, nomodelmins, ent->mins); + //VectorAdd(ent->origin, nomodelmaxs, ent->maxs); } } /* -===================== -CL_NextDemo +=============== +CL_LerpPoint -Called to play the next demo in the demo loop -===================== +Determines the fraction between the last two messages that the objects +should be put at. +=============== */ -void CL_NextDemo (void) +static float CL_LerpPoint(void) { - char str[1024]; + float f; - if (cls.demonum == -1) - return; // don't play demos + // dropped packet, or start of demo + if (cl.mtime[1] < cl.mtime[0] - 0.1) + cl.mtime[1] = cl.mtime[0] - 0.1; -// SCR_BeginLoadingPlaque (); + cl.time = bound(cl.mtime[1], cl.time, cl.mtime[0]); - if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS) + // 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 || (sv.active && svs.maxclients == 1)) { - cls.demonum = 0; - if (!cls.demos[cls.demonum][0]) - { - Con_Printf ("No demos listed with startdemos\n"); - cls.demonum = -1; - return; - } + cl.time = cl.mtime[0]; + return 1; } - sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]); - Cbuf_InsertText (str); - cls.demonum++; + f = (cl.time - cl.mtime[1]) / f; + return bound(0, f, 1); } -/* -============== -CL_PrintEntities_f -============== -*/ -void CL_PrintEntities_f (void) +void CL_ClearTempEntities (void) { - entity_t *ent; - int i, j; - char name[32]; - - for (i = 0, ent = cl_entities;i < MAX_EDICTS /*cl.num_entities*/;i++, ent++) - { - if (!ent->state_current.active) - continue; - if (!ent->render.model) - continue; + cl_num_temp_entities = 0; +} - Con_Printf ("%3i:", i); - if (!ent->render.model) - { - Con_Printf ("EMPTY\n"); +entity_t *CL_NewTempEntity(void) +{ + entity_t *ent; + + if (r_refdef.numentities >= r_refdef.maxentities) + return NULL; + if (cl_num_temp_entities >= cl_max_temp_entities) + return NULL; + ent = &cl_temp_entities[cl_num_temp_entities++]; + memset (ent, 0, sizeof(*ent)); + r_refdef.entities[r_refdef.numentities++] = &ent->render; + + ent->render.colormap = -1; // no special coloring + ent->render.scale = 1; + ent->render.alpha = 1; + return ent; +} + +void CL_Effect(vec3_t org, int modelindex, int startframe, int framecount, float framerate) +{ + int i; + cl_effect_t *e; + if (!modelindex) // sanity check + return; + for (i = 0, e = cl_effects;i < cl_max_effects;i++, e++) + { + if (e->active) continue; - } - strncpy(name, ent->render.model->name, 30); - name[30] = 0; - for (j = strlen(name);j < 30;j++) - name[j] = ' '; - Con_Printf ("%s:%04i (%5i %5i %5i) [%3i %3i %3i]\n", 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); + e->active = true; + VectorCopy(org, e->origin); + e->modelindex = modelindex; + e->starttime = cl.time; + e->startframe = startframe; + e->endframe = startframe + framecount; + e->framerate = framerate; + + e->frame = 0; + e->frame1time = cl.time; + e->frame2time = cl.time; + break; } } - -/* -=============== -CL_AllocDlight - -=============== -*/ -void CL_AllocDlight (entity_t *ent, vec3_t org, float radius, float red, float green, float blue, float decay, float lifetime) +void CL_AllocDlight(entity_render_t *ent, vec3_t org, float radius, float red, float green, float blue, float decay, float lifetime) { - int i; - dlight_t *dl; + int i; + dlight_t *dl; + /* // first look for an exact key match if (ent) { @@ -302,6 +421,7 @@ void CL_AllocDlight (entity_t *ent, vec3_t org, float radius, float red, float g if (dl->ent == ent) goto dlightsetup; } + */ // then look for anything else dl = cl_dlights; @@ -313,33 +433,30 @@ void CL_AllocDlight (entity_t *ent, vec3_t org, float radius, float red, float g 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->ent = ent; - VectorCopy(org, dl->origin); + CL_FindNonSolidLocation(org, dl->origin, 6); + //VectorCopy(org, dl->origin); dl->radius = radius; dl->color[0] = red; dl->color[1] = green; dl->color[2] = blue; dl->decay = decay; - dl->die = cl.time + lifetime; + if (lifetime) + dl->die = cl.time + lifetime; + else + dl->die = 0; } - -/* -=============== -CL_DecayLights - -=============== -*/ -void CL_DecayLights (void) +void CL_DecayLights(void) { - int i; - dlight_t *dl; - float time; - + int i; + dlight_t *dl; + float time; + time = cl.time - cl.oldtime; - c_dlights = 0; dl = cl_dlights; for (i=0 ; iradius -= time*dl->decay; if (dl->radius < 0) dl->radius = 0; } } - -/* -=============== -CL_LerpPoint - -Determines the fraction between the last two messages that the objects -should be put at. -=============== -*/ -float CL_LerpPoint (void) +extern qboolean Nehahrademcompatibility; +#define MAXVIEWMODELS 32 +entity_t *viewmodels[MAXVIEWMODELS]; +int numviewmodels; +void CL_RelinkNetworkEntity(entity_t *e) { - float f, frac; + int trailtype, temp; + float oldorg[3], delta[3], lerp, dlightcolor[3], mins[3], maxs[3], v[3], v2[3], d; + entity_persistent_t *p; + entity_render_t *r; + p = &e->persistent; + r = &e->render; + + if (e->state_previous.active && e->state_current.modelindex == e->state_previous.modelindex) + { + // movement lerp + if (p->lerpdeltatime > 0 && (lerp = (cl.time - p->lerpstarttime) / p->lerpdeltatime) < 1) + { + // read the old origin + VectorCopy(r->origin, oldorg); + // interpolate the origin and angles + r->origin[0] = p->oldorigin[0] + lerp * (p->neworigin[0] - p->oldorigin[0]); + r->origin[1] = p->oldorigin[1] + lerp * (p->neworigin[1] - p->oldorigin[1]); + r->origin[2] = p->oldorigin[2] + lerp * (p->neworigin[2] - p->oldorigin[2]); + VectorSubtract(p->newangles, p->oldangles, delta); + if (delta[0] < -180) delta[0] += 360;else if (delta[0] >= 180) delta[0] -= 360; + if (delta[1] < -180) delta[1] += 360;else if (delta[1] >= 180) delta[1] -= 360; + if (delta[2] < -180) delta[2] += 360;else if (delta[2] >= 180) delta[2] -= 360; + VectorMA(p->oldangles, lerp, delta, r->angles); + } + else + { + // no interpolation + VectorCopy(p->neworigin, r->origin); + VectorCopy(p->neworigin, oldorg); + VectorCopy(p->newangles, r->angles); + } + // animation lerp + if (r->frame2 != e->state_current.frame) + { + // begin a new frame lerp + r->frame1 = r->frame2; + r->frame1time = r->frame2time; + r->frame = r->frame2 = e->state_current.frame; + r->frame2time = cl.time; + r->framelerp = 0; + } + else + { + // update frame lerp fraction + r->framelerp = r->frame2time > r->frame1time ? ((cl.time - r->frame2time) / (r->frame2time - r->frame1time)) : 1; + r->framelerp = bound(0, r->framelerp, 1); + } + } + else + { + // no interpolation + VectorCopy(p->neworigin, r->origin); + VectorCopy(p->neworigin, oldorg); + VectorCopy(p->newangles, r->angles); + r->frame = r->frame1 = r->frame2 = e->state_current.frame; + r->frame1time = r->frame2time = cl.time; + r->framelerp = 1; + } - f = cl.mtime[0] - cl.mtime[1]; + r->alpha = e->state_current.alpha * (1.0f / 255.0f); // FIXME: interpolate? + r->scale = e->state_current.scale * (1.0f / 16.0f); // FIXME: interpolate? + r->flags = e->state_current.flags; + if (e - cl_entities == cl.viewentity) + r->flags |= RENDER_EXTERIORMODEL; + r->effects = e->state_current.effects; + if (e->state_current.flags & RENDER_COLORMAPPED) + r->colormap = e->state_current.colormap; + else if (cl.scores != NULL && e->state_current.colormap) + r->colormap = cl.scores[e->state_current.colormap - 1].colors; // color it + else + r->colormap = -1; // no special coloring + r->skinnum = e->state_current.skin; - // LordHavoc: lerp in listen games as the server is being capped below the client (usually) - if (!f || cl_nolerp.value || cls.timedemo || (sv.active && svs.maxclients == 1)) + // handle effects now... + trailtype = -1; + dlightcolor[0] = 0; + dlightcolor[1] = 0; + dlightcolor[2] = 0; + + // LordHavoc: if the entity has no effects, don't check each + if (r->effects) { - cl.time = cl.mtime[0]; - return 1; - } - - if (f > 0.1) - { // dropped packet, or start of demo - cl.mtime[1] = cl.mtime[0] - 0.1; - f = 0.1; + if (r->effects & EF_BRIGHTFIELD) + { + if (gamemode == GAME_NEXUIZ) + { + dlightcolor[0] += 100.0f; + dlightcolor[1] += 200.0f; + dlightcolor[2] += 400.0f; + trailtype = 8; + } + else + CL_EntityParticles(e); + } + if (r->effects & EF_MUZZLEFLASH) + p->muzzleflash = 100.0f; + if (r->effects & EF_DIMLIGHT) + { + dlightcolor[0] += 200.0f; + dlightcolor[1] += 200.0f; + dlightcolor[2] += 200.0f; + } + if (r->effects & EF_BRIGHTLIGHT) + { + dlightcolor[0] += 400.0f; + dlightcolor[1] += 400.0f; + dlightcolor[2] += 400.0f; + } + // LordHavoc: added EF_RED and EF_BLUE + if (r->effects & EF_RED) // red + { + dlightcolor[0] += 200.0f; + dlightcolor[1] += 20.0f; + dlightcolor[2] += 20.0f; + } + if (r->effects & EF_BLUE) // blue + { + dlightcolor[0] += 20.0f; + dlightcolor[1] += 20.0f; + dlightcolor[2] += 200.0f; + } + if (r->effects & EF_FLAME) + { + mins[0] = r->origin[0] - 16.0f; + mins[1] = r->origin[1] - 16.0f; + mins[2] = r->origin[2] - 16.0f; + maxs[0] = r->origin[0] + 16.0f; + maxs[1] = r->origin[1] + 16.0f; + maxs[2] = r->origin[2] + 16.0f; + // how many flames to make + temp = (int) (cl.time * 300) - (int) (cl.oldtime * 300); + CL_FlameCube(mins, maxs, temp); + d = lhrandom(200, 250); + dlightcolor[0] += d * 1.0f; + dlightcolor[1] += d * 0.7f; + dlightcolor[2] += d * 0.3f; + } + if (r->effects & EF_STARDUST) + { + mins[0] = r->origin[0] - 16.0f; + mins[1] = r->origin[1] - 16.0f; + mins[2] = r->origin[2] - 16.0f; + maxs[0] = r->origin[0] + 16.0f; + maxs[1] = r->origin[1] + 16.0f; + maxs[2] = r->origin[2] + 16.0f; + // how many particles to make + temp = (int) (cl.time * 200) - (int) (cl.oldtime * 200); + CL_Stardust(mins, maxs, temp); + d = 100; + dlightcolor[0] += d * 1.0f; + dlightcolor[1] += d * 0.7f; + dlightcolor[2] += d * 0.3f; + } } - frac = (cl.time - cl.mtime[1]) / f; -// Con_Printf ("frac: %f\n",frac); - if (frac < 0) + + r->model = cl.model_precache[e->state_current.modelindex]; + if (r->model) { - if (frac < -0.01) + Mod_CheckLoaded(r->model); + if (r->model->type != mod_brush) + r->angles[0] = -r->angles[0]; + // LordHavoc: if the model has no flags, don't check each + if (r->model->flags & EF_ROTATE) { - cl.time = cl.mtime[1]; -// Con_Printf ("low frac\n"); + r->angles[1] = ANGLEMOD(100*cl.time); + if (cl_itembobheight.value) + r->origin[2] += (cos(cl.time * cl_itembobspeed.value * (2.0 * M_PI)) + 1.0) * 0.5 * cl_itembobheight.value; } - frac = 0; } - else if (frac > 1) + + Matrix4x4_CreateFromQuakeEntity(&r->matrix, r->origin[0], r->origin[1], r->origin[2], r->angles[0], r->angles[1], r->angles[2], r->scale); + Matrix4x4_Invert_Simple(&r->inversematrix, &r->matrix); + CL_BoundingBoxForEntity(&e->render); + + // LordHavoc: if the model has no flags, don't check each + if (r->model && r->model->flags) { - if (frac > 1.01) + if (r->model->flags & EF_GIB) + trailtype = 2; + else if (r->model->flags & EF_ZOMGIB) + trailtype = 4; + else if (r->model->flags & EF_TRACER) + { + trailtype = 3; + dlightcolor[0] += 0x10; + dlightcolor[1] += 0x40; + dlightcolor[2] += 0x10; + } + else if (r->model->flags & EF_TRACER2) + { + trailtype = 5; + dlightcolor[0] += 0x50; + dlightcolor[1] += 0x30; + dlightcolor[2] += 0x10; + } + else if (r->model->flags & EF_ROCKET) + { + trailtype = 0; + dlightcolor[0] += 200.0f; + dlightcolor[1] += 160.0f; + dlightcolor[2] += 80.0f; + } + else if (r->model->flags & EF_GRENADE) { - cl.time = cl.mtime[0]; -// Con_Printf ("high frac\n"); + // LordHavoc: r->alpha == -1 is for Nehahra dem compatibility (cigar smoke) + trailtype = r->alpha == -1 ? 7 : 1; + } + else if (r->model->flags & EF_TRACER3) + { + trailtype = 6; + dlightcolor[0] += 0x50; + dlightcolor[1] += 0x20; + dlightcolor[2] += 0x40; } - frac = 1; } - - return frac; -} -float CL_EntityLerpPoint (entity_t *ent) -{ - float f; + // LordHavoc: customizable glow + if (e->state_current.glowsize) + { + // * 4 for the expansion from 0-255 to 0-1023 range, + // / 255 to scale down byte colors + VectorMA(dlightcolor, e->state_current.glowsize * (4.0f / 255.0f), (qbyte *)&palette_complete[e->state_current.glowcolor], dlightcolor); + } - if (cl_nolerp.value || cls.timedemo || (sv.active && svs.maxclients == 1)) - return 1; + // trails need a previous frame... + if (e->state_previous.active) + { + // LordHavoc: customizable trail + if (r->flags & RENDER_GLOWTRAIL) + CL_RocketTrail2(oldorg, r->origin, e->state_current.glowcolor, e); + else if (trailtype >= 0) + CL_RocketTrail(oldorg, r->origin, trailtype, e); + } - f = ent->state_current.time - ent->state_previous.time; -// Con_Printf(" %g-%g=%g", ent->state_current.time, ent->state_previous.time, f); + if ((dlightcolor[0] || dlightcolor[1] || dlightcolor[2]) && !(r->flags & RENDER_VIEWMODEL)) + { + VectorCopy(r->origin, v); + // hack to make glowing player light shine on their gun + if ((e - cl_entities) == cl.viewentity/* && !chase_active.integer*/) + v[2] += 30; + CL_AllocDlight(r, v, 1, dlightcolor[0], dlightcolor[1], dlightcolor[2], 0, 0); + } - if (f <= 0) - return 1; - if (f >= 0.1) - f = 0.1; + if (p->muzzleflash > 0) + { + v2[0] = r->matrix.m[0][0] * 18 + r->matrix.m[0][3]; + v2[1] = r->matrix.m[0][1] * 18 + r->matrix.m[1][3]; + v2[2] = r->matrix.m[0][2] * 18 + r->matrix.m[2][3]; + CL_TraceLine(r->origin, v2, v, NULL, 0, true, NULL); -// Con_Printf(" %g-%g/%g=%f", cl.time, ent->state_previous.time, f, (cl.time - ent->state_previous.time) / f); - f = (cl.time - ent->state_previous.time) / f; - return bound(0, f, 1); + CL_AllocDlight(NULL, v, p->muzzleflash, 1, 1, 1, 0, 0); + p->muzzleflash -= cl.frametime * 1000; + } + + // note: the cl.viewentity and intermission check is to hide player + // shadow during intermission and during the Nehahra movie and + // Nehahra cinematics + if (!(r->effects & (EF_NOSHADOW | EF_ADDITIVE)) + && (r->alpha == 1) + && !(r->flags & RENDER_VIEWMODEL) + && ((e - cl_entities) != cl.viewentity || (!cl.intermission && !Nehahrademcompatibility && !cl_noplayershadow.integer))) + r->flags |= RENDER_SHADOW; + + // don't show entities with no modelindex (note: this still shows + // entities which have a modelindex that resolved to a NULL model) + if (r->model && !(r->effects & EF_NODRAW)) + { + if (r->flags & RENDER_VIEWMODEL) + { + // store a list of view-relative entities for later adjustment in view code + if (numviewmodels < MAXVIEWMODELS) + viewmodels[numviewmodels++] = e; + } + else + { + if (r->model->name[0] == '*' && r->model->type == mod_brush) + cl_brushmodel_entities[cl_num_brushmodel_entities++] = &e->render; + if (r_refdef.numentities < r_refdef.maxentities) + r_refdef.entities[r_refdef.numentities++] = &e->render; + if (cl_num_entities < e->state_current.number + 1) + cl_num_entities = e->state_current.number + 1; + } + } } -void CL_RelinkStaticEntities(void) +void CL_RelinkWorld (void) { - entity_t *ent, *endent; - if (cl.num_statics > MAX_VISEDICTS) - Host_Error("CL_RelinkStaticEntities: cl.num_statics > MAX_VISEDICTS??\n"); - - ent = cl_static_entities; - endent = ent + cl.num_statics; - for (;ent < endent;ent++) - cl_visedicts[cl_numvisedicts++] = ent; + entity_t *ent = &cl_entities[0]; + if (cl_num_entities < 1) + cl_num_entities = 1; + cl_brushmodel_entities[cl_num_brushmodel_entities++] = &ent->render; + Matrix4x4_CreateIdentity(&ent->render.matrix); + Matrix4x4_CreateIdentity(&ent->render.inversematrix); + CL_BoundingBoxForEntity(&ent->render); +} + +static void CL_RelinkStaticEntities(void) +{ + int i; + for (i = 0;i < cl_num_static_entities && r_refdef.numentities < r_refdef.maxentities;i++) + { + Mod_CheckLoaded(cl_static_entities[i].render.model); + r_refdef.entities[r_refdef.numentities++] = &cl_static_entities[i].render; + } } /* @@ -447,259 +791,247 @@ void CL_RelinkStaticEntities(void) CL_RelinkEntities =============== */ -void R_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent); -void CL_RelinkEntities (void) +static void CL_RelinkNetworkEntities(void) { - entity_t *ent; - int i, j, glowcolor, effects; - float frac, f, d, bobjrotate/*, bobjoffset*/, dlightradius, glowsize; - vec3_t oldorg, delta, dlightcolor; - -// determine partial update time - frac = CL_LerpPoint (); - - cl_numvisedicts = 0; - - CL_RelinkStaticEntities(); - -// -// interpolate player info -// - for (i = 0;i < 3;i++) - cl.velocity[i] = cl.mvelocity[1][i] + frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]); + entity_t *ent; + int i; - if (cls.demoplayback) + // start on the entity after the world + for (i = 1, ent = cl_entities + 1;i < MAX_EDICTS;i++, ent++) { - // interpolate the angles - for (j = 0;j < 3;j++) + if (cl_entities_active[i]) { - d = cl.mviewangles[0][j] - cl.mviewangles[1][j]; - if (d > 180) - d -= 360; - else if (d < -180) - d += 360; - cl.viewangles[j] = cl.mviewangles[1][j] + frac*d; + if (ent->state_current.active) + CL_RelinkNetworkEntity(ent); + else + cl_entities_active[i] = false; } } - - bobjrotate = ANGLEMOD(100*cl.time); -// bobjoffset = cos(180 * cl.time * M_PI / 180) * 4.0f + 4.0f; - -// start on the entity after the world - for (i = 1, ent = cl_entities + 1;i < MAX_EDICTS /*cl.num_entities*/;i++, ent++) - { - // if the object wasn't included in the latest packet, remove it - if (!ent->state_current.active) - continue; +} - VectorCopy (ent->render.origin, oldorg); +static void CL_RelinkEffects(void) +{ + int i, intframe; + cl_effect_t *e; + entity_t *ent; + float frame; - if (!ent->state_previous.active) - { - // only one state available - VectorCopy (ent->state_current.origin, ent->render.origin); - VectorCopy (ent->state_current.angles, ent->render.angles); -// Con_Printf(" %i", i); - } - else + for (i = 0, e = cl_effects;i < cl_max_effects;i++, e++) + { + if (e->active) { - // if the delta is large, assume a teleport and don't lerp - f = CL_EntityLerpPoint(ent); - if (f < 1) + frame = (cl.time - e->starttime) * e->framerate + e->startframe; + intframe = frame; + if (intframe < 0 || intframe >= e->endframe) { - for (j = 0;j < 3;j++) - { - delta[j] = ent->state_current.origin[j] - ent->state_previous.origin[j]; - // LordHavoc: increased lerp tolerance from 100 to 200 - if (delta[j] > 200 || delta[j] < -200) - f = 1; - } + memset(e, 0, sizeof(*e)); + continue; } - if (f >= 1) + + if (intframe != e->frame) { - // no interpolation - VectorCopy (ent->state_current.origin, ent->render.origin); - VectorCopy (ent->state_current.angles, ent->render.angles); + e->frame = intframe; + e->frame1time = e->frame2time; + e->frame2time = cl.time; } - else + + // if we're drawing effects, get a new temp entity + // (NewTempEntity adds it to the render entities list for us) + if (r_draweffects.integer && (ent = CL_NewTempEntity())) { - // interpolate the origin and angles - for (j = 0;j < 3;j++) - { - ent->render.origin[j] = ent->state_previous.origin[j] + f*delta[j]; - - d = ent->state_current.angles[j] - ent->state_previous.angles[j]; - if (d > 180) - d -= 360; - else if (d < -180) - d += 360; - ent->render.angles[j] = ent->state_previous.angles[j] + f*d; - } + // interpolation stuff + ent->render.frame1 = intframe; + ent->render.frame2 = intframe + 1; + if (ent->render.frame2 >= e->endframe) + ent->render.frame2 = -1; // disappear + ent->render.framelerp = frame - intframe; + ent->render.frame1time = e->frame1time; + ent->render.frame2time = e->frame2time; + + // normal stuff + ent->render.model = cl.model_precache[e->modelindex]; + ent->render.frame = ent->render.frame2; + ent->render.colormap = -1; // no special coloring + ent->render.alpha = 1; + + Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, e->origin[0], e->origin[1], e->origin[2], 0, 0, 0, 1); + Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix); + CL_BoundingBoxForEntity(&ent->render); } } + } +} - ent->render.flags = ent->state_current.flags; - ent->render.effects = effects = ent->state_current.effects; - ent->render.model = cl.model_precache[ent->state_current.modelindex]; - ent->render.frame = ent->state_current.frame; - if (cl.scores == NULL || !ent->state_current.colormap) - ent->render.colormap = -1; // no special coloring - else - ent->render.colormap = cl.scores[ent->state_current.colormap - 1].colors; // color it - ent->render.skinnum = ent->state_current.skin; - ent->render.alpha = ent->state_current.alpha * (1.0f / 255.0f); // FIXME: interpolate? - ent->render.scale = ent->state_current.scale * (1.0f / 16.0f); // FIXME: interpolate? - glowsize = ent->state_current.glowsize * 4.0f; // FIXME: interpolate? - glowcolor = ent->state_current.glowcolor; - ent->render.colormod[0] = (float) ((ent->state_current.colormod >> 5) & 7) * (1.0f / 7.0f); - ent->render.colormod[1] = (float) ((ent->state_current.colormod >> 2) & 7) * (1.0f / 7.0f); - ent->render.colormod[2] = (float) (ent->state_current.colormod & 3) * (1.0f / 3.0f); - - dlightradius = 0; - dlightcolor[0] = 0; - dlightcolor[1] = 0; - dlightcolor[2] = 0; - - // LordHavoc: if the entity has no effects, don't check each - if (effects) - { - if (effects & EF_BRIGHTFIELD) - R_EntityParticles (ent); - if (effects & EF_MUZZLEFLASH) - { - vec3_t v; - - AngleVectors (ent->render.angles, v, NULL, NULL); - - v[0] = v[0] * 18 + ent->render.origin[0]; - v[1] = v[1] * 18 + ent->render.origin[1]; - v[2] = v[2] * 18 + ent->render.origin[2] + 16; +void CL_RelinkBeams(void) +{ + int i; + beam_t *b; + vec3_t dist, org; + float d; + entity_t *ent; + float yaw, pitch; + float forward; + + for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++) + { + if (!b->model || b->endtime < cl.time) + continue; - CL_AllocDlight (NULL, v, 100, 1, 1, 1, 0, 0.1); - } - if (effects & EF_DIMLIGHT) - { - dlightcolor[0] += 200.0f; - dlightcolor[1] += 200.0f; - dlightcolor[2] += 200.0f; - } - if (effects & EF_BRIGHTLIGHT) - { - dlightcolor[0] += 400.0f; - dlightcolor[1] += 400.0f; - dlightcolor[2] += 400.0f; - } - // LordHavoc: added EF_RED and EF_BLUE - if (effects & EF_RED) // red - { - dlightcolor[0] += 200.0f; - dlightcolor[1] += 20.0f; - dlightcolor[2] += 20.0f; - } - if (effects & EF_BLUE) // blue + // 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_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) { - dlightcolor[0] += 20.0f; - dlightcolor[1] += 20.0f; - dlightcolor[2] += 200.0f; + // 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 (effects & EF_FLAME) + else { - if (ent->render.model) - { - vec3_t mins, maxs; - int temp; - VectorAdd(ent->render.origin, ent->render.model->mins, mins); - VectorAdd(ent->render.origin, ent->render.model->maxs, maxs); - // how many flames to make - temp = (int) (cl.time * 300) - (int) (cl.oldtime * 300); - R_FlameCube(mins, maxs, temp); - } - d = lhrandom(200, 250); - dlightcolor[0] += d * 1.0f; - dlightcolor[1] += d * 0.7f; - dlightcolor[2] += d * 0.3f; + 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); } } - // LordHavoc: if the model has no flags, don't check each - if (ent->render.model && ent->render.model->flags) + if (b->lightning) { - if (ent->render.model->flags & EF_ROTATE) - { - ent->render.angles[1] = bobjrotate; -// ent->render.origin[2] += bobjoffset; - } - // only do trails if present in the previous frame as well - if (ent->state_previous.active) - { - if (ent->render.model->flags & EF_GIB) - R_RocketTrail (oldorg, ent->render.origin, 2, ent); - else if (ent->render.model->flags & EF_ZOMGIB) - R_RocketTrail (oldorg, ent->render.origin, 4, ent); - else if (ent->render.model->flags & EF_TRACER) - R_RocketTrail (oldorg, ent->render.origin, 3, ent); - else if (ent->render.model->flags & EF_TRACER2) - R_RocketTrail (oldorg, ent->render.origin, 5, ent); - else if (ent->render.model->flags & EF_ROCKET) - { - R_RocketTrail (oldorg, ent->render.origin, 0, ent); - dlightcolor[0] += 200.0f; - dlightcolor[1] += 160.0f; - dlightcolor[2] += 80.0f; - } - else if (ent->render.model->flags & EF_GRENADE) - { - if (ent->render.alpha == -1) // LordHavoc: Nehahra dem compatibility - R_RocketTrail (oldorg, ent->render.origin, 7, ent); - else - R_RocketTrail (oldorg, ent->render.origin, 1, ent); - } - else if (ent->render.model->flags & EF_TRACER3) - R_RocketTrail (oldorg, ent->render.origin, 6, ent); - } + if (cl_beams_lightatend.integer) + CL_AllocDlight (NULL, b->end, 200, 0.3, 0.7, 1, 0, 0); + if (cl_beams_polygons.integer) + continue; } - // LordHavoc: customizable glow - if (glowsize) + + // calculate pitch and yaw + VectorSubtract (b->end, b->start, dist); + + if (dist[1] == 0 && dist[0] == 0) { - byte *tempcolor = (byte *)&d_8to24table[glowcolor]; - dlightcolor[0] += glowsize * tempcolor[0] * (1.0f / 255.0f); - dlightcolor[1] += glowsize * tempcolor[1] * (1.0f / 255.0f); - dlightcolor[2] += glowsize * tempcolor[2] * (1.0f / 255.0f); + yaw = 0; + if (dist[2] > 0) + pitch = 90; + else + pitch = 270; } - // LordHavoc: customizable trail - if (ent->render.flags & RENDER_GLOWTRAIL) - R_RocketTrail2 (oldorg, ent->render.origin, glowcolor, ent); - - if (dlightcolor[0] || dlightcolor[1] || dlightcolor[2]) + else { - vec3_t vec; - dlightradius = VectorLength(dlightcolor); - d = 1.0f / dlightradius; - VectorCopy(ent->render.origin, vec); - if (i == cl.viewentity && !chase_active.value) - vec[2] += 30; - CL_AllocDlight (ent, vec, dlightradius, dlightcolor[0] * d, dlightcolor[1] * d, dlightcolor[2] * d, 0, 0); + yaw = (int) (atan2(dist[1], dist[0]) * 180 / M_PI); + if (yaw < 0) + yaw += 360; + + forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]); + pitch = (int) (atan2(dist[2], forward) * 180 / M_PI); + if (pitch < 0) + pitch += 360; } - if (chase_active.value) + // add new entities for the lightning + VectorCopy (b->start, org); + d = VectorNormalizeLength(dist); + while (d > 0) { - if (ent->render.flags & RENDER_VIEWMODEL) - continue; + ent = CL_NewTempEntity (); + if (!ent) + return; + //VectorCopy (org, ent->render.origin); + ent->render.model = b->model; + ent->render.effects = EF_FULLBRIGHT; + //ent->render.angles[0] = pitch; + //ent->render.angles[1] = yaw; + //ent->render.angles[2] = rand()%360; + Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, org[0], org[1], org[2], -pitch, yaw, lhrandom(0, 360), 1); + Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix); + CL_BoundingBoxForEntity(&ent->render); + VectorMA(org, 30, dist, org); + d -= 30; } - else + } +} + +void CL_LerpPlayer(float frac) +{ + int i; + float d; + entity_t *ent; + + cl.viewzoom = cl.viewzoomold + frac * (cl.viewzoomnew - cl.viewzoomold); + + for (i = 0;i < 3;i++) + cl.velocity[i] = cl.mvelocity[1][i] + frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]); + + if (cls.demoplayback) + { + // interpolate the angles + for (i = 0;i < 3;i++) { - if (i == cl.viewentity || (ent->render.flags & RENDER_EXTERIORMODEL)) - continue; + d = cl.mviewangles[0][i] - cl.mviewangles[1][i]; + if (d > 180) + d -= 360; + else if (d < -180) + d += 360; + cl.viewangles[i] = cl.mviewangles[1][i] + frac * d; } + } - if (ent->render.model == NULL) - continue; - if (effects & EF_NODRAW) - continue; - if (cl_numvisedicts < MAX_VISEDICTS) - cl_visedicts[cl_numvisedicts++] = ent; + // set up gun + ent = &cl.viewent; + ent->state_previous = ent->state_current; + ClearStateToDefault(&ent->state_current); + 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]; + if (cl.viewentity >= 0 && cl.viewentity < MAX_EDICTS && cl_entities[cl.viewentity].state_current.active) + { + ent->state_current.alpha = cl_entities[cl.viewentity].state_current.alpha; + ent->state_current.effects = cl_entities[cl.viewentity].state_current.effects; } -// Con_Printf("\n"); + ent->state_current.flags = RENDER_VIEWMODEL; + CL_RelinkNetworkEntity(ent); +} + +void CL_RelinkEntities(void) +{ + float frac; + + numviewmodels = 0; + + // fraction from previous network update to current + frac = CL_LerpPoint(); + + CL_ClearTempEntities(); + CL_DecayLights(); + CL_RelinkWorld(); + CL_RelinkStaticEntities(); + CL_RelinkNetworkEntities(); + CL_RelinkEffects(); + CL_MoveParticles(); + + CL_LerpPlayer(frac); + + CL_RelinkBeams(); } @@ -710,41 +1042,22 @@ CL_ReadFromServer Read all incoming data from the server =============== */ -int CL_ReadFromServer (void) +int CL_ReadFromServer(void) { - int ret, netshown; + CL_ReadDemoMessage(); - cl.oldtime = cl.time; - cl.time += cl.frametime; - - netshown = false; - do + r_refdef.numentities = 0; + cl_num_entities = 0; + cl_num_brushmodel_entities = 0; + + if (cls.state == ca_connected && cls.signon == SIGNONS) { - ret = CL_GetMessage (); - if (ret == -1) - Host_Error ("CL_ReadFromServer: lost server connection"); - if (!ret) - break; - - cl.last_received_message = realtime; - - if (cl_shownet.value) - netshown = true; - - CL_ParseServerMessage (); - } - while (ret && cls.state == ca_connected); - - if (netshown) - Con_Printf ("\n"); + CL_RelinkEntities(); - CL_RelinkEntities (); - CL_UpdateTEnts (); - CL_DoEffects (); + // run cgame code (which can add more entities) + CL_CGVM_Frame(); + } -// -// bring the links up to date -// return 0; } @@ -753,49 +1066,50 @@ int CL_ReadFromServer (void) CL_SendCmd ================= */ -void CL_SendCmd (void) +void CL_SendCmd(void) { - usercmd_t cmd; - - if (cls.state != ca_connected) - return; + usercmd_t cmd; if (cls.signon == SIGNONS) { - // get basic movement from keyboard - CL_BaseMove (&cmd); - - // allow mice or other external controllers to add to the move - IN_Move (&cmd); - - // send the unreliable message - CL_SendMove (&cmd); + // get basic movement from keyboard + CL_BaseMove(&cmd); + + // OS independent code + IN_PreMove(); + + // allow mice or other external controllers to add to the move + IN_Move(&cmd); + + // OS independent code + IN_PostMove(); + + // send the unreliable message + CL_SendMove(&cmd); } if (cls.demoplayback) { - SZ_Clear (&cls.message); + SZ_Clear(&cls.message); return; } - -// send the reliable message - if (!cls.message.cursize) - return; // no message at all - - if (!NET_CanSendMessage (cls.netcon)) + + // send the reliable message (forwarded commands) if there is one + if (cls.message.cursize && NetConn_CanSendMessage(cls.netcon)) { - Con_DPrintf ("CL_WriteToServer: can't send\n"); - return; + if (developer.integer) + { + Con_Printf("CL_SendCmd: sending reliable message:\n"); + SZ_HexDumpToConsole(&cls.message); + } + if (NetConn_SendReliableMessage(cls.netcon, &cls.message) == -1) + Host_Error("CL_WriteToServer: lost server connection"); + SZ_Clear(&cls.message); } - - if (NET_SendMessage (cls.netcon, &cls.message) == -1) - Host_Error ("CL_WriteToServer: lost server connection"); - - SZ_Clear (&cls.message); } // LordHavoc: pausedemo command -void CL_PauseDemo_f (void) +static void CL_PauseDemo_f (void) { cls.demopaused = !cls.demopaused; if (cls.demopaused) @@ -804,45 +1118,12 @@ void CL_PauseDemo_f (void) Con_Printf("Demo unpaused\n"); } -/* -====================== -CL_PModel_f -LordHavoc: Intended for Nehahra, I personally think this is dumb, but Mindcrime won't listen. -====================== -*/ -void CL_PModel_f (void) -{ - int i; - eval_t *val; - - if (Cmd_Argc () == 1) - { - Con_Printf ("\"pmodel\" is \"%s\"\n", cl_pmodel.string); - return; - } - i = atoi(Cmd_Argv(1)); - - if (cmd_source == src_command) - { - if (cl_pmodel.value == i) - return; - Cvar_SetValue ("_cl_pmodel", i); - if (cls.state == ca_connected) - Cmd_ForwardToServer (); - return; - } - - host_client->pmodel = i; - if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_pmodel))) - val->_float = i; -} - /* ====================== CL_Fog_f ====================== */ -void CL_Fog_f (void) +static void CL_Fog_f (void) { if (Cmd_Argc () == 1) { @@ -861,18 +1142,26 @@ CL_Init ================= */ void CL_Init (void) -{ - SZ_Alloc (&cls.message, 1024); +{ + cl_entities_mempool = Mem_AllocPool("client entities"); + cl_refdef_mempool = Mem_AllocPool("refdef"); + + 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_refdef_mempool, sizeof(entity_render_t *) * r_refdef.maxentities); + // 256k drawqueue buffer + r_refdef.maxdrawqueuesize = 256 * 1024; + r_refdef.drawqueue = Mem_Alloc(cl_refdef_mempool, r_refdef.maxdrawqueuesize); + + SZ_Alloc (&cls.message, 1024, "cls.message"); CL_InitInput (); CL_InitTEnts (); - + // // register our commands // - Cvar_RegisterVariable (&cl_name); - Cvar_RegisterVariable (&cl_color); - Cvar_RegisterVariable (&cl_pmodel); Cvar_RegisterVariable (&cl_upspeed); Cvar_RegisterVariable (&cl_forwardspeed); Cvar_RegisterVariable (&cl_backspeed); @@ -893,10 +1182,10 @@ void CL_Init (void) Cvar_RegisterVariable (&m_forward); Cvar_RegisterVariable (&m_side); -// Cvar_RegisterVariable (&cl_autofire); - + Cvar_RegisterVariable (&cl_itembobspeed); + Cvar_RegisterVariable (&cl_itembobheight); + Cmd_AddCommand ("entities", CL_PrintEntities_f); - Cmd_AddCommand ("bitprofile", CL_BitProfile_f); Cmd_AddCommand ("disconnect", CL_Disconnect_f); Cmd_AddCommand ("record", CL_Record_f); Cmd_AddCommand ("stop", CL_Stop_f); @@ -907,8 +1196,20 @@ void CL_Init (void) // LordHavoc: added pausedemo Cmd_AddCommand ("pausedemo", CL_PauseDemo_f); - // LordHavoc: added pmodel command (like name, etc, only intended for Nehahra) - Cmd_AddCommand ("pmodel", CL_PModel_f); + + Cvar_RegisterVariable(&r_draweffects); + Cvar_RegisterVariable(&cl_explosions); + Cvar_RegisterVariable(&cl_stainmaps); + Cvar_RegisterVariable(&cl_beams_polygons); + Cvar_RegisterVariable(&cl_beams_relative); + Cvar_RegisterVariable(&cl_beams_lightatend); + Cvar_RegisterVariable(&cl_noplayershadow); CL_Parse_Init(); + CL_Particles_Init(); + CL_Screen_Init(); + CL_CGVM_Init(); + + CL_Video_Init(); } +