1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
6 // Copyright (C) 1993-1996 by id Software, Inc.
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.
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
20 // The actual span/column drawing functions.
21 // Here find the main potential for optimization,
22 // e.g. inline assembly, different algorithms.
24 //-----------------------------------------------------------------------------
28 rcsid[] = "$Id: r_draw.c,v 1.4 1997/02/03 16:47:55 b1 Exp $";
39 // Needs access to LFB (guess what).
50 // status bar height at bottom of screen
54 // All drawing to the view buffer is accomplished in this file.
55 // The other refresh files only know about ccordinates,
56 // not the architecture of the frame buffer.
57 // Conveniently, the frame buffer is a linear one,
58 // and we need only the base address,
59 // and the total size == width*height*depth/8.,
69 byte* ylookup[MAXHEIGHT];
70 int columnofs[MAXWIDTH];
72 // Color tables for different players,
73 // translate a limited part to another
74 // (color ramps used for suit colors).
76 byte translations[3][256];
83 // Source is the top of the column to scale.
85 lighttable_t* dc_colormap;
90 fixed_t dc_texturemid;
92 // first pixel in a column (possibly virtual)
99 // A column is a vertical slice/span from a wall texture that,
100 // given the DOOM style restrictions on the view orientation,
101 // will always have constant z depth.
102 // Thus a special case loop for very fast rendering can
103 // be used. It has also been used with Wolfenstein 3D.
105 void R_DrawColumn (void)
112 count = dc_yh - dc_yl;
114 // Zero length, column does not exceed a pixel.
119 if ((unsigned)dc_x >= SCREENWIDTH
121 || dc_yh >= SCREENHEIGHT)
122 I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
125 // Framebuffer destination address.
126 // Use ylookup LUT to avoid multiply with ScreenWidth.
127 // Use columnofs LUT for subwindows?
128 dest = ylookup[dc_yl] + columnofs[dc_x];
130 // Determine scaling,
131 // which is the only mapping to be done.
132 fracstep = dc_iscale;
133 frac = dc_texturemid + (dc_yl-centery)*fracstep;
135 // Inner loop that does the actual texture mapping,
136 // e.g. a DDA-lile scaling.
137 // This is as fast as it gets.
140 // Re-map color indices from wall texture column
141 // using a lighting/special effects LUT.
142 *dest = dc_colormap[dc_source[(frac>>FRACBITS)&127]];
151 void R_DrawColumnLow (void)
159 count = dc_yh - dc_yl;
166 if ((unsigned)dc_x >= SCREENWIDTH
168 || dc_yh >= SCREENHEIGHT)
171 I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
175 // Blocky mode, need to multiply by 2.
178 dest = ylookup[dc_yl] + columnofs[dc_x];
179 dest2 = ylookup[dc_yl] + columnofs[dc_x+1];
181 fracstep = dc_iscale;
182 frac = dc_texturemid + (dc_yl-centery)*fracstep;
186 // Hack. Does not work corretly.
187 *dest2 = *dest = dc_colormap[dc_source[(frac>>FRACBITS)&127]];
189 dest2 += SCREENWIDTH;
197 // Spectre/Invisibility.
200 #define FUZZOFF (SCREENWIDTH)
203 int fuzzoffset[FUZZTABLE] =
205 FUZZOFF,-FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
206 FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
207 FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,
208 FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
209 FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,
210 FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,
211 FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF
218 // Framebuffer postprocessing.
219 // Creates a fuzzy image by copying pixels
220 // from adjacent ones to left and right.
221 // Used with an all black colormap, this
222 // could create the SHADOW effect,
223 // i.e. spectres and invisible players.
225 void R_DrawFuzzColumn (void)
232 // Adjust borders. Low...
237 if (dc_yh == viewheight-1)
238 dc_yh = viewheight - 2;
240 count = dc_yh - dc_yl;
248 if ((unsigned)dc_x >= SCREENWIDTH
249 || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
251 I_Error ("R_DrawFuzzColumn: %i to %i at %i",
257 // Keep till detailshift bug in blocky mode fixed,
258 // or blocky mode removed.
264 outpw (GC_INDEX,GC_READMAP+(2<<8) );
265 outp (SC_INDEX+1,12);
269 outpw (GC_INDEX,GC_READMAP);
272 dest = destview + dc_yl*80 + (dc_x>>1);
276 outpw (GC_INDEX,GC_READMAP+((dc_x&3)<<8) );
277 outp (SC_INDEX+1,1<<(dc_x&3));
278 dest = destview + dc_yl*80 + (dc_x>>2);
282 // Does not work with blocky mode.
283 dest = ylookup[dc_yl] + columnofs[dc_x];
286 fracstep = dc_iscale;
287 frac = dc_texturemid + (dc_yl-centery)*fracstep;
289 // Looks like an attempt at dithering,
290 // using the colormap #6 (of 0-31, a bit
291 // brighter than average).
294 // Lookup framebuffer, and retrieve
295 // a pixel that is either one column
296 // left or right of the current one.
297 // Add index from colormap to index.
298 *dest = colormaps[6*256+dest[fuzzoffset[fuzzpos]]];
300 // Clamp table lookup index.
301 if (++fuzzpos == FUZZTABLE)
314 // R_DrawTranslatedColumn
315 // Used to draw player sprites
316 // with the green colorramp mapped to others.
317 // Could be used with different translation
318 // tables, e.g. the lighter colored version
319 // of the BaronOfHell, the HellKnight, uses
320 // identical sprites, kinda brightened up.
322 byte* dc_translation;
323 byte* translationtables;
325 void R_DrawTranslatedColumn (void)
332 count = dc_yh - dc_yl;
337 if ((unsigned)dc_x >= SCREENWIDTH
339 || dc_yh >= SCREENHEIGHT)
341 I_Error ( "R_DrawColumn: %i to %i at %i",
348 // WATCOM VGA specific.
353 outp (SC_INDEX+1,12);
357 dest = destview + dc_yl*80 + (dc_x>>1);
361 outp (SC_INDEX+1,1<<(dc_x&3));
363 dest = destview + dc_yl*80 + (dc_x>>2);
368 dest = ylookup[dc_yl] + columnofs[dc_x];
371 fracstep = dc_iscale;
372 frac = dc_texturemid + (dc_yl-centery)*fracstep;
374 // Here we do an additional index re-mapping.
377 // Translation tables are used
378 // to map certain colorramps to other ones,
379 // used with PLAY sprites.
380 // Thus the "green" ramp of the player 0 sprite
381 // is mapped to gray, red, black/indigo.
382 *dest = dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]];
393 // R_InitTranslationTables
394 // Creates the translation tables to map
395 // the green color ramp to gray, brown, red.
396 // Assumes a given structure of the PLAYPAL.
397 // Could be read from a lump instead.
399 void R_InitTranslationTables (void)
403 translationtables = Z_Malloc (256*3+255, PU_STATIC, 0);
404 translationtables = (byte *)(( (int)translationtables + 255 )& ~255);
406 // translate just the 16 green colors
407 for (i=0 ; i<256 ; i++)
409 if (i >= 0x70 && i<= 0x7f)
411 // map green ramp to gray, brown, red
412 translationtables[i] = 0x60 + (i&0xf);
413 translationtables [i+256] = 0x40 + (i&0xf);
414 translationtables [i+512] = 0x20 + (i&0xf);
418 // Keep all other colors as is.
419 translationtables[i] = translationtables[i+256]
420 = translationtables[i+512] = i;
430 // With DOOM style restrictions on view orientation,
431 // the floors and ceilings consist of horizontal slices
432 // or spans with constant z depth.
433 // However, rotation around the world z axis is possible,
434 // thus this mapping, while simpler and faster than
435 // perspective correct texture mapping, has to traverse
436 // the texture at an angle in all but a few cases.
437 // In consequence, flats are not stored by column (like walls),
438 // and the inner loop has to step in texture space u and v.
444 lighttable_t* ds_colormap;
451 // start of a 64*64 tile image
454 // just for profiling
459 // Draws the actual span.
460 void R_DrawSpan (void)
471 || ds_x2>=SCREENWIDTH
472 || (unsigned)ds_y>SCREENHEIGHT)
474 I_Error( "R_DrawSpan: %i to %i at %i",
484 dest = ylookup[ds_y] + columnofs[ds_x1];
486 // We do not check for zero spans here?
487 count = ds_x2 - ds_x1;
491 // Current texture index in u,v.
492 spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63);
494 // Lookup pixel from flat texture tile,
495 // re-index using light/colormap.
496 *dest++ = ds_colormap[ds_source[spot]];
509 void R_DrawSpanLow (void)
520 || ds_x2>=SCREENWIDTH
521 || (unsigned)ds_y>SCREENHEIGHT)
523 I_Error( "R_DrawSpan: %i to %i at %i",
532 // Blocky mode, need to multiply by 2.
536 dest = ylookup[ds_y] + columnofs[ds_x1];
539 count = ds_x2 - ds_x1;
542 spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63);
543 // Lowres/blocky mode does it twice,
544 // while scale is adjusted appropriately.
545 *dest++ = ds_colormap[ds_source[spot]];
546 *dest++ = ds_colormap[ds_source[spot]];
556 // Creats lookup tables that avoid
557 // multiplies and other hazzles
558 // for getting the framebuffer address
559 // of a pixel to draw.
569 // e.g. smaller view windows
570 // with border and/or status bar.
571 viewwindowx = (SCREENWIDTH-width) >> 1;
573 // Column offset. For windows.
574 for (i=0 ; i<width ; i++)
575 columnofs[i] = viewwindowx + i;
577 // Samw with base row offset.
578 if (width == SCREENWIDTH)
581 viewwindowy = (SCREENHEIGHT-SBARHEIGHT-height) >> 1;
583 // Preclaculate all row offsets.
584 for (i=0 ; i<height ; i++)
585 ylookup[i] = screens[0] + (i+viewwindowy)*SCREENWIDTH;
593 // Fills the back screen with a pattern
594 // for variable screen sizes
595 // Also draws a beveled edge.
597 void R_FillBackScreen (void)
605 // DOOM border patch.
606 char name1[] = "FLOOR7_2";
608 // DOOM II border patch.
609 char name2[] = "GRNROCK";
613 if (scaledviewwidth == 320)
616 if ( gamemode == commercial)
621 src = W_CacheLumpName (name, PU_CACHE);
624 for (y=0 ; y<SCREENHEIGHT-SBARHEIGHT ; y++)
626 for (x=0 ; x<SCREENWIDTH/64 ; x++)
628 memcpy (dest, src+((y&63)<<6), 64);
634 memcpy (dest, src+((y&63)<<6), SCREENWIDTH&63);
635 dest += (SCREENWIDTH&63);
639 patch = W_CacheLumpName ("brdr_t",PU_CACHE);
641 for (x=0 ; x<scaledviewwidth ; x+=8)
642 V_DrawPatch (viewwindowx+x,viewwindowy-8,1,patch);
643 patch = W_CacheLumpName ("brdr_b",PU_CACHE);
645 for (x=0 ; x<scaledviewwidth ; x+=8)
646 V_DrawPatch (viewwindowx+x,viewwindowy+viewheight,1,patch);
647 patch = W_CacheLumpName ("brdr_l",PU_CACHE);
649 for (y=0 ; y<viewheight ; y+=8)
650 V_DrawPatch (viewwindowx-8,viewwindowy+y,1,patch);
651 patch = W_CacheLumpName ("brdr_r",PU_CACHE);
653 for (y=0 ; y<viewheight ; y+=8)
654 V_DrawPatch (viewwindowx+scaledviewwidth,viewwindowy+y,1,patch);
657 // Draw beveled edge.
658 V_DrawPatch (viewwindowx-8,
661 W_CacheLumpName ("brdr_tl",PU_CACHE));
663 V_DrawPatch (viewwindowx+scaledviewwidth,
666 W_CacheLumpName ("brdr_tr",PU_CACHE));
668 V_DrawPatch (viewwindowx-8,
669 viewwindowy+viewheight,
671 W_CacheLumpName ("brdr_bl",PU_CACHE));
673 V_DrawPatch (viewwindowx+scaledviewwidth,
674 viewwindowy+viewheight,
676 W_CacheLumpName ("brdr_br",PU_CACHE));
681 // Copy a screen buffer.
689 // This might not be a good idea if memcpy
690 // is not optiomal, e.g. byte by byte on
691 // a 32bit CPU, as GNU GCC/Linux libc did
693 memcpy (screens[0]+ofs, screens[1]+ofs, count);
699 // Draws the border around the view
700 // for different size windows?
709 void R_DrawViewBorder (void)
716 if (scaledviewwidth == SCREENWIDTH)
719 top = ((SCREENHEIGHT-SBARHEIGHT)-viewheight)/2;
720 side = (SCREENWIDTH-scaledviewwidth)/2;
722 // copy top and one line of left side
723 R_VideoErase (0, top*SCREENWIDTH+side);
725 // copy one line of right side and bottom
726 ofs = (viewheight+top)*SCREENWIDTH-side;
727 R_VideoErase (ofs, top*SCREENWIDTH+side);
729 // copy sides using wraparound
730 ofs = top*SCREENWIDTH + SCREENWIDTH-side;
733 for (i=1 ; i<viewheight ; i++)
735 R_VideoErase (ofs, side);
740 V_MarkRect (0,0,SCREENWIDTH, SCREENHEIGHT-SBARHEIGHT);