Move c/h files implementing/defining standard library stuff into a new libc directory...
[kugel-rb.git] / apps / plugins / doom / r_draw.c
blob8208972a660b81bee8cbb284e7614d0bfd057dbf
1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
5 * PrBoom a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 * 02111-1307, USA.
27 * DESCRIPTION:
28 * The actual span/column drawing functions.
29 * Here find the main potential for optimization,
30 * e.g. inline assembly, different algorithms.
32 *-----------------------------------------------------------------------------*/
34 #include "doomstat.h"
35 #include "w_wad.h"
36 #include "r_main.h"
37 #include "v_video.h"
38 #include "st_stuff.h"
39 #include "g_game.h"
40 #include "am_map.h"
41 //#include "lprintf.h"
42 #include "rockmacros.h"
45 // All drawing to the view buffer is accomplished in this file.
46 // The other refresh files only know about ccordinates,
47 // not the architecture of the frame buffer.
48 // Conveniently, the frame buffer is a linear one,
49 // and we need only the base address,
50 // and the total size == width*height*depth/8.,
53 //byte* viewimage;
54 int viewwidth;
55 int scaledviewwidth;
56 int viewheight;
57 int viewwindowx;
58 int viewwindowy;
60 byte *topleft IBSS_ATTR;
62 // Color tables for different players,
63 // translate a limited part to another
64 // (color ramps used for suit colors).
67 // CPhipps - made const*'s
68 const byte *tranmap IBSS_ATTR; // translucency filter maps 256x256 // phares
69 const byte *main_tranmap IBSS_ATTR; // killough 4/11/98
72 // R_DrawColumn
73 // Source is the top of the column to scale.
76 lighttable_t *dc_colormap IBSS_ATTR;
77 int dc_x IBSS_ATTR;
78 int dc_yl IBSS_ATTR;
79 int dc_yh IBSS_ATTR;
80 fixed_t dc_iscale IBSS_ATTR;
81 fixed_t dc_texturemid IBSS_ATTR;
82 int dc_texheight IBSS_ATTR; // killough
83 const byte *dc_source IBSS_ATTR; // first pixel in a column (possibly virtual)
87 // A column is a vertical slice/span from a wall texture that,
88 // given the DOOM style restrictions on the view orientation,
89 // will always have constant z depth.
90 // Thus a special case loop for very fast rendering can
91 // be used. It has also been used with Wolfenstein 3D.
93 void R_DrawColumn (void)
95 int count;
96 register byte *dest; // killough
97 register fixed_t frac; // killough
99 // leban 1/17/99:
100 // removed the + 1 here, adjusted the if test, and added an increment
101 // later. this helps a compiler pipeline a bit better. the x86
102 // assembler also does this.
103 count = dc_yh - dc_yl;
105 // Zero length, column does not exceed a pixel.
106 if (count < 0)
107 return;
109 #ifdef RANGECHECK
111 if ((unsigned)dc_x >= SCREENWIDTH
112 || dc_yl < 0
113 || dc_yh >= SCREENHEIGHT)
114 I_Error ("R_DrawColumn: %d to %d at %d", dc_yl, dc_yh, dc_x);
115 #endif
117 count++;
119 // Framebuffer destination address.
120 dest = topleft + dc_yl*SCREENWIDTH + dc_x;
122 // Determine scaling,
123 // which is the only mapping to be done.
124 #define fracstep dc_iscale
126 frac = dc_texturemid + (dc_yl-centery)*fracstep;
128 // Inner loop that does the actual texture mapping,
129 // e.g. a DDA-lile scaling.
130 // This is as fast as it gets. (Yeah, right!!! -- killough)
132 // killough 2/1/98: more performance tuning
134 if (dc_texheight == 128)
136 while(count--)
138 *dest = dc_colormap[dc_source[(frac>>FRACBITS)&127]];
139 frac += fracstep;
140 dest += SCREENWIDTH;
143 else if (dc_texheight == 0)
145 /* cph - another special case */
146 while (count--)
148 *dest = dc_colormap[dc_source[frac>>FRACBITS]];
149 frac += fracstep;
150 dest += SCREENWIDTH;
153 else
155 register unsigned heightmask = dc_texheight-1; // CPhipps - specify type
156 if (! (dc_texheight & heightmask) ) // power of 2 -- killough
158 while (count>0) // texture height is a power of 2 -- killough
160 *dest = dc_colormap[dc_source[(frac>>FRACBITS) & heightmask]];
161 dest += SCREENWIDTH;
162 frac += fracstep;
163 count--;
166 else
168 heightmask++;
169 heightmask <<= FRACBITS;
171 if (frac < 0)
172 while ((frac += heightmask) < 0)
174 else
175 while (frac >= (int)heightmask)
176 frac -= heightmask;
178 while(count>0)
180 // Re-map color indices from wall texture column
181 // using a lighting/special effects LUT.
183 // heightmask is the Tutti-Frutti fix -- killough
185 *dest = dc_colormap[dc_source[frac>>FRACBITS]];
186 dest += SCREENWIDTH;
187 if ((frac += fracstep) >= (int)heightmask)
188 frac -= heightmask;
189 count--;
194 #undef fracstep
196 // Here is the version of R_DrawColumn that deals with translucent // phares
197 // textures and sprites. It's identical to R_DrawColumn except // |
198 // for the spot where the color index is stuffed into *dest. At // V
199 // that point, the existing color index and the new color index
200 // are mapped through the TRANMAP lump filters to get a new color
201 // index whose RGB values are the average of the existing and new
202 // colors.
204 // Since we're concerned about performance, the 'translucent or
205 // opaque' decision is made outside this routine, not down where the
206 // actual code differences are.
208 void R_DrawTLColumn (void)
210 int count;
211 register byte *dest; // killough
212 register fixed_t frac; // killough
214 count = dc_yh - dc_yl + 1;
216 // Zero length, column does not exceed a pixel.
217 if (count <= 0)
218 return;
220 #ifdef RANGECHECK
222 if ((unsigned)dc_x >= (unsigned)SCREENWIDTH
223 || dc_yl < 0
224 || dc_yh >= SCREENHEIGHT)
225 I_Error("R_DrawTLColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
226 #endif
228 // Framebuffer destination address.
229 dest = topleft + dc_yl*SCREENWIDTH + dc_x;
231 // Determine scaling,
232 // which is the only mapping to be done.
233 #define fracstep dc_iscale
235 frac = dc_texturemid + (dc_yl-centery)*fracstep;
237 // Inner loop that does the actual texture mapping,
238 // e.g. a DDA-lile scaling.
239 // This is as fast as it gets. (Yeah, right!!! -- killough)
241 // killough 2/1/98, 2/21/98: more performance tuning
244 register const byte *source = dc_source;
245 register const lighttable_t *colormap = dc_colormap;
246 register unsigned heightmask = dc_texheight-1; // CPhipps - specify type
247 if (dc_texheight & heightmask) // not a power of 2 -- killough
249 heightmask++;
250 heightmask <<= FRACBITS;
252 if (frac < 0)
253 while ((frac += heightmask) < 0)
255 else
256 while (frac >= (int)heightmask)
257 frac -= heightmask;
261 // Re-map color indices from wall texture column
262 // using a lighting/special effects LUT.
264 // heightmask is the Tutti-Frutti fix -- killough
266 *dest = tranmap[(*dest<<8)+colormap[source[frac>>FRACBITS]]]; // phares
267 dest += SCREENWIDTH;
268 if ((frac += fracstep) >= (int)heightmask)
269 frac -= heightmask;
271 while (--count);
273 else
275 while ((count-=2)>=0) // texture height is a power of 2 -- killough
277 *dest = tranmap[(*dest<<8)+colormap[source[(frac>>FRACBITS) & heightmask]]]; // phares
278 dest += SCREENWIDTH;
279 frac += fracstep;
280 *dest = tranmap[(*dest<<8)+colormap[source[(frac>>FRACBITS) & heightmask]]]; // phares
281 dest += SCREENWIDTH;
282 frac += fracstep;
284 if (count & 1)
285 *dest = tranmap[(*dest<<8)+colormap[source[(frac>>FRACBITS) & heightmask]]]; // phares
289 #undef fracstep
292 // Spectre/Invisibility.
295 #define FUZZTABLE 50
296 // proff 08/17/98: Changed for high-res
297 //#define FUZZOFF (SCREENWIDTH)
298 #define FUZZOFF 1
300 static const int fuzzoffset_org[FUZZTABLE] ICONST_ATTR = {
301 FUZZOFF,-FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
302 FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
303 FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,
304 FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
305 FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,
306 FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,
307 FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF
310 static int fuzzoffset[FUZZTABLE] IBSS_ATTR;
312 static int fuzzpos IBSS_ATTR = 0;
315 // Framebuffer postprocessing.
316 // Creates a fuzzy image by copying pixels
317 // from adjacent ones to left and right.
318 // Used with an all black colormap, this
319 // could create the SHADOW effect,
320 // i.e. spectres and invisible players.
323 void R_DrawFuzzColumn(void)
325 int count;
326 byte *dest;
327 fixed_t frac;
328 fixed_t fracstep;
330 // Adjust borders. Low...
331 if (!dc_yl)
332 dc_yl = 1;
334 // .. and high.
335 if (dc_yh == viewheight-1)
336 dc_yh = viewheight - 2;
338 count = dc_yh - dc_yl;
340 // Zero length.
341 if (count < 0)
342 return;
344 #ifdef RANGECHECK
346 if ((unsigned) dc_x >= (unsigned)SCREENWIDTH
347 || dc_yl < 0
348 || (unsigned)dc_yh >= (unsigned)SCREENHEIGHT)
349 I_Error("R_DrawFuzzColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
350 #endif
352 // Keep till detailshift bug in blocky mode fixed,
353 // or blocky mode removed.
355 // Does not work with blocky mode.
356 dest = topleft + dc_yl*SCREENWIDTH + dc_x;
358 // Looks familiar.
359 fracstep = dc_iscale;
360 frac = dc_texturemid + (dc_yl-centery)*fracstep;
362 // Looks like an attempt at dithering,
363 // using the colormap #6 (of 0-31, a bit brighter than average).
367 // Lookup framebuffer, and retrieve
368 // a pixel that is either one column
369 // left or right of the current one.
370 // Add index from colormap to index.
371 // killough 3/20/98: use fullcolormap instead of colormaps
373 *dest = fullcolormap[6*256+dest[fuzzoffset[fuzzpos]]];
375 // Some varying invisibility effects can be gotten by playing // phares
376 // with this logic. For example, try // phares
377 // // phares
378 // *dest = fullcolormap[0*256+dest[FUZZOFF]]; // phares
380 // Clamp table lookup index.
381 if (++fuzzpos == FUZZTABLE)
382 fuzzpos = 0;
384 dest += SCREENWIDTH;
386 frac += fracstep;
388 while (count--);
392 // R_DrawTranslatedColumn
393 // Used to draw player sprites
394 // with the green colorramp mapped to others.
395 // Could be used with different translation
396 // tables, e.g. the lighter colored version
397 // of the BaronOfHell, the HellKnight, uses
398 // identical sprites, kinda brightened up.
401 byte *dc_translation, *translationtables;
403 void R_DrawTranslatedColumn (void)
405 int count;
406 byte *dest;
407 fixed_t frac;
408 fixed_t fracstep;
410 count = dc_yh - dc_yl;
411 if (count < 0)
412 return;
414 #ifdef RANGECHECK
416 if ((unsigned)dc_x >= (unsigned)SCREENWIDTH
417 || dc_yl < 0
418 || (unsigned)dc_yh >= (unsigned)SCREENHEIGHT)
419 I_Error("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
420 #endif
422 // FIXME. As above.
423 dest = topleft + dc_yl*SCREENWIDTH + dc_x;
425 // Looks familiar.
426 fracstep = dc_iscale;
427 frac = dc_texturemid + (dc_yl-centery)*fracstep;
429 // Here we do an additional index re-mapping.
432 // Translation tables are used
433 // to map certain colorramps to other ones,
434 // used with PLAY sprites.
435 // Thus the "green" ramp of the player 0 sprite
436 // is mapped to gray, red, black/indigo.
438 *dest = dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]];
439 dest += SCREENWIDTH;
441 frac += fracstep;
443 while (count--);
447 // R_InitTranslationTables
448 // Creates the translation tables to map
449 // the green color ramp to gray, brown, red.
450 // Assumes a given structure of the PLAYPAL.
451 // Could be read from a lump instead.
454 byte playernumtotrans[MAXPLAYERS];
455 extern lighttable_t *(*c_zlight)[LIGHTLEVELS][MAXLIGHTZ];
457 void R_InitTranslationTables (void)
459 int i, j;
460 #define MAXTRANS 3
462 byte transtocolour[MAXTRANS];
464 // killough 5/2/98:
465 // Remove dependency of colormaps aligned on 256-byte boundary
467 if (translationtables == NULL) // CPhipps - allow multiple calls
468 translationtables = Z_Malloc(256*MAXTRANS, PU_STATIC, 0);
470 for (i=0; i<MAXTRANS; i++)
471 transtocolour[i] = 255;
473 for (i=0; i<MAXPLAYERS; i++)
475 byte wantcolour = mapcolor_plyr[i];
476 playernumtotrans[i] = 0;
477 if (wantcolour != 0x70) // Not green, would like translation
478 for (j=0; j<MAXTRANS; j++)
479 if (transtocolour[j] == 255)
481 transtocolour[j] = wantcolour;
482 playernumtotrans[i] = j+1;
483 break;
487 // translate just the 16 green colors
488 for (i=0; i<256; i++)
489 if (i >= 0x70 && i<= 0x7f)
491 // CPhipps - configurable player colours
492 translationtables[i] = colormaps[0][((i&0xf)<<9) + transtocolour[0]];
493 translationtables[i+256] = colormaps[0][((i&0xf)<<9) + transtocolour[1]];
494 translationtables[i+512] = colormaps[0][((i&0xf)<<9) + transtocolour[2]];
496 else // Keep all other colors as is.
497 translationtables[i]=translationtables[i+256]=translationtables[i+512]=i;
501 // R_DrawSpan
502 // With DOOM style restrictions on view orientation,
503 // the floors and ceilings consist of horizontal slices
504 // or spans with constant z depth.
505 // However, rotation around the world z axis is possible,
506 // thus this mapping, while simpler and faster than
507 // perspective correct texture mapping, has to traverse
508 // the texture at an angle in all but a few cases.
509 // In consequence, flats are not stored by column (like walls),
510 // and the inner loop has to step in texture space u and v.
513 int ds_y IBSS_ATTR;
514 int ds_x1 IBSS_ATTR;
515 int ds_x2 IBSS_ATTR;
517 lighttable_t *ds_colormap IBSS_ATTR;
519 fixed_t ds_xfrac IBSS_ATTR;
520 fixed_t ds_yfrac IBSS_ATTR;
521 fixed_t ds_xstep IBSS_ATTR;
522 fixed_t ds_ystep IBSS_ATTR;
524 // start of a 64*64 tile image
525 byte *ds_source IBSS_ATTR;
527 void R_DrawSpan (void)
529 #ifdef CPU_COLDFIRE
530 // only slightly faster
531 asm volatile (
532 "tst %[count] \n"
533 "beq endspanloop \n"
534 "clr.l %%d4 \n"
535 "spanloop: \n"
536 "move.l %[xfrac], %%d1 \n"
537 "swap %%d1 \n"
538 "and.l #63,%%d1 \n"
539 "move.l %[yfrac], %%d2 \n"
540 "lsr.l %[ten],%%d2 \n"
541 "and.l #4032,%%d2 \n"
542 "or.l %%d2, %%d1 \n"
543 "move.b (%[source], %%d1), %%d4 \n"
544 "add.l %[ds_xstep], %[xfrac] \n"
545 "add.l %[ds_ystep], %[yfrac] \n"
546 "move.b (%[colormap],%%d4.l), (%[dest])+ \n"
547 "subq.l #1, %[count] \n"
548 "bne spanloop \n"
549 "endspanloop: \n"
550 : /* outputs */
551 : /* inputs */
552 [ten] "d"(10),
553 [count] "d" (ds_x2-ds_x1+1),
554 [xfrac] "a" (ds_xfrac),
555 [yfrac] "a" (ds_yfrac),
556 [source] "a" (ds_source),
557 [colormap] "a" (ds_colormap),
558 [dest] "a" (topleft+ds_y*SCREENWIDTH +ds_x1),
559 [ds_xstep] "d" (ds_xstep),
560 [ds_ystep] "d" (ds_ystep)
561 : /* clobbers */
562 "d1", "d2", "d4"
564 #else
565 register unsigned count = ds_x2 - ds_x1 + 1,xfrac = ds_xfrac,yfrac = ds_yfrac;
567 register byte *source = ds_source;
568 register byte *colormap = ds_colormap;
569 register byte *dest = topleft + ds_y*SCREENWIDTH + ds_x1;
571 while (count)
573 register unsigned xtemp = xfrac >> 16;
574 register unsigned ytemp = yfrac >> 10;
575 register unsigned spot;
576 ytemp &= 4032;
577 xtemp &= 63;
578 spot = xtemp | ytemp;
579 xfrac += ds_xstep;
580 yfrac += ds_ystep;
581 *dest++ = colormap[source[spot]];
582 count--;
584 #endif
588 // R_InitBuffer
589 // Creats lookup tables that avoid
590 // multiplies and other hazzles
591 // for getting the framebuffer address
592 // of a pixel to draw.
595 void R_InitBuffer(int width, int height)
597 int i=0;
598 // Handle resize,
599 // e.g. smaller view windows
600 // with border and/or status bar.
602 viewwindowx = (SCREENWIDTH-width) >> 1;
604 // Same with base row offset.
606 viewwindowy = width==SCREENWIDTH ? 0 : (SCREENHEIGHT-(ST_SCALED_HEIGHT-1)-height)>>1;
608 topleft = d_screens[0] + viewwindowy*SCREENWIDTH + viewwindowx;
610 // Preclaculate all row offsets.
611 // CPhipps - merge viewwindowx into here
612 for (i=0; i<FUZZTABLE; i++)
613 fuzzoffset[i] = fuzzoffset_org[i]*SCREENWIDTH;
618 // R_FillBackScreen
619 // Fills the back screen with a pattern
620 // for variable screen sizes
621 // Also draws a beveled edge.
623 // CPhipps - patch drawing updated
625 void R_FillBackScreen (void)
627 int x,y;
629 if (scaledviewwidth == SCREENWIDTH)
630 return;
632 V_DrawBackground(gamemode == commercial ? "GRNROCK" : "FLOOR7_2", 1);
634 for (x=0 ; x<scaledviewwidth ; x+=8)
635 V_DrawNamePatch(viewwindowx+x,viewwindowy-8,1,"brdr_t", CR_DEFAULT, VPT_NONE);
637 for (x=0 ; x<scaledviewwidth ; x+=8)
638 V_DrawNamePatch(viewwindowx+x,viewwindowy+viewheight,1,"brdr_b", CR_DEFAULT, VPT_NONE);
640 for (y=0 ; y<viewheight ; y+=8)
641 V_DrawNamePatch(viewwindowx-8,viewwindowy+y,1,"brdr_l", CR_DEFAULT, VPT_NONE);
643 for (y=0 ; y<viewheight ; y+=8)
644 V_DrawNamePatch(viewwindowx+scaledviewwidth,viewwindowy+y,1,"brdr_r", CR_DEFAULT, VPT_NONE);
646 // Draw beveled edge.
647 V_DrawNamePatch(viewwindowx-8,viewwindowy-8,1,"brdr_tl", CR_DEFAULT, VPT_NONE);
649 V_DrawNamePatch(viewwindowx+scaledviewwidth,viewwindowy-8,1,"brdr_tr", CR_DEFAULT, VPT_NONE);
651 V_DrawNamePatch(viewwindowx-8,viewwindowy+viewheight,1,"brdr_bl", CR_DEFAULT, VPT_NONE);
653 V_DrawNamePatch(viewwindowx+scaledviewwidth,viewwindowy+viewheight,1,"brdr_br", CR_DEFAULT, VPT_NONE);
657 // Copy a screen buffer.
660 void R_VideoErase(unsigned ofs, int count)
662 memcpy(d_screens[0]+ofs, d_screens[1]+ofs, count); // LFB copy.
666 // R_DrawViewBorder
667 // Draws the border around the view
668 // for different size windows?
671 void R_DrawViewBorder(void)
673 int top, side, ofs, i;
674 // proff/nicolas 09/20/98: Added for high-res (inspired by DosDOOM)
675 int side2;
677 // proff/nicolas 09/20/98: Removed for high-res
678 // if (scaledviewwidth == SCREENWIDTH)
679 // return;
681 // proff/nicolas 09/20/98: Added for high-res (inspired by DosDOOM)
682 if ((SCREENHEIGHT != viewheight) ||
683 ((automapmode & am_active) && ! (automapmode & am_overlay)))
685 ofs = ( SCREENHEIGHT - ST_SCALED_HEIGHT ) * SCREENWIDTH;
686 side= ( SCREENWIDTH - ST_SCALED_WIDTH ) / 2;
687 side2 = side * 2;
689 R_VideoErase ( ofs, side );
691 ofs += ( SCREENWIDTH - side );
692 for ( i = 1; i < ST_SCALED_HEIGHT; i++ )
694 R_VideoErase ( ofs, side2 );
695 ofs += SCREENWIDTH;
698 R_VideoErase ( ofs, side );
701 if ( viewheight >= ( SCREENHEIGHT - ST_SCALED_HEIGHT ))
702 return; // if high-res, don't go any further!
704 top = ((SCREENHEIGHT-ST_SCALED_HEIGHT)-viewheight)/2;
705 side = (SCREENWIDTH-scaledviewwidth)/2;
707 // copy top and one line of left side
708 R_VideoErase (0, top*SCREENWIDTH+side);
710 // copy one line of right side and bottom
711 ofs = (viewheight+top)*SCREENWIDTH-side;
712 R_VideoErase (ofs, top*SCREENWIDTH+side);
714 // copy sides using wraparound
715 ofs = top*SCREENWIDTH + SCREENWIDTH-side;
716 side <<= 1;
718 for (i=1 ; i<viewheight ; i++)
720 R_VideoErase (ofs, side);
721 ofs += SCREENWIDTH;