+ Matrix4x4_Transform(&e->render.matrix, muzzleflashorigin, v2);
+ trace = CL_TraceBox(origin, vec3_origin, vec3_origin, v2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, false);
+ tempmatrix = e->render.matrix;
+ tempmatrix.m[0][3] = trace.endpos[0];
+ tempmatrix.m[1][3] = trace.endpos[1];
+ tempmatrix.m[2][3] = trace.endpos[2];
+ CL_AllocDlight(NULL, &tempmatrix, 100, e->persistent.muzzleflash, e->persistent.muzzleflash, e->persistent.muzzleflash, 0, 0, 0, -1, true, 0, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ e->persistent.muzzleflash -= cl.frametime * 10;
+ }
+ // LordHavoc: if the model has no flags, don't check each
+ if (e->render.model && e->render.model->flags && (!e->state_current.tagentity && !(e->render.flags & RENDER_VIEWMODEL)))
+ {
+ if (e->render.model->flags & EF_GIB)
+ trailtype = 2;
+ else if (e->render.model->flags & EF_ZOMGIB)
+ trailtype = 4;
+ 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;
+ }
+ 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;
+ }
+ else if (e->render.model->flags & EF_ROCKET)
+ {
+ trailtype = 0;
+ dlightradius = max(dlightradius, 200);
+ dlightcolor[0] += 3.00f;
+ dlightcolor[1] += 1.50f;
+ dlightcolor[2] += 0.50f;
+ }
+ else if (e->render.model->flags & EF_GRENADE)
+ {
+ // LordHavoc: e->render.alpha == -1 is for Nehahra dem compatibility (cigar smoke)
+ trailtype = e->render.alpha == -1 ? 7 : 1;
+ }
+ else if (e->render.model->flags & EF_TRACER3)
+ {
+ trailtype = 6;
+ if (gamemode == GAME_PRYDON)
+ {
+ dlightradius = max(dlightradius, 100);
+ dlightcolor[0] += 0.30f;
+ dlightcolor[1] += 0.60f;
+ dlightcolor[2] += 1.20f;
+ }
+ else
+ {
+ dlightradius = max(dlightradius, 200);
+ dlightcolor[0] += 1.20f;
+ dlightcolor[1] += 0.50f;
+ dlightcolor[2] += 1.00f;
+ }
+ }
+ }
+ // 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
+ dlightradius = max(dlightradius, e->state_current.glowsize * 4);
+ VectorMA(dlightcolor, (1.0f / 255.0f), (qbyte *)&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))
+ {
+ //dlightmatrix = e->render.matrix;
+ // hack to make glowing player light shine on their gun
+ //if (e->state_current.number == cl.viewentity/* && !chase_active.integer*/)
+ // dlightmatrix.m[2][3] += 30;
+ CL_AllocDlight(&e->render, &e->render.matrix, dlightradius, dlightcolor[0], dlightcolor[1], dlightcolor[2], 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ }
+ // custom rtlight
+ if (e->state_current.lightpflags & PFLAGS_FULLDYNAMIC)
+ {
+ float light[4];
+ VectorScale(e->state_current.light, (1.0f / 256.0f), light);
+ light[3] = e->state_current.light[3];
+ if (light[0] == 0 && light[1] == 0 && light[2] == 0)
+ VectorSet(light, 1, 1, 1);
+ if (light[3] == 0)
+ light[3] = 350;
+ // FIXME: add ambient/diffuse/specular scales as an extension ontop of TENEBRAE_GFX_DLIGHTS?
+ CL_AllocDlight(&e->render, &e->render.matrix, light[3], light[0], light[1], light[2], 0, 0, e->state_current.skin, e->state_current.lightstyle, !(e->state_current.lightpflags & PFLAGS_NOSHADOW), (e->state_current.lightpflags & PFLAGS_CORONA) != 0, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+ }
+ // do trails
+ if (e->render.flags & RENDER_GLOWTRAIL)
+ trailtype = 9;
+ if (trailtype >= 0)
+ CL_RocketTrail(e->persistent.trail_origin, origin, trailtype, e->state_current.glowcolor, e);
+ VectorCopy(origin, e->persistent.trail_origin);
+ // tenebrae's sprites are all additive mode (weird)
+ if (gamemode == GAME_TENEBRAE && e->render.model && e->render.model->type == mod_sprite)
+ e->render.effects |= EF_ADDITIVE;
+ // player model is only shown with chase_active on
+ if (e->state_current.number == cl.viewentity)
+ e->render.flags |= RENDER_EXTERIORMODEL;
+ // 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;
+ // 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 && cl.protocol != PROTOCOL_NEHAHRAMOVIE && !cl_noplayershadow.integer)))
+ e->render.flags |= RENDER_SHADOW;
+ // as soon as player is known we can call V_CalcRefDef
+ 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;
+ // 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)
+ r_refdef.entities[r_refdef.numentities++] = &e->render;
+ //if (cl.viewentity && e->state_current.number == cl.viewentity)
+ // Matrix4x4_Print(&e->render.matrix);
+ }
+}
+
+void CL_RelinkWorld(void)
+{
+ entity_t *ent = &cl_entities[0];
+ cl_brushmodel_entities[cl_num_brushmodel_entities++] = 0;
+ // FIXME: this should be done at load
+ Matrix4x4_CreateIdentity(&ent->render.matrix);
+ Matrix4x4_CreateIdentity(&ent->render.inversematrix);
+ 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;
+ 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)
+ e->render.flags |= RENDER_TRANSPARENT;
+ // 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_TRANSPARENT))
+ e->render.flags |= RENDER_SHADOW;
+ VectorSet(e->render.colormod, 1, 1, 1);
+ R_LerpAnimation(&e->render);
+ r_refdef.entities[r_refdef.numentities++] = &e->render;
+ }
+}
+
+/*
+===============
+CL_RelinkEntities
+===============
+*/
+static void CL_RelinkNetworkEntities(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.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_LinkNetworkEntity(ent);
+ else
+ cl_entities_active[i] = false;
+ }
+ }
+ CL_LinkNetworkEntity(&cl.viewent);
+}
+
+static void CL_RelinkEffects(void)
+{
+ int i, intframe;
+ cl_effect_t *e;
+ entity_t *ent;
+ float frame;
+
+ for (i = 0, e = cl_effects;i < cl_max_effects;i++, e++)
+ {
+ if (e->active)
+ {
+ frame = (cl.time - e->starttime) * e->framerate + e->startframe;
+ intframe = frame;
+ if (intframe < 0 || intframe >= e->endframe)
+ {
+ memset(e, 0, sizeof(*e));
+ continue;
+ }
+
+ if (intframe != e->frame)
+ {
+ e->frame = intframe;
+ e->frame1time = e->frame2time;
+ e->frame2time = cl.time;
+ }
+
+ // 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()))
+ {
+ // 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;
+ VectorSet(ent->render.colormod, 1, 1, 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);
+ R_LerpAnimation(&ent->render);
+ CL_BoundingBoxForEntity(&ent->render);
+ }