Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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.