d_sprite.c 9.9 KB

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