|
|
1.1 ! root 1: /* ! 2: Copyright (C) 1996-1997 Id Software, Inc. ! 3: ! 4: This program is free software; you can redistribute it and/or ! 5: modify it under the terms of the GNU General Public License ! 6: as published by the Free Software Foundation; either version 2 ! 7: of the License, or (at your option) any later version. ! 8: ! 9: This program is distributed in the hope that it will be useful, ! 10: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ! 12: ! 13: See the GNU General Public License for more details. ! 14: ! 15: You should have received a copy of the GNU General Public License ! 16: along with this program; if not, write to the Free Software ! 17: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ! 18: ! 19: */ ! 20: // r_sprite.c ! 21: ! 22: #include "quakedef.h" ! 23: #include "r_local.h" ! 24: ! 25: static int clip_current; ! 26: static vec5_t clip_verts[2][MAXWORKINGVERTS]; ! 27: static int sprite_width, sprite_height; ! 28: ! 29: spritedesc_t r_spritedesc; ! 30: ! 31: ! 32: /* ! 33: ================ ! 34: R_RotateSprite ! 35: ================ ! 36: */ ! 37: void R_RotateSprite (float beamlength) ! 38: { ! 39: vec3_t vec; ! 40: ! 41: if (beamlength == 0.0) ! 42: return; ! 43: ! 44: VectorScale (r_spritedesc.vpn, -beamlength, vec); ! 45: VectorAdd (r_entorigin, vec, r_entorigin); ! 46: VectorSubtract (modelorg, vec, modelorg); ! 47: } ! 48: ! 49: ! 50: /* ! 51: ============= ! 52: R_ClipSpriteFace ! 53: ! 54: Clips the winding at clip_verts[clip_current] and changes clip_current ! 55: Throws out the back side ! 56: ============== ! 57: */ ! 58: int R_ClipSpriteFace (int nump, clipplane_t *pclipplane) ! 59: { ! 60: int i, outcount; ! 61: float dists[MAXWORKINGVERTS+1]; ! 62: float frac, clipdist, *pclipnormal; ! 63: float *in, *instep, *outstep, *vert2; ! 64: ! 65: clipdist = pclipplane->dist; ! 66: pclipnormal = pclipplane->normal; ! 67: ! 68: // calc dists ! 69: if (clip_current) ! 70: { ! 71: in = clip_verts[1][0]; ! 72: outstep = clip_verts[0][0]; ! 73: clip_current = 0; ! 74: } ! 75: else ! 76: { ! 77: in = clip_verts[0][0]; ! 78: outstep = clip_verts[1][0]; ! 79: clip_current = 1; ! 80: } ! 81: ! 82: instep = in; ! 83: for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float)) ! 84: { ! 85: dists[i] = DotProduct (instep, pclipnormal) - clipdist; ! 86: } ! 87: ! 88: // handle wraparound case ! 89: dists[nump] = dists[0]; ! 90: Q_memcpy (instep, in, sizeof (vec5_t)); ! 91: ! 92: ! 93: // clip the winding ! 94: instep = in; ! 95: outcount = 0; ! 96: ! 97: for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float)) ! 98: { ! 99: if (dists[i] >= 0) ! 100: { ! 101: Q_memcpy (outstep, instep, sizeof (vec5_t)); ! 102: outstep += sizeof (vec5_t) / sizeof (float); ! 103: outcount++; ! 104: } ! 105: ! 106: if (dists[i] == 0 || dists[i+1] == 0) ! 107: continue; ! 108: ! 109: if ( (dists[i] > 0) == (dists[i+1] > 0) ) ! 110: continue; ! 111: ! 112: // split it into a new vertex ! 113: frac = dists[i] / (dists[i] - dists[i+1]); ! 114: ! 115: vert2 = instep + sizeof (vec5_t) / sizeof (float); ! 116: ! 117: outstep[0] = instep[0] + frac*(vert2[0] - instep[0]); ! 118: outstep[1] = instep[1] + frac*(vert2[1] - instep[1]); ! 119: outstep[2] = instep[2] + frac*(vert2[2] - instep[2]); ! 120: outstep[3] = instep[3] + frac*(vert2[3] - instep[3]); ! 121: outstep[4] = instep[4] + frac*(vert2[4] - instep[4]); ! 122: ! 123: outstep += sizeof (vec5_t) / sizeof (float); ! 124: outcount++; ! 125: } ! 126: ! 127: return outcount; ! 128: } ! 129: ! 130: ! 131: /* ! 132: ================ ! 133: R_SetupAndDrawSprite ! 134: ================ ! 135: */ ! 136: void R_SetupAndDrawSprite () ! 137: { ! 138: int i, nump; ! 139: float dot, scale, *pv; ! 140: vec5_t *pverts; ! 141: vec3_t left, up, right, down, transformed, local; ! 142: emitpoint_t outverts[MAXWORKINGVERTS+1], *pout; ! 143: ! 144: dot = DotProduct (r_spritedesc.vpn, modelorg); ! 145: ! 146: // backface cull ! 147: if (dot >= 0) ! 148: return; ! 149: ! 150: // build the sprite poster in worldspace ! 151: VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->right, right); ! 152: VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->up, up); ! 153: VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->left, left); ! 154: VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->down, down); ! 155: ! 156: pverts = clip_verts[0]; ! 157: ! 158: pverts[0][0] = r_entorigin[0] + up[0] + left[0]; ! 159: pverts[0][1] = r_entorigin[1] + up[1] + left[1]; ! 160: pverts[0][2] = r_entorigin[2] + up[2] + left[2]; ! 161: pverts[0][3] = 0; ! 162: pverts[0][4] = 0; ! 163: ! 164: pverts[1][0] = r_entorigin[0] + up[0] + right[0]; ! 165: pverts[1][1] = r_entorigin[1] + up[1] + right[1]; ! 166: pverts[1][2] = r_entorigin[2] + up[2] + right[2]; ! 167: pverts[1][3] = sprite_width; ! 168: pverts[1][4] = 0; ! 169: ! 170: pverts[2][0] = r_entorigin[0] + down[0] + right[0]; ! 171: pverts[2][1] = r_entorigin[1] + down[1] + right[1]; ! 172: pverts[2][2] = r_entorigin[2] + down[2] + right[2]; ! 173: pverts[2][3] = sprite_width; ! 174: pverts[2][4] = sprite_height; ! 175: ! 176: pverts[3][0] = r_entorigin[0] + down[0] + left[0]; ! 177: pverts[3][1] = r_entorigin[1] + down[1] + left[1]; ! 178: pverts[3][2] = r_entorigin[2] + down[2] + left[2]; ! 179: pverts[3][3] = 0; ! 180: pverts[3][4] = sprite_height; ! 181: ! 182: // clip to the frustum in worldspace ! 183: nump = 4; ! 184: clip_current = 0; ! 185: ! 186: for (i=0 ; i<4 ; i++) ! 187: { ! 188: nump = R_ClipSpriteFace (nump, &view_clipplanes[i]); ! 189: if (nump < 3) ! 190: return; ! 191: if (nump >= MAXWORKINGVERTS) ! 192: Sys_Error("R_SetupAndDrawSprite: too many points"); ! 193: } ! 194: ! 195: // transform vertices into viewspace and project ! 196: pv = &clip_verts[clip_current][0][0]; ! 197: r_spritedesc.nearzi = -999999; ! 198: ! 199: for (i=0 ; i<nump ; i++) ! 200: { ! 201: VectorSubtract (pv, r_origin, local); ! 202: TransformVector (local, transformed); ! 203: ! 204: if (transformed[2] < NEAR_CLIP) ! 205: transformed[2] = NEAR_CLIP; ! 206: ! 207: pout = &outverts[i]; ! 208: pout->zi = 1.0 / transformed[2]; ! 209: if (pout->zi > r_spritedesc.nearzi) ! 210: r_spritedesc.nearzi = pout->zi; ! 211: ! 212: pout->s = pv[3]; ! 213: pout->t = pv[4]; ! 214: ! 215: scale = xscale * pout->zi; ! 216: pout->u = (xcenter + scale * transformed[0]); ! 217: ! 218: scale = yscale * pout->zi; ! 219: pout->v = (ycenter - scale * transformed[1]); ! 220: ! 221: pv += sizeof (vec5_t) / sizeof (pv); ! 222: } ! 223: ! 224: // draw it ! 225: r_spritedesc.nump = nump; ! 226: r_spritedesc.pverts = outverts; ! 227: D_DrawSprite (); ! 228: } ! 229: ! 230: ! 231: /* ! 232: ================ ! 233: R_GetSpriteframe ! 234: ================ ! 235: */ ! 236: mspriteframe_t *R_GetSpriteframe (msprite_t *psprite) ! 237: { ! 238: mspritegroup_t *pspritegroup; ! 239: mspriteframe_t *pspriteframe; ! 240: int i, numframes, frame; ! 241: float *pintervals, fullinterval, targettime, time; ! 242: ! 243: frame = currententity->frame; ! 244: ! 245: if ((frame >= psprite->numframes) || (frame < 0)) ! 246: { ! 247: Con_Printf ("R_DrawSprite: no such frame %d\n", frame); ! 248: frame = 0; ! 249: } ! 250: ! 251: if (psprite->frames[frame].type == SPR_SINGLE) ! 252: { ! 253: pspriteframe = psprite->frames[frame].frameptr; ! 254: } ! 255: else ! 256: { ! 257: pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr; ! 258: pintervals = pspritegroup->intervals; ! 259: numframes = pspritegroup->numframes; ! 260: fullinterval = pintervals[numframes-1]; ! 261: ! 262: time = cl.time + currententity->syncbase; ! 263: ! 264: // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values ! 265: // are positive, so we don't have to worry about division by 0 ! 266: targettime = time - ((int)(time / fullinterval)) * fullinterval; ! 267: ! 268: for (i=0 ; i<(numframes-1) ; i++) ! 269: { ! 270: if (pintervals[i] > targettime) ! 271: break; ! 272: } ! 273: ! 274: pspriteframe = pspritegroup->frames[i]; ! 275: } ! 276: ! 277: return pspriteframe; ! 278: } ! 279: ! 280: ! 281: /* ! 282: ================ ! 283: R_DrawSprite ! 284: ================ ! 285: */ ! 286: void R_DrawSprite (void) ! 287: { ! 288: int i; ! 289: msprite_t *psprite; ! 290: vec3_t tvec; ! 291: float dot, angle, sr, cr; ! 292: ! 293: psprite = currententity->model->cache.data; ! 294: ! 295: r_spritedesc.pspriteframe = R_GetSpriteframe (psprite); ! 296: ! 297: sprite_width = r_spritedesc.pspriteframe->width; ! 298: sprite_height = r_spritedesc.pspriteframe->height; ! 299: ! 300: // TODO: make this caller-selectable ! 301: if (psprite->type == SPR_FACING_UPRIGHT) ! 302: { ! 303: // generate the sprite's axes, with vup straight up in worldspace, and ! 304: // r_spritedesc.vright perpendicular to modelorg. ! 305: // This will not work if the view direction is very close to straight up or ! 306: // down, because the cross product will be between two nearly parallel ! 307: // vectors and starts to approach an undefined state, so we don't draw if ! 308: // the two vectors are less than 1 degree apart ! 309: tvec[0] = -modelorg[0]; ! 310: tvec[1] = -modelorg[1]; ! 311: tvec[2] = -modelorg[2]; ! 312: VectorNormalize (tvec); ! 313: dot = tvec[2]; // same as DotProduct (tvec, r_spritedesc.vup) because ! 314: // r_spritedesc.vup is 0, 0, 1 ! 315: if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848 ! 316: return; ! 317: r_spritedesc.vup[0] = 0; ! 318: r_spritedesc.vup[1] = 0; ! 319: r_spritedesc.vup[2] = 1; ! 320: r_spritedesc.vright[0] = tvec[1]; ! 321: // CrossProduct(r_spritedesc.vup, -modelorg, ! 322: r_spritedesc.vright[1] = -tvec[0]; ! 323: // r_spritedesc.vright) ! 324: r_spritedesc.vright[2] = 0; ! 325: VectorNormalize (r_spritedesc.vright); ! 326: r_spritedesc.vpn[0] = -r_spritedesc.vright[1]; ! 327: r_spritedesc.vpn[1] = r_spritedesc.vright[0]; ! 328: r_spritedesc.vpn[2] = 0; ! 329: // CrossProduct (r_spritedesc.vright, r_spritedesc.vup, ! 330: // r_spritedesc.vpn) ! 331: } ! 332: else if (psprite->type == SPR_VP_PARALLEL) ! 333: { ! 334: // generate the sprite's axes, completely parallel to the viewplane. There ! 335: // are no problem situations, because the sprite is always in the same ! 336: // position relative to the viewer ! 337: for (i=0 ; i<3 ; i++) ! 338: { ! 339: r_spritedesc.vup[i] = vup[i]; ! 340: r_spritedesc.vright[i] = vright[i]; ! 341: r_spritedesc.vpn[i] = vpn[i]; ! 342: } ! 343: } ! 344: else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT) ! 345: { ! 346: // generate the sprite's axes, with vup straight up in worldspace, and ! 347: // r_spritedesc.vright parallel to the viewplane. ! 348: // This will not work if the view direction is very close to straight up or ! 349: // down, because the cross product will be between two nearly parallel ! 350: // vectors and starts to approach an undefined state, so we don't draw if ! 351: // the two vectors are less than 1 degree apart ! 352: dot = vpn[2]; // same as DotProduct (vpn, r_spritedesc.vup) because ! 353: // r_spritedesc.vup is 0, 0, 1 ! 354: if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848 ! 355: return; ! 356: r_spritedesc.vup[0] = 0; ! 357: r_spritedesc.vup[1] = 0; ! 358: r_spritedesc.vup[2] = 1; ! 359: r_spritedesc.vright[0] = vpn[1]; ! 360: // CrossProduct (r_spritedesc.vup, vpn, ! 361: r_spritedesc.vright[1] = -vpn[0]; // r_spritedesc.vright) ! 362: r_spritedesc.vright[2] = 0; ! 363: VectorNormalize (r_spritedesc.vright); ! 364: r_spritedesc.vpn[0] = -r_spritedesc.vright[1]; ! 365: r_spritedesc.vpn[1] = r_spritedesc.vright[0]; ! 366: r_spritedesc.vpn[2] = 0; ! 367: // CrossProduct (r_spritedesc.vright, r_spritedesc.vup, ! 368: // r_spritedesc.vpn) ! 369: } ! 370: else if (psprite->type == SPR_ORIENTED) ! 371: { ! 372: // generate the sprite's axes, according to the sprite's world orientation ! 373: AngleVectors (currententity->angles, r_spritedesc.vpn, ! 374: r_spritedesc.vright, r_spritedesc.vup); ! 375: } ! 376: else if (psprite->type == SPR_VP_PARALLEL_ORIENTED) ! 377: { ! 378: // generate the sprite's axes, parallel to the viewplane, but rotated in ! 379: // that plane around the center according to the sprite entity's roll ! 380: // angle. So vpn stays the same, but vright and vup rotate ! 381: angle = currententity->angles[ROLL] * (M_PI*2 / 360); ! 382: sr = sin(angle); ! 383: cr = cos(angle); ! 384: ! 385: for (i=0 ; i<3 ; i++) ! 386: { ! 387: r_spritedesc.vpn[i] = vpn[i]; ! 388: r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr; ! 389: r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr; ! 390: } ! 391: } ! 392: else ! 393: { ! 394: Sys_Error ("R_DrawSprite: Bad sprite type %d", psprite->type); ! 395: } ! 396: ! 397: R_RotateSprite (psprite->beamlength); ! 398: ! 399: R_SetupAndDrawSprite (); ! 400: } ! 401:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.