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