summaryrefslogtreecommitdiff
path: root/apps/plugins/sdl/progs/quake/d_sprite.c
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2018-02-11 15:34:30 -0500
committerFranklin Wei <git@fwei.tk>2019-07-19 22:37:40 -0400
commit5d05b9d3e920a6aa5fcb553758e98ed0da8c91e4 (patch)
tree84406e21639529a185556a33e5de7f43cffc277b /apps/plugins/sdl/progs/quake/d_sprite.c
parentb70fecf21ddc21877ec1ae7888d9c18a979e37ad (diff)
downloadrockbox-5d05b9d3e920a6aa5fcb553758e98ed0da8c91e4.tar.gz
rockbox-5d05b9d3e920a6aa5fcb553758e98ed0da8c91e4.zip
Quake!
This ports id Software's Quake to run on the SDL plugin runtime. The source code originated from id under the GPLv2 license. I used https://github.com/ahefner/sdlquake as the base of my port. Performance is, unsurprisingly, not on par with what you're probably used to on PC. I average about 10FPS on ipod6g, but it's still playable. Sound works well enough, but in-game music is not supported. I've written ARM assembly routines for the inner sound loop. Make sure you turn the "brightness" all the way down, or colors will look funky. To run, extract Quake's data files to /.rockbox/quake. Have fun! Change-Id: I4285036e967d7f0722802d43cf2096c808ca5799
Diffstat (limited to 'apps/plugins/sdl/progs/quake/d_sprite.c')
-rw-r--r--apps/plugins/sdl/progs/quake/d_sprite.c442
1 files changed, 442 insertions, 0 deletions
diff --git a/apps/plugins/sdl/progs/quake/d_sprite.c b/apps/plugins/sdl/progs/quake/d_sprite.c
new file mode 100644
index 0000000000..2f02ad2c64
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/d_sprite.c
@@ -0,0 +1,442 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// d_sprite.c: software top-level rasterization driver module for drawing
21// sprites
22
23#include "quakedef.h"
24#include "d_local.h"
25
26static int sprite_height;
27static int minindex, maxindex;
28static sspan_t *sprite_spans;
29
30#if !id386
31
32/*
33=====================
34D_SpriteDrawSpans
35=====================
36*/
37void D_SpriteDrawSpans (sspan_t *pspan)
38{
39 int count, spancount, izistep;
40 int izi;
41 byte *pbase, *pdest;
42 fixed16_t s, t, snext, tnext, sstep, tstep;
43 float sdivz, tdivz, zi, z, du, dv, spancountminus1;
44 float sdivz8stepu, tdivz8stepu, zi8stepu;
45 byte btemp;
46 short *pz;
47
48 sstep = 0; // keep compiler happy
49 tstep = 0; // ditto
50
51 pbase = cacheblock;
52
53 sdivz8stepu = d_sdivzstepu * 8;
54 tdivz8stepu = d_tdivzstepu * 8;
55 zi8stepu = d_zistepu * 8;
56
57// we count on FP exceptions being turned off to avoid range problems
58 izistep = (int)(d_zistepu * 0x8000 * 0x10000);
59
60 do
61 {
62 pdest = (byte *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u;
63 pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
64
65 count = pspan->count;
66
67 if (count <= 0)
68 goto NextSpan;
69
70 // calculate the initial s/z, t/z, 1/z, s, and t and clamp
71 du = (float)pspan->u;
72 dv = (float)pspan->v;
73
74 sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
75 tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
76 zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
77 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
78 // we count on FP exceptions being turned off to avoid range problems
79 izi = (int)(zi * 0x8000 * 0x10000);
80
81 s = (int)(sdivz * z) + sadjust;
82 if (s > bbextents)
83 s = bbextents;
84 else if (s < 0)
85 s = 0;
86
87 t = (int)(tdivz * z) + tadjust;
88 if (t > bbextentt)
89 t = bbextentt;
90 else if (t < 0)
91 t = 0;
92
93 do
94 {
95 // calculate s and t at the far end of the span
96 if (count >= 8)
97 spancount = 8;
98 else
99 spancount = count;
100
101 count -= spancount;
102
103 if (count)
104 {
105 // calculate s/z, t/z, zi->fixed s and t at far end of span,
106 // calculate s and t steps across span by shifting
107 sdivz += sdivz8stepu;
108 tdivz += tdivz8stepu;
109 zi += zi8stepu;
110 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
111
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
120 tnext = (int)(tdivz * z) + tadjust;
121 if (tnext > bbextentt)
122 tnext = bbextentt;
123 else if (tnext < 8)
124 tnext = 8; // guard against round-off error on <0 steps
125
126 sstep = (snext - s) >> 3;
127 tstep = (tnext - t) >> 3;
128 }
129 else
130 {
131 // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
132 // can't step off polygon), clamp, calculate s and t steps across
133 // span by division, biasing steps low so we don't run off the
134 // texture
135 spancountminus1 = (float)(spancount - 1);
136 sdivz += d_sdivzstepu * spancountminus1;
137 tdivz += d_tdivzstepu * spancountminus1;
138 zi += d_zistepu * spancountminus1;
139 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
140 snext = (int)(sdivz * z) + sadjust;
141 if (snext > bbextents)
142 snext = bbextents;
143 else if (snext < 8)
144 snext = 8; // prevent round-off error on <0 steps from
145 // from causing overstepping & running off the
146 // edge of the texture
147
148 tnext = (int)(tdivz * z) + tadjust;
149 if (tnext > bbextentt)
150 tnext = bbextentt;
151 else if (tnext < 8)
152 tnext = 8; // guard against round-off error on <0 steps
153
154 if (spancount > 1)
155 {
156 sstep = (snext - s) / (spancount - 1);
157 tstep = (tnext - t) / (spancount - 1);
158 }
159 }
160
161 do
162 {
163 btemp = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
164 if (btemp != 255)
165 {
166 if (*pz <= (izi >> 16))
167 {
168 *pz = izi >> 16;
169 *pdest = btemp;
170 }
171 }
172
173 izi += izistep;
174 pdest++;
175 pz++;
176 s += sstep;
177 t += tstep;
178 } while (--spancount > 0);
179
180 s = snext;
181 t = tnext;
182
183 } while (count > 0);
184
185NextSpan:
186 pspan++;
187
188 } while (pspan->count != DS_SPAN_LIST_END);
189}
190
191#endif
192
193
194/*
195=====================
196D_SpriteScanLeftEdge
197=====================
198*/
199void D_SpriteScanLeftEdge (void)
200{
201 int i, v, itop, ibottom, lmaxindex;
202 emitpoint_t *pvert, *pnext;
203 sspan_t *pspan;
204 float du, dv, vtop, vbottom, slope;
205 fixed16_t u, u_step;
206
207 pspan = sprite_spans;
208 i = minindex;
209 if (i == 0)
210 i = r_spritedesc.nump;
211
212 lmaxindex = maxindex;
213 if (lmaxindex == 0)
214 lmaxindex = r_spritedesc.nump;
215
216 vtop = ceil (r_spritedesc.pverts[i].v);
217
218 do
219 {
220 pvert = &r_spritedesc.pverts[i];
221 pnext = pvert - 1;
222
223 vbottom = ceil (pnext->v);
224
225 if (vtop < vbottom)
226 {
227 du = pnext->u - pvert->u;
228 dv = pnext->v - pvert->v;
229 slope = du / dv;
230 u_step = (int)(slope * 0x10000);
231 // adjust u to ceil the integer portion
232 u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) +
233 (0x10000 - 1);
234 itop = (int)vtop;
235 ibottom = (int)vbottom;
236
237 for (v=itop ; v<ibottom ; v++)
238 {
239 pspan->u = u >> 16;
240 pspan->v = v;
241 u += u_step;
242 pspan++;
243 }
244 }
245
246 vtop = vbottom;
247
248 i--;
249 if (i == 0)
250 i = r_spritedesc.nump;
251
252 } while (i != lmaxindex);
253}
254
255
256/*
257=====================
258D_SpriteScanRightEdge
259=====================
260*/
261void D_SpriteScanRightEdge (void)
262{
263 int i, v, itop, ibottom;
264 emitpoint_t *pvert, *pnext;
265 sspan_t *pspan;
266 float du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext;
267 fixed16_t u, u_step;
268
269 pspan = sprite_spans;
270 i = minindex;
271
272 vvert = r_spritedesc.pverts[i].v;
273 if (vvert < r_refdef.fvrecty_adj)
274 vvert = r_refdef.fvrecty_adj;
275 if (vvert > r_refdef.fvrectbottom_adj)
276 vvert = r_refdef.fvrectbottom_adj;
277
278 vtop = ceil (vvert);
279
280 do
281 {
282 pvert = &r_spritedesc.pverts[i];
283 pnext = pvert + 1;
284
285 vnext = pnext->v;
286 if (vnext < r_refdef.fvrecty_adj)
287 vnext = r_refdef.fvrecty_adj;
288 if (vnext > r_refdef.fvrectbottom_adj)
289 vnext = r_refdef.fvrectbottom_adj;
290
291 vbottom = ceil (vnext);
292
293 if (vtop < vbottom)
294 {
295 uvert = pvert->u;
296 if (uvert < r_refdef.fvrectx_adj)
297 uvert = r_refdef.fvrectx_adj;
298 if (uvert > r_refdef.fvrectright_adj)
299 uvert = r_refdef.fvrectright_adj;
300
301 unext = pnext->u;
302 if (unext < r_refdef.fvrectx_adj)
303 unext = r_refdef.fvrectx_adj;
304 if (unext > r_refdef.fvrectright_adj)
305 unext = r_refdef.fvrectright_adj;
306
307 du = unext - uvert;
308 dv = vnext - vvert;
309 slope = du / dv;
310 u_step = (int)(slope * 0x10000);
311 // adjust u to ceil the integer portion
312 u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) +
313 (0x10000 - 1);
314 itop = (int)vtop;
315 ibottom = (int)vbottom;
316
317 for (v=itop ; v<ibottom ; v++)
318 {
319 pspan->count = (u >> 16) - pspan->u;
320 u += u_step;
321 pspan++;
322 }
323 }
324
325 vtop = vbottom;
326 vvert = vnext;
327
328 i++;
329 if (i == r_spritedesc.nump)
330 i = 0;
331
332 } while (i != maxindex);
333
334 pspan->count = DS_SPAN_LIST_END; // mark the end of the span list
335}
336
337
338/*
339=====================
340D_SpriteCalculateGradients
341=====================
342*/
343void D_SpriteCalculateGradients (void)
344{
345 vec3_t p_normal, p_saxis, p_taxis, p_temp1;
346 float distinv;
347
348 TransformVector (r_spritedesc.vpn, p_normal);
349 TransformVector (r_spritedesc.vright, p_saxis);
350 TransformVector (r_spritedesc.vup, p_taxis);
351 VectorInverse (p_taxis);
352
353 distinv = 1.0 / (-DotProduct (modelorg, r_spritedesc.vpn));
354
355 d_sdivzstepu = p_saxis[0] * xscaleinv;
356 d_tdivzstepu = p_taxis[0] * xscaleinv;
357
358 d_sdivzstepv = -p_saxis[1] * yscaleinv;
359 d_tdivzstepv = -p_taxis[1] * yscaleinv;
360
361 d_zistepu = p_normal[0] * xscaleinv * distinv;
362 d_zistepv = -p_normal[1] * yscaleinv * distinv;
363
364 d_sdivzorigin = p_saxis[2] - xcenter * d_sdivzstepu -
365 ycenter * d_sdivzstepv;
366 d_tdivzorigin = p_taxis[2] - xcenter * d_tdivzstepu -
367 ycenter * d_tdivzstepv;
368 d_ziorigin = p_normal[2] * distinv - xcenter * d_zistepu -
369 ycenter * d_zistepv;
370
371 TransformVector (modelorg, p_temp1);
372
373 sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) -
374 (-(cachewidth >> 1) << 16);
375 tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) -
376 (-(sprite_height >> 1) << 16);
377
378// -1 (-epsilon) so we never wander off the edge of the texture
379 bbextents = (cachewidth << 16) - 1;
380 bbextentt = (sprite_height << 16) - 1;
381}
382
383
384/*
385=====================
386D_DrawSprite
387=====================
388*/
389void D_DrawSprite (void)
390{
391 int i, nump;
392 float ymin, ymax;
393 emitpoint_t *pverts;
394 sspan_t spans[MAXHEIGHT+1];
395
396 sprite_spans = spans;
397
398// find the top and bottom vertices, and make sure there's at least one scan to
399// draw
400 ymin = 999999.9;
401 ymax = -999999.9;
402 pverts = r_spritedesc.pverts;
403
404 for (i=0 ; i<r_spritedesc.nump ; i++)
405 {
406 if (pverts->v < ymin)
407 {
408 ymin = pverts->v;
409 minindex = i;
410 }
411
412 if (pverts->v > ymax)
413 {
414 ymax = pverts->v;
415 maxindex = i;
416 }
417
418 pverts++;
419 }
420
421 ymin = ceil (ymin);
422 ymax = ceil (ymax);
423
424 if (ymin >= ymax)
425 return; // doesn't cross any scans at all
426
427 cachewidth = r_spritedesc.pspriteframe->width;
428 sprite_height = r_spritedesc.pspriteframe->height;
429 cacheblock = (byte *)&r_spritedesc.pspriteframe->pixels[0];
430
431// copy the first vertex to the last vertex, so we don't have to deal with
432// wrapping
433 nump = r_spritedesc.nump;
434 pverts = r_spritedesc.pverts;
435 pverts[nump] = pverts[0];
436
437 D_SpriteCalculateGradients ();
438 D_SpriteScanLeftEdge ();
439 D_SpriteScanRightEdge ();
440 D_SpriteDrawSpans (sprite_spans);
441}
442