+ else
+ {
+ t = cl_entities + e->state_current.tagentity;
+ if (!t->state_current.active)
+ return;
+ // note: this can link to world
+ CL_LinkNetworkEntity(t);
+ // make relative to the entity
+ matrix = &t->render.matrix;
+ // if a valid tagindex is used, make it relative to that tag instead
+ if (e->state_current.tagentity && e->state_current.tagindex >= 1 && (model = t->render.model) && e->state_current.tagindex <= t->render.model->alias.aliasnum_tags)
+ {
+ // blend the matrices
+ memset(&blendmatrix, 0, sizeof(blendmatrix));
+ for (j = 0;j < 4 && t->render.frameblend[j].lerp > 0;j++)
+ {
+ matrix = &t->render.model->alias.aliasdata_tags[t->render.frameblend[j].frame * t->render.model->alias.aliasnum_tags + (e->state_current.tagindex - 1)].matrix;
+ d = t->render.frameblend[j].lerp;
+ for (l = 0;l < 4;l++)
+ for (k = 0;k < 4;k++)
+ blendmatrix.m[l][k] += d * matrix->m[l][k];
+ }
+ // concat the tag matrices onto the entity matrix
+ Matrix4x4_Concat(&tempmatrix, &t->render.matrix, &blendmatrix);
+ // use the constructed tag matrix
+ matrix = &tempmatrix;
+ }
+ }
+ e->render.alpha = e->state_current.alpha * (1.0f / 255.0f); // FIXME: interpolate?
+ e->render.scale = e->state_current.scale * (1.0f / 16.0f); // FIXME: interpolate?
+ e->render.flags = e->state_current.flags;
+ if (e - cl_entities == cl.viewentity)
+ e->render.flags |= RENDER_EXTERIORMODEL;
+ e->render.effects = e->state_current.effects;
+ if (e->state_current.flags & RENDER_COLORMAPPED)
+ e->render.colormap = e->state_current.colormap;
+ else if (cl.scores != NULL && e->state_current.colormap)
+ e->render.colormap = cl.scores[e->state_current.colormap - 1].colors; // color it
+ else
+ e->render.colormap = -1; // no special coloring
+ e->render.skinnum = e->state_current.skin;
+ // set up the render matrix
+ if (e->state_previous.active && e->state_current.modelindex == e->state_previous.modelindex)
+ {
+ // movement lerp
+ if (e->persistent.lerpdeltatime > 0 && (lerp = (cl.time - e->persistent.lerpstarttime) / e->persistent.lerpdeltatime) < 1)
+ {
+ // interpolate the origin and angles
+ VectorLerp(e->persistent.oldorigin, lerp, e->persistent.neworigin, origin);
+ VectorSubtract(e->persistent.newangles, e->persistent.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(e->persistent.oldangles, lerp, delta, angles);
+ }
+ else
+ {
+ // no interpolation
+ VectorCopy(e->persistent.neworigin, origin);
+ VectorCopy(e->persistent.newangles, angles);
+ }
+ // animation lerp
+ if (e->render.frame2 == e->state_current.frame)
+ {
+ // update frame lerp fraction
+ e->render.framelerp = 1;
+ if (e->render.frame2time > e->render.frame1time)
+ {
+ e->render.framelerp = (cl.time - e->render.frame2time) / (e->render.frame2time - e->render.frame1time);
+ e->render.framelerp = bound(0, e->render.framelerp, 1);
+ }
+ }
+ else
+ {
+ // begin a new frame lerp
+ e->render.frame1 = e->render.frame2;
+ e->render.frame1time = e->render.frame2time;
+ e->render.frame = e->render.frame2 = e->state_current.frame;
+ e->render.frame2time = cl.time;
+ e->render.framelerp = 0;
+ }
+ }
+ else
+ {
+ // no interpolation
+ VectorCopy(e->persistent.neworigin, origin);
+ VectorCopy(e->persistent.newangles, angles);
+ e->render.frame = e->render.frame1 = e->render.frame2 = e->state_current.frame;
+ e->render.frame1time = e->render.frame2time = cl.time;
+ e->render.framelerp = 1;
+ }
+
+ e->render.model = cl.model_precache[e->state_current.modelindex];
+ if (e->render.model)
+ {
+ Mod_CheckLoaded(e->render.model);
+ if (e->render.model->type == mod_alias || e->render.model->type == mod_sprite)
+ angles[0] = -angles[0];
+ if (e->render.model->flags & EF_ROTATE)
+ {
+ angles[1] = ANGLEMOD(100*cl.time);
+ if (cl_itembobheight.value)
+ origin[2] += (cos(cl.time * cl_itembobspeed.value * (2.0 * M_PI)) + 1.0) * 0.5 * cl_itembobheight.value;
+ }
+ }
+
+ R_LerpAnimation(&e->render);
+
+ // FIXME: e->render.scale should go away
+ Matrix4x4_CreateFromQuakeEntity(&matrix2, origin[0], origin[1], 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, matrix, &matrix2);
+ // make the other useful stuff
+ Matrix4x4_Invert_Simple(&e->render.inversematrix, &e->render.matrix);
+ 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];
+ trailtype = -1;
+ dlightcolor[0] = 0;
+ dlightcolor[1] = 0;
+ dlightcolor[2] = 0;
+ // LordHavoc: if the entity has no effects, don't check each
+ if (e->render.effects)
+ {
+ if (e->render.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 (e->render.effects & EF_MUZZLEFLASH)
+ e->persistent.muzzleflash = 100.0f;
+ if (e->render.effects & EF_DIMLIGHT)
+ {
+ dlightcolor[0] += 200.0f;
+ dlightcolor[1] += 200.0f;
+ dlightcolor[2] += 200.0f;
+ }
+ if (e->render.effects & EF_BRIGHTLIGHT)
+ {
+ dlightcolor[0] += 400.0f;
+ dlightcolor[1] += 400.0f;
+ dlightcolor[2] += 400.0f;
+ }
+ // LordHavoc: more effects
+ if (e->render.effects & EF_RED) // red
+ {
+ dlightcolor[0] += 200.0f;
+ dlightcolor[1] += 20.0f;
+ dlightcolor[2] += 20.0f;
+ }
+ if (e->render.effects & EF_BLUE) // blue
+ {
+ dlightcolor[0] += 20.0f;
+ dlightcolor[1] += 20.0f;
+ dlightcolor[2] += 200.0f;
+ }
+ if (e->render.effects & EF_FLAME)
+ {
+ mins[0] = origin[0] - 16.0f;
+ mins[1] = origin[1] - 16.0f;
+ mins[2] = origin[2] - 16.0f;
+ maxs[0] = origin[0] + 16.0f;
+ maxs[1] = origin[1] + 16.0f;
+ maxs[2] = 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 (e->render.effects & EF_STARDUST)
+ {
+ mins[0] = origin[0] - 16.0f;
+ mins[1] = origin[1] - 16.0f;
+ mins[2] = origin[2] - 16.0f;
+ maxs[0] = origin[0] + 16.0f;
+ maxs[1] = origin[1] + 16.0f;
+ maxs[2] = 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;
+ }
+ }
+ // muzzleflash fades over time, and is offset a bit
+ if (e->persistent.muzzleflash > 0)