/* 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= 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 ; izi = 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 ; izi = 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 ; izi = 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 (); }