PageRenderTime 50ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/quakeforge/trunk/libs/video/renderer/sw/d_sprite.c

#
C | 418 lines | 288 code | 80 blank | 50 comment | 58 complexity | 4bafd8ff377cbbd58971837acf1b05af MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, AGPL-3.0, AGPL-1.0, Unlicense
  1. /*
  2. d_sprite.c
  3. software top-level rasterization driver module for drawing sprites
  4. Copyright (C) 1996-1997 Id Software, Inc.
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  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. See the GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to:
  15. Free Software Foundation, Inc.
  16. 59 Temple Place - Suite 330
  17. Boston, MA 02111-1307, USA
  18. */
  19. #ifdef HAVE_CONFIG_H
  20. # include "config.h"
  21. #endif
  22. static __attribute__ ((used)) const char rcsid[] =
  23. "$Id: d_sprite.c 11379 2007-03-10 12:00:59Z taniwha $";
  24. #include "QF/render.h"
  25. #include "d_local.h"
  26. static int sprite_height;
  27. static int minindex, maxindex;
  28. static sspan_t *sprite_spans;
  29. #ifdef PIC
  30. #undef USE_INTEL_ASM //XXX asm pic hack
  31. #endif
  32. #ifndef USE_INTEL_ASM
  33. void
  34. D_SpriteDrawSpans (sspan_t *pspan)
  35. {
  36. int count, spancount, izistep;
  37. int izi;
  38. byte *pbase, *pdest;
  39. fixed16_t s, t, snext, tnext, sstep, tstep;
  40. float sdivz, tdivz, zi, z, du, dv, spancountminus1;
  41. float sdivz8stepu, tdivz8stepu, zi8stepu;
  42. byte btemp;
  43. short *pz;
  44. sstep = 0; // keep compiler happy
  45. tstep = 0; // ditto
  46. pbase = cacheblock;
  47. sdivz8stepu = d_sdivzstepu * 8;
  48. tdivz8stepu = d_tdivzstepu * 8;
  49. zi8stepu = d_zistepu * 8;
  50. // we count on FP exceptions being turned off to avoid range problems
  51. izistep = (int) (d_zistepu * 0x8000 * 0x10000);
  52. do {
  53. pdest = (byte *) d_viewbuffer + (screenwidth * pspan->v) + pspan->u;
  54. pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
  55. count = pspan->count;
  56. if (count <= 0)
  57. goto NextSpan;
  58. // calculate the initial s/z, t/z, 1/z, s, and t and clamp
  59. du = (float) pspan->u;
  60. dv = (float) pspan->v;
  61. sdivz = d_sdivzorigin + dv * d_sdivzstepv + du * d_sdivzstepu;
  62. tdivz = d_tdivzorigin + dv * d_tdivzstepv + du * d_tdivzstepu;
  63. zi = d_ziorigin + dv * d_zistepv + du * d_zistepu;
  64. z = (float) 0x10000 / zi; // prescale to 16.16 fixed-point
  65. // we count on FP exceptions being turned off to avoid range problems
  66. izi = (int) (zi * 0x8000 * 0x10000);
  67. s = (int) (sdivz * z) + sadjust;
  68. if (s > bbextents)
  69. s = bbextents;
  70. else if (s < 0)
  71. s = 0;
  72. t = (int) (tdivz * z) + tadjust;
  73. if (t > bbextentt)
  74. t = bbextentt;
  75. else if (t < 0)
  76. t = 0;
  77. do {
  78. // calculate s and t at the far end of the span
  79. if (count >= 8)
  80. spancount = 8;
  81. else
  82. spancount = count;
  83. count -= spancount;
  84. if (count) {
  85. // calculate s/z, t/z, zi->fixed s and t at far end of span,
  86. // calculate s and t steps across span by shifting
  87. sdivz += sdivz8stepu;
  88. tdivz += tdivz8stepu;
  89. zi += zi8stepu;
  90. z = (float) 0x10000 / zi; // prescale to 16.16 fixed-point
  91. snext = (int) (sdivz * z) + sadjust;
  92. if (snext > bbextents)
  93. snext = bbextents;
  94. else if (snext < 8)
  95. snext = 8; // prevent round-off error on <0
  96. // steps from
  97. // from causing overstepping & running off the
  98. // edge of the texture
  99. tnext = (int) (tdivz * z) + tadjust;
  100. if (tnext > bbextentt)
  101. tnext = bbextentt;
  102. else if (tnext < 8)
  103. tnext = 8; // guard against round-off error on
  104. // <0 steps
  105. sstep = (snext - s) >> 3;
  106. tstep = (tnext - t) >> 3;
  107. } else {
  108. // calculate s/z, t/z, zi->fixed s and t at last pixel in
  109. // span (so can't step off polygon), clamp, calculate s and t
  110. // steps across span by division, biasing steps low so we
  111. // don't run off the texture
  112. spancountminus1 = (float) (spancount - 1);
  113. sdivz += d_sdivzstepu * spancountminus1;
  114. tdivz += d_tdivzstepu * spancountminus1;
  115. zi += d_zistepu * spancountminus1;
  116. z = (float) 0x10000 / zi; // prescale to 16.16 fixed-point
  117. snext = (int) (sdivz * z) + sadjust;
  118. if (snext > bbextents)
  119. snext = bbextents;
  120. else if (snext < 8)
  121. snext = 8; // prevent round-off error on <0 steps
  122. // from from causing overstepping &
  123. // running off the edge of the texture
  124. tnext = (int) (tdivz * z) + tadjust;
  125. if (tnext > bbextentt)
  126. tnext = bbextentt;
  127. else if (tnext < 8)
  128. tnext = 8; // guard against round-off error on
  129. // <0 steps
  130. if (spancount > 1) {
  131. sstep = (snext - s) / (spancount - 1);
  132. tstep = (tnext - t) / (spancount - 1);
  133. }
  134. }
  135. do {
  136. btemp = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
  137. if (btemp != 255) {
  138. if (*pz <= (izi >> 16)) {
  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. static void
  158. D_SpriteScanLeftEdge (void)
  159. {
  160. int i, v, itop, ibottom, lmaxindex;
  161. emitpoint_t *pvert, *pnext;
  162. sspan_t *pspan;
  163. float du, dv, vtop, vbottom, slope;
  164. fixed16_t u, u_step;
  165. pspan = sprite_spans;
  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. pvert = &r_spritedesc.pverts[i];
  175. pnext = pvert - 1;
  176. vbottom = ceil (pnext->v);
  177. if (vtop < vbottom) {
  178. du = pnext->u - pvert->u;
  179. dv = pnext->v - pvert->v;
  180. slope = du / dv;
  181. u_step = (int) (slope * 0x10000);
  182. // adjust u to ceil the integer portion
  183. u = (int) ((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) +
  184. (0x10000 - 1);
  185. itop = (int) vtop;
  186. ibottom = (int) vbottom;
  187. for (v = itop; v < ibottom; v++) {
  188. pspan->u = u >> 16;
  189. pspan->v = v;
  190. u += u_step;
  191. pspan++;
  192. }
  193. }
  194. vtop = vbottom;
  195. i--;
  196. if (i == 0)
  197. i = r_spritedesc.nump;
  198. } while (i != lmaxindex);
  199. }
  200. static void
  201. D_SpriteScanRightEdge (void)
  202. {
  203. int i, v, itop, ibottom;
  204. emitpoint_t *pvert, *pnext;
  205. sspan_t *pspan;
  206. float du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext;
  207. fixed16_t u, u_step;
  208. pspan = sprite_spans;
  209. i = minindex;
  210. vvert = r_spritedesc.pverts[i].v;
  211. if (vvert < r_refdef.fvrecty_adj)
  212. vvert = r_refdef.fvrecty_adj;
  213. if (vvert > r_refdef.fvrectbottom_adj)
  214. vvert = r_refdef.fvrectbottom_adj;
  215. vtop = ceil (vvert);
  216. do {
  217. pvert = &r_spritedesc.pverts[i];
  218. pnext = pvert + 1;
  219. vnext = pnext->v;
  220. if (vnext < r_refdef.fvrecty_adj)
  221. vnext = r_refdef.fvrecty_adj;
  222. if (vnext > r_refdef.fvrectbottom_adj)
  223. vnext = r_refdef.fvrectbottom_adj;
  224. vbottom = ceil (vnext);
  225. if (vtop < vbottom) {
  226. uvert = pvert->u;
  227. if (uvert < r_refdef.fvrectx_adj)
  228. uvert = r_refdef.fvrectx_adj;
  229. if (uvert > r_refdef.fvrectright_adj)
  230. uvert = r_refdef.fvrectright_adj;
  231. unext = pnext->u;
  232. if (unext < r_refdef.fvrectx_adj)
  233. unext = r_refdef.fvrectx_adj;
  234. if (unext > r_refdef.fvrectright_adj)
  235. unext = r_refdef.fvrectright_adj;
  236. du = unext - uvert;
  237. dv = vnext - vvert;
  238. slope = du / dv;
  239. u_step = (int) (slope * 0x10000);
  240. // adjust u to ceil the integer portion
  241. u = (int) ((uvert + (slope * (vtop - vvert))) * 0x10000) +
  242. (0x10000 - 1);
  243. itop = (int) vtop;
  244. ibottom = (int) vbottom;
  245. for (v = itop; v < ibottom; v++) {
  246. pspan->count = (u >> 16) - pspan->u;
  247. u += u_step;
  248. pspan++;
  249. }
  250. }
  251. vtop = vbottom;
  252. vvert = vnext;
  253. i++;
  254. if (i == r_spritedesc.nump)
  255. i = 0;
  256. } while (i != maxindex);
  257. pspan->count = DS_SPAN_LIST_END; // mark the end of the span list
  258. }
  259. static void
  260. D_SpriteCalculateGradients (void)
  261. {
  262. vec3_t p_normal, p_saxis, p_taxis, p_temp1;
  263. float distinv;
  264. TransformVector (r_spritedesc.vpn, p_normal);
  265. TransformVector (r_spritedesc.vright, p_saxis);
  266. TransformVector (r_spritedesc.vup, p_taxis);
  267. VectorNegate (p_taxis, p_taxis);
  268. distinv = 1.0 / (-DotProduct (modelorg, r_spritedesc.vpn));
  269. d_sdivzstepu = p_saxis[0] * xscaleinv;
  270. d_tdivzstepu = p_taxis[0] * xscaleinv;
  271. d_sdivzstepv = -p_saxis[1] * yscaleinv;
  272. d_tdivzstepv = -p_taxis[1] * yscaleinv;
  273. d_zistepu = p_normal[0] * xscaleinv * distinv;
  274. d_zistepv = -p_normal[1] * yscaleinv * distinv;
  275. d_sdivzorigin = p_saxis[2] - xcenter * d_sdivzstepu -
  276. ycenter * d_sdivzstepv;
  277. d_tdivzorigin = p_taxis[2] - xcenter * d_tdivzstepu -
  278. ycenter * d_tdivzstepv;
  279. d_ziorigin = p_normal[2] * distinv - xcenter * d_zistepu -
  280. ycenter * d_zistepv;
  281. TransformVector (modelorg, p_temp1);
  282. sadjust = ((fixed16_t) (DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) -
  283. (-(cachewidth >> 1) << 16);
  284. tadjust = ((fixed16_t) (DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) -
  285. (-(sprite_height >> 1) << 16);
  286. // -1 (-epsilon) so we never wander off the edge of the texture
  287. bbextents = (cachewidth << 16) - 1;
  288. bbextentt = (sprite_height << 16) - 1;
  289. }
  290. void
  291. D_DrawSprite (void)
  292. {
  293. int i, nump;
  294. float ymin, ymax;
  295. emitpoint_t *pverts;
  296. sspan_t spans[MAXHEIGHT + 1];
  297. sprite_spans = spans;
  298. // find the top and bottom vertices, and make sure there's at least one
  299. // scan to draw
  300. ymin = 999999.9;
  301. ymax = -999999.9;
  302. pverts = r_spritedesc.pverts;
  303. for (i = 0; i < r_spritedesc.nump; i++) {
  304. if (pverts->v < ymin) {
  305. ymin = pverts->v;
  306. minindex = i;
  307. }
  308. if (pverts->v > ymax) {
  309. ymax = pverts->v;
  310. maxindex = i;
  311. }
  312. pverts++;
  313. }
  314. ymin = ceil (ymin);
  315. ymax = ceil (ymax);
  316. if (ymin >= ymax)
  317. return; // doesn't cross any scans at all
  318. cachewidth = r_spritedesc.pspriteframe->width;
  319. sprite_height = r_spritedesc.pspriteframe->height;
  320. cacheblock = &r_spritedesc.pspriteframe->pixels[0];
  321. // copy the first vertex to the last vertex, so we don't have to deal with
  322. // wrapping
  323. nump = r_spritedesc.nump;
  324. pverts = r_spritedesc.pverts;
  325. pverts[nump] = pverts[0];
  326. D_SpriteCalculateGradients ();
  327. D_SpriteScanLeftEdge ();
  328. D_SpriteScanRightEdge ();
  329. D_SpriteDrawSpans (sprite_spans);
  330. }