DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

r_draw.cpp (19086B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #include "Precompiled.h"
     30 #include "globaldata.h"
     31 
     32 #include "doomdef.h"
     33 
     34 #include "i_system.h"
     35 #include "z_zone.h"
     36 #include "w_wad.h"
     37 
     38 #include "r_local.h"
     39 
     40 // Needs access to LFB (guess what).
     41 #include "v_video.h"
     42 
     43 // State.
     44 #include "doomstat.h"
     45 
     46 
     47 // ?
     48 
     49 // status bar height at bottom of screen
     50 
     51 //
     52 // All drawing to the view buffer is accomplished in this file.
     53 // The other refresh files only know about ccordinates,
     54 //  not the architecture of the frame buffer.
     55 // Conveniently, the frame buffer is a linear one,
     56 //  and we need only the base address,
     57 //  and the total size == width*height*depth/8.,
     58 //
     59 
     60 
     61 
     62 // Color tables for different ::g->players,
     63 //  translate a limited part to another
     64 //  (color ramps used for  suit colors).
     65 //
     66 
     67 
     68 
     69 
     70 //
     71 // R_DrawColumn
     72 // Source is the top of the column to scale.
     73 //
     74 
     75 // first pixel in a column (possibly virtual) 
     76 
     77 // just for profiling 
     78 
     79 //
     80 // A column is a vertical slice/span from a wall texture that,
     81 //  given the DOOM style restrictions on the view orientation,
     82 //  will always have constant z depth.
     83 // Thus a special case loop for very fast rendering can
     84 //  be used. It has also been used with Wolfenstein 3D.
     85 // 
     86 void R_DrawColumn ( lighttable_t * dc_colormap,
     87 					byte * dc_source ) 
     88 { 
     89 	int			count; 
     90 	byte*		dest; 
     91 	fixed_t		frac;
     92 	fixed_t		fracstep;	 
     93 
     94 	count = ::g->dc_yh - ::g->dc_yl; 
     95 
     96 	// Zero length, column does not exceed a pixel.
     97 	if (count >= 0) {
     98 		//return; 
     99 
    100 	#ifdef RANGECHECK 
    101 		if ((unsigned)::g->dc_x >= SCREENWIDTH
    102 			|| ::g->dc_yl < 0
    103 			|| ::g->dc_yh >= SCREENHEIGHT) 
    104 			I_Error ("R_DrawColumn: %i to %i at %i", ::g->dc_yl, ::g->dc_yh, ::g->dc_x); 
    105 	#endif 
    106 
    107 		// Framebuffer destination address.
    108 		// Use ::g->ylookup LUT to avoid multiply with ScreenWidth.
    109 		// Use ::g->columnofs LUT for subwindows? 
    110 		dest = ::g->ylookup[::g->dc_yl] + ::g->columnofs[::g->dc_x];  
    111 
    112 		// Determine scaling,
    113 		//  which is the only mapping to be done.
    114 		fracstep = ::g->dc_iscale; 
    115 		frac = ::g->dc_texturemid + (::g->dc_yl-::g->centery)*fracstep; 
    116 
    117 		// Inner loop that does the actual texture mapping,
    118 		//  e.g. a DDA-lile scaling.
    119 		// This is as fast as it gets.
    120 		do 
    121 		{
    122 			// Re-map color indices from wall texture column
    123 			//  using a lighting/special effects LUT.
    124 			const int truncated1 = frac >> FRACBITS;
    125 			const int wrapped1 = truncated1 & 127;
    126 
    127 			*dest = dc_colormap[dc_source[wrapped1]];
    128 
    129 			frac += fracstep;
    130 			dest += SCREENWIDTH; 
    131 		} while (count--);
    132 	}
    133 } 
    134 
    135 
    136 
    137 // UNUSED.
    138 // Loop unrolled.
    139 #if 0
    140 void R_DrawColumn (void) 
    141 { 
    142 	int			count; 
    143 	byte*		source;
    144 	byte*		dest;
    145 	byte*		colormap;
    146 
    147 	unsigned		frac;
    148 	unsigned		fracstep;
    149 	unsigned		fracstep2;
    150 	unsigned		fracstep3;
    151 	unsigned		fracstep4;	 
    152 
    153 	count = ::g->dc_yh - ::g->dc_yl + 1; 
    154 
    155 	source = ::g->dc_source;
    156 	colormap = ::g->dc_colormap;		 
    157 	dest = ::g->ylookup[::g->dc_yl] + ::g->columnofs[::g->dc_x];  
    158 
    159 	fracstep = ::g->dc_iscale<<9; 
    160 	frac = (::g->dc_texturemid + (::g->dc_yl-::g->centery)*::g->dc_iscale)<<9; 
    161 
    162 	fracstep2 = fracstep+fracstep;
    163 	fracstep3 = fracstep2+fracstep;
    164 	fracstep4 = fracstep3+fracstep;
    165 
    166 	while (count >= 8) 
    167 	{ 
    168 		dest[0] = colormap[source[frac>>25]]; 
    169 		dest[SCREENWIDTH] = colormap[source[(frac+fracstep)>>25]]; 
    170 		dest[SCREENWIDTH*2] = colormap[source[(frac+fracstep2)>>25]]; 
    171 		dest[SCREENWIDTH*3] = colormap[source[(frac+fracstep3)>>25]];
    172 
    173 		frac += fracstep4; 
    174 
    175 		dest[SCREENWIDTH*4] = colormap[source[frac>>25]]; 
    176 		dest[SCREENWIDTH*5] = colormap[source[(frac+fracstep)>>25]]; 
    177 		dest[SCREENWIDTH*6] = colormap[source[(frac+fracstep2)>>25]]; 
    178 		dest[SCREENWIDTH*7] = colormap[source[(frac+fracstep3)>>25]]; 
    179 
    180 		frac += fracstep4; 
    181 		dest += SCREENWIDTH*8; 
    182 		count -= 8;
    183 	} 
    184 
    185 	while (count > 0)
    186 	{ 
    187 		*dest = colormap[source[frac>>25]]; 
    188 		dest += SCREENWIDTH; 
    189 		frac += fracstep; 
    190 		count--;
    191 	} 
    192 }
    193 #endif
    194 
    195 
    196 void R_DrawColumnLow ( lighttable_t * dc_colormap,
    197 					   byte * dc_source ) 
    198 { 
    199 	int			count; 
    200 	byte*		dest; 
    201 	byte*		dest2;
    202 	fixed_t		frac;
    203 	fixed_t		fracstep;	 
    204 
    205 	count = ::g->dc_yh - ::g->dc_yl; 
    206 
    207 	// Zero length.
    208 	if (count < 0) 
    209 		return; 
    210 
    211 #ifdef RANGECHECK 
    212 	if ((unsigned)::g->dc_x >= SCREENWIDTH
    213 		|| ::g->dc_yl < 0
    214 		|| ::g->dc_yh >= SCREENHEIGHT)
    215 	{
    216 
    217 		I_Error ("R_DrawColumn: %i to %i at %i", ::g->dc_yl, ::g->dc_yh, ::g->dc_x);
    218 	}
    219 	//	::g->dccount++; 
    220 #endif 
    221 	// Blocky mode, need to multiply by 2.
    222 	::g->dc_x <<= 1;
    223 
    224 	dest = ::g->ylookup[::g->dc_yl] + ::g->columnofs[::g->dc_x];
    225 	dest2 = ::g->ylookup[::g->dc_yl] + ::g->columnofs[::g->dc_x+1];
    226 
    227 	fracstep = ::g->dc_iscale; 
    228 	frac = ::g->dc_texturemid + (::g->dc_yl-::g->centery)*fracstep;
    229 
    230 	do 
    231 	{
    232 		// Hack. Does not work corretly.
    233 		*dest2 = *dest = ::g->dc_colormap[::g->dc_source[(frac>>FRACBITS)&127]];
    234 		dest += SCREENWIDTH;
    235 		dest2 += SCREENWIDTH;
    236 		frac += fracstep; 
    237 
    238 	} while (count--);
    239 }
    240 
    241 
    242 //
    243 // Spectre/Invisibility.
    244 //
    245 
    246 
    247 
    248 
    249 
    250 //
    251 // Framebuffer postprocessing.
    252 // Creates a fuzzy image by copying pixels
    253 //  from adjacent ones to left and right.
    254 // Used with an all black colormap, this
    255 //  could create the SHADOW effect,
    256 //  i.e. spectres and invisible ::g->players.
    257 //
    258 void R_DrawFuzzColumn ( lighttable_t * dc_colormap,
    259 						  byte * dc_source ) 
    260 { 
    261 	int			count; 
    262 	byte*		dest; 
    263 	fixed_t		frac;
    264 	fixed_t		fracstep;	 
    265 
    266 	// Adjust borders. Low... 
    267 	if (!::g->dc_yl) 
    268 		::g->dc_yl = 1;
    269 
    270 	// .. and high.
    271 	if (::g->dc_yh == ::g->viewheight-1) 
    272 		::g->dc_yh = ::g->viewheight - 2; 
    273 
    274 	count = ::g->dc_yh - ::g->dc_yl; 
    275 
    276 	// Zero length.
    277 	if (count < 0) 
    278 		return; 
    279 
    280 
    281 #ifdef RANGECHECK 
    282 	if ((unsigned)::g->dc_x >= SCREENWIDTH
    283 		|| ::g->dc_yl < 0 || ::g->dc_yh >= SCREENHEIGHT)
    284 	{
    285 		I_Error ("R_DrawFuzzColumn: %i to %i at %i",
    286 			::g->dc_yl, ::g->dc_yh, ::g->dc_x);
    287 	}
    288 #endif
    289 
    290 
    291 	// Keep till ::g->detailshift bug in blocky mode fixed,
    292 	//  or blocky mode removed.
    293 	/* WATCOM code 
    294 	if (::g->detailshift)
    295 	{
    296 	if (::g->dc_x & 1)
    297 	{
    298 	outpw (GC_INDEX,GC_READMAP+(2<<8) ); 
    299 	outp (SC_INDEX+1,12); 
    300 	}
    301 	else
    302 	{
    303 	outpw (GC_INDEX,GC_READMAP); 
    304 	outp (SC_INDEX+1,3); 
    305 	}
    306 	dest = destview + ::g->dc_yl*80 + (::g->dc_x>>1); 
    307 	}
    308 	else
    309 	{
    310 	outpw (GC_INDEX,GC_READMAP+((::g->dc_x&3)<<8) ); 
    311 	outp (SC_INDEX+1,1<<(::g->dc_x&3)); 
    312 	dest = destview + ::g->dc_yl*80 + (::g->dc_x>>2); 
    313 	}*/
    314 
    315 
    316 	// Does not work with blocky mode.
    317 	dest = ::g->ylookup[::g->dc_yl] + ::g->columnofs[::g->dc_x];
    318 
    319 	// Looks familiar.
    320 	fracstep = ::g->dc_iscale; 
    321 	frac = ::g->dc_texturemid + (::g->dc_yl-::g->centery)*fracstep; 
    322 
    323 	// Looks like an attempt at dithering,
    324 	//  using the colormap #6 (of 0-31, a bit
    325 	//  brighter than average).
    326 	do 
    327 	{
    328 		// Lookup framebuffer, and retrieve
    329 		//  a pixel that is either one column
    330 		//  left or right of the current one.
    331 		// Add index from colormap to index.
    332 		*dest = ::g->colormaps[6*256+dest[::g->fuzzoffset[::g->fuzzpos]]]; 
    333 
    334 		// Clamp table lookup index.
    335 		if (++::g->fuzzpos == FUZZTABLE) 
    336 			::g->fuzzpos = 0;
    337 
    338 		dest += SCREENWIDTH;
    339 
    340 		frac += fracstep; 
    341 	} while (count--); 
    342 } 
    343 
    344 
    345 
    346 
    347 //
    348 // R_DrawTranslatedColumn
    349 // Used to draw player ::g->sprites
    350 //  with the green colorramp mapped to others.
    351 // Could be used with different translation
    352 //  tables, e.g. the lighter colored version
    353 //  of the BaronOfHell, the HellKnight, uses
    354 //  identical ::g->sprites, kinda brightened up.
    355 //
    356 
    357 void R_DrawTranslatedColumn ( lighttable_t * dc_colormap,
    358 						  byte * dc_source ) 
    359 { 
    360 	int			count; 
    361 	byte*		dest; 
    362 	fixed_t		frac;
    363 	fixed_t		fracstep;	 
    364 
    365 	count = ::g->dc_yh - ::g->dc_yl; 
    366 	if (count < 0) 
    367 		return; 
    368 
    369 #ifdef RANGECHECK 
    370 	if ((unsigned)::g->dc_x >= SCREENWIDTH
    371 		|| ::g->dc_yl < 0
    372 		|| ::g->dc_yh >= SCREENHEIGHT)
    373 	{
    374 		I_Error ( "R_DrawColumn: %i to %i at %i",
    375 			::g->dc_yl, ::g->dc_yh, ::g->dc_x);
    376 	}
    377 
    378 #endif 
    379 
    380 
    381 	// WATCOM VGA specific.
    382 	/* Keep for fixing.
    383 	if (::g->detailshift)
    384 	{
    385 	if (::g->dc_x & 1)
    386 	outp (SC_INDEX+1,12); 
    387 	else
    388 	outp (SC_INDEX+1,3);
    389 
    390 	dest = destview + ::g->dc_yl*80 + (::g->dc_x>>1); 
    391 	}
    392 	else
    393 	{
    394 	outp (SC_INDEX+1,1<<(::g->dc_x&3)); 
    395 
    396 	dest = destview + ::g->dc_yl*80 + (::g->dc_x>>2); 
    397 	}*/
    398 
    399 
    400 	// FIXME. As above.
    401 	dest = ::g->ylookup[::g->dc_yl] + ::g->columnofs[::g->dc_x]; 
    402 
    403 	// Looks familiar.
    404 	fracstep = ::g->dc_iscale; 
    405 	frac = ::g->dc_texturemid + (::g->dc_yl-::g->centery)*fracstep; 
    406 
    407 	// Here we do an additional index re-mapping.
    408 	do 
    409 	{
    410 		// Translation tables are used
    411 		//  to map certain colorramps to other ones,
    412 		//  used with PLAY ::g->sprites.
    413 		// Thus the "green" ramp of the player 0 sprite
    414 		//  is mapped to gray, red, black/indigo. 
    415 		*dest = dc_colormap[::g->dc_translation[dc_source[frac>>FRACBITS]]];
    416 		dest += SCREENWIDTH;
    417 
    418 		frac += fracstep; 
    419 	} while (count--); 
    420 } 
    421 
    422 
    423 
    424 
    425 //
    426 // R_InitTranslationTables
    427 // Creates the translation tables to map
    428 //  the green color ramp to gray, brown, red.
    429 // Assumes a given structure of the PLAYPAL.
    430 // Could be read from a lump instead.
    431 //
    432 void R_InitTranslationTables (void)
    433 {
    434 	int		i;
    435 
    436 	::g->translationtables = (byte*)DoomLib::Z_Malloc (256*3+255, PU_STATIC, 0);
    437 	::g->translationtables = (byte *)(( (int)::g->translationtables + 255 )& ~255);
    438 
    439 	// translate just the 16 green colors
    440 	for (i=0 ; i<256 ; i++)
    441 	{
    442 		if (i >= 0x70 && i<= 0x7f)
    443 		{
    444 			// map green ramp to gray, brown, red
    445 			::g->translationtables[i] = 0x60 + (i&0xf);
    446 			::g->translationtables [i+256] = 0x40 + (i&0xf);
    447 			::g->translationtables [i+512] = 0x20 + (i&0xf);
    448 		}
    449 		else
    450 		{
    451 			// Keep all other colors as is.
    452 			::g->translationtables[i] = ::g->translationtables[i+256] 
    453 			= ::g->translationtables[i+512] = i;
    454 		}
    455 	}
    456 }
    457 
    458 
    459 
    460 
    461 //
    462 // R_DrawSpan 
    463 // With DOOM style restrictions on view orientation,
    464 //  the floors and ceilings consist of horizontal slices
    465 //  or spans with constant z depth.
    466 // However, rotation around the world z axis is possible,
    467 //  thus this mapping, while simpler and faster than
    468 //  perspective correct texture mapping, has to traverse
    469 //  the texture at an angle in all but a few cases.
    470 // In consequence, flats are not stored by column (like walls),
    471 //  and the inner loop has to step in texture space u and v.
    472 //
    473 
    474 
    475 
    476 // start of a 64*64 tile image 
    477 
    478 // just for profiling
    479 
    480 
    481 //
    482 // Draws the actual span.
    483 void R_DrawSpan ( fixed_t xfrac,
    484 				  fixed_t yfrac,
    485 				  fixed_t ds_y,
    486 				  int ds_x1,
    487 				  int ds_x2,
    488 				  fixed_t ds_xstep,
    489 				  fixed_t ds_ystep,
    490 				  lighttable_t * ds_colormap,
    491 				  byte * ds_source ) 
    492 { 
    493 	byte*		dest; 
    494 	int			count;
    495 	int			spot; 
    496 
    497 #ifdef RANGECHECK
    498 	if (::g->ds_x2 < ::g->ds_x1
    499 		|| ::g->ds_x1<0
    500 		|| ::g->ds_x2>=SCREENWIDTH  
    501 		|| (unsigned)::g->ds_y>SCREENHEIGHT)
    502 	{
    503 		I_Error( "R_DrawSpan: %i to %i at %i",
    504 			::g->ds_x1,::g->ds_x2,::g->ds_y);
    505 	}
    506 	//	::g->dscount++; 
    507 #endif 
    508 
    509 	dest = ::g->ylookup[::g->ds_y] + ::g->columnofs[::g->ds_x1];
    510 
    511 	// We do not check for zero spans here?
    512 	count = ds_x2 - g->ds_x1; 
    513 
    514 	if ( ds_x2 < ds_x1 ) {
    515 		return;						// SMF - think this is the sky
    516 	}
    517 
    518 	do 
    519 	{
    520 		// Current texture index in u,v.
    521 		spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63);
    522 
    523 		// Lookup pixel from flat texture tile,
    524 		//  re-index using light/colormap.
    525 		*dest++ = ds_colormap[ds_source[spot]];
    526 
    527 		// Next step in u,v.
    528 		xfrac += ds_xstep; 
    529 		yfrac += ds_ystep;
    530 
    531 	} while (count--); 
    532 } 
    533 
    534 
    535 
    536 // UNUSED.
    537 // Loop unrolled by 4.
    538 #if 0
    539 void R_DrawSpan (void) 
    540 { 
    541 	unsigned	position, step;
    542 
    543 	byte*	source;
    544 	byte*	colormap;
    545 	byte*	dest;
    546 
    547 	unsigned	count;
    548 	usingned	spot; 
    549 	unsigned	value;
    550 	unsigned	temp;
    551 	unsigned	xtemp;
    552 	unsigned	ytemp;
    553 
    554 	position = ((::g->ds_xfrac<<10)&0xffff0000) | ((::g->ds_yfrac>>6)&0xffff);
    555 	step = ((::g->ds_xstep<<10)&0xffff0000) | ((::g->ds_ystep>>6)&0xffff);
    556 
    557 	source = ::g->ds_source;
    558 	colormap = ::g->ds_colormap;
    559 	dest = ::g->ylookup[::g->ds_y] + ::g->columnofs[::g->ds_x1];	 
    560 	count = ::g->ds_x2 - ::g->ds_x1 + 1; 
    561 
    562 	while (count >= 4) 
    563 	{ 
    564 		ytemp = position>>4;
    565 		ytemp = ytemp & 4032;
    566 		xtemp = position>>26;
    567 		spot = xtemp | ytemp;
    568 		position += step;
    569 		dest[0] = colormap[source[spot]]; 
    570 
    571 		ytemp = position>>4;
    572 		ytemp = ytemp & 4032;
    573 		xtemp = position>>26;
    574 		spot = xtemp | ytemp;
    575 		position += step;
    576 		dest[1] = colormap[source[spot]];
    577 
    578 		ytemp = position>>4;
    579 		ytemp = ytemp & 4032;
    580 		xtemp = position>>26;
    581 		spot = xtemp | ytemp;
    582 		position += step;
    583 		dest[2] = colormap[source[spot]];
    584 
    585 		ytemp = position>>4;
    586 		ytemp = ytemp & 4032;
    587 		xtemp = position>>26;
    588 		spot = xtemp | ytemp;
    589 		position += step;
    590 		dest[3] = colormap[source[spot]]; 
    591 
    592 		count -= 4;
    593 		dest += 4;
    594 	} 
    595 	while (count > 0) 
    596 	{ 
    597 		ytemp = position>>4;
    598 		ytemp = ytemp & 4032;
    599 		xtemp = position>>26;
    600 		spot = xtemp | ytemp;
    601 		position += step;
    602 		*dest++ = colormap[source[spot]]; 
    603 		count--;
    604 	} 
    605 } 
    606 #endif
    607 
    608 
    609 //
    610 // Again..
    611 //
    612 void R_DrawSpanLow ( fixed_t xfrac,
    613 				  fixed_t yfrac,
    614 				  fixed_t ds_y,
    615 				  int ds_x1,
    616 				  int ds_x2,
    617 				  fixed_t ds_xstep,
    618 				  fixed_t ds_ystep,
    619 				  lighttable_t * ds_colormap,
    620 				  byte * ds_source ) 
    621 {
    622 	byte*		dest; 
    623 	int			count;
    624 	int			spot; 
    625 
    626 #ifdef RANGECHECK 
    627 	if (::g->ds_x2 < ::g->ds_x1
    628 		|| ::g->ds_x1<0
    629 		|| ::g->ds_x2>=SCREENWIDTH  
    630 		|| (unsigned)::g->ds_y>SCREENHEIGHT)
    631 	{
    632 		I_Error( "R_DrawSpan: %i to %i at %i",
    633 			::g->ds_x1,::g->ds_x2,::g->ds_y);
    634 	}
    635 	//	::g->dscount++; 
    636 #endif 
    637 
    638 	// Blocky mode, need to multiply by 2.
    639 	::g->ds_x1 <<= 1;
    640 	::g->ds_x2 <<= 1;
    641 
    642 	dest = ::g->ylookup[::g->ds_y] + ::g->columnofs[::g->ds_x1];
    643 
    644 
    645 	count = ::g->ds_x2 - ::g->ds_x1; 
    646 	do 
    647 	{ 
    648 		spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63);
    649 		// Lowres/blocky mode does it twice,
    650 		//  while scale is adjusted appropriately.
    651 		*dest++ = ::g->ds_colormap[::g->ds_source[spot]]; 
    652 		*dest++ = ::g->ds_colormap[::g->ds_source[spot]];
    653 
    654 		xfrac += ::g->ds_xstep; 
    655 		yfrac += ::g->ds_ystep; 
    656 
    657 	} while (count--); 
    658 }
    659 
    660 //
    661 // R_InitBuffer 
    662 // Creats lookup tables that avoid
    663 //  multiplies and other hazzles
    664 //  for getting the framebuffer address
    665 //  of a pixel to draw.
    666 //
    667 void
    668 R_InitBuffer
    669 ( int		width,
    670  int		height ) 
    671 { 
    672 	int		i; 
    673 
    674 	// Handle resize,
    675 	//  e.g. smaller view windows
    676 	//  with border and/or status bar.
    677 	::g->viewwindowx = (SCREENWIDTH-width) >> 1; 
    678 
    679 	// Column offset. For windows.
    680 	for (i=0 ; i<width ; i++) 
    681 		::g->columnofs[i] = ::g->viewwindowx + i;
    682 
    683 	// Samw with base row offset.
    684 	if (width == SCREENWIDTH) 
    685 		::g->viewwindowy = 0; 
    686 	else 
    687 		::g->viewwindowy = (SCREENHEIGHT-SBARHEIGHT-height) >> 1; 
    688 
    689 	// Preclaculate all row offsets.
    690 	for (i=0 ; i<height ; i++) 
    691 		::g->ylookup[i] = ::g->screens[0] + (i+::g->viewwindowy)*SCREENWIDTH; 
    692 } 
    693 
    694 
    695 
    696 
    697 //
    698 // R_FillBackScreen
    699 // Fills the back screen with a pattern
    700 //  for variable screen sizes
    701 // Also draws a beveled edge.
    702 //
    703 void R_FillBackScreen (void) 
    704 { 
    705 	byte*		src;
    706 	byte*		dest; 
    707 	int			x;
    708 	int			y; 
    709 	int			width, height, windowx, windowy;
    710 	patch_t*	patch;
    711 
    712 	// DOOM border patch.
    713 	char	name1[] = "FLOOR7_2";
    714 	// DOOM II border patch.
    715 	char	name2[] = "GRNROCK";	
    716 
    717 	char*	name;
    718 
    719 	if (::g->scaledviewwidth == SCREENWIDTH)
    720 		return;
    721 
    722 	if ( ::g->gamemode == commercial)
    723 		name = name2;
    724 	else
    725 		name = name1;
    726 
    727 	src = (byte*)W_CacheLumpName (name, PU_CACHE_SHARED); 
    728 	dest = ::g->screens[1]; 
    729 
    730 	for (y=0 ; y<SCREENHEIGHT-SBARHEIGHT ; y++) { 
    731 		for (x=0 ; x<SCREENWIDTH/64 ; x++) 	{ 
    732 			memcpy(dest, src+((y&63)<<6), 64); 
    733 			dest += 64; 
    734 		} 
    735 		if (SCREENWIDTH&63) 
    736 		{ 
    737 			memcpy(dest, src+((y&63)<<6), SCREENWIDTH&63); 
    738 			dest += (SCREENWIDTH&63); 
    739 		} 
    740 	} 
    741 
    742 	width = ::g->scaledviewwidth / GLOBAL_IMAGE_SCALER;
    743 	height = ::g->viewheight / GLOBAL_IMAGE_SCALER;
    744 	windowx = ::g->viewwindowx / GLOBAL_IMAGE_SCALER;
    745 	windowy = ::g->viewwindowy / GLOBAL_IMAGE_SCALER;
    746 
    747 	patch = (patch_t*)W_CacheLumpName ("brdr_t",PU_CACHE_SHARED);
    748 	for (x=0 ; x<width ; x+=8) {
    749 		V_DrawPatch (windowx+x,windowy-8,1,patch);
    750 	}
    751 
    752 	patch = (patch_t*)W_CacheLumpName ("brdr_b",PU_CACHE_SHARED);
    753 	for (x=0 ; x<width ; x+=8) {
    754 		V_DrawPatch (windowx+x,windowy+height,1,patch);
    755 	}
    756 
    757 	patch = (patch_t*)W_CacheLumpName ("brdr_l",PU_CACHE_SHARED);
    758 	for (y=0 ; y<height ; y+=8) {
    759 		V_DrawPatch (windowx-8,windowy+y,1,patch);
    760 	}
    761 
    762 	patch = (patch_t*)W_CacheLumpName ("brdr_r",PU_CACHE_SHARED);
    763 	for (y=0 ; y<height ; y+=8) {
    764 		V_DrawPatch (windowx+width,windowy+y,1,patch);
    765 	}
    766 
    767 	// Draw beveled edge. 
    768 	V_DrawPatch(windowx-8, windowy-8, 1, (patch_t*)W_CacheLumpName ("brdr_tl",PU_CACHE_SHARED));
    769 	V_DrawPatch(windowx+width, windowy-8, 1, (patch_t*)W_CacheLumpName ("brdr_tr",PU_CACHE_SHARED));
    770 	V_DrawPatch(windowx-8, windowy+height, 1, (patch_t*)W_CacheLumpName ("brdr_bl",PU_CACHE_SHARED));
    771 	V_DrawPatch (windowx+width, windowy+height, 1, (patch_t*)W_CacheLumpName ("brdr_br",PU_CACHE_SHARED));
    772 } 
    773 
    774 
    775 //
    776 // Copy a screen buffer.
    777 //
    778 void
    779 R_VideoErase
    780 ( unsigned	ofs,
    781  int		count ) 
    782 { 
    783 	// LFB copy.
    784 	// This might not be a good idea if memcpy
    785 	//  is not optiomal, e.g. byte by byte on
    786 	//  a 32bit CPU, as GNU GCC/Linux libc did
    787 	//  at one point.
    788 	memcpy(::g->screens[0]+ofs, ::g->screens[1]+ofs, count); 
    789 } 
    790 
    791 
    792 //
    793 // R_DrawViewBorder
    794 // Draws the border around the view
    795 //  for different size windows?
    796 //
    797 void
    798 V_MarkRect
    799 ( int		x,
    800  int		y,
    801  int		width,
    802  int		height ); 
    803 
    804 void R_DrawViewBorder (void) 
    805 { 
    806 	int		top;
    807 	int		side;
    808 	int		ofs;
    809 	int		i; 
    810 
    811 	if (::g->scaledviewwidth == SCREENWIDTH) 
    812 		return; 
    813 
    814 	top = ((SCREENHEIGHT-SBARHEIGHT)-::g->viewheight)/2; 
    815 	side = (SCREENWIDTH-::g->scaledviewwidth)/2; 
    816 
    817 	// copy top and one line of left side 
    818 	R_VideoErase (0, top*SCREENWIDTH+side); 
    819 
    820 	// copy one line of right side and bottom 
    821 	ofs = (::g->viewheight+top)*SCREENWIDTH-side; 
    822 	R_VideoErase (ofs, top*SCREENWIDTH+side); 
    823 
    824 	// copy ::g->sides using wraparound 
    825 	ofs = top*SCREENWIDTH + SCREENWIDTH-side; 
    826 	side <<= 1;
    827 
    828 	for (i=1 ; i < ::g->viewheight ; i++) 
    829 	{ 
    830 		R_VideoErase (ofs, side); 
    831 		ofs += SCREENWIDTH; 
    832 	} 
    833 
    834 	// ? 
    835 	V_MarkRect (0,0,SCREENWIDTH, SCREENHEIGHT-SBARHEIGHT); 
    836 } 
    837 
    838 
    839