Move the entity transform setup into the clients.

This has several benifits:
  o The silly issue with alias model pitches being backwards is kept out
    of the renderer (it's a quakec thing: entites do their pitch
    backwards, but originally, only alias models were rotated. Hipnotic
    did brush entity rotations in the correct direction).
  o Angle to frame vector conversions are done only when the entity's
    angles vector changes, rather than every frame. This avoids a lot of
    unnecessary trig function calls.
  o Once transformed, an entity's frame vectors are always available.
    However, the vectors are left handed rather than right handed (ie,
    forward/left/up instead of forward/right/up): just a matter of
    watching the sign. This avoids even more trig calls (flag models in
    qw).
  o This paves the way for merging brush entity surface rendering with the
    world model surface rendering (the actual goal of this patch).
  o This also paves the way for using quaternions to represent entity
    orientation, as that would be a protocol change.
This commit is contained in:
Bill Currie 2011-12-15 12:06:03 +09:00
parent f6ebb78140
commit 3eb859a88f
24 changed files with 205 additions and 223 deletions

View file

@ -250,7 +250,7 @@ QFGL_DONT_NEED (void, glMaterialiv, (GLenum face, GLenum pname, const GLint * pa
QFGL_NEED (void, glMatrixMode, (GLenum mode)) QFGL_NEED (void, glMatrixMode, (GLenum mode))
QFGL_DONT_NEED (void, glMinmax, (GLenum target, GLenum internalformat, GLboolean sink)) QFGL_DONT_NEED (void, glMinmax, (GLenum target, GLenum internalformat, GLboolean sink))
QFGL_DONT_NEED (void, glMultMatrixd, (const GLdouble * m)) QFGL_DONT_NEED (void, glMultMatrixd, (const GLdouble * m))
QFGL_DONT_NEED (void, glMultMatrixf, (const GLfloat * m)) QFGL_NEED (void, glMultMatrixf, (const GLfloat * m))
QFGL_NEED (void, glNewList, (GLuint list, GLenum mode)) QFGL_NEED (void, glNewList, (GLuint list, GLenum mode))
QFGL_DONT_NEED (void, glNormal3b, (GLbyte nx, GLbyte ny, GLbyte nz)) QFGL_DONT_NEED (void, glNormal3b, (GLbyte nx, GLbyte ny, GLbyte nz))
QFGL_NEED (void, glNormal3bv, (const GLbyte * v)) QFGL_NEED (void, glNormal3bv, (const GLbyte * v))

View file

@ -73,6 +73,7 @@ typedef struct entity_s {
vec3_t origin; vec3_t origin;
vec3_t old_origin; vec3_t old_origin;
vec3_t angles; vec3_t angles;
vec_t transform[4 * 4];
struct model_s *model; // NULL = no model struct model_s *model; // NULL = no model
int frame; int frame;
byte *colormap; byte *colormap;

View file

@ -110,16 +110,15 @@ R_DrawSpriteModel_f (entity_t *e)
float *up, *right; float *up, *right;
msprite_t *psprite; msprite_t *psprite;
mspriteframe_t *frame; mspriteframe_t *frame;
vec3_t point, point1, point2, v_forward, v_right, v_up; vec3_t point, point1, point2, v_up;
// don't bother culling, it's just a single polygon without a surface cache // don't bother culling, it's just a single polygon without a surface cache
frame = R_GetSpriteFrame (e); frame = R_GetSpriteFrame (e);
psprite = e->model->cache.data; psprite = e->model->cache.data;
if (psprite->type == SPR_ORIENTED) { // bullet marks on walls if (psprite->type == SPR_ORIENTED) { // bullet marks on walls
AngleVectors (e->angles, v_forward, v_right, v_up); up = e->transform + 2 * 4;
up = v_up; right = e->transform + 1 * 4;
right = v_right;
} else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT) { } else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT) {
v_up[0] = 0; v_up[0] = 0;
v_up[1] = 0; v_up[1] = 0;
@ -179,7 +178,7 @@ R_DrawSpriteModel_VA_f (entity_t *e)
// unsigned int vacount; // unsigned int vacount;
msprite_t *psprite; msprite_t *psprite;
mspriteframe_t *frame; mspriteframe_t *frame;
vec3_t point1, point2, v_forward, v_right, v_up; vec3_t point1, point2, v_up;
varray_t2f_c4ub_v3f_t *VA; varray_t2f_c4ub_v3f_t *VA;
VA = spriteVertexArray; // FIXME: Despair VA = spriteVertexArray; // FIXME: Despair
@ -191,9 +190,8 @@ R_DrawSpriteModel_VA_f (entity_t *e)
qfglBindTexture (GL_TEXTURE_2D, frame->gl_texturenum); // FIXME: DESPAIR qfglBindTexture (GL_TEXTURE_2D, frame->gl_texturenum); // FIXME: DESPAIR
if (psprite->type == SPR_ORIENTED) { // bullet marks on walls if (psprite->type == SPR_ORIENTED) { // bullet marks on walls
AngleVectors (e->angles, v_forward, v_right, v_up); up = e->transform + 2 * 4;
up = v_up; right = e->transform + 1 * 4;
right = v_right;
} else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT) { } else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT) {
v_up[0] = 0; v_up[0] = 0;
v_up[1] = 0; v_up[1] = 0;

View file

@ -203,11 +203,7 @@ glrmain_init (void)
void void
R_RotateForEntity (entity_t *e) R_RotateForEntity (entity_t *e)
{ {
qfglTranslatef (e->origin[0], e->origin[1], e->origin[2]); qfglMultMatrixf (e->transform);
qfglRotatef ( e->angles[YAW], 0, 0, 1);
qfglRotatef (-e->angles[PITCH], 0, 1, 0);
qfglRotatef ( e->angles[ROLL], 1, 0, 0);
} }
/* /*

View file

@ -388,7 +388,7 @@ R_DrawBrushModel (entity_t *e)
model = e->model; model = e->model;
if (e->angles[0] || e->angles[1] || e->angles[2]) { if (e->transform[0] != 1 || e->transform[5] != 1 || e->transform[10] != 1) {
rotated = true; rotated = true;
radius = model->radius; radius = model->radius;
#if 0 //QSG FIXME #if 0 //QSG FIXME
@ -423,13 +423,12 @@ R_DrawBrushModel (entity_t *e)
VectorSubtract (r_refdef.vieworg, e->origin, modelorg); VectorSubtract (r_refdef.vieworg, e->origin, modelorg);
if (rotated) { if (rotated) {
vec3_t temp, forward, right, up; vec3_t temp;
VectorCopy (modelorg, temp); VectorCopy (modelorg, temp);
AngleVectors (e->angles, forward, right, up); modelorg[0] = DotProduct (temp, e->transform + 0);
modelorg[0] = DotProduct (temp, forward); modelorg[1] = DotProduct (temp, e->transform + 4);
modelorg[1] = -DotProduct (temp, right); modelorg[2] = DotProduct (temp, e->transform + 8);
modelorg[2] = DotProduct (temp, up);
} }
psurf = &model->surfaces[model->firstmodelsurface]; psurf = &model->surfaces[model->firstmodelsurface];
@ -449,9 +448,7 @@ R_DrawBrushModel (entity_t *e)
} }
qfglPushMatrix (); qfglPushMatrix ();
e->angles[0] = -e->angles[0]; // stupid quake bug
R_RotateForEntity (e); R_RotateForEntity (e);
e->angles[0] = -e->angles[0]; // stupid quake bug
// Build lightmap chains // Build lightmap chains
for (i = 0; i < model->nummodelsurfaces; i++, psurf++) { for (i = 0; i < model->nummodelsurfaces; i++, psurf++) {

View file

@ -360,16 +360,10 @@ R_AliasSetUpTransform (int trivial_accept)
float rotationmatrix[3][4], t2matrix[3][4]; float rotationmatrix[3][4], t2matrix[3][4];
static float tmatrix[3][4]; static float tmatrix[3][4];
static float viewmatrix[3][4]; static float viewmatrix[3][4];
vec3_t angles;
// TODO: should really be stored with the entity instead of being reconstructed VectorCopy (currententity->transform + 0, alias_forward);
// TODO: should use a look-up table VectorNegate (currententity->transform + 4, alias_right);
// TODO: could cache lazily, stored in the entity VectorCopy (currententity->transform + 8, alias_up);
angles[ROLL] = currententity->angles[ROLL];
angles[PITCH] = -currententity->angles[PITCH];
angles[YAW] = currententity->angles[YAW];
AngleVectors (angles, alias_forward, alias_right, alias_up);
tmatrix[0][0] = pmdl->scale[0]; tmatrix[0][0] = pmdl->scale[0];
tmatrix[1][1] = pmdl->scale[1]; tmatrix[1][1] = pmdl->scale[1];

View file

@ -80,64 +80,9 @@ R_EntityRotate (vec3_t vec)
void void
R_RotateBmodel (void) R_RotateBmodel (void)
{ {
float angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3]; VectorCopy (currententity->transform + 0, entity_rotation[0]);
VectorCopy (currententity->transform + 4, entity_rotation[1]);
// TODO: should use a look-up table VectorCopy (currententity->transform + 8, entity_rotation[2]);
// TODO: should really be stored with the entity instead of being reconstructed
// TODO: could cache lazily, stored in the entity
// TODO: share work with R_SetUpAliasTransform
// yaw
angle = currententity->angles[YAW];
angle = angle * M_PI * 2 / 360;
s = sin (angle);
c = cos (angle);
temp1[0][0] = c;
temp1[0][1] = s;
temp1[0][2] = 0;
temp1[1][0] = -s;
temp1[1][1] = c;
temp1[1][2] = 0;
temp1[2][0] = 0;
temp1[2][1] = 0;
temp1[2][2] = 1;
// pitch
angle = currententity->angles[PITCH];
angle = angle * M_PI * 2 / 360;
s = sin (angle);
c = cos (angle);
temp2[0][0] = c;
temp2[0][1] = 0;
temp2[0][2] = -s;
temp2[1][0] = 0;
temp2[1][1] = 1;
temp2[1][2] = 0;
temp2[2][0] = s;
temp2[2][1] = 0;
temp2[2][2] = c;
R_ConcatRotations (temp2, temp1, temp3);
// roll
angle = currententity->angles[ROLL];
angle = angle * M_PI * 2 / 360;
s = sin (angle);
c = cos (angle);
temp1[0][0] = 1;
temp1[0][1] = 0;
temp1[0][2] = 0;
temp1[1][0] = 0;
temp1[1][1] = c;
temp1[1][2] = s;
temp1[2][0] = 0;
temp1[2][1] = -s;
temp1[2][2] = c;
R_ConcatRotations (temp1, temp3, entity_rotation);
// rotate modelorg and the transformation matrix // rotate modelorg and the transformation matrix
R_EntityRotate (modelorg); R_EntityRotate (modelorg);

View file

@ -550,8 +550,8 @@ R_BmodelCheckBBox (model_t *clmodel, float *minmaxs)
clipflags = 0; clipflags = 0;
if (currententity->angles[0] || currententity->angles[1] if (currententity->transform[0] != 1 || currententity->transform[5] != 1
|| currententity->angles[2]) { || currententity->transform[10] != 1) {
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
d = DotProduct (currententity->origin, view_clipplanes[i].normal); d = DotProduct (currententity->origin, view_clipplanes[i].normal);
d -= view_clipplanes[i].dist; d -= view_clipplanes[i].dist;

View file

@ -364,8 +364,9 @@ R_DrawSprite (void)
} else if (psprite->type == SPR_ORIENTED) { } else if (psprite->type == SPR_ORIENTED) {
// generate the sprite's axes, according to the sprite's world // generate the sprite's axes, according to the sprite's world
// orientation // orientation
AngleVectors (currententity->angles, r_spritedesc.vpn, VectorCopy (currententity->transform + 0, r_spritedesc.vpn);
r_spritedesc.vright, r_spritedesc.vup); VectorNegate (currententity->transform + 4, r_spritedesc.vright);
VectorCopy (currententity->transform + 8, r_spritedesc.vup);
} else if (psprite->type == SPR_VP_PARALLEL_ORIENTED) { } else if (psprite->type == SPR_VP_PARALLEL_ORIENTED) {
// generate the sprite's axes, parallel to the viewplane, but rotated // generate the sprite's axes, parallel to the viewplane, but rotated
// in that plane around the center according to the sprite entity's // in that plane around the center according to the sprite entity's

View file

@ -363,16 +363,10 @@ R_AliasSetUpTransform (int trivial_accept)
float rotationmatrix[3][4], t2matrix[3][4]; float rotationmatrix[3][4], t2matrix[3][4];
static float tmatrix[3][4]; static float tmatrix[3][4];
static float viewmatrix[3][4]; static float viewmatrix[3][4];
vec3_t angles;
// TODO: should really be stored with the entity instead of being reconstructed VectorCopy (currententity->transform + 0, alias_forward);
// TODO: should use a look-up table VectorNegate (currententity->transform + 4, alias_right);
// TODO: could cache lazily, stored in the entity VectorCopy (currententity->transform + 8, alias_up);
angles[ROLL] = currententity->angles[ROLL];
angles[PITCH] = -currententity->angles[PITCH];
angles[YAW] = currententity->angles[YAW];
AngleVectors (angles, alias_forward, alias_right, alias_up);
tmatrix[0][0] = pmdl->scale[0]; tmatrix[0][0] = pmdl->scale[0];
tmatrix[1][1] = pmdl->scale[1]; tmatrix[1][1] = pmdl->scale[1];

View file

@ -80,64 +80,9 @@ R_EntityRotate (vec3_t vec)
void void
R_RotateBmodel (void) R_RotateBmodel (void)
{ {
float angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3]; VectorCopy (currententity->transform + 0, entity_rotation[0]);
VectorCopy (currententity->transform + 4, entity_rotation[1]);
// TODO: should use a look-up table VectorCopy (currententity->transform + 8, entity_rotation[2]);
// TODO: should really be stored with the entity instead of being reconstructed
// TODO: could cache lazily, stored in the entity
// TODO: share work with R_SetUpAliasTransform
// yaw
angle = currententity->angles[YAW];
angle = angle * M_PI * 2 / 360;
s = sin (angle);
c = cos (angle);
temp1[0][0] = c;
temp1[0][1] = s;
temp1[0][2] = 0;
temp1[1][0] = -s;
temp1[1][1] = c;
temp1[1][2] = 0;
temp1[2][0] = 0;
temp1[2][1] = 0;
temp1[2][2] = 1;
// pitch
angle = currententity->angles[PITCH];
angle = angle * M_PI * 2 / 360;
s = sin (angle);
c = cos (angle);
temp2[0][0] = c;
temp2[0][1] = 0;
temp2[0][2] = -s;
temp2[1][0] = 0;
temp2[1][1] = 1;
temp2[1][2] = 0;
temp2[2][0] = s;
temp2[2][1] = 0;
temp2[2][2] = c;
R_ConcatRotations (temp2, temp1, temp3);
// roll
angle = currententity->angles[ROLL];
angle = angle * M_PI * 2 / 360;
s = sin (angle);
c = cos (angle);
temp1[0][0] = 1;
temp1[0][1] = 0;
temp1[0][2] = 0;
temp1[1][0] = 0;
temp1[1][1] = c;
temp1[1][2] = s;
temp1[2][0] = 0;
temp1[2][1] = -s;
temp1[2][2] = c;
R_ConcatRotations (temp1, temp3, entity_rotation);
// rotate modelorg and the transformation matrix // rotate modelorg and the transformation matrix
R_EntityRotate (modelorg); R_EntityRotate (modelorg);

View file

@ -569,8 +569,8 @@ R_BmodelCheckBBox (model_t *clmodel, float *minmaxs)
clipflags = 0; clipflags = 0;
if (currententity->angles[0] || currententity->angles[1] if (currententity->transform[0] != 1 || currententity->transform[5] != 1
|| currententity->angles[2]) { || currententity->transform[10] != 1) {
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
d = DotProduct (currententity->origin, view_clipplanes[i].normal); d = DotProduct (currententity->origin, view_clipplanes[i].normal);
d -= view_clipplanes[i].dist; d -= view_clipplanes[i].dist;

View file

@ -357,8 +357,9 @@ R_DrawSprite (void)
} else if (psprite->type == SPR_ORIENTED) { } else if (psprite->type == SPR_ORIENTED) {
// generate the sprite's axes, according to the sprite's world // generate the sprite's axes, according to the sprite's world
// orientation // orientation
AngleVectors (currententity->angles, r_spritedesc.vpn, VectorCopy (currententity->transform + 0, r_spritedesc.vpn);
r_spritedesc.vright, r_spritedesc.vup); VectorNegate (currententity->transform + 4, r_spritedesc.vright);
VectorCopy (currententity->transform + 8, r_spritedesc.vup);
} else if (psprite->type == SPR_VP_PARALLEL_ORIENTED) { } else if (psprite->type == SPR_VP_PARALLEL_ORIENTED) {
// generate the sprite's axes, parallel to the viewplane, but rotated // generate the sprite's axes, parallel to the viewplane, but rotated
// in that plane around the center according to the sprite entity's // in that plane around the center according to the sprite entity's

View file

@ -380,6 +380,8 @@ void CL_ClearTEnts (void);
void CL_Init_Entity (struct entity_s *ent); void CL_Init_Entity (struct entity_s *ent);
void CL_ParseTEnt (void); void CL_ParseTEnt (void);
void CL_SignonReply (void); void CL_SignonReply (void);
void CL_TransformEntity (struct entity_s *ent, const vec3_t
angles, qboolean force);
void CL_RelinkEntities (void); void CL_RelinkEntities (void);
void CL_ClearEnts (void); void CL_ClearEnts (void);

View file

@ -179,6 +179,38 @@ CL_LerpPoint (void)
return frac; return frac;
} }
void
CL_TransformEntity (entity_t *ent, const vec3_t angles, qboolean force)
{
vec3_t ang;
vec_t *forward, *left, *up;
if (VectorIsZero (angles)) {
VectorSet (1, 0, 0, ent->transform + 0);
VectorSet (0, 1, 0, ent->transform + 4);
VectorSet (0, 0, 1, ent->transform + 8);
} else if (force || !VectorCompare (angles, ent->angles)) {
forward = ent->transform + 0;
left = ent->transform + 4;
up = ent->transform + 8;
VectorCopy (angles, ang);
if (ent->model && ent->model->type == mod_alias) {
// stupid quake bug
// why, oh, why, do alias models pitch in the opposite direction
// to everything else?
ang[PITCH] = -ang[PITCH];
}
AngleVectors (ang, forward, left, up);
VectorNegate (left, left); // AngleVectors is right-handed
}
VectorCopy (angles, ent->angles);
ent->transform[3] = 0;
ent->transform[7] = 0;
ent->transform[11] = 0;
VectorCopy (ent->origin, ent->transform + 12);
ent->transform[15] = 1;
}
void void
CL_RelinkEntities (void) CL_RelinkEntities (void)
{ {
@ -251,18 +283,24 @@ CL_RelinkEntities (void)
|| fabs (delta[2]) > 100) { || fabs (delta[2]) > 100) {
// assume a teleportation, not a motion // assume a teleportation, not a motion
VectorCopy (state->msg_origins[0], ent->origin); VectorCopy (state->msg_origins[0], ent->origin);
VectorCopy (state->msg_angles[0], ent->angles); if (!(ent->model->flags & EF_ROTATE))
CL_TransformEntity (ent, state->msg_angles[0], true);
ent->pose1 = ent->pose2 = -1; ent->pose1 = ent->pose2 = -1;
} else { } else {
VectorMultAdd (state->msg_origins[1], f, delta, ent->origin); vec3_t angles, d;
// interpolate the origin and angles // interpolate the origin and angles
for (j = 0; j < 3; j++) { VectorMultAdd (state->msg_origins[1], f, delta, ent->origin);
d = state->msg_angles[0][j] - state->msg_angles[1][j]; if (!(ent->model->flags & EF_ROTATE)) {
if (d > 180) VectorSubtract (state->msg_angles[0],
d -= 360; state->msg_angles[1], d);
else if (d < -180) for (j = 0; j < 3; j++) {
d += 360; if (d[j] > 180)
ent->angles[j] = state->msg_angles[1][j] + f * d; d[j] -= 360;
else if (d[j] < -180)
d[j] += 360;
}
VectorMultAdd (state->msg_angles[1], f, d, angles);
CL_TransformEntity (ent, angles, false);
} }
} }
if (i != cl.viewentity || chase_active->int_val) { if (i != cl.viewentity || chase_active->int_val) {
@ -278,18 +316,20 @@ CL_RelinkEntities (void)
} }
// rotate binary objects locally // rotate binary objects locally
if (ent->model->flags & EF_ROTATE) if (ent->model->flags & EF_ROTATE) {
ent->angles[1] = bobjrotate; vec3_t angles;
VectorCopy (state->msg_angles[0], angles);
angles[YAW] = bobjrotate;
CL_TransformEntity (ent, angles, false);
}
if (state->effects & EF_BRIGHTFIELD) if (state->effects & EF_BRIGHTFIELD)
R_EntityParticles (ent); R_EntityParticles (ent);
if (state->effects & EF_MUZZLEFLASH) { if (state->effects & EF_MUZZLEFLASH) {
vec3_t fv, rv, uv; vec_t *fv = ent->transform;
dl = R_AllocDlight (i); dl = R_AllocDlight (i);
if (dl) { if (dl) {
AngleVectors (ent->angles, fv, rv, uv);
VectorMultAdd (ent->origin, 18, fv, dl->origin); VectorMultAdd (ent->origin, 18, fv, dl->origin);
dl->origin[2] += 16; dl->origin[2] += 16;
dl->radius = 200 + (rand () & 31); dl->radius = 200 + (rand () & 31);

View file

@ -344,9 +344,8 @@ CL_PrintEntities_f (void)
continue; continue;
} }
Sys_Printf ("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n", Sys_Printf ("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n",
ent->model->name, ent->frame, ent->origin[0], ent->model->name, ent->frame, VectorExpand (ent->origin),
ent->origin[1], ent->origin[2], ent->angles[0], VectorExpand (ent->angles));
ent->angles[1], ent->angles[2]);
} }
} }

View file

@ -628,7 +628,7 @@ CL_ParseUpdate (int bits)
VectorCopy (state->msg_origins[0], state->msg_origins[1]); VectorCopy (state->msg_origins[0], state->msg_origins[1]);
VectorCopy (state->msg_origins[0], ent->origin); VectorCopy (state->msg_origins[0], ent->origin);
VectorCopy (state->msg_angles[0], state->msg_angles[1]); VectorCopy (state->msg_angles[0], state->msg_angles[1]);
VectorCopy (state->msg_angles[0], ent->angles); CL_TransformEntity (ent, state->msg_angles[0], true);
state->forcelink = true; state->forcelink = true;
} }
} }
@ -821,8 +821,6 @@ CL_ParseStatic (int version)
CL_ParseBaseline (&state, version); CL_ParseBaseline (&state, version);
// copy it to the current state // copy it to the current state
VectorCopy (state.baseline.origin, ent->origin);
VectorCopy (state.baseline.angles, ent->angles);
//FIXME alpha & lerp //FIXME alpha & lerp
ent->model = cl.model_precache[state.baseline.modelindex]; ent->model = cl.model_precache[state.baseline.modelindex];
ent->frame = state.baseline.frame; ent->frame = state.baseline.frame;
@ -840,6 +838,8 @@ CL_ParseStatic (int version)
} }
ent->colormod[3] = ENTALPHA_DECODE (state.baseline.alpha); ent->colormod[3] = ENTALPHA_DECODE (state.baseline.alpha);
ent->scale = state.baseline.scale / 16.0; ent->scale = state.baseline.scale / 16.0;
VectorCopy (state.baseline.origin, ent->origin);
CL_TransformEntity (ent, state.baseline.angles, true);
R_AddEfrags (ent); R_AddEfrags (ent);
} }

View file

@ -67,6 +67,8 @@ typedef struct {
int seed; int seed;
} beam_t; } beam_t;
#define BEAM_SEED_INTERVAL 72
#define BEAM_SEED_PRIME 3191
typedef struct { typedef struct {
float start; float start;
@ -238,12 +240,13 @@ beam_clear (beam_t *b)
} }
static inline void static inline void
beam_setup (beam_t *b) beam_setup (beam_t *b, qboolean transform)
{ {
tent_t *tent; tent_t *tent;
float forward, pitch, yaw, d; float forward, pitch, yaw, d;
int ent_count; int ent_count;
vec3_t dist, org; vec3_t dist, org, ang;
unsigned seed;
// calculate pitch and yaw // calculate pitch and yaw
VectorSubtract (b->end, b->start, dist); VectorSubtract (b->end, b->start, dist);
@ -271,6 +274,10 @@ beam_setup (beam_t *b)
VectorScale (dist, 30, dist); VectorScale (dist, 30, dist);
ent_count = ceil (d / 30); ent_count = ceil (d / 30);
d = 0; d = 0;
seed = b->seed + ((int) (cl.time * BEAM_SEED_INTERVAL) %
BEAM_SEED_INTERVAL);
while (ent_count--) { while (ent_count--) {
tent = new_temp_entity (); tent = new_temp_entity ();
tent->next = b->tents; tent->next = b->tents;
@ -279,8 +286,13 @@ beam_setup (beam_t *b)
VectorMultAdd (org, d, dist, tent->ent.origin); VectorMultAdd (org, d, dist, tent->ent.origin);
d += 1.0; d += 1.0;
tent->ent.model = b->model; tent->ent.model = b->model;
tent->ent.angles[0] = pitch; ang[PITCH] = pitch;
tent->ent.angles[1] = yaw; ang[YAW] = yaw;
if (transform) {
seed = seed * BEAM_SEED_PRIME;
ang[ROLL] = seed % 360;
CL_TransformEntity (&tent->ent, ang, true);
}
R_AddEfrags (&tent->ent); R_AddEfrags (&tent->ent);
} }
} }
@ -313,7 +325,7 @@ CL_ParseBeam (model_t *m)
if (b->entity != cl.viewentity) { if (b->entity != cl.viewentity) {
// this will be done in CL_UpdateBeams // this will be done in CL_UpdateBeams
VectorCopy (start, b->start); VectorCopy (start, b->start);
beam_setup (b); beam_setup (b, true);
} }
} }
@ -408,6 +420,7 @@ CL_ParseTEnt (void)
if (!cl_spr_explod->cache.data) if (!cl_spr_explod->cache.data)
cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true); cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true);
ex->tent->ent.model = cl_spr_explod; ex->tent->ent.model = cl_spr_explod;
CL_TransformEntity (&ex->tent->ent, ex->tent->ent.angles, true);
break; break;
case TE_TAREXPLOSION: // tarbaby explosion case TE_TAREXPLOSION: // tarbaby explosion
@ -493,9 +506,6 @@ CL_ParseTEnt (void)
} }
} }
#define BEAM_SEED_INTERVAL 72
#define BEAM_SEED_PRIME 3191
static void static void
CL_UpdateBeams (void) CL_UpdateBeams (void)
{ {
@ -525,7 +535,7 @@ CL_UpdateBeams (void)
if (b->entity == cl.viewentity) { if (b->entity == cl.viewentity) {
beam_clear (b); beam_clear (b);
VectorCopy (cl_entities[cl.viewentity].origin, b->start); VectorCopy (cl_entities[cl.viewentity].origin, b->start);
beam_setup (b); beam_setup (b, false);
} }
seed = b->seed + ((int) (cl.time * BEAM_SEED_INTERVAL) % seed = b->seed + ((int) (cl.time * BEAM_SEED_INTERVAL) %
@ -534,7 +544,8 @@ CL_UpdateBeams (void)
// add new entities for the lightning // add new entities for the lightning
for (t = b->tents; t; t = t->next) { for (t = b->tents; t; t = t->next) {
seed = seed * BEAM_SEED_PRIME; seed = seed * BEAM_SEED_PRIME;
t->ent.angles[2] = seed % 360; t->ent.angles[ROLL] = seed % 360;
CL_TransformEntity (&t->ent, t->ent.angles, true);
} }
} }
} }

View file

@ -691,6 +691,8 @@ V_CalcRefdef (void)
if (chase_active->int_val) if (chase_active->int_val)
Chase_Update (); Chase_Update ();
CL_TransformEntity (view, view->angles, true);
} }
/* /*

View file

@ -35,6 +35,8 @@
void CL_SetSolidPlayers (int playernum); void CL_SetSolidPlayers (int playernum);
void CL_ClearPredict (void); void CL_ClearPredict (void);
void CL_SetUpPlayerPrediction(qboolean dopred); void CL_SetUpPlayerPrediction(qboolean dopred);
void CL_TransformEntity (struct entity_s * ent, const vec3_t angles,
qboolean force);
void CL_EmitEntities (void); void CL_EmitEntities (void);
void CL_ClearProjectiles (void); void CL_ClearProjectiles (void);
void CL_ParseProjectiles (qboolean nail2); void CL_ParseProjectiles (qboolean nail2);

View file

@ -167,6 +167,38 @@ is_gib (entity_state_t *s1)
return 0; return 0;
} }
void
CL_TransformEntity (entity_t *ent, const vec3_t angles, qboolean force)
{
vec3_t ang;
vec_t *forward, *left, *up;
if (VectorIsZero (angles)) {
VectorSet (1, 0, 0, ent->transform + 0);
VectorSet (0, 1, 0, ent->transform + 4);
VectorSet (0, 0, 1, ent->transform + 8);
} else if (force || !VectorCompare (angles, ent->angles)) {
forward = ent->transform + 0;
left = ent->transform + 4;
up = ent->transform + 8;
VectorCopy (angles, ang);
if (ent->model && ent->model->type == mod_alias) {
// stupid quake bug
// why, oh, why, do alias models pitch in the opposite direction
// to everything else?
ang[PITCH] = -ang[PITCH];
}
AngleVectors (ang, forward, left, up);
VectorNegate (left, left); // AngleVectors is right-handed
}
VectorCopy (angles, ent->angles);
ent->transform[3] = 0;
ent->transform[7] = 0;
ent->transform[11] = 0;
VectorCopy (ent->origin, ent->transform + 12);
ent->transform[15] = 1;
}
static void static void
CL_LinkPacketEntities (void) CL_LinkPacketEntities (void)
{ {
@ -272,11 +304,13 @@ CL_LinkPacketEntities (void)
R_AddEfrags (ent); R_AddEfrags (ent);
if (model->flags & EF_ROTATE) { // rotate binary objects locally if (model->flags & EF_ROTATE) { // rotate binary objects locally
ent->angles[0] = 0; vec3_t ang;
ent->angles[1] = anglemod (100 * cl.time); ang[PITCH] = 0;
ent->angles[2] = 0; ang[YAW] = anglemod (100 * cl.time);
ang[ROLL] = 0;
CL_TransformEntity (ent, ang, false);
} else { } else {
VectorCopy (s1->angles, ent->angles); CL_TransformEntity (ent, s1->angles, false);
} }
// add automatic particle trails // add automatic particle trails
@ -314,6 +348,9 @@ CL_LinkPacketEntities (void)
CL_AddFlagModels CL_AddFlagModels
Called when the CTF flags are set. Flags are effectively temp entities. Called when the CTF flags are set. Flags are effectively temp entities.
NOTE: this must be called /after/ the entity has been transformed as it
uses the entity's transform matrix to get the frame vectors
*/ */
static void static void
CL_AddFlagModels (entity_t *ent, int team, int key) CL_AddFlagModels (entity_t *ent, int team, int key)
@ -322,9 +359,10 @@ CL_AddFlagModels (entity_t *ent, int team, int key)
16.0, 22.0, 26.0, 25.0, 24.0, 18.0, // 29-34 axpain 16.0, 22.0, 26.0, 25.0, 24.0, 18.0, // 29-34 axpain
16.0, 24.0, 24.0, 22.0, 18.0, 16.0, // 35-40 pain 16.0, 24.0, 24.0, 22.0, 18.0, 16.0, // 35-40 pain
}; };
float f; float f;
entity_t *fent; entity_t *fent;
vec3_t v_forward, v_right, v_up; vec_t *v_forward, *v_left;
vec3_t ang;
if (cl_flagindex == -1) if (cl_flagindex == -1)
return; return;
@ -343,15 +381,16 @@ CL_AddFlagModels (entity_t *ent, int team, int key)
fent->model = cl.model_precache[cl_flagindex]; fent->model = cl.model_precache[cl_flagindex];
fent->skinnum = team; fent->skinnum = team;
AngleVectors (ent->angles, v_forward, v_right, v_up); v_forward = ent->transform + 0;
v_forward[2] = -v_forward[2]; // reverse z component v_left = ent->transform + 4;
VectorMultAdd (ent->origin, -f, v_forward, fent->origin); VectorMultAdd (ent->origin, -f, v_forward, fent->origin);
VectorMultAdd (fent->origin, 22, v_right, fent->origin); VectorMultAdd (fent->origin, -22, v_left, fent->origin);
fent->origin[2] -= 16.0; fent->origin[2] -= 16.0;
VectorCopy (ent->angles, fent->angles); VectorCopy (ent->angles, ang);
fent->angles[2] -= 45.0; ang[2] -= 45.0;
CL_TransformEntity (fent, ang, false);
R_EnqueueEntity (fent); //FIXME should use efrag (needs smarter handling R_EnqueueEntity (fent); //FIXME should use efrag (needs smarter handling
//in the player code) //in the player code)
@ -374,7 +413,7 @@ CL_LinkPlayers (void)
player_state_t exact; player_state_t exact;
player_state_t *state; player_state_t *state;
qboolean clientplayer; qboolean clientplayer;
vec3_t org; vec3_t org, ang;
playertime = realtime - cls.latency + 0.02; playertime = realtime - cls.latency + 0.02;
if (playertime > realtime) if (playertime > realtime)
@ -436,20 +475,21 @@ CL_LinkPlayers (void)
// angles // angles
if (j == cl.playernum) if (j == cl.playernum)
{ {
ent->angles[PITCH] = -cl.viewangles[PITCH] / 3.0; ang[PITCH] = -cl.viewangles[PITCH] / 3.0;
ent->angles[YAW] = cl.viewangles[YAW]; ang[YAW] = cl.viewangles[YAW];
} else { } else {
ent->angles[PITCH] = -state->viewangles[PITCH] / 3.0; ang[PITCH] = -state->viewangles[PITCH] / 3.0;
ent->angles[YAW] = state->viewangles[YAW]; ang[YAW] = state->viewangles[YAW];
} }
ent->angles[ROLL] = V_CalcRoll (ent->angles, ang[ROLL] = V_CalcRoll (ang, state->pls.velocity) * 4.0;
state->pls.velocity) * 4.0;
ent->model = cl.model_precache[state->pls.modelindex]; ent->model = cl.model_precache[state->pls.modelindex];
ent->frame = state->pls.frame; ent->frame = state->pls.frame;
ent->colormap = info->translations; ent->colormap = info->translations;
ent->skinnum = state->pls.skinnum; ent->skinnum = state->pls.skinnum;
CL_TransformEntity (ent, ang, false);
ent->min_light = 0; ent->min_light = 0;
ent->fullbright = 0; ent->fullbright = 0;

