1255 lines
35 KiB
C
1255 lines
35 KiB
C
/*
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
// r_sprite.c
|
|
|
|
#include "globaldef.h"
|
|
#include "r_local.h"
|
|
|
|
static int clip_current;
|
|
static vec5_t clip_verts[2][MAXWORKINGVERTS];
|
|
static int sprite_width, sprite_height;
|
|
|
|
spritedesc_t r_spritedesc;
|
|
extern float lensreflection;
|
|
particle_t *currentparticle;
|
|
flare_t *currentflare;
|
|
extern int flared; // tells the renderer this is a flared flare
|
|
/*
|
|
================
|
|
R_RotateSprite
|
|
================
|
|
*/
|
|
extern cvar_t *temp2;
|
|
void R_RotateSprite (float beamlength)
|
|
{
|
|
vec3_t vec;
|
|
|
|
if (beamlength == 0.0)
|
|
return;
|
|
|
|
VectorScale (r_spritedesc.vpn, -beamlength, vec);
|
|
VectorAdd (r_entorigin, vec, r_entorigin);
|
|
VectorSubtract (modelorg, vec, modelorg);
|
|
}
|
|
|
|
void R_RotateSprite2 (float beamlength)
|
|
{
|
|
vec3_t vec;
|
|
|
|
if (beamlength == 0.0)
|
|
return;
|
|
|
|
VectorScale (r_spritedesc.vpn, -beamlength, vec);
|
|
VectorAdd (currentparticle->org, vec, currentparticle->org);
|
|
VectorSubtract (modelorg, vec, modelorg);
|
|
}
|
|
|
|
|
|
void R_RotateSprite3 (float beamlength)
|
|
{
|
|
vec3_t vec;
|
|
|
|
if (beamlength == 0.0)
|
|
return;
|
|
|
|
VectorScale (r_spritedesc.vpn, -beamlength, vec);
|
|
VectorAdd (currentflare->org, vec, currentflare->org);
|
|
VectorSubtract (modelorg, vec, modelorg);
|
|
}
|
|
|
|
|
|
/*
|
|
=============
|
|
R_ClipSpriteFace
|
|
|
|
Clips the winding at clip_verts[clip_current] and changes clip_current
|
|
Throws out the back side
|
|
==============
|
|
*/
|
|
int R_ClipSpriteFace (int nump, clipplane_t *pclipplane)
|
|
{
|
|
int i, outcount;
|
|
float dists[MAXWORKINGVERTS+1];
|
|
float frac, clipdist, *pclipnormal;
|
|
float *in, *instep, *outstep, *vert2;
|
|
|
|
clipdist = pclipplane->dist;
|
|
pclipnormal = pclipplane->normal;
|
|
|
|
// calc dists
|
|
if (clip_current)
|
|
{
|
|
in = clip_verts[1][0];
|
|
outstep = clip_verts[0][0];
|
|
clip_current = 0;
|
|
}
|
|
else
|
|
{
|
|
in = clip_verts[0][0];
|
|
outstep = clip_verts[1][0];
|
|
clip_current = 1;
|
|
}
|
|
|
|
instep = in;
|
|
for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
|
|
{
|
|
dists[i] = DotProduct (instep, pclipnormal) - clipdist;
|
|
}
|
|
|
|
|
|
// handle wraparound case
|
|
dists[nump] = dists[0];
|
|
Q_memcpy (instep, in, sizeof (vec5_t));
|
|
|
|
|
|
// clip the winding
|
|
instep = in;
|
|
outcount = 0;
|
|
|
|
for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
|
|
{
|
|
if (dists[i] >= 0)
|
|
{
|
|
Q_memcpy (outstep, instep, sizeof (vec5_t));
|
|
outstep += sizeof (vec5_t) / sizeof (float);
|
|
outcount++;
|
|
}
|
|
|
|
if (dists[i] == 0 || dists[i+1] == 0)
|
|
continue;
|
|
|
|
if ( (dists[i] > 0) == (dists[i+1] > 0) )
|
|
continue;
|
|
|
|
// split it into a new vertex
|
|
frac = dists[i] / (dists[i] - dists[i+1]);
|
|
|
|
vert2 = instep + sizeof (vec5_t) / sizeof (float);
|
|
|
|
outstep[0] = instep[0] + frac*(vert2[0] - instep[0]);
|
|
outstep[1] = instep[1] + frac*(vert2[1] - instep[1]);
|
|
outstep[2] = instep[2] + frac*(vert2[2] - instep[2]);
|
|
outstep[3] = instep[3] + frac*(vert2[3] - instep[3]);
|
|
outstep[4] = instep[4] + frac*(vert2[4] - instep[4]);
|
|
|
|
outstep += sizeof (vec5_t) / sizeof (float);
|
|
outcount++;
|
|
}
|
|
|
|
return outcount;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
R_SetupAndDrawSprite
|
|
================
|
|
*/
|
|
void R_SetupAndDrawSprite ()
|
|
{
|
|
int i, nump;
|
|
float dot, scale, *pv;
|
|
vec5_t *pverts;
|
|
vec3_t left, up, right, down, transformed, local;
|
|
emitpoint_t outverts[MAXWORKINGVERTS+1], *pout;
|
|
|
|
dot = DotProduct (r_spritedesc.vpn, modelorg);
|
|
|
|
// backface cull
|
|
if (dot >= 0)
|
|
return;
|
|
|
|
// Manoel Kasimier - QC Scale - edited - begin
|
|
#ifdef SCALEE
|
|
VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->right*currententity->scale2, right);
|
|
VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->left *currententity->scale2, left);
|
|
|
|
VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->up *currententity->scale2, up);
|
|
VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->down *currententity->scale2, down);
|
|
#else
|
|
VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->right, right);
|
|
VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->left, left);
|
|
|
|
VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->up, up);
|
|
VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->down, down);
|
|
#endif
|
|
// Manoel Kasimier - QC Scale - edited - end
|
|
|
|
pverts = clip_verts[0];
|
|
|
|
pverts[0][0] = r_entorigin[0] + up[0] + left[0];
|
|
pverts[0][1] = r_entorigin[1] + up[1] + left[1];
|
|
pverts[0][2] = r_entorigin[2] + up[2] + left[2];
|
|
pverts[0][3] = 0;
|
|
pverts[0][4] = 0;
|
|
|
|
pverts[1][0] = r_entorigin[0] + up[0] + right[0];
|
|
pverts[1][1] = r_entorigin[1] + up[1] + right[1];
|
|
pverts[1][2] = r_entorigin[2] + up[2] + right[2];
|
|
pverts[1][3] = sprite_width;
|
|
pverts[1][4] = 0;
|
|
|
|
pverts[2][0] = r_entorigin[0] + down[0] + right[0];
|
|
pverts[2][1] = r_entorigin[1] + down[1] + right[1];
|
|
pverts[2][2] = r_entorigin[2] + down[2] + right[2];
|
|
pverts[2][3] = sprite_width;
|
|
pverts[2][4] = sprite_height;
|
|
|
|
pverts[3][0] = r_entorigin[0] + down[0] + left[0];
|
|
pverts[3][1] = r_entorigin[1] + down[1] + left[1];
|
|
pverts[3][2] = r_entorigin[2] + down[2] + left[2];
|
|
pverts[3][3] = 0;
|
|
pverts[3][4] = sprite_height;
|
|
|
|
// clip
|
|
nump = 4;
|
|
clip_current = 0;
|
|
|
|
for (i=0 ; i<4 ; i++)
|
|
{
|
|
nump = R_ClipSpriteFace (nump, &view_clipplanes[i]);
|
|
if (nump < 3)
|
|
return;
|
|
if (nump >= MAXWORKINGVERTS)
|
|
Sys_Error("R_SetupAndDrawSprite: too many points");
|
|
}
|
|
|
|
// transform vertices into viewspace and project
|
|
pv = &clip_verts[clip_current][0][0];
|
|
r_spritedesc.nearzi = -99999;
|
|
// leilei - sprite clip crash fix..
|
|
{
|
|
VectorSubtract (pv, r_origin, local);
|
|
TransformVector (local, transformed);
|
|
|
|
if (transformed[2] < 4) // leilei - try not to draw sprites too close, or we'll overflow the screen cache and crash!
|
|
return;
|
|
}
|
|
for (i=0 ; i<nump ; i++)
|
|
{
|
|
VectorSubtract (pv, r_origin, local);
|
|
TransformVector (local, transformed);
|
|
|
|
if (transformed[2] < NEAR_CLIP)
|
|
transformed[2] = NEAR_CLIP;
|
|
|
|
|
|
pout = &outverts[i];
|
|
pout->zi = 1.0 / transformed[2];
|
|
|
|
if (pout->zi > r_spritedesc.nearzi)
|
|
r_spritedesc.nearzi = pout->zi;
|
|
|
|
pout->s = pv[3];
|
|
pout->t = pv[4];
|
|
|
|
scale = xscale * pout->zi;
|
|
pout->u = (xcenter + scale * transformed[0]);
|
|
|
|
scale = yscale * pout->zi;
|
|
pout->v = (ycenter - scale * transformed[1]);
|
|
|
|
pv += sizeof (vec5_t) / sizeof (*pv);
|
|
|
|
}
|
|
|
|
// draw it
|
|
r_spritedesc.nump = nump;
|
|
r_spritedesc.pverts = outverts;
|
|
D_DrawSprite (0);
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
R_GetSpriteframe
|
|
================
|
|
*/
|
|
mspriteframe_t *R_GetSpriteframe (msprite_t *psprite)
|
|
{
|
|
mspritegroup_t *pspritegroup;
|
|
mspriteframe_t *pspriteframe;
|
|
int i, numframes, frame;
|
|
float *pintervals, fullinterval, targettime, time;
|
|
|
|
frame = currententity->frame;
|
|
|
|
if ((frame >= psprite->numframes) || (frame < 0))
|
|
{
|
|
Con_Printf ("R_DrawSprite: no such frame %d\n", frame);
|
|
frame = 0;
|
|
}
|
|
|
|
if (psprite->frames[frame].type == SPR_SINGLE)
|
|
{
|
|
pspriteframe = psprite->frames[frame].frameptr;
|
|
}
|
|
else
|
|
{
|
|
pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
|
|
pintervals = pspritegroup->intervals;
|
|
numframes = pspritegroup->numframes;
|
|
fullinterval = pintervals[numframes-1];
|
|
|
|
time = cl.time + currententity->syncbase;
|
|
|
|
// when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
|
|
// are positive, so we don't have to worry about division by 0
|
|
targettime = time - ((int)(time / fullinterval)) * fullinterval;
|
|
|
|
for (i=0 ; i<(numframes-1) ; i++)
|
|
{
|
|
if (pintervals[i] > targettime)
|
|
break;
|
|
}
|
|
|
|
pspriteframe = pspritegroup->frames[i];
|
|
}
|
|
|
|
return pspriteframe;
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
R_DrawSprite
|
|
================
|
|
*/
|
|
void R_DrawSprite (void)
|
|
{
|
|
int i;
|
|
msprite_t *psprite;
|
|
vec3_t tvec;
|
|
float dot, angle, sr, cr;
|
|
|
|
psprite = currententity->model->cache.data;
|
|
|
|
r_spritedesc.pspriteframe = R_GetSpriteframe (psprite);
|
|
// LEIDTIED
|
|
sprite_width = r_spritedesc.pspriteframe->width;
|
|
sprite_height = r_spritedesc.pspriteframe->height;
|
|
|
|
// TODO: make this caller-selectable
|
|
if (psprite->type == SPR_FACING_UPRIGHT)
|
|
{
|
|
// generate the sprite's axes, with vup straight up in worldspace, and
|
|
// r_spritedesc.vright perpendicular to modelorg.
|
|
// This will not work if the view direction is very close to straight up or
|
|
// down, because the cross product will be between two nearly parallel
|
|
// vectors and starts to approach an undefined state, so we don't draw if
|
|
// the two vectors are less than 1 degree apart
|
|
tvec[0] = -modelorg[0];
|
|
tvec[1] = -modelorg[1];
|
|
tvec[2] = -modelorg[2];
|
|
VectorNormalize (tvec);
|
|
dot = tvec[2]; // same as DotProduct (tvec, r_spritedesc.vup) because
|
|
// r_spritedesc.vup is 0, 0, 1
|
|
if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
|
|
return;
|
|
r_spritedesc.vup[0] = 0;
|
|
r_spritedesc.vup[1] = 0;
|
|
r_spritedesc.vup[2] = 1;
|
|
r_spritedesc.vright[0] = tvec[1];
|
|
// CrossProduct(r_spritedesc.vup, -modelorg,
|
|
r_spritedesc.vright[1] = -tvec[0];
|
|
// r_spritedesc.vright)
|
|
r_spritedesc.vright[2] = 0;
|
|
VectorNormalize (r_spritedesc.vright);
|
|
r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
|
|
r_spritedesc.vpn[1] = r_spritedesc.vright[0];
|
|
r_spritedesc.vpn[2] = 0;
|
|
// CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
|
|
// r_spritedesc.vpn)
|
|
}
|
|
else if (psprite->type == SPR_VP_PARALLEL)
|
|
{
|
|
// generate the sprite's axes, completely parallel to the viewplane. There
|
|
// are no problem situations, because the sprite is always in the same
|
|
// position relative to the viewer
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
r_spritedesc.vup[i] = vup[i];
|
|
r_spritedesc.vright[i] = vright[i];
|
|
r_spritedesc.vpn[i] = vpn[i];
|
|
}
|
|
}
|
|
else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT)
|
|
{
|
|
// generate the sprite's axes, with vup straight up in worldspace, and
|
|
// r_spritedesc.vright parallel to the viewplane.
|
|
// This will not work if the view direction is very close to straight up or
|
|
// down, because the cross product will be between two nearly parallel
|
|
// vectors and starts to approach an undefined state, so we don't draw if
|
|
// the two vectors are less than 1 degree apart
|
|
dot = vpn[2]; // same as DotProduct (vpn, r_spritedesc.vup) because
|
|
// r_spritedesc.vup is 0, 0, 1
|
|
if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
|
|
return;
|
|
r_spritedesc.vup[0] = 0;
|
|
r_spritedesc.vup[1] = 0;
|
|
r_spritedesc.vup[2] = 1;
|
|
r_spritedesc.vright[0] = vpn[1];
|
|
// CrossProduct (r_spritedesc.vup, vpn,
|
|
r_spritedesc.vright[1] = -vpn[0]; // r_spritedesc.vright)
|
|
r_spritedesc.vright[2] = 0;
|
|
VectorNormalize (r_spritedesc.vright);
|
|
r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
|
|
r_spritedesc.vpn[1] = r_spritedesc.vright[0];
|
|
r_spritedesc.vpn[2] = 0;
|
|
|
|
|
|
// CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
|
|
//r_spritedesc.vpn);
|
|
}
|
|
else if (psprite->type == SPR_ORIENTED)
|
|
{
|
|
// generate the sprite's axes, according to the sprite's world orientation
|
|
AngleVectors (currententity->angles, r_spritedesc.vpn,
|
|
r_spritedesc.vright, r_spritedesc.vup);
|
|
|
|
}
|
|
|
|
else if (psprite->type == SPR_VP_PARALLEL_ORIENTED)
|
|
{
|
|
// generate the sprite's axes, parallel to the viewplane, but rotated in
|
|
// that plane around the center according to the sprite entity's roll
|
|
// angle. So vpn stays the same, but vright and vup rotate
|
|
angle = currententity->angles[ROLL] * (M_PI*2 / 360);
|
|
angle = currententity->angles[ROLL] * (M_PI*2 / 360);
|
|
sr = sin(angle);
|
|
cr = cos(angle);
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
r_spritedesc.vpn[i] = vpn[i];
|
|
r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr;
|
|
r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
angle = currententity->angles[ROLL] * (M_PI*2 / 360);
|
|
angle = currententity->angles[ROLL] * (M_PI*2 / 360);
|
|
sr = sin(angle);
|
|
cr = cos(angle);
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
r_spritedesc.vpn[i] = vpn[i];
|
|
r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr;
|
|
r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr;
|
|
}
|
|
|
|
// Sys_Error ("R_DrawSprite: Bad sprite type %d", psprite->type);
|
|
}
|
|
|
|
R_RotateSprite (psprite->beamlength);
|
|
|
|
R_SetupAndDrawSprite ();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern float lensreflection;
|
|
void R_SetupAndDrawSprite2 (int pass)
|
|
{
|
|
int i, nump;
|
|
float dot, scale, *pv;
|
|
vec5_t *pverts;
|
|
vec3_t left, up, right, down, transformed, local;
|
|
emitpoint_t outverts[MAXWORKINGVERTS+1], *pout;
|
|
vec3_t forg;
|
|
dot = DotProduct (r_spritedesc.vpn, modelorg);
|
|
|
|
// backface cull
|
|
if (dot >= 0)
|
|
return;
|
|
|
|
VectorCopy(currentparticle->org, forg);
|
|
|
|
|
|
|
|
// build the sprite poster in worldspace
|
|
|
|
VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->right*currentparticle->scale, right);
|
|
VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->left *currentparticle->scale, left);
|
|
|
|
VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->up *currentparticle->scaley, up);
|
|
VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->down *currentparticle->scaley, down); // leilei - oops
|
|
|
|
pverts = clip_verts[0];
|
|
|
|
pverts[0][0] = forg[0] + (up[0] + left[0]);
|
|
pverts[0][1] = forg[1] + (up[1] + left[1]);
|
|
pverts[0][2] = forg[2] + (up[2] + left[2]);
|
|
pverts[0][3] = 0;
|
|
pverts[0][4] = 0;
|
|
|
|
pverts[1][0] = forg[0] + (up[0] + right[0]);
|
|
pverts[1][1] = forg[1] + (up[1] + right[1]);
|
|
pverts[1][2] = forg[2] + (up[2] + right[2]);
|
|
pverts[1][3] = sprite_width;
|
|
pverts[1][4] = 0;
|
|
|
|
pverts[2][0] = forg[0] + (down[0] + right[0]);
|
|
pverts[2][1] = forg[1] + (down[1] + right[1]);
|
|
pverts[2][2] = forg[2] + (down[2] + right[2]);
|
|
pverts[2][3] = sprite_width;
|
|
pverts[2][4] = sprite_height;
|
|
|
|
pverts[3][0] = forg[0] + (down[0] + left[0]);
|
|
pverts[3][1] = forg[1] + (down[1] + left[1]);
|
|
pverts[3][2] = forg[2] + (down[2] + left[2]);
|
|
pverts[3][3] = 0;
|
|
pverts[3][4] = sprite_height;
|
|
|
|
|
|
// clip
|
|
nump = 4;
|
|
clip_current = 0;
|
|
|
|
for (i=0 ; i<4 ; i++)
|
|
{
|
|
nump = R_ClipSpriteFace (nump, &view_clipplanes[i]);
|
|
if (nump < 3)
|
|
return;
|
|
if (nump >= MAXWORKINGVERTS)
|
|
Sys_Error("R_SetupAndDrawSprite: too many points");
|
|
}
|
|
|
|
// transform vertices into viewspace and project
|
|
pv = &clip_verts[clip_current][0][0];
|
|
r_spritedesc.nearzi = -99999;
|
|
// leilei - sprite clip crash fix..
|
|
{
|
|
VectorSubtract (pv, r_origin, local);
|
|
TransformVector (local, transformed);
|
|
// if (transformed[2] < 74 && currentparticle->stickable == 1){
|
|
//
|
|
// currentparticle->stickable == 2;
|
|
//
|
|
// }
|
|
/* if (currentparticle->stickable == 2){
|
|
VectorSubtract(forg, currentparticle->org, currentparticle->viewstuckangle);
|
|
|
|
|
|
}
|
|
|
|
if (transformed[2] < 74 && currentparticle->stickable == 1){
|
|
currentparticle->stickable = 2; // leilei - stick to screen particles
|
|
currentparticle->frame = 1;
|
|
currentparticle->type = pt_static;
|
|
currentparticle->vel[0] = 0;
|
|
currentparticle->vel[1] = 0;
|
|
currentparticle->vel[2] = 0;
|
|
|
|
VectorCopy(currentparticle->org, currentparticle->viewstuck);
|
|
|
|
//VectorCopy(currentparticle->org, currentparticle->viewstuckangle);
|
|
VectorCopy(currentparticle->org, currentparticle->viewstuckangle);
|
|
currentparticle->viewstuckangle[0] = transformed[0];
|
|
currentparticle->viewstuckangle[1] = transformed[1];
|
|
currentparticle->viewstuck[0] = pv[3];
|
|
currentparticle->viewstuck[1] = pv[4];
|
|
|
|
}
|
|
*/
|
|
if (transformed[2] < 5) // leilei - no particle should ever be this close (performance reasons)
|
|
return;
|
|
|
|
}
|
|
for (i=0 ; i<nump ; i++)
|
|
{
|
|
|
|
VectorSubtract (pv, r_origin, local);
|
|
TransformVector (local, transformed);
|
|
|
|
if (transformed[2] < NEAR_CLIP)
|
|
transformed[2] = NEAR_CLIP;
|
|
|
|
pout = &outverts[i];
|
|
pout->zi = 1.0 / transformed[2];
|
|
|
|
if (pout->zi > r_spritedesc.nearzi)
|
|
r_spritedesc.nearzi = pout->zi;
|
|
|
|
pout->s = pv[3];
|
|
pout->t = pv[4];
|
|
/*
|
|
if (currentparticle->stickable == 2)
|
|
{
|
|
pout->s = currentparticle->viewstuck[0];
|
|
pout->t = currentparticle->viewstuck[1];
|
|
|
|
scale = xscale * pout->zi;
|
|
pout->u = (xcenter + scale * currentparticle->viewstuckangle[0]);
|
|
|
|
scale = yscale * pout->zi;
|
|
pout->v = (ycenter - scale * currentparticle->viewstuckangle[1]);
|
|
|
|
}
|
|
|
|
else
|
|
*/
|
|
{
|
|
scale = xscale * pout->zi;
|
|
pout->u = (xcenter + scale * transformed[0]);
|
|
|
|
scale = yscale * pout->zi;
|
|
pout->v = (ycenter - scale * transformed[1]);
|
|
}
|
|
|
|
pv += sizeof (vec5_t) / sizeof (*pv);
|
|
|
|
}
|
|
|
|
// draw it
|
|
r_spritedesc.nump = nump;
|
|
r_spritedesc.pverts = outverts;
|
|
|
|
|
|
D_DrawSprite (1);
|
|
}
|
|
|
|
|
|
// flares
|
|
void R_SetupAndDrawSprite3 ()
|
|
{
|
|
int i, nump;
|
|
float agh;
|
|
vec3_t aggh;
|
|
float dot, scale, *pv;
|
|
vec5_t *pverts;
|
|
vec3_t left, up, right, down, transformed, local;
|
|
emitpoint_t outverts[MAXWORKINGVERTS+1], *pout;
|
|
agh = temp2->value;
|
|
|
|
VectorCopy(r_spritedesc.vpn, aggh);
|
|
//dot = DotProduct (r_spritedesc.vpn, modelorg);
|
|
dot = DotProduct (aggh, modelorg);
|
|
|
|
|
|
// backface cull
|
|
if (dot >= 0)
|
|
return;
|
|
|
|
// build the sprite poster in worldspace
|
|
/*
|
|
VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->right, right);
|
|
VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->up, up);
|
|
VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->left, left);
|
|
VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->down, down);
|
|
|
|
|
|
*/
|
|
|
|
//VectorScale (r_spritedesc.vright, agh, r_spritedesc.vright);
|
|
//VectorScale (r_spritedesc.vup, agh, r_spritedesc.vup);
|
|
VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->right*currentflare->scale, right);
|
|
VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->left *currentflare->scale, left);
|
|
|
|
VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->up *currentflare->scaley, up);
|
|
VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->down *currentflare->scaley, down);
|
|
|
|
pverts = clip_verts[0];
|
|
|
|
pverts[0][0] = currentflare->org[0] + ( up[0] + left[0]);
|
|
pverts[0][1] = currentflare->org[1] + (up[1] + left[1]);
|
|
pverts[0][2] = currentflare->org[2] + (up[2] + left[2]);
|
|
pverts[0][3] = 0;
|
|
pverts[0][4] = 0;
|
|
|
|
pverts[1][0] = currentflare->org[0] + (up[0] + right[0]);
|
|
pverts[1][1] = currentflare->org[1] + (up[1] + right[1]);
|
|
pverts[1][2] = currentflare->org[2] + (up[2] + right[2]);
|
|
pverts[1][3] = sprite_width;
|
|
pverts[1][4] = 0;
|
|
|
|
pverts[2][0] = currentflare->org[0] + (down[0] + right[0]);
|
|
pverts[2][1] = currentflare->org[1] + (down[1] + right[1]);
|
|
pverts[2][2] = currentflare->org[2] + (down[2] + right[2]);
|
|
pverts[2][3] = sprite_width;
|
|
pverts[2][4] = sprite_height;
|
|
|
|
pverts[3][0] = currentflare->org[0] + (down[0] + left[0]);
|
|
pverts[3][1] = currentflare->org[1] +( down[1] + left[1]);
|
|
pverts[3][2] = currentflare->org[2] + (down[2] + left[2]);
|
|
pverts[3][3] = 0;
|
|
pverts[3][4] = sprite_height;
|
|
/*
|
|
{
|
|
int ehhhh;
|
|
for (ehhhh = 0; ehhhh < 4; ehhhh++)
|
|
{
|
|
pverts[ehhhh][0] *= lensreflection;
|
|
pverts[ehhhh][1] *= lensreflection;
|
|
pverts[ehhhh][2] *= lensreflection;
|
|
pverts[ehhhh][3] *= lensreflection;
|
|
pverts[ehhhh][4] *= lensreflection;
|
|
|
|
}
|
|
}
|
|
*/
|
|
|
|
|
|
// clip
|
|
nump = 4;
|
|
clip_current = 0;
|
|
|
|
for (i=0 ; i<4 ; i++)
|
|
{
|
|
nump = R_ClipSpriteFace (nump, &view_clipplanes[i]);
|
|
if (nump < 3)
|
|
return;
|
|
if (nump >= MAXWORKINGVERTS)
|
|
Sys_Error("R_SetupAndDrawSprite: too many points");
|
|
}
|
|
|
|
// transform vertices into viewspace and project
|
|
pv = &clip_verts[clip_current][0][0];
|
|
r_spritedesc.nearzi = -99999;
|
|
// leilei - sprite clip crash fix..
|
|
{
|
|
VectorSubtract (pv, r_origin, local);
|
|
TransformVector (local, transformed);
|
|
|
|
if (transformed[2] < 4) // leilei - try not to draw sprites too close, or we'll overflow the screen cache and crash!
|
|
return;
|
|
}
|
|
for (i=0 ; i<nump ; i++)
|
|
{
|
|
VectorSubtract (pv, r_origin, local);
|
|
TransformVector (local, transformed);
|
|
|
|
if (transformed[2] < NEAR_CLIP)
|
|
transformed[2] = NEAR_CLIP;
|
|
|
|
pout = &outverts[i];
|
|
pout->zi = 1.0 / transformed[2];
|
|
|
|
if (pout->zi > r_spritedesc.nearzi)
|
|
r_spritedesc.nearzi = pout->zi;
|
|
|
|
pout->s = pv[3];
|
|
pout->t = pv[4];
|
|
|
|
scale = xscale * pout->zi;
|
|
pout->u = (xcenter + scale * transformed[0]);
|
|
|
|
scale = yscale * pout->zi;
|
|
pout->v = (ycenter - scale * transformed[1]);
|
|
|
|
pv += sizeof (vec5_t) / sizeof (*pv);
|
|
|
|
}
|
|
|
|
// draw it
|
|
r_spritedesc.nump = nump;
|
|
r_spritedesc.pverts = outverts;
|
|
D_DrawSprite (2);
|
|
}
|
|
|
|
|
|
|
|
mspriteframe_t *R_GetSpriteframe2 (msprite_t *psprite)
|
|
{
|
|
mspritegroup_t *pspritegroup;
|
|
mspriteframe_t *pspriteframe;
|
|
int i, numframes, frame;
|
|
float *pintervals, fullinterval, targettime, time;
|
|
|
|
frame = currentparticle->frame;
|
|
|
|
if ((frame >= psprite->numframes) || (frame < 0))
|
|
{
|
|
Con_Printf ("R_DrawSprite: no such frame %d\n", frame);
|
|
frame = 0;
|
|
}
|
|
|
|
if (psprite->frames[frame].type == SPR_SINGLE)
|
|
{
|
|
pspriteframe = psprite->frames[frame].frameptr;
|
|
}
|
|
else
|
|
{
|
|
pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
|
|
pintervals = pspritegroup->intervals;
|
|
numframes = pspritegroup->numframes;
|
|
fullinterval = pintervals[numframes-1];
|
|
|
|
time = currentparticle->die;
|
|
|
|
// when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
|
|
// are positive, so we don't have to worry about division by 0
|
|
targettime = time - ((int)(time / fullinterval)) * fullinterval;
|
|
|
|
for (i=0 ; i<(numframes-1) ; i++)
|
|
{
|
|
if (pintervals[i] > targettime)
|
|
break;
|
|
}
|
|
|
|
pspriteframe = pspritegroup->frames[i];
|
|
}
|
|
|
|
return pspriteframe;
|
|
}
|
|
|
|
|
|
|
|
// pass:
|
|
|
|
// 0 - modulates and subtracts
|
|
// 1 - alphas and everything else
|
|
// 2 - additives
|
|
int currentparticlepass;
|
|
void R_DrawSprite2 ()
|
|
{
|
|
int i;
|
|
msprite_t *psprite;
|
|
vec3_t tvec;
|
|
float dot, angle, sr, cr;
|
|
int pass = currentparticlepass;
|
|
|
|
// leilei - stupid pass control
|
|
if (currentparticle->blend == 0 && currentparticlepass != 1) return;
|
|
else if (currentparticle->blend == 1 && currentparticlepass != 2) return;
|
|
else if (currentparticle->blend == 2 && currentparticlepass != 1) return;
|
|
else if (currentparticle->blend == 3 && currentparticlepass != 1) return;
|
|
else if (currentparticle->blend == 4 && currentparticlepass != 1) return;
|
|
else if (currentparticle->blend == 5 && currentparticlepass != 2) return;
|
|
else if (currentparticle->blend == 6 && currentparticlepass != 3) return;
|
|
else if (currentparticle->blend == 7 && currentparticlepass != 1) return;
|
|
else if (currentparticle->blend == 8 && currentparticlepass != 2) return;
|
|
else if (currentparticle->blend == 9 && currentparticlepass != 1) return;
|
|
else if (currentparticle->blend == 10 && currentparticlepass != 1) return;
|
|
// else return; // nah.
|
|
|
|
|
|
psprite = currentparticle->model->cache.data;
|
|
|
|
r_spritedesc.pspriteframe = R_GetSpriteframe2 (psprite);
|
|
// LEIDTIED
|
|
sprite_width = r_spritedesc.pspriteframe->width;
|
|
sprite_height = r_spritedesc.pspriteframe->height;
|
|
// We override the sprite type because we can. And if you ain't down with t...forget it
|
|
|
|
// TODO: make this caller-selectable
|
|
if (currentparticle->sprtype == SPR_FACING_UPRIGHT)
|
|
{
|
|
// generate the sprite's axes, with vup straight up in worldspace, and
|
|
// r_spritedesc.vright perpendicular to modelorg.
|
|
// This will not work if the view direction is very close to straight up or
|
|
// down, because the cross product will be between two nearly parallel
|
|
// vectors and starts to approach an undefined state, so we don't draw if
|
|
// the two vectors are less than 1 degree apart
|
|
tvec[0] = -modelorg[0];
|
|
tvec[1] = -modelorg[1];
|
|
tvec[2] = -modelorg[2];
|
|
VectorNormalize (tvec);
|
|
dot = tvec[2]; // same as DotProduct (tvec, r_spritedesc.vup) because
|
|
// r_spritedesc.vup is 0, 0, 1
|
|
if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
|
|
return;
|
|
r_spritedesc.vup[0] = 0;
|
|
r_spritedesc.vup[1] = 0;
|
|
r_spritedesc.vup[2] = 1;
|
|
r_spritedesc.vright[0] = tvec[1];
|
|
// CrossProduct(r_spritedesc.vup, -modelorg,
|
|
r_spritedesc.vright[1] = -tvec[0];
|
|
// r_spritedesc.vright)
|
|
r_spritedesc.vright[2] = 0;
|
|
VectorNormalize (r_spritedesc.vright);
|
|
r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
|
|
r_spritedesc.vpn[1] = r_spritedesc.vright[0];
|
|
r_spritedesc.vpn[2] = 0;
|
|
// CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
|
|
// r_spritedesc.vpn)
|
|
}
|
|
else if (currentparticle->sprtype == SPR_VP_PARALLEL)
|
|
{
|
|
// generate the sprite's axes, completely parallel to the viewplane. There
|
|
// are no problem situations, because the sprite is always in the same
|
|
// position relative to the viewer
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
r_spritedesc.vup[i] = vup[i];
|
|
r_spritedesc.vright[i] = vright[i];
|
|
r_spritedesc.vpn[i] = vpn[i];
|
|
}
|
|
}
|
|
else if (currentparticle->sprtype == SPR_VP_PARALLEL_UPRIGHT)
|
|
{
|
|
// generate the sprite's axes, with vup straight up in worldspace, and
|
|
// r_spritedesc.vright parallel to the viewplane.
|
|
// This will not work if the view direction is very close to straight up or
|
|
// down, because the cross product will be between two nearly parallel
|
|
// vectors and starts to approach an undefined state, so we don't draw if
|
|
// the two vectors are less than 1 degree apart
|
|
dot = vpn[2]; // same as DotProduct (vpn, r_spritedesc.vup) because
|
|
// r_spritedesc.vup is 0, 0, 1
|
|
if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
|
|
return;
|
|
r_spritedesc.vup[0] = 0;
|
|
r_spritedesc.vup[1] = 0;
|
|
r_spritedesc.vup[2] = 1;
|
|
r_spritedesc.vright[0] = vpn[1];
|
|
// CrossProduct (r_spritedesc.vup, vpn,
|
|
r_spritedesc.vright[1] = -vpn[0]; // r_spritedesc.vright)
|
|
r_spritedesc.vright[2] = 0;
|
|
VectorNormalize (r_spritedesc.vright);
|
|
r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
|
|
r_spritedesc.vpn[1] = r_spritedesc.vright[0];
|
|
r_spritedesc.vpn[2] = 0;
|
|
|
|
|
|
// CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
|
|
//r_spritedesc.vpn);
|
|
}
|
|
else if (currentparticle->sprtype == SPR_ORIENTED)
|
|
{
|
|
|
|
// generate the sprite's axes, according to the sprite's world orientation
|
|
AngleVectors (currentparticle->angles, r_spritedesc.vpn,
|
|
r_spritedesc.vright, r_spritedesc.vup);
|
|
|
|
|
|
}
|
|
else if (currentparticle->sprtype == SPR_VP_PARALLEL_ORIENTED)
|
|
{
|
|
// generate the sprite's axes, parallel to the viewplane, but rotated in
|
|
// that plane around the center according to the sprite particle's roll
|
|
// angle. So vpn stays the same, but vright and vup rotate
|
|
angle = currentparticle->angles[ROLL] * (M_PI*2 / 360);
|
|
angle = currentparticle->angles[ROLL] * (M_PI*2 / 360);
|
|
sr = sin(angle);
|
|
cr = cos(angle);
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
r_spritedesc.vpn[i] = vpn[i];
|
|
r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr;
|
|
r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr;
|
|
}
|
|
}
|
|
else if (currentparticle->sprtype == 98)
|
|
{
|
|
/*
|
|
tvec[0] = -modelorg[0];
|
|
tvec[1] = -modelorg[1];
|
|
tvec[2] = -modelorg[2];
|
|
VectorNormalize (tvec);
|
|
dot = tvec[2]; // same as DotProduct (tvec, r_spritedesc.vup) because
|
|
// r_spritedesc.vup is 0, 0, 1
|
|
if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
|
|
return;
|
|
|
|
//r_spritedesc.vup[0] = 0;
|
|
//r_spritedesc.vup[1] = 0;
|
|
//r_spritedesc.vup[2] = 1;
|
|
|
|
r_spritedesc.vright[0] = tvec[1];
|
|
|
|
r_spritedesc.vright[1] = -tvec[0];
|
|
r_spritedesc.vright[2] = 0;
|
|
VectorNormalize (r_spritedesc.vright);
|
|
r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
|
|
r_spritedesc.vpn[1] = r_spritedesc.vright[0];
|
|
r_spritedesc.vpn[2] = 0;
|
|
// CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
|
|
// r_spritedesc.vpn)
|
|
// attempt to do the beamy beam thingy beam.
|
|
|
|
//
|
|
*/
|
|
|
|
// AngleVectors (currentparticle->angles, r_spritedesc.vpn,
|
|
// r_spritedesc.vright, r_spritedesc.vup);
|
|
AngleVectors (currentparticle->angles, r_spritedesc.vpn,
|
|
r_spritedesc.vup, r_spritedesc.vup);
|
|
|
|
CrossProduct (r_spritedesc.vup, r_spritedesc.vright, r_spritedesc.vpn);
|
|
angle = currentparticle->angles[ROLL] * (M_PI*2 / 360);
|
|
angle = currentparticle->angles[ROLL] * (M_PI*2 / 360);
|
|
sr = sin(angle);
|
|
cr = cos(angle);
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
// r_spritedesc.vpn[i] = vpn[i] * -sr + vup[i] * cr;
|
|
// r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr;
|
|
// r_spritedesc.vup[i] += vright[i] * -sr + vup[i] * cr;
|
|
}
|
|
}
|
|
else if (currentparticle->sprtype == 5)
|
|
{
|
|
// like above but try to occlude check some how
|
|
// angle. So vpn stays the same, but vright and vup rotate
|
|
angle = currentparticle->angles[ROLL] * (M_PI*2 / 360);
|
|
angle = currentparticle->angles[ROLL] * (M_PI*2 / 360);
|
|
sr = sin(angle);
|
|
cr = cos(angle);
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
r_spritedesc.vpn[i] = vpn[i];
|
|
r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr;
|
|
r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// like above but try to occlude check some how
|
|
// angle. So vpn stays the same, but vright and vup rotate
|
|
angle = currentparticle->angles[ROLL] * (M_PI*2 / 360);
|
|
angle = currentparticle->angles[ROLL] * (M_PI*2 / 360);
|
|
sr = sin(angle);
|
|
cr = cos(angle);
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
r_spritedesc.vpn[i] = vpn[i];
|
|
r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr;
|
|
r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr;
|
|
}
|
|
// Sys_Error ("R_DrawSprite: Bad sprite type %d", psprite->type);
|
|
}
|
|
if(currentparticle->sprtype == 5)flared = 1; else flared = 0;
|
|
R_RotateSprite2 (psprite->beamlength);
|
|
//R_RotateSprite2And (psprite->beamlength);
|
|
|
|
// leilei - stupid pass control
|
|
|
|
R_SetupAndDrawSprite2 (pass);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mspriteframe_t *R_GetSpriteframe3 (msprite_t *psprite)
|
|
{
|
|
mspritegroup_t *pspritegroup;
|
|
mspriteframe_t *pspriteframe;
|
|
int i, numframes, frame;
|
|
float *pintervals, fullinterval, targettime, time;
|
|
|
|
frame = currentflare->frame;
|
|
|
|
if ((frame >= psprite->numframes) || (frame < 0))
|
|
{
|
|
Con_Printf ("R_DrawSprite3: no such frame %d\n", frame);
|
|
frame = 0;
|
|
}
|
|
|
|
if (psprite->frames[frame].type == SPR_SINGLE)
|
|
{
|
|
pspriteframe = psprite->frames[frame].frameptr;
|
|
}
|
|
else
|
|
{
|
|
pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
|
|
pintervals = pspritegroup->intervals;
|
|
numframes = pspritegroup->numframes;
|
|
fullinterval = pintervals[numframes-1];
|
|
|
|
time = currentflare->die;
|
|
|
|
// when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
|
|
// are positive, so we don't have to worry about division by 0
|
|
targettime = time - ((int)(time / fullinterval)) * fullinterval;
|
|
|
|
for (i=0 ; i<(numframes-1) ; i++)
|
|
{
|
|
if (pintervals[i] > targettime)
|
|
break;
|
|
}
|
|
|
|
pspriteframe = pspritegroup->frames[i];
|
|
}
|
|
|
|
return pspriteframe;
|
|
}
|
|
|
|
|
|
|
|
// Flares only do one type.
|
|
void R_DrawSprite3 (void)
|
|
{
|
|
int i;
|
|
msprite_t *psprite;
|
|
vec3_t tvec;
|
|
float dot, angle, sr, cr;
|
|
|
|
psprite = currentflare->model->cache.data;
|
|
|
|
r_spritedesc.pspriteframe = R_GetSpriteframe3 (psprite);
|
|
// LEIDTIED
|
|
sprite_width = r_spritedesc.pspriteframe->width;
|
|
sprite_height = r_spritedesc.pspriteframe->height;
|
|
|
|
lensreflection = currentflare->lensreflection;
|
|
lensreflection = 1;
|
|
|
|
// sprite_width *= lensreflection;
|
|
// sprite_height *= lensreflection;
|
|
{
|
|
// generate the sprite's axes, completely parallel to the viewplane. There
|
|
// are no problem situations, because the sprite is always in the same
|
|
// position relative to the viewer
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
r_spritedesc.vup[i] = vup[i];
|
|
r_spritedesc.vright[i] = vright[i];
|
|
r_spritedesc.vpn[i] = vpn[i];
|
|
|
|
}
|
|
}
|
|
/* else if (currentflare->sprtype == SPR_VP_PARALLEL_UPRIGHT)
|
|
{
|
|
// generate the sprite's axes, with vup straight up in worldspace, and
|
|
// r_spritedesc.vright parallel to the viewplane.
|
|
// This will not work if the view direction is very close to straight up or
|
|
// down, because the cross product will be between two nearly parallel
|
|
// vectors and starts to approach an undefined state, so we don't draw if
|
|
// the two vectors are less than 1 degree apart
|
|
dot = vpn[2]; // same as DotProduct (vpn, r_spritedesc.vup) because
|
|
// r_spritedesc.vup is 0, 0, 1
|
|
if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
|
|
return;
|
|
r_spritedesc.vup[0] = 0;
|
|
r_spritedesc.vup[1] = 0;
|
|
r_spritedesc.vup[2] = 1;
|
|
r_spritedesc.vright[0] = vpn[1];
|
|
// CrossProduct (r_spritedesc.vup, vpn,
|
|
r_spritedesc.vright[1] = -vpn[0]; // r_spritedesc.vright)
|
|
r_spritedesc.vright[2] = 0;
|
|
VectorNormalize (r_spritedesc.vright);
|
|
r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
|
|
r_spritedesc.vpn[1] = r_spritedesc.vright[0];
|
|
r_spritedesc.vpn[2] = 0;
|
|
|
|
|
|
// CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
|
|
//r_spritedesc.vpn);
|
|
}
|
|
else if (currentflare->sprtype == SPR_ORIENTED)
|
|
{
|
|
// generate the sprite's axes, according to the sprite's world orientation
|
|
AngleVectors (currentflare->angles, r_spritedesc.vpn,
|
|
r_spritedesc.vright, r_spritedesc.vup);
|
|
}
|
|
else if (currentflare->sprtype == SPR_VP_PARALLEL_ORIENTED)
|
|
{
|
|
// generate the sprite's axes, parallel to the viewplane, but rotated in
|
|
// that plane around the center according to the sprite particle's roll
|
|
// angle. So vpn stays the same, but vright and vup rotate
|
|
angle = currentflare->angles[ROLL] * (M_PI*2 / 360);
|
|
angle = currentflare->angles[ROLL] * (M_PI*2 / 360);
|
|
sr = sin(angle);
|
|
cr = cos(angle);
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
r_spritedesc.vpn[i] = vpn[i];
|
|
r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr;
|
|
r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr;
|
|
}
|
|
}
|
|
else if (currentflare->sprtype == 5)
|
|
{
|
|
// like above but try to occlude check some how
|
|
// angle. So vpn stays the same, but vright and vup rotate
|
|
angle = currentflare->angles[ROLL] * (M_PI*2 / 360);
|
|
angle = currentflare->angles[ROLL] * (M_PI*2 / 360);
|
|
sr = sin(angle);
|
|
cr = cos(angle);
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
r_spritedesc.vpn[i] = vpn[i];
|
|
r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr;
|
|
r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// like above but try to occlude check some how
|
|
// angle. So vpn stays the same, but vright and vup rotate
|
|
angle = currentflare->angles[ROLL] * (M_PI*2 / 360);
|
|
angle = currentflare->angles[ROLL] * (M_PI*2 / 360);
|
|
sr = sin(angle);
|
|
cr = cos(angle);
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
r_spritedesc.vpn[i] = vpn[i];
|
|
r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr;
|
|
r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr;
|
|
}
|
|
// Sys_Error ("R_DrawSprite: Bad sprite type %d", psprite->type);
|
|
}
|
|
*/
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
r_spritedesc.vpn[i] = vpn[i];
|
|
|
|
|
|
}
|
|
if(currentflare->sprtype == 5 || currentflare->sprtype == SPR_VP_PARALLEL_UPRIGHT)flared = 1; else flared = 0;
|
|
R_RotateSprite3 (psprite->beamlength);
|
|
|
|
|
|
R_SetupAndDrawSprite3 ();
|
|
}
|
|
|
|
|
|
|
|
|