home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quake_src / r_sprite.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-17  |  11.0 KB  |  402 lines

  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.  
  402.