View file

@ -981,7 +981,7 @@ CL_ParseStatic (void)
ent->skinnum = es.skinnum; ent->skinnum = es.skinnum;
VectorCopy (es.origin, ent->origin); VectorCopy (es.origin, ent->origin);
VectorCopy (es.angles, ent->angles); CL_TransformEntity (ent, es.angles, true);
R_AddEfrags (ent); R_AddEfrags (ent);
} }

View file

@ -72,6 +72,8 @@ typedef struct {
int seed; int seed;
} beam_t; } beam_t;
#define BEAM_SEED_INTERVAL 72
#define BEAM_SEED_PRIME 3191
typedef struct { typedef struct {
float start; float start;
@ -244,12 +246,13 @@ beam_clear (beam_t *b)
} }
static inline void static inline void
beam_setup (beam_t *b) beam_setup (beam_t *b, qboolean transform)
{ {
tent_t *tent; tent_t *tent;
float forward, pitch, yaw, d; float forward, pitch, yaw, d;
int ent_count; int ent_count;
vec3_t dist, org; vec3_t dist, org, ang;
unsigned seed;
// calculate pitch and yaw // calculate pitch and yaw
VectorSubtract (b->end, b->start, dist); VectorSubtract (b->end, b->start, dist);
@ -277,6 +280,10 @@ beam_setup (beam_t *b)
VectorScale (dist, 30, dist); VectorScale (dist, 30, dist);
ent_count = ceil (d / 30); ent_count = ceil (d / 30);
d = 0; d = 0;
seed = b->seed + ((int) (cl.time * BEAM_SEED_INTERVAL) %
BEAM_SEED_INTERVAL);
while (ent_count--) { while (ent_count--) {
tent = new_temp_entity (); tent = new_temp_entity ();
tent->next = b->tents; tent->next = b->tents;
@ -285,8 +292,13 @@ beam_setup (beam_t *b)
VectorMultAdd (org, d, dist, tent->ent.origin); VectorMultAdd (org, d, dist, tent->ent.origin);
d += 1.0; d += 1.0;
tent->ent.model = b->model; tent->ent.model = b->model;
tent->ent.angles[0] = pitch; ang[PITCH] = pitch;
tent->ent.angles[1] = yaw; ang[YAW] = yaw;
if (transform) {
seed = seed * BEAM_SEED_PRIME;
ang[ROLL] = seed % 360;
CL_TransformEntity (&tent->ent, ang, true);
}
R_AddEfrags (&tent->ent); R_AddEfrags (&tent->ent);
} }
} }
@ -319,7 +331,7 @@ CL_ParseBeam (model_t *m)
if (b->entity != cl.viewentity) { if (b->entity != cl.viewentity) {
// this will be done in CL_UpdateBeams // this will be done in CL_UpdateBeams
VectorCopy (start, b->start); VectorCopy (start, b->start);
beam_setup (b); beam_setup (b, true);
} }
} }
@ -414,6 +426,7 @@ CL_ParseTEnt (void)
if (!cl_spr_explod->cache.data) if (!cl_spr_explod->cache.data)
cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true); cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true);
ex->tent->ent.model = cl_spr_explod; ex->tent->ent.model = cl_spr_explod;
CL_TransformEntity (&ex->tent->ent, ex->tent->ent.angles, true);
break; break;
case TE_TAREXPLOSION: // tarbaby explosion case TE_TAREXPLOSION: // tarbaby explosion
@ -502,9 +515,6 @@ CL_ParseTEnt (void)
} }
} }
#define BEAM_SEED_INTERVAL 72
#define BEAM_SEED_PRIME 3191
static void static void
CL_UpdateBeams (void) CL_UpdateBeams (void)
{ {
@ -534,7 +544,7 @@ CL_UpdateBeams (void)
if (b->entity == cl.viewentity) { if (b->entity == cl.viewentity) {
beam_clear (b); beam_clear (b);
VectorCopy (cl.simorg, b->start); VectorCopy (cl.simorg, b->start);
beam_setup (b); beam_setup (b, false);
} }
seed = b->seed + ((int) (cl.time * BEAM_SEED_INTERVAL) % seed = b->seed + ((int) (cl.time * BEAM_SEED_INTERVAL) %
@ -543,7 +553,8 @@ CL_UpdateBeams (void)
// add new entities for the lightning // add new entities for the lightning
for (t = b->tents; t; t = t->next) { for (t = b->tents; t; t = t->next) {
seed = seed * BEAM_SEED_PRIME; seed = seed * BEAM_SEED_PRIME;
t->ent.angles[2] = seed % 360; t->ent.angles[ROLL] = seed % 360;
CL_TransformEntity (&t->ent, t->ent.angles, true);
} }
} }
} }
@ -636,6 +647,7 @@ CL_ParseProjectiles (qboolean nail2)
pr->angles[0] = (bits[4] >> 4) * (360.0 / 16.0); pr->angles[0] = (bits[4] >> 4) * (360.0 / 16.0);
pr->angles[1] = bits[5] * (360.0 / 256.0); pr->angles[1] = bits[5] * (360.0 / 256.0);
pr->angles[2] = 0; pr->angles[2] = 0;
CL_TransformEntity (&tent->ent, tent->ent.angles, true);
R_AddEfrags (&tent->ent); R_AddEfrags (&tent->ent);
} }

View file

@ -42,6 +42,7 @@ static __attribute__ ((used)) const char rcsid[] =
#include "qw/bothdefs.h" #include "qw/bothdefs.h"
#include "cl_cam.h" #include "cl_cam.h"
#include "cl_ents.h"
#include "cl_main.h" #include "cl_main.h"
#include "client.h" #include "client.h"
#include "compat.h" #include "compat.h"
@ -693,6 +694,7 @@ V_CalcRefdef (void)
if (cl.chase && chase_active->int_val) if (cl.chase && chase_active->int_val)
Chase_Update (); Chase_Update ();
CL_TransformEntity (view, view->angles, true);
} }
static void static void