summaryrefslogtreecommitdiff
path: root/apps/plugins/sdl/progs/quake/r_edge.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/sdl/progs/quake/r_edge.c')
-rw-r--r--apps/plugins/sdl/progs/quake/r_edge.c775
1 files changed, 775 insertions, 0 deletions
diff --git a/apps/plugins/sdl/progs/quake/r_edge.c b/apps/plugins/sdl/progs/quake/r_edge.c
new file mode 100644
index 0000000000..1fff765a3a
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/r_edge.c
@@ -0,0 +1,775 @@
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// r_edge.c
21
22#include "quakedef.h"
23#include "r_local.h"
24
25#if 0
26// FIXME
27the complex cases add new polys on most lines, so dont optimize for keeping them the same
28have multiple free span lists to try to get better coherence?
29low depth complexity -- 1 to 3 or so
30
31this breaks spans at every edge, even hidden ones (bad)
32
33have a sentinal at both ends?
34#endif
35
36
37edge_t *auxedges;
38edge_t *r_edges, *edge_p, *edge_max;
39
40surf_t *surfaces, *surface_p, *surf_max;
41
42// surfaces are generated in back to front order by the bsp, so if a surf
43// pointer is greater than another one, it should be drawn in front
44// surfaces[1] is the background, and is used as the active surface stack
45
46edge_t *newedges[MAXHEIGHT];
47edge_t *removeedges[MAXHEIGHT];
48
49espan_t *span_p, *max_span_p;
50
51int r_currentkey;
52
53extern int screenwidth;
54
55int current_iv;
56
57int edge_head_u_shift20, edge_tail_u_shift20;
58
59static void (*pdrawfunc)(void);
60
61edge_t edge_head;
62edge_t edge_tail;
63edge_t edge_aftertail;
64edge_t edge_sentinel;
65
66float fv;
67
68void R_GenerateSpans (void);
69void R_GenerateSpansBackward (void);
70
71// made static
72//void R_LeadingEdge (edge_t *edge);
73//void R_LeadingEdgeBackwards (edge_t *edge);
74//void R_TrailingEdge (surf_t *surf, edge_t *edge);
75
76
77//=============================================================================
78
79
80/*
81==============
82R_DrawCulledPolys
83==============
84*/
85static inline void R_DrawCulledPolys (void)
86{
87 surf_t *s;
88 msurface_t *pface;
89
90 currententity = &cl_entities[0];
91
92 if (r_worldpolysbacktofront)
93 {
94 for (s=surface_p-1 ; s>&surfaces[1] ; s--)
95 {
96 if (!s->spans)
97 continue;
98
99 if (!(s->flags & SURF_DRAWBACKGROUND))
100 {
101 pface = (msurface_t *)s->data;
102 R_RenderPoly (pface, 15);
103 }
104 }
105 }
106 else
107 {
108 for (s = &surfaces[1] ; s<surface_p ; s++)
109 {
110 if (!s->spans)
111 continue;
112
113 if (!(s->flags & SURF_DRAWBACKGROUND))
114 {
115 pface = (msurface_t *)s->data;
116 R_RenderPoly (pface, 15);
117 }
118 }
119 }
120}
121
122
123/*
124==============
125R_BeginEdgeFrame
126==============
127*/
128void R_BeginEdgeFrame (void)
129{
130 int v;
131
132 edge_p = r_edges;
133 edge_max = &r_edges[r_numallocatededges];
134
135 surface_p = &surfaces[2]; // background is surface 1,
136 // surface 0 is a dummy
137 surfaces[1].spans = NULL; // no background spans yet
138 surfaces[1].flags = SURF_DRAWBACKGROUND;
139
140// put the background behind everything in the world
141 if (r_draworder.value)
142 {
143 pdrawfunc = R_GenerateSpansBackward;
144 surfaces[1].key = 0;
145 r_currentkey = 1;
146 }
147 else
148 {
149 pdrawfunc = R_GenerateSpans;
150 surfaces[1].key = 0x7FFFFFFF;
151 r_currentkey = 0;
152 }
153
154// FIXME: set with memset
155 for (v=r_refdef.vrect.y ; v<r_refdef.vrectbottom ; v++)
156 {
157 newedges[v] = removeedges[v] = NULL;
158 }
159}
160
161
162#if !id386
163
164/*
165==============
166R_InsertNewEdges
167
168Adds the edges in the linked list edgestoadd, adding them to the edges in the
169linked list edgelist. edgestoadd is assumed to be sorted on u, and non-empty (this is actually newedges[v]). edgelist is assumed to be sorted on u, with a
170sentinel at the end (actually, this is the active edge table starting at
171edge_head.next).
172==============
173*/
174void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist)
175{
176 edge_t *next_edge;
177
178 do
179 {
180 next_edge = edgestoadd->next;
181edgesearch:
182 if (edgelist->u >= edgestoadd->u)
183 goto addedge;
184 edgelist=edgelist->next;
185 if (edgelist->u >= edgestoadd->u)
186 goto addedge;
187 edgelist=edgelist->next;
188 if (edgelist->u >= edgestoadd->u)
189 goto addedge;
190 edgelist=edgelist->next;
191 if (edgelist->u >= edgestoadd->u)
192 goto addedge;
193 edgelist=edgelist->next;
194 goto edgesearch;
195
196 // insert edgestoadd before edgelist
197addedge:
198 edgestoadd->next = edgelist;
199 edgestoadd->prev = edgelist->prev;
200 edgelist->prev->next = edgestoadd;
201 edgelist->prev = edgestoadd;
202 } while ((edgestoadd = next_edge) != NULL);
203}
204
205#endif // !id386
206
207
208#if !id386
209
210/*
211==============
212R_RemoveEdges
213==============
214*/
215void R_RemoveEdges (edge_t *pedge)
216{
217
218 do
219 {
220 pedge->next->prev = pedge->prev;
221 pedge->prev->next = pedge->next;
222 } while ((pedge = pedge->nextremove) != NULL);
223}
224
225#endif // !id386
226
227
228#if !id386
229
230/*
231==============
232R_StepActiveU
233==============
234*/
235void R_StepActiveU (edge_t *pedge)
236{
237 edge_t *pnext_edge, *pwedge;
238
239 while (1)
240 {
241nextedge:
242 pedge->u += pedge->u_step;
243 if (pedge->u < pedge->prev->u)
244 goto pushback;
245 pedge = pedge->next;
246
247 pedge->u += pedge->u_step;
248 if (pedge->u < pedge->prev->u)
249 goto pushback;
250 pedge = pedge->next;
251
252 pedge->u += pedge->u_step;
253 if (pedge->u < pedge->prev->u)
254 goto pushback;
255 pedge = pedge->next;
256
257 pedge->u += pedge->u_step;
258 if (pedge->u < pedge->prev->u)
259 goto pushback;
260 pedge = pedge->next;
261
262 goto nextedge;
263
264pushback:
265 if (pedge == &edge_aftertail)
266 return;
267
268 // push it back to keep it sorted
269 pnext_edge = pedge->next;
270
271 // pull the edge out of the edge list
272 pedge->next->prev = pedge->prev;
273 pedge->prev->next = pedge->next;
274
275 // find out where the edge goes in the edge list
276 pwedge = pedge->prev->prev;
277
278 while (pwedge->u > pedge->u)
279 {
280 pwedge = pwedge->prev;
281 }
282
283 // put the edge back into the edge list
284 pedge->next = pwedge->next;
285 pedge->prev = pwedge;
286 pedge->next->prev = pedge;
287 pwedge->next = pedge;
288
289 pedge = pnext_edge;
290 if (pedge == &edge_tail)
291 return;
292 }
293}
294
295#endif // !id386
296
297
298/*
299==============
300R_CleanupSpan
301==============
302*/
303void R_CleanupSpan ()
304{
305 surf_t *surf;
306 int iu;
307 espan_t *span;
308
309// now that we've reached the right edge of the screen, we're done with any
310// unfinished surfaces, so emit a span for whatever's on top
311 surf = surfaces[1].next;
312 iu = edge_tail_u_shift20;
313 if (iu > surf->last_u)
314 {
315 span = span_p++;
316 span->u = surf->last_u;
317 span->count = iu - span->u;
318 span->v = current_iv;
319 span->pnext = surf->spans;
320 surf->spans = span;
321 }
322
323// reset spanstate for all surfaces in the surface stack
324 do
325 {
326 surf->spanstate = 0;
327 surf = surf->next;
328 } while (surf != &surfaces[1]);
329}
330
331
332/*
333==============
334R_LeadingEdgeBackwards
335==============
336*/
337static inline void R_LeadingEdgeBackwards (edge_t *edge)
338{
339 espan_t *span;
340 surf_t *surf, *surf2;
341 int iu;
342
343// it's adding a new surface in, so find the correct place
344 surf = &surfaces[edge->surfs[1]];
345
346// don't start a span if this is an inverted span, with the end
347// edge preceding the start edge (that is, we've already seen the
348// end edge)
349 if (++surf->spanstate == 1)
350 {
351 surf2 = surfaces[1].next;
352
353 if (surf->key > surf2->key)
354 goto newtop;
355
356 // if it's two surfaces on the same plane, the one that's already
357 // active is in front, so keep going unless it's a bmodel
358 if (surf->insubmodel && (surf->key == surf2->key))
359 {
360 // must be two bmodels in the same leaf; don't care, because they'll
361 // never be farthest anyway
362 goto newtop;
363 }
364
365continue_search:
366
367 do
368 {
369 surf2 = surf2->next;
370 } while (surf->key < surf2->key);
371
372 if (surf->key == surf2->key)
373 {
374 // if it's two surfaces on the same plane, the one that's already
375 // active is in front, so keep going unless it's a bmodel
376 if (!surf->insubmodel)
377 goto continue_search;
378
379 // must be two bmodels in the same leaf; don't care which is really
380 // in front, because they'll never be farthest anyway
381 }
382
383 goto gotposition;
384
385newtop:
386 // emit a span (obscures current top)
387 iu = edge->u >> 20;
388
389 if (iu > surf2->last_u)
390 {
391 span = span_p++;
392 span->u = surf2->last_u;
393 span->count = iu - span->u;
394 span->v = current_iv;
395 span->pnext = surf2->spans;
396 surf2->spans = span;
397 }
398
399 // set last_u on the new span
400 surf->last_u = iu;
401
402gotposition:
403 // insert before surf2
404 surf->next = surf2;
405 surf->prev = surf2->prev;
406 surf2->prev->next = surf;
407 surf2->prev = surf;
408 }
409}
410
411
412/*
413==============
414R_TrailingEdge
415==============
416*/
417static inline void R_TrailingEdge (surf_t *surf, edge_t *edge)
418{
419 espan_t *span;
420 int iu;
421
422// don't generate a span if this is an inverted span, with the end
423// edge preceding the start edge (that is, we haven't seen the
424// start edge yet)
425 if (--surf->spanstate == 0)
426 {
427 if (surf->insubmodel)
428 r_bmodelactive--;
429
430 if (surf == surfaces[1].next)
431 {
432 // emit a span (current top going away)
433 iu = edge->u >> 20;
434 if (iu > surf->last_u)
435 {
436 span = span_p++;
437 span->u = surf->last_u;
438 span->count = iu - span->u;
439 span->v = current_iv;
440 span->pnext = surf->spans;
441 surf->spans = span;
442 }
443
444 // set last_u on the surface below
445 surf->next->last_u = iu;
446 }
447
448 surf->prev->next = surf->next;
449 surf->next->prev = surf->prev;
450 }
451}
452
453
454#if !id386
455
456/*
457==============
458R_LeadingEdge
459==============
460*/
461static inline void R_LeadingEdge (edge_t *edge)
462{
463 espan_t *span;
464 surf_t *surf, *surf2;
465 int iu;
466 double fu, newzi, testzi, newzitop, newzibottom;
467
468 if (edge->surfs[1])
469 {
470 // it's adding a new surface in, so find the correct place
471 surf = &surfaces[edge->surfs[1]];
472
473 // don't start a span if this is an inverted span, with the end
474 // edge preceding the start edge (that is, we've already seen the
475 // end edge)
476 if (++surf->spanstate == 1)
477 {
478 if (surf->insubmodel)
479 r_bmodelactive++;
480
481 surf2 = surfaces[1].next;
482
483 if (surf->key < surf2->key)
484 goto newtop;
485
486 // if it's two surfaces on the same plane, the one that's already
487 // active is in front, so keep going unless it's a bmodel
488 if (surf->insubmodel && (surf->key == surf2->key))
489 {
490 // must be two bmodels in the same leaf; sort on 1/z
491 fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
492 newzi = surf->d_ziorigin + fv*surf->d_zistepv +
493 fu*surf->d_zistepu;
494 newzibottom = newzi * 0.99;
495
496 testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
497 fu*surf2->d_zistepu;
498
499 if (newzibottom >= testzi)
500 {
501 goto newtop;
502 }
503
504 newzitop = newzi * 1.01;
505 if (newzitop >= testzi)
506 {
507 if (surf->d_zistepu >= surf2->d_zistepu)
508 {
509 goto newtop;
510 }
511 }
512 }
513
514continue_search:
515
516 do
517 {
518 surf2 = surf2->next;
519 } while (surf->key > surf2->key);
520
521 if (surf->key == surf2->key)
522 {
523 // if it's two surfaces on the same plane, the one that's already
524 // active is in front, so keep going unless it's a bmodel
525 if (!surf->insubmodel)
526 goto continue_search;
527
528 // must be two bmodels in the same leaf; sort on 1/z
529 fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
530 newzi = surf->d_ziorigin + fv*surf->d_zistepv +
531 fu*surf->d_zistepu;
532 newzibottom = newzi * 0.99;
533
534 testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
535 fu*surf2->d_zistepu;
536
537 if (newzibottom >= testzi)
538 {
539 goto gotposition;
540 }
541
542 newzitop = newzi * 1.01;
543 if (newzitop >= testzi)
544 {
545 if (surf->d_zistepu >= surf2->d_zistepu)
546 {
547 goto gotposition;
548 }
549 }
550
551 goto continue_search;
552 }
553
554 goto gotposition;
555
556newtop:
557 // emit a span (obscures current top)
558 iu = edge->u >> 20;
559
560 if (iu > surf2->last_u)
561 {
562 span = span_p++;
563 span->u = surf2->last_u;
564 span->count = iu - span->u;
565 span->v = current_iv;
566 span->pnext = surf2->spans;
567 surf2->spans = span;
568 }
569
570 // set last_u on the new span
571 surf->last_u = iu;
572
573gotposition:
574 // insert before surf2
575 surf->next = surf2;
576 surf->prev = surf2->prev;
577 surf2->prev->next = surf;
578 surf2->prev = surf;
579 }
580 }
581}
582
583
584/*
585==============
586R_GenerateSpans
587==============
588*/
589void R_GenerateSpans (void)
590{
591 edge_t *edge;
592 surf_t *surf;
593
594 r_bmodelactive = 0;
595
596// clear active surfaces to just the background surface
597 surfaces[1].next = surfaces[1].prev = &surfaces[1];
598 surfaces[1].last_u = edge_head_u_shift20;
599
600// generate spans
601 for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
602 {
603 if (edge->surfs[0])
604 {
605 // it has a left surface, so a surface is going away for this span
606 surf = &surfaces[edge->surfs[0]];
607
608 R_TrailingEdge (surf, edge);
609
610 if (!edge->surfs[1])
611 continue;
612 }
613
614 R_LeadingEdge (edge);
615 }
616
617 R_CleanupSpan ();
618}
619
620#endif // !id386
621
622
623/*
624==============
625R_GenerateSpansBackward
626==============
627*/
628void R_GenerateSpansBackward (void)
629{
630 edge_t *edge;
631
632 r_bmodelactive = 0;
633
634// clear active surfaces to just the background surface
635 surfaces[1].next = surfaces[1].prev = &surfaces[1];
636 surfaces[1].last_u = edge_head_u_shift20;
637
638// generate spans
639 for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
640 {
641 if (edge->surfs[0])
642 R_TrailingEdge (&surfaces[edge->surfs[0]], edge);
643
644 if (edge->surfs[1])
645 R_LeadingEdgeBackwards (edge);
646 }
647
648 R_CleanupSpan ();
649}
650
651
652/*
653==============
654R_ScanEdges
655
656Input:
657newedges[] array
658 this has links to edges, which have links to surfaces
659
660Output:
661Each surface has a linked list of its visible spans
662==============
663*/
664void R_ScanEdges (void)
665{
666 int iv, bottom;
667 byte basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE];
668 espan_t *basespan_p;
669 surf_t *s;
670
671 basespan_p = (espan_t *)
672 ((long)(basespans + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
673 max_span_p = &basespan_p[MAXSPANS - r_refdef.vrect.width];
674
675 span_p = basespan_p;
676
677// clear active edges to just the background edges around the whole screen
678// FIXME: most of this only needs to be set up once
679 edge_head.u = r_refdef.vrect.x << 20;
680 edge_head_u_shift20 = edge_head.u >> 20;
681 edge_head.u_step = 0;
682 edge_head.prev = NULL;
683 edge_head.next = &edge_tail;
684 edge_head.surfs[0] = 0;
685 edge_head.surfs[1] = 1;
686
687 edge_tail.u = (r_refdef.vrectright << 20) + 0xFFFFF;
688 edge_tail_u_shift20 = edge_tail.u >> 20;
689 edge_tail.u_step = 0;
690 edge_tail.prev = &edge_head;
691 edge_tail.next = &edge_aftertail;
692 edge_tail.surfs[0] = 1;
693 edge_tail.surfs[1] = 0;
694
695 edge_aftertail.u = -1; // force a move
696 edge_aftertail.u_step = 0;
697 edge_aftertail.next = &edge_sentinel;
698 edge_aftertail.prev = &edge_tail;
699
700// FIXME: do we need this now that we clamp x in r_draw.c?
701 edge_sentinel.u = 2000 << 24; // make sure nothing sorts past this
702 edge_sentinel.prev = &edge_aftertail;
703
704//
705// process all scan lines
706//
707 bottom = r_refdef.vrectbottom - 1;
708
709 for (iv=r_refdef.vrect.y ; iv<bottom ; iv++)
710 {
711 current_iv = iv;
712 fv = (float)iv;
713
714 // mark that the head (background start) span is pre-included
715 surfaces[1].spanstate = 1;
716
717 if (newedges[iv])
718 {
719 R_InsertNewEdges (newedges[iv], edge_head.next);
720 }
721
722 (*pdrawfunc) ();
723
724 // flush the span list if we can't be sure we have enough spans left for
725 // the next scan
726 if (span_p >= max_span_p)
727 {
728 VID_UnlockBuffer ();
729 S_ExtraUpdate (); // don't let sound get messed up if going slow
730 VID_LockBuffer ();
731
732 if (r_drawculledpolys)
733 {
734 R_DrawCulledPolys ();
735 }
736 else
737 {
738 D_DrawSurfaces ();
739 }
740
741 // clear the surface span pointers
742 for (s = &surfaces[1] ; s<surface_p ; s++)
743 s->spans = NULL;
744
745 span_p = basespan_p;
746 }
747
748 if (removeedges[iv])
749 R_RemoveEdges (removeedges[iv]);
750
751 if (edge_head.next != &edge_tail)
752 R_StepActiveU (edge_head.next);
753 }
754
755// do the last scan (no need to step or sort or remove on the last scan)
756
757 current_iv = iv;
758 fv = (float)iv;
759
760// mark that the head (background start) span is pre-included
761 surfaces[1].spanstate = 1;
762
763 if (newedges[iv])
764 R_InsertNewEdges (newedges[iv], edge_head.next);
765
766 (*pdrawfunc) ();
767
768// draw whatever's left in the span list
769 if (r_drawculledpolys)
770 R_DrawCulledPolys ();
771 else
772 D_DrawSurfaces ();
773}
774
775