Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

r_edge.c (23657B)


      1 /*
      2 Copyright (C) 1997-2001 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 "r_local.h"
     23 
     24 #ifndef id386
     25 void R_SurfacePatch (void)
     26 {
     27 }
     28 
     29 void R_EdgeCodeStart (void)
     30 {
     31 }
     32 
     33 void R_EdgeCodeEnd (void)
     34 {
     35 }
     36 #endif
     37 
     38 
     39 #if 0
     40 the complex cases add new polys on most lines, so dont optimize for keeping them the same
     41 have multiple free span lists to try to get better coherence?
     42 low depth complexity -- 1 to 3 or so
     43 
     44 have a sentinal at both ends?
     45 #endif
     46 
     47 
     48 edge_t	*auxedges;
     49 edge_t	*r_edges, *edge_p, *edge_max;
     50 
     51 surf_t	*surfaces, *surface_p, *surf_max;
     52 
     53 // surfaces are generated in back to front order by the bsp, so if a surf
     54 // pointer is greater than another one, it should be drawn in front
     55 // surfaces[1] is the background, and is used as the active surface stack
     56 
     57 edge_t	*newedges[MAXHEIGHT];
     58 edge_t	*removeedges[MAXHEIGHT];
     59 
     60 espan_t	*span_p, *max_span_p;
     61 
     62 int		r_currentkey;
     63 
     64 int	current_iv;
     65 
     66 int	edge_head_u_shift20, edge_tail_u_shift20;
     67 
     68 static void (*pdrawfunc)(void);
     69 
     70 edge_t	edge_head;
     71 edge_t	edge_tail;
     72 edge_t	edge_aftertail;
     73 edge_t	edge_sentinel;
     74 
     75 float	fv;
     76 
     77 static int	miplevel;
     78 
     79 float		scale_for_mip;
     80 int			ubasestep, errorterm, erroradjustup, erroradjustdown;
     81 
     82 // FIXME: should go away
     83 extern void			R_RotateBmodel (void);
     84 extern void			R_TransformFrustum (void);
     85 
     86 
     87 
     88 void R_GenerateSpans (void);
     89 void R_GenerateSpansBackward (void);
     90 
     91 void R_LeadingEdge (edge_t *edge);
     92 void R_LeadingEdgeBackwards (edge_t *edge);
     93 void R_TrailingEdge (surf_t *surf, edge_t *edge);
     94 
     95 
     96 /*
     97 ===============================================================================
     98 
     99 EDGE SCANNING
    100 
    101 ===============================================================================
    102 */
    103 
    104 /*
    105 ==============
    106 R_BeginEdgeFrame
    107 ==============
    108 */
    109 void R_BeginEdgeFrame (void)
    110 {
    111 	int		v;
    112 
    113 	edge_p = r_edges;
    114 	edge_max = &r_edges[r_numallocatededges];
    115 
    116 	surface_p = &surfaces[2];	// background is surface 1,
    117 								//  surface 0 is a dummy
    118 	surfaces[1].spans = NULL;	// no background spans yet
    119 	surfaces[1].flags = SURF_DRAWBACKGROUND;
    120 
    121 // put the background behind everything in the world
    122 	if (sw_draworder->value)
    123 	{
    124 		pdrawfunc = R_GenerateSpansBackward;
    125 		surfaces[1].key = 0;
    126 		r_currentkey = 1;
    127 	}
    128 	else
    129 	{
    130 		pdrawfunc = R_GenerateSpans;
    131 		surfaces[1].key = 0x7FFfFFFF;
    132 		r_currentkey = 0;
    133 	}
    134 
    135 // FIXME: set with memset
    136 	for (v=r_refdef.vrect.y ; v<r_refdef.vrectbottom ; v++)
    137 	{
    138 		newedges[v] = removeedges[v] = NULL;
    139 	}
    140 }
    141 
    142 
    143 #if	!id386
    144 
    145 /*
    146 ==============
    147 R_InsertNewEdges
    148 
    149 Adds the edges in the linked list edgestoadd, adding them to the edges in the
    150 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
    151 sentinel at the end (actually, this is the active edge table starting at
    152 edge_head.next).
    153 ==============
    154 */
    155 void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist)
    156 {
    157 	edge_t	*next_edge;
    158 
    159 	do
    160 	{
    161 		next_edge = edgestoadd->next;
    162 edgesearch:
    163 		if (edgelist->u >= edgestoadd->u)
    164 			goto addedge;
    165 		edgelist=edgelist->next;
    166 		if (edgelist->u >= edgestoadd->u)
    167 			goto addedge;
    168 		edgelist=edgelist->next;
    169 		if (edgelist->u >= edgestoadd->u)
    170 			goto addedge;
    171 		edgelist=edgelist->next;
    172 		if (edgelist->u >= edgestoadd->u)
    173 			goto addedge;
    174 		edgelist=edgelist->next;
    175 		goto edgesearch;
    176 
    177 	// insert edgestoadd before edgelist
    178 addedge:
    179 		edgestoadd->next = edgelist;
    180 		edgestoadd->prev = edgelist->prev;
    181 		edgelist->prev->next = edgestoadd;
    182 		edgelist->prev = edgestoadd;
    183 	} while ((edgestoadd = next_edge) != NULL);
    184 }
    185 
    186 #endif	// !id386
    187 	
    188 
    189 #if	!id386
    190 
    191 /*
    192 ==============
    193 R_RemoveEdges
    194 ==============
    195 */
    196 void R_RemoveEdges (edge_t *pedge)
    197 {
    198 
    199 	do
    200 	{
    201 		pedge->next->prev = pedge->prev;
    202 		pedge->prev->next = pedge->next;
    203 	} while ((pedge = pedge->nextremove) != NULL);
    204 }
    205 
    206 #endif	// !id386
    207 
    208 
    209 #if	!id386
    210 
    211 /*
    212 ==============
    213 R_StepActiveU
    214 ==============
    215 */
    216 void R_StepActiveU (edge_t *pedge)
    217 {
    218 	edge_t		*pnext_edge, *pwedge;
    219 
    220 	while (1)
    221 	{
    222 nextedge:
    223 		pedge->u += pedge->u_step;
    224 		if (pedge->u < pedge->prev->u)
    225 			goto pushback;
    226 		pedge = pedge->next;
    227 			
    228 		pedge->u += pedge->u_step;
    229 		if (pedge->u < pedge->prev->u)
    230 			goto pushback;
    231 		pedge = pedge->next;
    232 			
    233 		pedge->u += pedge->u_step;
    234 		if (pedge->u < pedge->prev->u)
    235 			goto pushback;
    236 		pedge = pedge->next;
    237 			
    238 		pedge->u += pedge->u_step;
    239 		if (pedge->u < pedge->prev->u)
    240 			goto pushback;
    241 		pedge = pedge->next;
    242 			
    243 		goto nextedge;		
    244 		
    245 pushback:
    246 		if (pedge == &edge_aftertail)
    247 			return;
    248 			
    249 	// push it back to keep it sorted		
    250 		pnext_edge = pedge->next;
    251 
    252 	// pull the edge out of the edge list
    253 		pedge->next->prev = pedge->prev;
    254 		pedge->prev->next = pedge->next;
    255 
    256 	// find out where the edge goes in the edge list
    257 		pwedge = pedge->prev->prev;
    258 
    259 		while (pwedge->u > pedge->u)
    260 		{
    261 			pwedge = pwedge->prev;
    262 		}
    263 
    264 	// put the edge back into the edge list
    265 		pedge->next = pwedge->next;
    266 		pedge->prev = pwedge;
    267 		pedge->next->prev = pedge;
    268 		pwedge->next = pedge;
    269 
    270 		pedge = pnext_edge;
    271 		if (pedge == &edge_tail)
    272 			return;
    273 	}
    274 }
    275 
    276 #endif	// !id386
    277 
    278 
    279 /*
    280 ==============
    281 R_CleanupSpan
    282 ==============
    283 */
    284 void R_CleanupSpan (void)
    285 {
    286 	surf_t	*surf;
    287 	int		iu;
    288 	espan_t	*span;
    289 
    290 // now that we've reached the right edge of the screen, we're done with any
    291 // unfinished surfaces, so emit a span for whatever's on top
    292 	surf = surfaces[1].next;
    293 	iu = edge_tail_u_shift20;
    294 	if (iu > surf->last_u)
    295 	{
    296 		span = span_p++;
    297 		span->u = surf->last_u;
    298 		span->count = iu - span->u;
    299 		span->v = current_iv;
    300 		span->pnext = surf->spans;
    301 		surf->spans = span;
    302 	}
    303 
    304 // reset spanstate for all surfaces in the surface stack
    305 	do
    306 	{
    307 		surf->spanstate = 0;
    308 		surf = surf->next;
    309 	} while (surf != &surfaces[1]);
    310 }
    311 
    312 
    313 /*
    314 ==============
    315 R_LeadingEdgeBackwards
    316 ==============
    317 */
    318 void R_LeadingEdgeBackwards (edge_t *edge)
    319 {
    320 	espan_t			*span;
    321 	surf_t			*surf, *surf2;
    322 	int				iu;
    323 
    324 // it's adding a new surface in, so find the correct place
    325 	surf = &surfaces[edge->surfs[1]];
    326 
    327 // don't start a span if this is an inverted span, with the end
    328 // edge preceding the start edge (that is, we've already seen the
    329 // end edge)
    330 	if (++surf->spanstate == 1)
    331 	{
    332 		surf2 = surfaces[1].next;
    333 
    334 		if (surf->key > surf2->key)
    335 			goto newtop;
    336 
    337 	// if it's two surfaces on the same plane, the one that's already
    338 	// active is in front, so keep going unless it's a bmodel
    339 		if (surf->insubmodel && (surf->key == surf2->key))
    340 		{
    341 		// must be two bmodels in the same leaf; don't care, because they'll
    342 		// never be farthest anyway
    343 			goto newtop;
    344 		}
    345 
    346 continue_search:
    347 
    348 		do
    349 		{
    350 			surf2 = surf2->next;
    351 		} while (surf->key < surf2->key);
    352 
    353 		if (surf->key == surf2->key)
    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)
    358 				goto continue_search;
    359 
    360 		// must be two bmodels in the same leaf; don't care which is really
    361 		// in front, because they'll never be farthest anyway
    362 		}
    363 
    364 		goto gotposition;
    365 
    366 newtop:
    367 	// emit a span (obscures current top)
    368 		iu = edge->u >> 20;
    369 
    370 		if (iu > surf2->last_u)
    371 		{
    372 			span = span_p++;
    373 			span->u = surf2->last_u;
    374 			span->count = iu - span->u;
    375 			span->v = current_iv;
    376 			span->pnext = surf2->spans;
    377 			surf2->spans = span;
    378 		}
    379 
    380 		// set last_u on the new span
    381 		surf->last_u = iu;
    382 				
    383 gotposition:
    384 	// insert before surf2
    385 		surf->next = surf2;
    386 		surf->prev = surf2->prev;
    387 		surf2->prev->next = surf;
    388 		surf2->prev = surf;
    389 	}
    390 }
    391 
    392 
    393 /*
    394 ==============
    395 R_TrailingEdge
    396 ==============
    397 */
    398 void R_TrailingEdge (surf_t *surf, edge_t *edge)
    399 {
    400 	espan_t			*span;
    401 	int				iu;
    402 
    403 // don't generate a span if this is an inverted span, with the end
    404 // edge preceding the start edge (that is, we haven't seen the
    405 // start edge yet)
    406 	if (--surf->spanstate == 0)
    407 	{
    408 		if (surf == surfaces[1].next)
    409 		{
    410 		// emit a span (current top going away)
    411 			iu = edge->u >> 20;
    412 			if (iu > surf->last_u)
    413 			{
    414 				span = span_p++;
    415 				span->u = surf->last_u;
    416 				span->count = iu - span->u;
    417 				span->v = current_iv;
    418 				span->pnext = surf->spans;
    419 				surf->spans = span;
    420 			}
    421 
    422 		// set last_u on the surface below
    423 			surf->next->last_u = iu;
    424 		}
    425 
    426 		surf->prev->next = surf->next;
    427 		surf->next->prev = surf->prev;
    428 	}
    429 }
    430 
    431 
    432 #if	!id386
    433 
    434 /*
    435 ==============
    436 R_LeadingEdge
    437 ==============
    438 */
    439 void R_LeadingEdge (edge_t *edge)
    440 {
    441 	espan_t			*span;
    442 	surf_t			*surf, *surf2;
    443 	int				iu;
    444 	float			fu, newzi, testzi, newzitop, newzibottom;
    445 
    446 	if (edge->surfs[1])
    447 	{
    448 	// it's adding a new surface in, so find the correct place
    449 		surf = &surfaces[edge->surfs[1]];
    450 
    451 	// don't start a span if this is an inverted span, with the end
    452 	// edge preceding the start edge (that is, we've already seen the
    453 	// end edge)
    454 		if (++surf->spanstate == 1)
    455 		{
    456 			surf2 = surfaces[1].next;
    457 
    458 			if (surf->key < surf2->key)
    459 				goto newtop;
    460 
    461 		// if it's two surfaces on the same plane, the one that's already
    462 		// active is in front, so keep going unless it's a bmodel
    463 			if (surf->insubmodel && (surf->key == surf2->key))
    464 			{
    465 			// must be two bmodels in the same leaf; sort on 1/z
    466 				fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
    467 				newzi = surf->d_ziorigin + fv*surf->d_zistepv +
    468 						fu*surf->d_zistepu;
    469 				newzibottom = newzi * 0.99;
    470 
    471 				testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
    472 						fu*surf2->d_zistepu;
    473 
    474 				if (newzibottom >= testzi)
    475 				{
    476 					goto newtop;
    477 				}
    478 
    479 				newzitop = newzi * 1.01;
    480 				if (newzitop >= testzi)
    481 				{
    482 					if (surf->d_zistepu >= surf2->d_zistepu)
    483 					{
    484 						goto newtop;
    485 					}
    486 				}
    487 			}
    488 
    489 continue_search:
    490 
    491 			do
    492 			{
    493 				surf2 = surf2->next;
    494 			} while (surf->key > surf2->key);
    495 
    496 			if (surf->key == surf2->key)
    497 			{
    498 			// if it's two surfaces on the same plane, the one that's already
    499 			// active is in front, so keep going unless it's a bmodel
    500 				if (!surf->insubmodel)
    501 					goto continue_search;
    502 
    503 			// must be two bmodels in the same leaf; sort on 1/z
    504 				fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
    505 				newzi = surf->d_ziorigin + fv*surf->d_zistepv +
    506 						fu*surf->d_zistepu;
    507 				newzibottom = newzi * 0.99;
    508 
    509 				testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
    510 						fu*surf2->d_zistepu;
    511 
    512 				if (newzibottom >= testzi)
    513 				{
    514 					goto gotposition;
    515 				}
    516 
    517 				newzitop = newzi * 1.01;
    518 				if (newzitop >= testzi)
    519 				{
    520 					if (surf->d_zistepu >= surf2->d_zistepu)
    521 					{
    522 						goto gotposition;
    523 					}
    524 				}
    525 
    526 				goto continue_search;
    527 			}
    528 
    529 			goto gotposition;
    530 
    531 newtop:
    532 		// emit a span (obscures current top)
    533 			iu = edge->u >> 20;
    534 
    535 			if (iu > surf2->last_u)
    536 			{
    537 				span = span_p++;
    538 				span->u = surf2->last_u;
    539 				span->count = iu - span->u;
    540 				span->v = current_iv;
    541 				span->pnext = surf2->spans;
    542 				surf2->spans = span;
    543 			}
    544 
    545 			// set last_u on the new span
    546 			surf->last_u = iu;
    547 				
    548 gotposition:
    549 		// insert before surf2
    550 			surf->next = surf2;
    551 			surf->prev = surf2->prev;
    552 			surf2->prev->next = surf;
    553 			surf2->prev = surf;
    554 		}
    555 	}
    556 }
    557 
    558 
    559 /*
    560 ==============
    561 R_GenerateSpans
    562 ==============
    563 */
    564 void R_GenerateSpans (void)
    565 {
    566 	edge_t			*edge;
    567 	surf_t			*surf;
    568 
    569 // clear active surfaces to just the background surface
    570 	surfaces[1].next = surfaces[1].prev = &surfaces[1];
    571 	surfaces[1].last_u = edge_head_u_shift20;
    572 
    573 // generate spans
    574 	for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
    575 	{			
    576 		if (edge->surfs[0])
    577 		{
    578 		// it has a left surface, so a surface is going away for this span
    579 			surf = &surfaces[edge->surfs[0]];
    580 
    581 			R_TrailingEdge (surf, edge);
    582 
    583 			if (!edge->surfs[1])
    584 				continue;
    585 		}
    586 
    587 		R_LeadingEdge (edge);
    588 	}
    589 
    590 	R_CleanupSpan ();
    591 }
    592 
    593 #endif	// !id386
    594 
    595 
    596 /*
    597 ==============
    598 R_GenerateSpansBackward
    599 ==============
    600 */
    601 void R_GenerateSpansBackward (void)
    602 {
    603 	edge_t			*edge;
    604 
    605 // clear active surfaces to just the background surface
    606 	surfaces[1].next = surfaces[1].prev = &surfaces[1];
    607 	surfaces[1].last_u = edge_head_u_shift20;
    608 
    609 // generate spans
    610 	for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
    611 	{			
    612 		if (edge->surfs[0])
    613 			R_TrailingEdge (&surfaces[edge->surfs[0]], edge);
    614 
    615 		if (edge->surfs[1])
    616 			R_LeadingEdgeBackwards (edge);
    617 	}
    618 
    619 	R_CleanupSpan ();
    620 }
    621 
    622 
    623 /*
    624 ==============
    625 R_ScanEdges
    626 
    627 Input: 
    628 newedges[] array
    629 	this has links to edges, which have links to surfaces
    630 
    631 Output:
    632 Each surface has a linked list of its visible spans
    633 ==============
    634 */
    635 void R_ScanEdges (void)
    636 {
    637 	int		iv, bottom;
    638 	byte	basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE];
    639 	espan_t	*basespan_p;
    640 	surf_t	*s;
    641 
    642 	basespan_p = (espan_t *)
    643 			((long)(basespans + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
    644 	max_span_p = &basespan_p[MAXSPANS - r_refdef.vrect.width];
    645 
    646 	span_p = basespan_p;
    647 
    648 // clear active edges to just the background edges around the whole screen
    649 // FIXME: most of this only needs to be set up once
    650 	edge_head.u = r_refdef.vrect.x << 20;
    651 	edge_head_u_shift20 = edge_head.u >> 20;
    652 	edge_head.u_step = 0;
    653 	edge_head.prev = NULL;
    654 	edge_head.next = &edge_tail;
    655 	edge_head.surfs[0] = 0;
    656 	edge_head.surfs[1] = 1;
    657 	
    658 	edge_tail.u = (r_refdef.vrectright << 20) + 0xFFFFF;
    659 	edge_tail_u_shift20 = edge_tail.u >> 20;
    660 	edge_tail.u_step = 0;
    661 	edge_tail.prev = &edge_head;
    662 	edge_tail.next = &edge_aftertail;
    663 	edge_tail.surfs[0] = 1;
    664 	edge_tail.surfs[1] = 0;
    665 	
    666 	edge_aftertail.u = -1;		// force a move
    667 	edge_aftertail.u_step = 0;
    668 	edge_aftertail.next = &edge_sentinel;
    669 	edge_aftertail.prev = &edge_tail;
    670 
    671 // FIXME: do we need this now that we clamp x in r_draw.c?
    672 	edge_sentinel.u = 2000 << 24;		// make sure nothing sorts past this
    673 	edge_sentinel.prev = &edge_aftertail;
    674 
    675 //	
    676 // process all scan lines
    677 //
    678 	bottom = r_refdef.vrectbottom - 1;
    679 
    680 	for (iv=r_refdef.vrect.y ; iv<bottom ; iv++)
    681 	{
    682 		current_iv = iv;
    683 		fv = (float)iv;
    684 
    685 	// mark that the head (background start) span is pre-included
    686 		surfaces[1].spanstate = 1;
    687 
    688 		if (newedges[iv])
    689 		{
    690 			R_InsertNewEdges (newedges[iv], edge_head.next);
    691 		}
    692 
    693 		(*pdrawfunc) ();
    694 
    695 	// flush the span list if we can't be sure we have enough spans left for
    696 	// the next scan
    697 		if (span_p > max_span_p)
    698 		{
    699 			D_DrawSurfaces ();
    700 
    701 		// clear the surface span pointers
    702 			for (s = &surfaces[1] ; s<surface_p ; s++)
    703 				s->spans = NULL;
    704 
    705 			span_p = basespan_p;
    706 		}
    707 
    708 		if (removeedges[iv])
    709 			R_RemoveEdges (removeedges[iv]);
    710 
    711 		if (edge_head.next != &edge_tail)
    712 			R_StepActiveU (edge_head.next);
    713 	}
    714 
    715 // do the last scan (no need to step or sort or remove on the last scan)
    716 
    717 	current_iv = iv;
    718 	fv = (float)iv;
    719 
    720 // mark that the head (background start) span is pre-included
    721 	surfaces[1].spanstate = 1;
    722 
    723 	if (newedges[iv])
    724 		R_InsertNewEdges (newedges[iv], edge_head.next);
    725 
    726 	(*pdrawfunc) ();
    727 
    728 // draw whatever's left in the span list
    729 	D_DrawSurfaces ();
    730 }
    731 
    732 
    733 /*
    734 =========================================================================
    735 
    736 SURFACE FILLING
    737 
    738 =========================================================================
    739 */
    740 
    741 msurface_t		*pface;
    742 surfcache_t		*pcurrentcache;
    743 vec3_t			transformed_modelorg;
    744 vec3_t			world_transformed_modelorg;
    745 vec3_t			local_modelorg;
    746 
    747 /*
    748 =============
    749 D_MipLevelForScale
    750 =============
    751 */
    752 int D_MipLevelForScale (float scale)
    753 {
    754 	int		lmiplevel;
    755 
    756 	if (scale >= d_scalemip[0] )
    757 		lmiplevel = 0;
    758 	else if (scale >= d_scalemip[1] )
    759 		lmiplevel = 1;
    760 	else if (scale >= d_scalemip[2] )
    761 		lmiplevel = 2;
    762 	else
    763 		lmiplevel = 3;
    764 
    765 	if (lmiplevel < d_minmip)
    766 		lmiplevel = d_minmip;
    767 
    768 	return lmiplevel;
    769 }
    770 
    771 
    772 /*
    773 ==============
    774 D_FlatFillSurface
    775 
    776 Simple single color fill with no texture mapping
    777 ==============
    778 */
    779 void D_FlatFillSurface (surf_t *surf, int color)
    780 {
    781 	espan_t	*span;
    782 	byte	*pdest;
    783 	int		u, u2;
    784 	
    785 	for (span=surf->spans ; span ; span=span->pnext)
    786 	{
    787 		pdest = (byte *)d_viewbuffer + r_screenwidth*span->v;
    788 		u = span->u;
    789 		u2 = span->u + span->count - 1;
    790 		for ( ; u <= u2 ; u++)
    791 			pdest[u] = color;
    792 	}
    793 }
    794 
    795 
    796 /*
    797 ==============
    798 D_CalcGradients
    799 ==============
    800 */
    801 void D_CalcGradients (msurface_t *pface)
    802 {
    803 	mplane_t	*pplane;
    804 	float		mipscale;
    805 	vec3_t		p_temp1;
    806 	vec3_t		p_saxis, p_taxis;
    807 	float		t;
    808 
    809 	pplane = pface->plane;
    810 
    811 	mipscale = 1.0 / (float)(1 << miplevel);
    812 
    813 	TransformVector (pface->texinfo->vecs[0], p_saxis);
    814 	TransformVector (pface->texinfo->vecs[1], p_taxis);
    815 
    816 	t = xscaleinv * mipscale;
    817 	d_sdivzstepu = p_saxis[0] * t;
    818 	d_tdivzstepu = p_taxis[0] * t;
    819 
    820 	t = yscaleinv * mipscale;
    821 	d_sdivzstepv = -p_saxis[1] * t;
    822 	d_tdivzstepv = -p_taxis[1] * t;
    823 
    824 	d_sdivzorigin = p_saxis[2] * mipscale - xcenter * d_sdivzstepu -
    825 			ycenter * d_sdivzstepv;
    826 	d_tdivzorigin = p_taxis[2] * mipscale - xcenter * d_tdivzstepu -
    827 			ycenter * d_tdivzstepv;
    828 
    829 	VectorScale (transformed_modelorg, mipscale, p_temp1);
    830 
    831 	t = 0x10000*mipscale;
    832 	sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) -
    833 			((pface->texturemins[0] << 16) >> miplevel)
    834 			+ pface->texinfo->vecs[0][3]*t;
    835 	tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) -
    836 			((pface->texturemins[1] << 16) >> miplevel)
    837 			+ pface->texinfo->vecs[1][3]*t;
    838 
    839 	// PGM - changing flow speed for non-warping textures.
    840 	if (pface->texinfo->flags & SURF_FLOWING)
    841 	{
    842 		if(pface->texinfo->flags & SURF_WARP)
    843 			sadjust += 0x10000 * (-128 * ( (r_newrefdef.time * 0.25) - (int)(r_newrefdef.time * 0.25) ));
    844 		else
    845 			sadjust += 0x10000 * (-128 * ( (r_newrefdef.time * 0.77) - (int)(r_newrefdef.time * 0.77) ));
    846 	}
    847 	// PGM
    848 
    849 //
    850 // -1 (-epsilon) so we never wander off the edge of the texture
    851 //
    852 	bbextents = ((pface->extents[0] << 16) >> miplevel) - 1;
    853 	bbextentt = ((pface->extents[1] << 16) >> miplevel) - 1;
    854 }
    855 
    856 
    857 /*
    858 ==============
    859 D_BackgroundSurf
    860 
    861 The grey background filler seen when there is a hole in the map
    862 ==============
    863 */
    864 void D_BackgroundSurf (surf_t *s)
    865 {
    866 // set up a gradient for the background surface that places it
    867 // effectively at infinity distance from the viewpoint
    868 	d_zistepu = 0;
    869 	d_zistepv = 0;
    870 	d_ziorigin = -0.9;
    871 
    872 	D_FlatFillSurface (s, (int)sw_clearcolor->value & 0xFF);
    873 	D_DrawZSpans (s->spans);
    874 }
    875 
    876 /*
    877 =================
    878 D_TurbulentSurf
    879 =================
    880 */
    881 void D_TurbulentSurf (surf_t *s)
    882 {
    883 	d_zistepu = s->d_zistepu;
    884 	d_zistepv = s->d_zistepv;
    885 	d_ziorigin = s->d_ziorigin;
    886 
    887 	pface = s->msurf;
    888 	miplevel = 0;
    889 	cacheblock = pface->texinfo->image->pixels[0];
    890 	cachewidth = 64;
    891 
    892 	if (s->insubmodel)
    893 	{
    894 	// FIXME: we don't want to do all this for every polygon!
    895 	// TODO: store once at start of frame
    896 		currententity = s->entity;	//FIXME: make this passed in to
    897 									// R_RotateBmodel ()
    898 		VectorSubtract (r_origin, currententity->origin,
    899 				local_modelorg);
    900 		TransformVector (local_modelorg, transformed_modelorg);
    901 
    902 		R_RotateBmodel ();	// FIXME: don't mess with the frustum,
    903 							// make entity passed in
    904 	}
    905 
    906 	D_CalcGradients (pface);
    907 
    908 //============
    909 //PGM
    910 	// textures that aren't warping are just flowing. Use NonTurbulent8 instead
    911 	if(!(pface->texinfo->flags & SURF_WARP))
    912 		NonTurbulent8 (s->spans);
    913 	else
    914 		Turbulent8 (s->spans);
    915 //PGM
    916 //============
    917 
    918 	D_DrawZSpans (s->spans);
    919 
    920 	if (s->insubmodel)
    921 	{
    922 	//
    923 	// restore the old drawing state
    924 	// FIXME: we don't want to do this every time!
    925 	// TODO: speed up
    926 	//
    927 		currententity = NULL;	// &r_worldentity;
    928 		VectorCopy (world_transformed_modelorg,
    929 					transformed_modelorg);
    930 		VectorCopy (base_vpn, vpn);
    931 		VectorCopy (base_vup, vup);
    932 		VectorCopy (base_vright, vright);
    933 		R_TransformFrustum ();
    934 	}
    935 }
    936 
    937 /*
    938 ==============
    939 D_SkySurf
    940 ==============
    941 */
    942 void D_SkySurf (surf_t *s)
    943 {
    944 	pface = s->msurf;
    945 	miplevel = 0;
    946 	if (!pface->texinfo->image)
    947 		return;
    948 	cacheblock = pface->texinfo->image->pixels[0];
    949 	cachewidth = 256;
    950 
    951 	d_zistepu = s->d_zistepu;
    952 	d_zistepv = s->d_zistepv;
    953 	d_ziorigin = s->d_ziorigin;
    954 
    955 	D_CalcGradients (pface);
    956 
    957 	D_DrawSpans16 (s->spans);
    958 
    959 // set up a gradient for the background surface that places it
    960 // effectively at infinity distance from the viewpoint
    961 	d_zistepu = 0;
    962 	d_zistepv = 0;
    963 	d_ziorigin = -0.9;
    964 
    965 	D_DrawZSpans (s->spans);
    966 }
    967 
    968 /*
    969 ==============
    970 D_SolidSurf
    971 
    972 Normal surface cached, texture mapped surface
    973 ==============
    974 */
    975 void D_SolidSurf (surf_t *s)
    976 {
    977 	d_zistepu = s->d_zistepu;
    978 	d_zistepv = s->d_zistepv;
    979 	d_ziorigin = s->d_ziorigin;
    980 
    981 	if (s->insubmodel)
    982 	{
    983 	// FIXME: we don't want to do all this for every polygon!
    984 	// TODO: store once at start of frame
    985 		currententity = s->entity;	//FIXME: make this passed in to
    986 									// R_RotateBmodel ()
    987 		VectorSubtract (r_origin, currententity->origin, local_modelorg);
    988 		TransformVector (local_modelorg, transformed_modelorg);
    989 
    990 		R_RotateBmodel ();	// FIXME: don't mess with the frustum,
    991 							// make entity passed in
    992 	}
    993 	else
    994 		currententity = &r_worldentity;
    995 
    996 	pface = s->msurf;
    997 #if 1
    998 	miplevel = D_MipLevelForScale(s->nearzi * scale_for_mip * pface->texinfo->mipadjust);
    999 #else
   1000 	{
   1001 		float dot;
   1002 		float normal[3];
   1003 
   1004 		if ( s->insubmodel )
   1005 		{
   1006 			VectorCopy( pface->plane->normal, normal );
   1007 //			TransformVector( pface->plane->normal, normal);
   1008 			dot = DotProduct( normal, vpn );
   1009 		}
   1010 		else
   1011 		{
   1012 			VectorCopy( pface->plane->normal, normal );
   1013 			dot = DotProduct( normal, vpn );
   1014 		}
   1015 
   1016 		if ( pface->flags & SURF_PLANEBACK )
   1017 			dot = -dot;
   1018 
   1019 		if ( dot > 0 )
   1020 			printf( "blah" );
   1021 
   1022 		miplevel = D_MipLevelForScale(s->nearzi * scale_for_mip * pface->texinfo->mipadjust);
   1023 	}
   1024 #endif
   1025 
   1026 // FIXME: make this passed in to D_CacheSurface
   1027 	pcurrentcache = D_CacheSurface (pface, miplevel);
   1028 
   1029 	cacheblock = (pixel_t *)pcurrentcache->data;
   1030 	cachewidth = pcurrentcache->width;
   1031 
   1032 	D_CalcGradients (pface);
   1033 
   1034 	D_DrawSpans16 (s->spans);
   1035 
   1036 	D_DrawZSpans (s->spans);
   1037 
   1038 	if (s->insubmodel)
   1039 	{
   1040 	//
   1041 	// restore the old drawing state
   1042 	// FIXME: we don't want to do this every time!
   1043 	// TODO: speed up
   1044 	//
   1045 		VectorCopy (world_transformed_modelorg,
   1046 					transformed_modelorg);
   1047 		VectorCopy (base_vpn, vpn);
   1048 		VectorCopy (base_vup, vup);
   1049 		VectorCopy (base_vright, vright);
   1050 		R_TransformFrustum ();
   1051 		currententity = NULL;	//&r_worldentity;
   1052 	}
   1053 }
   1054 
   1055 /*
   1056 =============
   1057 D_DrawflatSurfaces
   1058 
   1059 To allow developers to see the polygon carving of the world
   1060 =============
   1061 */
   1062 void D_DrawflatSurfaces (void)
   1063 {
   1064 	surf_t			*s;
   1065 
   1066 	for (s = &surfaces[1] ; s<surface_p ; s++)
   1067 	{
   1068 		if (!s->spans)
   1069 			continue;
   1070 
   1071 		d_zistepu = s->d_zistepu;
   1072 		d_zistepv = s->d_zistepv;
   1073 		d_ziorigin = s->d_ziorigin;
   1074 
   1075 		// make a stable color for each surface by taking the low
   1076 		// bits of the msurface pointer
   1077 		D_FlatFillSurface (s, (int)s->msurf & 0xFF);
   1078 		D_DrawZSpans (s->spans);
   1079 	}
   1080 }
   1081 
   1082 /*
   1083 ==============
   1084 D_DrawSurfaces
   1085 
   1086 Rasterize all the span lists.  Guaranteed zero overdraw.
   1087 May be called more than once a frame if the surf list overflows (higher res)
   1088 ==============
   1089 */
   1090 void D_DrawSurfaces (void)
   1091 {
   1092 	surf_t			*s;
   1093 
   1094 //	currententity = NULL;	//&r_worldentity;
   1095 	VectorSubtract (r_origin, vec3_origin, modelorg);
   1096 	TransformVector (modelorg, transformed_modelorg);
   1097 	VectorCopy (transformed_modelorg, world_transformed_modelorg);
   1098 
   1099 	if (!sw_drawflat->value)
   1100 	{
   1101 		for (s = &surfaces[1] ; s<surface_p ; s++)
   1102 		{
   1103 			if (!s->spans)
   1104 				continue;
   1105 
   1106 			r_drawnpolycount++;
   1107 
   1108 			if (! (s->flags & (SURF_DRAWSKYBOX|SURF_DRAWBACKGROUND|SURF_DRAWTURB) ) )
   1109 				D_SolidSurf (s);
   1110 			else if (s->flags & SURF_DRAWSKYBOX)
   1111 				D_SkySurf (s);
   1112 			else if (s->flags & SURF_DRAWBACKGROUND)
   1113 				D_BackgroundSurf (s);
   1114 			else if (s->flags & SURF_DRAWTURB)
   1115 				D_TurbulentSurf (s);
   1116 		}
   1117 	}
   1118 	else
   1119 		D_DrawflatSurfaces ();
   1120 
   1121 	currententity = NULL;	//&r_worldentity;
   1122 	VectorSubtract (r_origin, vec3_origin, modelorg);
   1123 	R_TransformFrustum ();
   1124 }
   1125