r_sprite.c 11 KB

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