r_draw.c
上传用户:xuyinpeng
上传日期:2021-05-12
资源大小:455k
文件大小:20k
源码类别:

射击游戏

开发平台:

Visual C++

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