/d_sprite.c

https://gitlab.com/fzwoch/fodquake · C · 434 lines · 286 code · 81 blank · 67 comment · 57 complexity · 131bd6526243d6b4c604f983a4dbb59b MD5 · raw file

  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. // d_sprite.c: software top-level rasterization driver module for drawing
  16. // sprites
  17. #include <math.h>
  18. #include "quakedef.h"
  19. #include "d_local.h"
  20. #if !id386
  21. /*
  22. =====================
  23. D_SpriteDrawSpans
  24. =====================
  25. */
  26. void D_SpriteDrawSpans (sspan_t *pspan)
  27. {
  28. int count, spancount, izistep;
  29. int izi;
  30. byte *pbase, *pdest;
  31. fixed16_t s, t, snext, tnext, sstep, tstep;
  32. float sdivz, tdivz, zi, z, du, dv, spancountminus1;
  33. float sdivz8stepu, tdivz8stepu, zi8stepu;
  34. byte btemp;
  35. short *pz;
  36. sstep = 0; // keep compiler happy
  37. tstep = 0; // ditto
  38. pbase = cacheblock;
  39. sdivz8stepu = d_sdivzstepu * 8;
  40. tdivz8stepu = d_tdivzstepu * 8;
  41. zi8stepu = d_zistepu * 8;
  42. // we count on FP exceptions being turned off to avoid range problems
  43. izistep = (int)(d_zistepu * 0x8000 * 0x10000);
  44. do
  45. {
  46. pdest = (byte *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u;
  47. pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
  48. count = pspan->count;
  49. if (count <= 0)
  50. goto NextSpan;
  51. // calculate the initial s/z, t/z, 1/z, s, and t and clamp
  52. du = (float)pspan->u;
  53. dv = (float)pspan->v;
  54. sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
  55. tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
  56. zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
  57. z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
  58. // we count on FP exceptions being turned off to avoid range problems
  59. izi = (int)(zi * 0x8000 * 0x10000);
  60. s = (int)(sdivz * z) + sadjust;
  61. if (s > bbextents)
  62. s = bbextents;
  63. else if (s < 0)
  64. s = 0;
  65. t = (int)(tdivz * z) + tadjust;
  66. if (t > bbextentt)
  67. t = bbextentt;
  68. else if (t < 0)
  69. t = 0;
  70. do
  71. {
  72. // calculate s and t at the far end of the span
  73. if (count >= 8)
  74. spancount = 8;
  75. else
  76. spancount = count;
  77. count -= spancount;
  78. if (count)
  79. {
  80. // calculate s/z, t/z, zi->fixed s and t at far end of span,
  81. // calculate s and t steps across span by shifting
  82. sdivz += sdivz8stepu;
  83. tdivz += tdivz8stepu;
  84. zi += zi8stepu;
  85. z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
  86. snext = (int)(sdivz * z) + sadjust;
  87. if (snext > bbextents)
  88. snext = bbextents;
  89. else if (snext < 8)
  90. snext = 8; // prevent round-off error on <0 steps from
  91. // from causing overstepping & running off the
  92. // edge of the texture
  93. tnext = (int)(tdivz * z) + tadjust;
  94. if (tnext > bbextentt)
  95. tnext = bbextentt;
  96. else if (tnext < 8)
  97. tnext = 8; // guard against round-off error on <0 steps
  98. sstep = (snext - s) >> 3;
  99. tstep = (tnext - t) >> 3;
  100. }
  101. else
  102. {
  103. // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
  104. // can't step off polygon), clamp, calculate s and t steps across
  105. // span by division, biasing steps low so we don't run off the
  106. // texture
  107. spancountminus1 = (float)(spancount - 1);
  108. sdivz += d_sdivzstepu * spancountminus1;
  109. tdivz += d_tdivzstepu * spancountminus1;
  110. zi += d_zistepu * spancountminus1;
  111. z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
  112. snext = (int)(sdivz * z) + sadjust;
  113. if (snext > bbextents)
  114. snext = bbextents;
  115. else if (snext < 8)
  116. snext = 8; // prevent round-off error on <0 steps from
  117. // from causing overstepping & running off the
  118. // edge of the texture
  119. tnext = (int)(tdivz * z) + tadjust;
  120. if (tnext > bbextentt)
  121. tnext = bbextentt;
  122. else if (tnext < 8)
  123. tnext = 8; // guard against round-off error on <0 steps
  124. if (spancount > 1)
  125. {
  126. sstep = (snext - s) / (spancount - 1);
  127. tstep = (tnext - t) / (spancount - 1);
  128. }
  129. }
  130. do
  131. {
  132. btemp = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
  133. if (btemp != 255)
  134. {
  135. if (*pz <= (izi >> 16))
  136. {
  137. *pz = izi >> 16;
  138. *pdest = btemp;
  139. }
  140. }
  141. izi += izistep;
  142. pdest++;
  143. pz++;
  144. s += sstep;
  145. t += tstep;
  146. } while (--spancount > 0);
  147. s = snext;
  148. t = tnext;
  149. } while (count > 0);
  150. NextSpan:
  151. pspan++;
  152. } while (pspan->count != DS_SPAN_LIST_END);
  153. }
  154. #endif
  155. /*
  156. =====================
  157. D_SpriteScanLeftEdge
  158. =====================
  159. */
  160. void D_SpriteScanLeftEdge(sspan_t *pspan, int minindex, int maxindex)
  161. {
  162. int i, v, itop, ibottom, lmaxindex;
  163. emitpoint_t *pvert, *pnext;
  164. float du, dv, vtop, vbottom, slope;
  165. fixed16_t u, u_step;
  166. i = minindex;
  167. if (i == 0)
  168. i = r_spritedesc.nump;
  169. lmaxindex = maxindex;
  170. if (lmaxindex == 0)
  171. lmaxindex = r_spritedesc.nump;
  172. vtop = ceil (r_spritedesc.pverts[i].v);
  173. do
  174. {
  175. pvert = &r_spritedesc.pverts[i];
  176. pnext = pvert - 1;
  177. vbottom = ceil (pnext->v);
  178. if (vtop < vbottom)
  179. {
  180. du = pnext->u - pvert->u;
  181. dv = pnext->v - pvert->v;
  182. slope = du / dv;
  183. u_step = (int)(slope * 0x10000);
  184. // adjust u to ceil the integer portion
  185. u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) +
  186. (0x10000 - 1);
  187. itop = (int)vtop;
  188. ibottom = (int)vbottom;
  189. for (v=itop ; v<ibottom ; v++)
  190. {
  191. pspan->u = u >> 16;
  192. pspan->v = v;
  193. u += u_step;
  194. pspan++;
  195. }
  196. }
  197. vtop = vbottom;
  198. i--;
  199. if (i == 0)
  200. i = r_spritedesc.nump;
  201. } while (i != lmaxindex);
  202. }
  203. /*
  204. =====================
  205. D_SpriteScanRightEdge
  206. =====================
  207. */
  208. void D_SpriteScanRightEdge (sspan_t *pspan, int minindex, int maxindex)
  209. {
  210. int i, v, itop, ibottom;
  211. emitpoint_t *pvert, *pnext;
  212. float du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext;
  213. fixed16_t u, u_step;
  214. i = minindex;
  215. vvert = r_spritedesc.pverts[i].v;
  216. if (vvert < r_refdef.fvrecty_adj)
  217. vvert = r_refdef.fvrecty_adj;
  218. if (vvert > r_refdef.fvrectbottom_adj)
  219. vvert = r_refdef.fvrectbottom_adj;
  220. vtop = ceil (vvert);
  221. do
  222. {
  223. pvert = &r_spritedesc.pverts[i];
  224. pnext = pvert + 1;
  225. vnext = pnext->v;
  226. if (vnext < r_refdef.fvrecty_adj)
  227. vnext = r_refdef.fvrecty_adj;
  228. if (vnext > r_refdef.fvrectbottom_adj)
  229. vnext = r_refdef.fvrectbottom_adj;
  230. vbottom = ceil (vnext);
  231. if (vtop < vbottom)
  232. {
  233. uvert = pvert->u;
  234. if (uvert < r_refdef.fvrectx_adj)
  235. uvert = r_refdef.fvrectx_adj;
  236. if (uvert > r_refdef.fvrectright_adj)
  237. uvert = r_refdef.fvrectright_adj;
  238. unext = pnext->u;
  239. if (unext < r_refdef.fvrectx_adj)
  240. unext = r_refdef.fvrectx_adj;
  241. if (unext > r_refdef.fvrectright_adj)
  242. unext = r_refdef.fvrectright_adj;
  243. du = unext - uvert;
  244. dv = vnext - vvert;
  245. slope = du / dv;
  246. u_step = (int)(slope * 0x10000);
  247. // adjust u to ceil the integer portion
  248. u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) +
  249. (0x10000 - 1);
  250. itop = (int)vtop;
  251. ibottom = (int)vbottom;
  252. for (v=itop ; v<ibottom ; v++)
  253. {
  254. pspan->count = (u >> 16) - pspan->u;
  255. u += u_step;
  256. pspan++;
  257. }
  258. }
  259. vtop = vbottom;
  260. vvert = vnext;
  261. i++;
  262. if (i == r_spritedesc.nump)
  263. i = 0;
  264. } while (i != maxindex);
  265. pspan->count = DS_SPAN_LIST_END; // mark the end of the span list
  266. }
  267. /*
  268. =====================
  269. D_SpriteCalculateGradients
  270. =====================
  271. */
  272. void D_SpriteCalculateGradients(int sprite_height)
  273. {
  274. vec3_t p_normal, p_saxis, p_taxis, p_temp1;
  275. float distinv;
  276. TransformVector (r_spritedesc.vpn, p_normal);
  277. TransformVector (r_spritedesc.vright, p_saxis);
  278. TransformVector (r_spritedesc.vup, p_taxis);
  279. VectorNegate (p_taxis, p_taxis);
  280. distinv = 1.0 / (-DotProduct (modelorg, r_spritedesc.vpn));
  281. d_sdivzstepu = p_saxis[0] * xscaleinv;
  282. d_tdivzstepu = p_taxis[0] * xscaleinv;
  283. d_sdivzstepv = -p_saxis[1] * yscaleinv;
  284. d_tdivzstepv = -p_taxis[1] * yscaleinv;
  285. d_zistepu = p_normal[0] * xscaleinv * distinv;
  286. d_zistepv = -p_normal[1] * yscaleinv * distinv;
  287. d_sdivzorigin = p_saxis[2] - xcenter * d_sdivzstepu -
  288. ycenter * d_sdivzstepv;
  289. d_tdivzorigin = p_taxis[2] - xcenter * d_tdivzstepu -
  290. ycenter * d_tdivzstepv;
  291. d_ziorigin = p_normal[2] * distinv - xcenter * d_zistepu -
  292. ycenter * d_zistepv;
  293. TransformVector (modelorg, p_temp1);
  294. sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) -
  295. (-(cachewidth >> 1) << 16);
  296. tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) -
  297. (-(sprite_height >> 1) << 16);
  298. // -1 (-epsilon) so we never wander off the edge of the texture
  299. bbextents = (cachewidth << 16) - 1;
  300. bbextentt = (sprite_height << 16) - 1;
  301. }
  302. /*
  303. =====================
  304. D_DrawSprite
  305. =====================
  306. */
  307. void D_DrawSprite (void)
  308. {
  309. int i, nump;
  310. float ymin, ymax;
  311. emitpoint_t *pverts;
  312. sspan_t spans[MAXHEIGHT+1];
  313. int minindex = 0, maxindex = 0;
  314. // find the top and bottom vertices, and make sure there's at least one scan to
  315. // draw
  316. ymin = 999999.9;
  317. ymax = -999999.9;
  318. pverts = r_spritedesc.pverts;
  319. for (i=0 ; i<r_spritedesc.nump ; i++)
  320. {
  321. if (pverts->v < ymin)
  322. {
  323. ymin = pverts->v;
  324. minindex = i;
  325. }
  326. if (pverts->v > ymax)
  327. {
  328. ymax = pverts->v;
  329. maxindex = i;
  330. }
  331. pverts++;
  332. }
  333. ymin = ceil (ymin);
  334. ymax = ceil (ymax);
  335. if (ymin >= ymax)
  336. return; // doesn't cross any scans at all
  337. cachewidth = r_spritedesc.pspriteframe->width;
  338. cacheblock = (byte *)&r_spritedesc.pspriteframe->pixels[0];
  339. // copy the first vertex to the last vertex, so we don't have to deal with
  340. // wrapping
  341. nump = r_spritedesc.nump;
  342. pverts = r_spritedesc.pverts;
  343. pverts[nump] = pverts[0];
  344. D_SpriteCalculateGradients(r_spritedesc.pspriteframe->height);
  345. D_SpriteScanLeftEdge (spans, minindex, maxindex);
  346. D_SpriteScanRightEdge (spans, minindex, maxindex);
  347. D_SpriteDrawSpans (spans);
  348. }