git-svn-id: http://bladebattles.com/kurok/SVN@11 20cd92bb-ff49-0410-b73e-96a06e42c3b9
[kurok.git] / r_edge.c
blob700ccaa42088e9c506f9f3b30fe2d97e82c02be0
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 // r_edge.c
22 #include "quakedef.h"
23 #include "r_local.h"
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
31 this breaks spans at every edge, even hidden ones (bad)
33 have a sentinal at both ends?
34 #endif
37 edge_t *auxedges;
38 edge_t *r_edges, *edge_p, *edge_max;
40 surf_t *surfaces, *surface_p, *surf_max;
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
46 edge_t *newedges[MAXHEIGHT];
47 edge_t *removeedges[MAXHEIGHT];
49 espan_t *span_p, *max_span_p;
51 int r_currentkey;
53 extern int screenwidth;
55 int current_iv;
57 int edge_head_u_shift20, edge_tail_u_shift20;
59 static void (*pdrawfunc)(void);
61 edge_t edge_head;
62 edge_t edge_tail;
63 edge_t edge_aftertail;
64 edge_t edge_sentinel;
66 float fv;
68 void R_GenerateSpans (void);
69 void R_GenerateSpansBackward (void);
71 void R_LeadingEdge (edge_t *edge);
72 void R_LeadingEdgeBackwards (edge_t *edge);
73 void R_TrailingEdge (surf_t *surf, edge_t *edge);
76 //=============================================================================
80 ==============
81 R_DrawCulledPolys
82 ==============
84 void R_DrawCulledPolys (void)
86 surf_t *s;
87 msurface_t *pface;
89 currententity = &cl_entities[0];
91 if (r_worldpolysbacktofront)
93 for (s=surface_p-1 ; s>&surfaces[1] ; s--)
95 if (!s->spans)
96 continue;
98 if (!(s->flags & SURF_DRAWBACKGROUND))
100 pface = (msurface_t *)s->data;
101 R_RenderPoly (pface, 15);
105 else
107 for (s = &surfaces[1] ; s<surface_p ; s++)
109 if (!s->spans)
110 continue;
112 if (!(s->flags & SURF_DRAWBACKGROUND))
114 pface = (msurface_t *)s->data;
115 R_RenderPoly (pface, 15);
123 ==============
124 R_BeginEdgeFrame
125 ==============
127 void R_BeginEdgeFrame (void)
129 int v;
131 edge_p = r_edges;
132 edge_max = &r_edges[r_numallocatededges];
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;
139 // put the background behind everything in the world
140 if (r_draworder.value)
142 pdrawfunc = R_GenerateSpansBackward;
143 surfaces[1].key = 0;
144 r_currentkey = 1;
146 else
148 pdrawfunc = R_GenerateSpans;
149 surfaces[1].key = 0x7FFFFFFF;
150 r_currentkey = 0;
153 // FIXME: set with memset
154 for (v=r_refdef.vrect.y ; v<r_refdef.vrectbottom ; v++)
156 newedges[v] = removeedges[v] = NULL;
161 #if !id386
164 ==============
165 R_InsertNewEdges
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 ==============
173 void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist)
175 edge_t *next_edge;
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;
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);
204 #endif // !id386
207 #if !id386
210 ==============
211 R_RemoveEdges
212 ==============
214 void R_RemoveEdges (edge_t *pedge)
219 pedge->next->prev = pedge->prev;
220 pedge->prev->next = pedge->next;
221 } while ((pedge = pedge->nextremove) != NULL);
224 #endif // !id386
227 #if !id386
230 ==============
231 R_StepActiveU
232 ==============
234 void R_StepActiveU (edge_t *pedge)
236 edge_t *pnext_edge, *pwedge;
238 while (1)
240 nextedge:
241 pedge->u += pedge->u_step;
242 if (pedge->u < pedge->prev->u)
243 goto pushback;
244 pedge = pedge->next;
246 pedge->u += pedge->u_step;
247 if (pedge->u < pedge->prev->u)
248 goto pushback;
249 pedge = pedge->next;
251 pedge->u += pedge->u_step;
252 if (pedge->u < pedge->prev->u)
253 goto pushback;
254 pedge = pedge->next;
256 pedge->u += pedge->u_step;
257 if (pedge->u < pedge->prev->u)
258 goto pushback;
259 pedge = pedge->next;
261 goto nextedge;
263 pushback:
264 if (pedge == &edge_aftertail)
265 return;
267 // push it back to keep it sorted
268 pnext_edge = pedge->next;
270 // pull the edge out of the edge list
271 pedge->next->prev = pedge->prev;
272 pedge->prev->next = pedge->next;
274 // find out where the edge goes in the edge list
275 pwedge = pedge->prev->prev;
277 while (pwedge->u > pedge->u)
279 pwedge = pwedge->prev;
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;
288 pedge = pnext_edge;
289 if (pedge == &edge_tail)
290 return;
294 #endif // !id386
298 ==============
299 R_CleanupSpan
300 ==============
302 void R_CleanupSpan ()
304 surf_t *surf;
305 int iu;
306 espan_t *span;
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)
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;
322 // reset spanstate for all surfaces in the surface stack
325 surf->spanstate = 0;
326 surf = surf->next;
327 } while (surf != &surfaces[1]);
332 ==============
333 R_LeadingEdgeBackwards
334 ==============
336 void R_LeadingEdgeBackwards (edge_t *edge)
338 espan_t *span;
339 surf_t *surf, *surf2;
340 int iu;
342 // it's adding a new surface in, so find the correct place
343 surf = &surfaces[edge->surfs[1]];
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)
350 surf2 = surfaces[1].next;
352 if (surf->key > surf2->key)
353 goto newtop;
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))
359 // must be two bmodels in the same leaf; don't care, because they'll
360 // never be farthest anyway
361 goto newtop;
364 continue_search:
368 surf2 = surf2->next;
369 } while (surf->key < surf2->key);
371 if (surf->key == surf2->key)
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;
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
382 goto gotposition;
384 newtop:
385 // emit a span (obscures current top)
386 iu = edge->u >> 20;
388 if (iu > surf2->last_u)
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;
398 // set last_u on the new span
399 surf->last_u = iu;
401 gotposition:
402 // insert before surf2
403 surf->next = surf2;
404 surf->prev = surf2->prev;
405 surf2->prev->next = surf;
406 surf2->prev = surf;
412 ==============
413 R_TrailingEdge
414 ==============
416 void R_TrailingEdge (surf_t *surf, edge_t *edge)
418 espan_t *span;
419 int iu;
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)
426 if (surf->insubmodel)
427 r_bmodelactive--;
429 if (surf == surfaces[1].next)
431 // emit a span (current top going away)
432 iu = edge->u >> 20;
433 if (iu > surf->last_u)
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;
443 // set last_u on the surface below
444 surf->next->last_u = iu;
447 surf->prev->next = surf->next;
448 surf->next->prev = surf->prev;
453 #if !id386
456 ==============
457 R_LeadingEdge
458 ==============
460 void R_LeadingEdge (edge_t *edge)
462 espan_t *span;
463 surf_t *surf, *surf2;
464 int iu;
465 float fu, newzi, testzi, newzitop, newzibottom;
467 if (edge->surfs[1])
469 // it's adding a new surface in, so find the correct place
470 surf = &surfaces[edge->surfs[1]];
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)
477 if (surf->insubmodel)
478 r_bmodelactive++;
480 surf2 = surfaces[1].next;
482 if (surf->key < surf2->key)
483 goto newtop;
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))
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;
495 testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
496 fu*surf2->d_zistepu;
498 if (newzibottom >= testzi)
500 goto newtop;
503 newzitop = newzi * 1.01;
504 if (newzitop >= testzi)
506 if (surf->d_zistepu >= surf2->d_zistepu)
508 goto newtop;
513 continue_search:
517 surf2 = surf2->next;
518 } while (surf->key > surf2->key);
520 if (surf->key == surf2->key)
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;
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;
533 testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
534 fu*surf2->d_zistepu;
536 if (newzibottom >= testzi)
538 goto gotposition;
541 newzitop = newzi * 1.01;
542 if (newzitop >= testzi)
544 if (surf->d_zistepu >= surf2->d_zistepu)
546 goto gotposition;
550 goto continue_search;
553 goto gotposition;
555 newtop:
556 // emit a span (obscures current top)
557 iu = edge->u >> 20;
559 if (iu > surf2->last_u)
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;
569 // set last_u on the new span
570 surf->last_u = iu;
572 gotposition:
573 // insert before surf2
574 surf->next = surf2;
575 surf->prev = surf2->prev;
576 surf2->prev->next = surf;
577 surf2->prev = surf;
584 ==============
585 R_GenerateSpans
586 ==============
588 void R_GenerateSpans (void)
590 edge_t *edge;
591 surf_t *surf;
593 r_bmodelactive = 0;
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;
599 // generate spans
600 for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
602 if (edge->surfs[0])
604 // it has a left surface, so a surface is going away for this span
605 surf = &surfaces[edge->surfs[0]];
607 R_TrailingEdge (surf, edge);
609 if (!edge->surfs[1])
610 continue;
613 R_LeadingEdge (edge);
616 R_CleanupSpan ();
619 #endif // !id386
623 ==============
624 R_GenerateSpansBackward
625 ==============
627 void R_GenerateSpansBackward (void)
629 edge_t *edge;
631 r_bmodelactive = 0;
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;
637 // generate spans
638 for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
640 if (edge->surfs[0])
641 R_TrailingEdge (&surfaces[edge->surfs[0]], edge);
643 if (edge->surfs[1])
644 R_LeadingEdgeBackwards (edge);
647 R_CleanupSpan ();
652 ==============
653 R_ScanEdges
655 Input:
656 newedges[] array
657 this has links to edges, which have links to surfaces
659 Output:
660 Each surface has a linked list of its visible spans
661 ==============
663 void R_ScanEdges (void)
665 int iv, bottom;
666 byte basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE];
667 espan_t *basespan_p;
668 surf_t *s;
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];
674 span_p = basespan_p;
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;
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;
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;
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;
704 // process all scan lines
706 bottom = r_refdef.vrectbottom - 1;
708 for (iv=r_refdef.vrect.y ; iv<bottom ; iv++)
710 current_iv = iv;
711 fv = (float)iv;
713 // mark that the head (background start) span is pre-included
714 surfaces[1].spanstate = 1;
716 if (newedges[iv])
718 R_InsertNewEdges (newedges[iv], edge_head.next);
721 (*pdrawfunc) ();
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)
727 VID_UnlockBuffer ();
728 S_ExtraUpdate (); // don't let sound get messed up if going slow
729 VID_LockBuffer ();
731 if (r_drawculledpolys)
733 R_DrawCulledPolys ();
735 else
737 D_DrawSurfaces ();
740 // clear the surface span pointers
741 for (s = &surfaces[1] ; s<surface_p ; s++)
742 s->spans = NULL;
744 span_p = basespan_p;
747 if (removeedges[iv])
748 R_RemoveEdges (removeedges[iv]);
750 if (edge_head.next != &edge_tail)
751 R_StepActiveU (edge_head.next);
754 // do the last scan (no need to step or sort or remove on the last scan)
756 current_iv = iv;
757 fv = (float)iv;
759 // mark that the head (background start) span is pre-included
760 surfaces[1].spanstate = 1;
762 if (newedges[iv])
763 R_InsertNewEdges (newedges[iv], edge_head.next);
765 (*pdrawfunc) ();
767 // draw whatever's left in the span list
768 if (r_drawculledpolys)
769 R_DrawCulledPolys ();
770 else
771 D_DrawSurfaces ();