1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 2005-2014 Simon Howard
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // DESCRIPTION:
16 // The actual span/column drawing functions.
17 // Here find the main potential for optimization,
18 // e.g. inline assembly, different algorithms.
19 //
20
21
22
23
24 #include "doomdef.h"
25 #include "deh_main.h"
26
27 #include "i_system.h"
28 #include "z_zone.h"
29 #include "w_wad.h"
30
31 #include "r_local.h"
32
33 // Needs access to LFB (guess what).
34 #include "v_video.h"
35 #include "v_trans.h"
36
37 // State.
38 #include "doomstat.h"
39
40
41 // ?
42 //#define MAXWIDTH 1120
43 //#define MAXHEIGHT 832
44
45 // status bar height at bottom of screen
46 #define SBARHEIGHT (32 << crispy->hires)
47
48 //
49 // All drawing to the view buffer is accomplished in this file.
50 // The other refresh files only know about ccordinates,
51 // not the architecture of the frame buffer.
52 // Conveniently, the frame buffer is a linear one,
53 // and we need only the base address,
54 // and the total size == width*height*depth/8.,
55 //
56
57
58 byte* viewimage;
59 int viewwidth;
60 int scaledviewwidth;
61 int viewheight;
62 int viewwindowx;
63 int viewwindowy;
64 pixel_t* ylookup[MAXHEIGHT];
65 int columnofs[MAXWIDTH];
66
67 // Color tables for different players,
68 // translate a limited part to another
69 // (color ramps used for suit colors).
70 //
71 byte translations[3][256];
72
73 // Backing buffer containing the bezel drawn around the screen and
74 // surrounding background.
75
76 static pixel_t *background_buffer = NULL;
77
78
79 //
80 // R_DrawColumn
81 // Source is the top of the column to scale.
82 //
83 lighttable_t* dc_colormap[2]; // [crispy] brightmaps
84 int dc_x;
85 int dc_yl;
86 int dc_yh;
87 fixed_t dc_iscale;
88 fixed_t dc_texturemid;
89 int dc_texheight; // [crispy] Tutti-Frutti fix
90
91 // first pixel in a column (possibly virtual)
92 byte* dc_source;
93
94 // just for profiling
95 int dccount;
96
97 //
98 // A column is a vertical slice/span from a wall texture that,
99 // given the DOOM style restrictions on the view orientation,
100 // will always have constant z depth.
101 // Thus a special case loop for very fast rendering can
102 // be used. It has also been used with Wolfenstein 3D.
103 //
104 // [crispy] replace R_DrawColumn() with Lee Killough's implementation
105 // found in MBF to fix Tutti-Frutti, taken from mbfsrc/R_DRAW.C:99-1979
106
R_DrawColumn(void)107 void R_DrawColumn (void)
108 {
109 int count;
110 pixel_t* dest;
111 fixed_t frac;
112 fixed_t fracstep;
113 int heightmask = dc_texheight - 1;
114
115 count = dc_yh - dc_yl;
116
117 // Zero length, column does not exceed a pixel.
118 if (count < 0)
119 return;
120
121 #ifdef RANGECHECK
122 if ((unsigned)dc_x >= SCREENWIDTH
123 || dc_yl < 0
124 || dc_yh >= SCREENHEIGHT)
125 I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
126 #endif
127
128 // Framebuffer destination address.
129 // Use ylookup LUT to avoid multiply with ScreenWidth.
130 // Use columnofs LUT for subwindows?
131 dest = ylookup[dc_yl] + columnofs[flipviewwidth[dc_x]];
132
133 // Determine scaling,
134 // which is the only mapping to be done.
135 fracstep = dc_iscale;
136 frac = dc_texturemid + (dc_yl-centery)*fracstep;
137
138 // Inner loop that does the actual texture mapping,
139 // e.g. a DDA-lile scaling.
140 // This is as fast as it gets.
141
142 // heightmask is the Tutti-Frutti fix -- killough
143 if (dc_texheight & heightmask) // not a power of 2 -- killough
144 {
145 heightmask++;
146 heightmask <<= FRACBITS;
147
148 if (frac < 0)
149 while ((frac += heightmask) < 0);
150 else
151 while (frac >= heightmask)
152 frac -= heightmask;
153
154 do
155 {
156 // [crispy] brightmaps
157 const byte source = dc_source[frac>>FRACBITS];
158 *dest = dc_colormap[dc_brightmap[source]][source];
159
160 dest += SCREENWIDTH;
161 if ((frac += fracstep) >= heightmask)
162 frac -= heightmask;
163 } while (count--);
164 }
165 else // texture height is a power of 2 -- killough
166 {
167 do
168 {
169 // Re-map color indices from wall texture column
170 // using a lighting/special effects LUT.
171 // [crispy] brightmaps
172 const byte source = dc_source[(frac>>FRACBITS)&heightmask];
173 *dest = dc_colormap[dc_brightmap[source]][source];
174
175 dest += SCREENWIDTH;
176 frac += fracstep;
177
178 } while (count--);
179 }
180 }
181
182
183
184 // UNUSED.
185 // Loop unrolled.
186 #if 0
187 void R_DrawColumn (void)
188 {
189 int count;
190 byte* source;
191 byte* dest;
192 byte* colormap;
193
194 unsigned frac;
195 unsigned fracstep;
196 unsigned fracstep2;
197 unsigned fracstep3;
198 unsigned fracstep4;
199
200 count = dc_yh - dc_yl + 1;
201
202 source = dc_source;
203 colormap = dc_colormap;
204 dest = ylookup[dc_yl] + columnofs[dc_x];
205
206 fracstep = dc_iscale<<9;
207 frac = (dc_texturemid + (dc_yl-centery)*dc_iscale)<<9;
208
209 fracstep2 = fracstep+fracstep;
210 fracstep3 = fracstep2+fracstep;
211 fracstep4 = fracstep3+fracstep;
212
213 while (count >= 8)
214 {
215 dest[0] = colormap[source[frac>>25]];
216 dest[SCREENWIDTH] = colormap[source[(frac+fracstep)>>25]];
217 dest[SCREENWIDTH*2] = colormap[source[(frac+fracstep2)>>25]];
218 dest[SCREENWIDTH*3] = colormap[source[(frac+fracstep3)>>25]];
219
220 frac += fracstep4;
221
222 dest[SCREENWIDTH*4] = colormap[source[frac>>25]];
223 dest[SCREENWIDTH*5] = colormap[source[(frac+fracstep)>>25]];
224 dest[SCREENWIDTH*6] = colormap[source[(frac+fracstep2)>>25]];
225 dest[SCREENWIDTH*7] = colormap[source[(frac+fracstep3)>>25]];
226
227 frac += fracstep4;
228 dest += SCREENWIDTH*8;
229 count -= 8;
230 }
231
232 while (count > 0)
233 {
234 *dest = colormap[source[frac>>25]];
235 dest += SCREENWIDTH;
236 frac += fracstep;
237 count--;
238 }
239 }
240 #endif
241
242
R_DrawColumnLow(void)243 void R_DrawColumnLow (void)
244 {
245 int count;
246 pixel_t* dest;
247 pixel_t* dest2;
248 fixed_t frac;
249 fixed_t fracstep;
250 int x;
251 int heightmask = dc_texheight - 1;
252
253 count = dc_yh - dc_yl;
254
255 // Zero length.
256 if (count < 0)
257 return;
258
259 #ifdef RANGECHECK
260 if ((unsigned)dc_x >= SCREENWIDTH
261 || dc_yl < 0
262 || dc_yh >= SCREENHEIGHT)
263 {
264
265 I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
266 }
267 // dccount++;
268 #endif
269 // Blocky mode, need to multiply by 2.
270 x = dc_x << 1;
271
272 dest = ylookup[dc_yl] + columnofs[flipviewwidth[x]];
273 dest2 = ylookup[dc_yl] + columnofs[flipviewwidth[x+1]];
274
275 fracstep = dc_iscale;
276 frac = dc_texturemid + (dc_yl-centery)*fracstep;
277
278 // heightmask is the Tutti-Frutti fix -- killough
279 if (dc_texheight & heightmask) // not a power of 2 -- killough
280 {
281 heightmask++;
282 heightmask <<= FRACBITS;
283
284 if (frac < 0)
285 while ((frac += heightmask) < 0);
286 else
287 while (frac >= heightmask)
288 frac -= heightmask;
289
290 do
291 {
292 // [crispy] brightmaps
293 const byte source = dc_source[frac>>FRACBITS];
294 *dest2 = *dest = dc_colormap[dc_brightmap[source]][source];
295
296 dest += SCREENWIDTH;
297 dest2 += SCREENWIDTH;
298
299 if ((frac += fracstep) >= heightmask)
300 frac -= heightmask;
301 } while (count--);
302 }
303 else // texture height is a power of 2 -- killough
304 {
305 do
306 {
307 // Hack. Does not work corretly.
308 // [crispy] brightmaps
309 const byte source = dc_source[(frac>>FRACBITS)&heightmask];
310 *dest2 = *dest = dc_colormap[dc_brightmap[source]][source];
311 dest += SCREENWIDTH;
312 dest2 += SCREENWIDTH;
313
314 frac += fracstep;
315
316 } while (count--);
317 }
318 }
319
320
321 //
322 // Spectre/Invisibility.
323 //
324 #define FUZZTABLE 50
325 #define FUZZOFF (1)
326
327
328 int fuzzoffset[FUZZTABLE] =
329 {
330 FUZZOFF,-FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
331 FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
332 FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,
333 FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
334 FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,
335 FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,
336 FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF
337 };
338
339 int fuzzpos = 0;
340
341 // [crispy] draw fuzz effect independent of rendering frame rate
342 static int fuzzpos_tic;
R_SetFuzzPosTic(void)343 void R_SetFuzzPosTic (void)
344 {
345 // [crispy] prevent the animation from remaining static
346 if (fuzzpos == fuzzpos_tic)
347 {
348 fuzzpos = (fuzzpos + 1) % FUZZTABLE;
349 }
350 fuzzpos_tic = fuzzpos;
351 }
R_SetFuzzPosDraw(void)352 void R_SetFuzzPosDraw (void)
353 {
354 fuzzpos = fuzzpos_tic;
355 }
356
357 //
358 // Framebuffer postprocessing.
359 // Creates a fuzzy image by copying pixels
360 // from adjacent ones to left and right.
361 // Used with an all black colormap, this
362 // could create the SHADOW effect,
363 // i.e. spectres and invisible players.
364 //
R_DrawFuzzColumn(void)365 void R_DrawFuzzColumn (void)
366 {
367 int count;
368 pixel_t* dest;
369 fixed_t frac;
370 fixed_t fracstep;
371 boolean cutoff = false;
372
373 // Adjust borders. Low...
374 if (!dc_yl)
375 dc_yl = 1;
376
377 // .. and high.
378 if (dc_yh == viewheight-1)
379 {
380 dc_yh = viewheight - 2;
381 cutoff = true;
382 }
383
384 count = dc_yh - dc_yl;
385
386 // Zero length.
387 if (count < 0)
388 return;
389
390 #ifdef RANGECHECK
391 if ((unsigned)dc_x >= SCREENWIDTH
392 || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
393 {
394 I_Error ("R_DrawFuzzColumn: %i to %i at %i",
395 dc_yl, dc_yh, dc_x);
396 }
397 #endif
398
399 dest = ylookup[dc_yl] + columnofs[flipviewwidth[dc_x]];
400
401 // Looks familiar.
402 fracstep = dc_iscale;
403 frac = dc_texturemid + (dc_yl-centery)*fracstep;
404
405 // Looks like an attempt at dithering,
406 // using the colormap #6 (of 0-31, a bit
407 // brighter than average).
408 do
409 {
410 // Lookup framebuffer, and retrieve
411 // a pixel that is either one column
412 // left or right of the current one.
413 // Add index from colormap to index.
414 #ifndef CRISPY_TRUECOLOR
415 *dest = colormaps[6*256+dest[SCREENWIDTH*fuzzoffset[fuzzpos]]];
416 #else
417 *dest = I_BlendDark(dest[SCREENWIDTH*fuzzoffset[fuzzpos]], 0xD3);
418 #endif
419
420 // Clamp table lookup index.
421 if (++fuzzpos == FUZZTABLE)
422 fuzzpos = 0;
423
424 dest += SCREENWIDTH;
425
426 frac += fracstep;
427 } while (count--);
428
429 // [crispy] if the line at the bottom had to be cut off,
430 // draw one extra line using only pixels of that line and the one above
431 if (cutoff)
432 {
433 #ifndef CRISPY_TRUECOLOR
434 *dest = colormaps[6*256+dest[SCREENWIDTH*(fuzzoffset[fuzzpos]-FUZZOFF)/2]];
435 #else
436 *dest = I_BlendDark(dest[SCREENWIDTH*(fuzzoffset[fuzzpos]-FUZZOFF)/2], 0xD3);
437 #endif
438 }
439 }
440
441 // low detail mode version
442
R_DrawFuzzColumnLow(void)443 void R_DrawFuzzColumnLow (void)
444 {
445 int count;
446 pixel_t* dest;
447 pixel_t* dest2;
448 fixed_t frac;
449 fixed_t fracstep;
450 int x;
451 boolean cutoff = false;
452
453 // Adjust borders. Low...
454 if (!dc_yl)
455 dc_yl = 1;
456
457 // .. and high.
458 if (dc_yh == viewheight-1)
459 {
460 dc_yh = viewheight - 2;
461 cutoff = true;
462 }
463
464 count = dc_yh - dc_yl;
465
466 // Zero length.
467 if (count < 0)
468 return;
469
470 // low detail mode, need to multiply by 2
471
472 x = dc_x << 1;
473
474 #ifdef RANGECHECK
475 if ((unsigned)x >= SCREENWIDTH
476 || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
477 {
478 I_Error ("R_DrawFuzzColumn: %i to %i at %i",
479 dc_yl, dc_yh, dc_x);
480 }
481 #endif
482
483 dest = ylookup[dc_yl] + columnofs[flipviewwidth[x]];
484 dest2 = ylookup[dc_yl] + columnofs[flipviewwidth[x+1]];
485
486 // Looks familiar.
487 fracstep = dc_iscale;
488 frac = dc_texturemid + (dc_yl-centery)*fracstep;
489
490 // Looks like an attempt at dithering,
491 // using the colormap #6 (of 0-31, a bit
492 // brighter than average).
493 do
494 {
495 // Lookup framebuffer, and retrieve
496 // a pixel that is either one column
497 // left or right of the current one.
498 // Add index from colormap to index.
499 #ifndef CRISPY_TRUECOLOR
500 *dest = colormaps[6*256+dest[SCREENWIDTH*fuzzoffset[fuzzpos]]];
501 *dest2 = colormaps[6*256+dest2[SCREENWIDTH*fuzzoffset[fuzzpos]]];
502 #else
503 *dest = I_BlendDark(dest[SCREENWIDTH*fuzzoffset[fuzzpos]], 0xD3);
504 *dest2 = I_BlendDark(dest2[SCREENWIDTH*fuzzoffset[fuzzpos]], 0xD3);
505 #endif
506
507 // Clamp table lookup index.
508 if (++fuzzpos == FUZZTABLE)
509 fuzzpos = 0;
510
511 dest += SCREENWIDTH;
512 dest2 += SCREENWIDTH;
513
514 frac += fracstep;
515 } while (count--);
516
517 // [crispy] if the line at the bottom had to be cut off,
518 // draw one extra line using only pixels of that line and the one above
519 if (cutoff)
520 {
521 #ifndef CRISPY_TRUECOLOR
522 *dest = colormaps[6*256+dest[SCREENWIDTH*(fuzzoffset[fuzzpos]-FUZZOFF)/2]];
523 *dest2 = colormaps[6*256+dest2[SCREENWIDTH*(fuzzoffset[fuzzpos]-FUZZOFF)/2]];
524 #else
525 *dest = I_BlendDark(dest[SCREENWIDTH*(fuzzoffset[fuzzpos]-FUZZOFF)/2], 0xD3);
526 *dest2 = I_BlendDark(dest2[SCREENWIDTH*(fuzzoffset[fuzzpos]-FUZZOFF)/2], 0xD3);
527 #endif
528 }
529 }
530
531
532
533
534
535 //
536 // R_DrawTranslatedColumn
537 // Used to draw player sprites
538 // with the green colorramp mapped to others.
539 // Could be used with different translation
540 // tables, e.g. the lighter colored version
541 // of the BaronOfHell, the HellKnight, uses
542 // identical sprites, kinda brightened up.
543 //
544 byte* dc_translation;
545 byte* translationtables;
546
R_DrawTranslatedColumn(void)547 void R_DrawTranslatedColumn (void)
548 {
549 int count;
550 pixel_t* dest;
551 fixed_t frac;
552 fixed_t fracstep;
553
554 count = dc_yh - dc_yl;
555 if (count < 0)
556 return;
557
558 #ifdef RANGECHECK
559 if ((unsigned)dc_x >= SCREENWIDTH
560 || dc_yl < 0
561 || dc_yh >= SCREENHEIGHT)
562 {
563 I_Error ( "R_DrawColumn: %i to %i at %i",
564 dc_yl, dc_yh, dc_x);
565 }
566
567 #endif
568
569
570 dest = ylookup[dc_yl] + columnofs[flipviewwidth[dc_x]];
571
572 // Looks familiar.
573 fracstep = dc_iscale;
574 frac = dc_texturemid + (dc_yl-centery)*fracstep;
575
576 // Here we do an additional index re-mapping.
577 do
578 {
579 // Translation tables are used
580 // to map certain colorramps to other ones,
581 // used with PLAY sprites.
582 // Thus the "green" ramp of the player 0 sprite
583 // is mapped to gray, red, black/indigo.
584 *dest = dc_colormap[0][dc_translation[dc_source[frac>>FRACBITS]]];
585 dest += SCREENWIDTH;
586
587 frac += fracstep;
588 } while (count--);
589 }
590
R_DrawTranslatedColumnLow(void)591 void R_DrawTranslatedColumnLow (void)
592 {
593 int count;
594 pixel_t* dest;
595 pixel_t* dest2;
596 fixed_t frac;
597 fixed_t fracstep;
598 int x;
599
600 count = dc_yh - dc_yl;
601 if (count < 0)
602 return;
603
604 // low detail, need to scale by 2
605 x = dc_x << 1;
606
607 #ifdef RANGECHECK
608 if ((unsigned)x >= SCREENWIDTH
609 || dc_yl < 0
610 || dc_yh >= SCREENHEIGHT)
611 {
612 I_Error ( "R_DrawColumn: %i to %i at %i",
613 dc_yl, dc_yh, x);
614 }
615
616 #endif
617
618
619 dest = ylookup[dc_yl] + columnofs[flipviewwidth[x]];
620 dest2 = ylookup[dc_yl] + columnofs[flipviewwidth[x+1]];
621
622 // Looks familiar.
623 fracstep = dc_iscale;
624 frac = dc_texturemid + (dc_yl-centery)*fracstep;
625
626 // Here we do an additional index re-mapping.
627 do
628 {
629 // Translation tables are used
630 // to map certain colorramps to other ones,
631 // used with PLAY sprites.
632 // Thus the "green" ramp of the player 0 sprite
633 // is mapped to gray, red, black/indigo.
634 *dest = dc_colormap[0][dc_translation[dc_source[frac>>FRACBITS]]];
635 *dest2 = dc_colormap[0][dc_translation[dc_source[frac>>FRACBITS]]];
636 dest += SCREENWIDTH;
637 dest2 += SCREENWIDTH;
638
639 frac += fracstep;
640 } while (count--);
641 }
642
R_DrawTLColumn(void)643 void R_DrawTLColumn (void)
644 {
645 int count;
646 pixel_t* dest;
647 fixed_t frac;
648 fixed_t fracstep;
649
650 count = dc_yh - dc_yl;
651 if (count < 0)
652 return;
653
654 #ifdef RANGECHECK
655 if ((unsigned)dc_x >= SCREENWIDTH
656 || dc_yl < 0
657 || dc_yh >= SCREENHEIGHT)
658 {
659 I_Error ( "R_DrawColumn: %i to %i at %i",
660 dc_yl, dc_yh, dc_x);
661 }
662 #endif
663
664 dest = ylookup[dc_yl] + columnofs[flipviewwidth[dc_x]];
665
666 fracstep = dc_iscale;
667 frac = dc_texturemid + (dc_yl-centery)*fracstep;
668
669 do
670 {
671 #ifndef CRISPY_TRUECOLOR
672 // actual translucency map lookup taken from boom202s/R_DRAW.C:255
673 *dest = tranmap[(*dest<<8)+dc_colormap[0][dc_source[frac>>FRACBITS]]];
674 #else
675 const pixel_t destrgb = dc_colormap[0][dc_source[frac>>FRACBITS]];
676 *dest = blendfunc(*dest, destrgb);
677 #endif
678 dest += SCREENWIDTH;
679
680 frac += fracstep;
681 } while (count--);
682 }
683
684 // [crispy] draw translucent column, low-resolution version
R_DrawTLColumnLow(void)685 void R_DrawTLColumnLow (void)
686 {
687 int count;
688 pixel_t* dest;
689 pixel_t* dest2;
690 fixed_t frac;
691 fixed_t fracstep;
692 int x;
693
694 count = dc_yh - dc_yl;
695 if (count < 0)
696 return;
697
698 x = dc_x << 1;
699
700 #ifdef RANGECHECK
701 if ((unsigned)x >= SCREENWIDTH
702 || dc_yl < 0
703 || dc_yh >= SCREENHEIGHT)
704 {
705 I_Error ( "R_DrawColumn: %i to %i at %i",
706 dc_yl, dc_yh, x);
707 }
708 #endif
709
710 dest = ylookup[dc_yl] + columnofs[flipviewwidth[x]];
711 dest2 = ylookup[dc_yl] + columnofs[flipviewwidth[x+1]];
712
713 fracstep = dc_iscale;
714 frac = dc_texturemid + (dc_yl-centery)*fracstep;
715
716 do
717 {
718 #ifndef CRISPY_TRUECOLOR
719 *dest = tranmap[(*dest<<8)+dc_colormap[0][dc_source[frac>>FRACBITS]]];
720 *dest2 = tranmap[(*dest2<<8)+dc_colormap[0][dc_source[frac>>FRACBITS]]];
721 #else
722 const pixel_t destrgb = dc_colormap[0][dc_source[frac>>FRACBITS]];
723 *dest = blendfunc(*dest, destrgb);
724 *dest2 = blendfunc(*dest2, destrgb);
725 #endif
726 dest += SCREENWIDTH;
727 dest2 += SCREENWIDTH;
728
729 frac += fracstep;
730 } while (count--);
731 }
732
733 //
734 // R_InitTranslationTables
735 // Creates the translation tables to map
736 // the green color ramp to gray, brown, red.
737 // Assumes a given structure of the PLAYPAL.
738 // Could be read from a lump instead.
739 //
R_InitTranslationTables(void)740 void R_InitTranslationTables (void)
741 {
742 int i;
743
744 translationtables = Z_Malloc (256*3, PU_STATIC, 0);
745
746 // translate just the 16 green colors
747 for (i=0 ; i<256 ; i++)
748 {
749 if (i >= 0x70 && i<= 0x7f)
750 {
751 // map green ramp to gray, brown, red
752 translationtables[i] = 0x60 + (i&0xf);
753 translationtables [i+256] = 0x40 + (i&0xf);
754 translationtables [i+512] = 0x20 + (i&0xf);
755 }
756 else
757 {
758 // Keep all other colors as is.
759 translationtables[i] = translationtables[i+256]
760 = translationtables[i+512] = i;
761 }
762 }
763 }
764
765
766
767
768 //
769 // R_DrawSpan
770 // With DOOM style restrictions on view orientation,
771 // the floors and ceilings consist of horizontal slices
772 // or spans with constant z depth.
773 // However, rotation around the world z axis is possible,
774 // thus this mapping, while simpler and faster than
775 // perspective correct texture mapping, has to traverse
776 // the texture at an angle in all but a few cases.
777 // In consequence, flats are not stored by column (like walls),
778 // and the inner loop has to step in texture space u and v.
779 //
780 int ds_y;
781 int ds_x1;
782 int ds_x2;
783
784 lighttable_t* ds_colormap[2];
785 byte* ds_brightmap;
786
787 fixed_t ds_xfrac;
788 fixed_t ds_yfrac;
789 fixed_t ds_xstep;
790 fixed_t ds_ystep;
791
792 // start of a 64*64 tile image
793 byte* ds_source;
794
795 // just for profiling
796 int dscount;
797
798
799 //
800 // Draws the actual span.
R_DrawSpan(void)801 void R_DrawSpan (void)
802 {
803 // unsigned int position, step;
804 pixel_t *dest;
805 int count;
806 int spot;
807 unsigned int xtemp, ytemp;
808
809 #ifdef RANGECHECK
810 if (ds_x2 < ds_x1
811 || ds_x1<0
812 || ds_x2>=SCREENWIDTH
813 || (unsigned)ds_y>SCREENHEIGHT)
814 {
815 I_Error( "R_DrawSpan: %i to %i at %i",
816 ds_x1,ds_x2,ds_y);
817 }
818 // dscount++;
819 #endif
820
821 // Pack position and step variables into a single 32-bit integer,
822 // with x in the top 16 bits and y in the bottom 16 bits. For
823 // each 16-bit part, the top 6 bits are the integer part and the
824 // bottom 10 bits are the fractional part of the pixel position.
825
826 /*
827 position = ((ds_xfrac << 10) & 0xffff0000)
828 | ((ds_yfrac >> 6) & 0x0000ffff);
829 step = ((ds_xstep << 10) & 0xffff0000)
830 | ((ds_ystep >> 6) & 0x0000ffff);
831 */
832
833 // dest = ylookup[ds_y] + columnofs[ds_x1];
834
835 // We do not check for zero spans here?
836 count = ds_x2 - ds_x1;
837
838 do
839 {
840 byte source;
841 // Calculate current texture index in u,v.
842 // [crispy] fix flats getting more distorted the closer they are to the right
843 ytemp = (ds_yfrac >> 10) & 0x0fc0;
844 xtemp = (ds_xfrac >> 16) & 0x3f;
845 spot = xtemp | ytemp;
846
847 // Lookup pixel from flat texture tile,
848 // re-index using light/colormap.
849 source = ds_source[spot];
850 dest = ylookup[ds_y] + columnofs[flipviewwidth[ds_x1++]];
851 *dest = ds_colormap[ds_brightmap[source]][source];
852
853 // position += step;
854 ds_xfrac += ds_xstep;
855 ds_yfrac += ds_ystep;
856
857 } while (count--);
858 }
859
860
861
862 // UNUSED.
863 // Loop unrolled by 4.
864 #if 0
865 void R_DrawSpan (void)
866 {
867 unsigned position, step;
868
869 byte* source;
870 byte* colormap;
871 pixel_t* dest;
872
873 unsigned count;
874 usingned spot;
875 unsigned value;
876 unsigned temp;
877 unsigned xtemp;
878 unsigned ytemp;
879
880 position = ((ds_xfrac<<10)&0xffff0000) | ((ds_yfrac>>6)&0xffff);
881 step = ((ds_xstep<<10)&0xffff0000) | ((ds_ystep>>6)&0xffff);
882
883 source = ds_source;
884 colormap = ds_colormap;
885 dest = ylookup[ds_y] + columnofs[ds_x1];
886 count = ds_x2 - ds_x1 + 1;
887
888 while (count >= 4)
889 {
890 ytemp = position>>4;
891 ytemp = ytemp & 4032;
892 xtemp = position>>26;
893 spot = xtemp | ytemp;
894 position += step;
895 dest[0] = colormap[source[spot]];
896
897 ytemp = position>>4;
898 ytemp = ytemp & 4032;
899 xtemp = position>>26;
900 spot = xtemp | ytemp;
901 position += step;
902 dest[1] = colormap[source[spot]];
903
904 ytemp = position>>4;
905 ytemp = ytemp & 4032;
906 xtemp = position>>26;
907 spot = xtemp | ytemp;
908 position += step;
909 dest[2] = colormap[source[spot]];
910
911 ytemp = position>>4;
912 ytemp = ytemp & 4032;
913 xtemp = position>>26;
914 spot = xtemp | ytemp;
915 position += step;
916 dest[3] = colormap[source[spot]];
917
918 count -= 4;
919 dest += 4;
920 }
921 while (count > 0)
922 {
923 ytemp = position>>4;
924 ytemp = ytemp & 4032;
925 xtemp = position>>26;
926 spot = xtemp | ytemp;
927 position += step;
928 *dest++ = colormap[source[spot]];
929 count--;
930 }
931 }
932 #endif
933
934
935 //
936 // Again..
937 //
R_DrawSpanLow(void)938 void R_DrawSpanLow (void)
939 {
940 // unsigned int position, step;
941 unsigned int xtemp, ytemp;
942 pixel_t *dest;
943 int count;
944 int spot;
945
946 #ifdef RANGECHECK
947 if (ds_x2 < ds_x1
948 || ds_x1<0
949 || ds_x2>=SCREENWIDTH
950 || (unsigned)ds_y>SCREENHEIGHT)
951 {
952 I_Error( "R_DrawSpan: %i to %i at %i",
953 ds_x1,ds_x2,ds_y);
954 }
955 // dscount++;
956 #endif
957
958 /*
959 position = ((ds_xfrac << 10) & 0xffff0000)
960 | ((ds_yfrac >> 6) & 0x0000ffff);
961 step = ((ds_xstep << 10) & 0xffff0000)
962 | ((ds_ystep >> 6) & 0x0000ffff);
963 */
964
965 count = (ds_x2 - ds_x1);
966
967 // Blocky mode, need to multiply by 2.
968 ds_x1 <<= 1;
969 ds_x2 <<= 1;
970
971 // dest = ylookup[ds_y] + columnofs[ds_x1];
972
973 do
974 {
975 byte source;
976 // Calculate current texture index in u,v.
977 // [crispy] fix flats getting more distorted the closer they are to the right
978 ytemp = (ds_yfrac >> 10) & 0x0fc0;
979 xtemp = (ds_xfrac >> 16) & 0x3f;
980 spot = xtemp | ytemp;
981
982 // Lowres/blocky mode does it twice,
983 // while scale is adjusted appropriately.
984 source = ds_source[spot];
985 dest = ylookup[ds_y] + columnofs[flipviewwidth[ds_x1++]];
986 *dest = ds_colormap[ds_brightmap[source]][source];
987 dest = ylookup[ds_y] + columnofs[flipviewwidth[ds_x1++]];
988 *dest = ds_colormap[ds_brightmap[source]][source];
989
990 // position += step;
991 ds_xfrac += ds_xstep;
992 ds_yfrac += ds_ystep;
993
994
995 } while (count--);
996 }
997
998 //
999 // R_InitBuffer
1000 // Creats lookup tables that avoid
1001 // multiplies and other hazzles
1002 // for getting the framebuffer address
1003 // of a pixel to draw.
1004 //
1005 void
R_InitBuffer(int width,int height)1006 R_InitBuffer
1007 ( int width,
1008 int height )
1009 {
1010 int i;
1011
1012 // Handle resize,
1013 // e.g. smaller view windows
1014 // with border and/or status bar.
1015 viewwindowx = (SCREENWIDTH-width) >> 1;
1016
1017 // Column offset. For windows.
1018 for (i=0 ; i<width ; i++)
1019 columnofs[i] = viewwindowx + i;
1020
1021 // Samw with base row offset.
1022 if (width == SCREENWIDTH)
1023 viewwindowy = 0;
1024 else
1025 viewwindowy = (SCREENHEIGHT-SBARHEIGHT-height) >> 1;
1026
1027 // Preclaculate all row offsets.
1028 for (i=0 ; i<height ; i++)
1029 ylookup[i] = I_VideoBuffer + (i+viewwindowy)*SCREENWIDTH;
1030 }
1031
1032
1033
1034
1035 //
1036 // R_FillBackScreen
1037 // Fills the back screen with a pattern
1038 // for variable screen sizes
1039 // Also draws a beveled edge.
1040 //
R_FillBackScreen(void)1041 void R_FillBackScreen (void)
1042 {
1043 byte* src;
1044 pixel_t* dest;
1045 int x;
1046 int y;
1047 patch_t* patch;
1048
1049 // DOOM border patch.
1050 const char *name1 = DEH_String("FLOOR7_2");
1051
1052 // DOOM II border patch.
1053 const char *name2 = DEH_String("GRNROCK");
1054
1055 const char *name;
1056
1057 // If we are running full screen, there is no need to do any of this,
1058 // and the background buffer can be freed if it was previously in use.
1059
1060 if (scaledviewwidth == SCREENWIDTH)
1061 {
1062 if (background_buffer != NULL)
1063 {
1064 Z_Free(background_buffer);
1065 background_buffer = NULL;
1066 }
1067
1068 return;
1069 }
1070
1071 // Allocate the background buffer if necessary
1072
1073 if (background_buffer == NULL)
1074 {
1075 background_buffer = Z_Malloc(MAXWIDTH * (MAXHEIGHT - SBARHEIGHT) * sizeof(*background_buffer),
1076 PU_STATIC, NULL);
1077 }
1078
1079 if (gamemode == commercial)
1080 name = name2;
1081 else
1082 name = name1;
1083
1084 src = W_CacheLumpName(name, PU_CACHE);
1085 dest = background_buffer;
1086
1087 for (y=0 ; y<SCREENHEIGHT-SBARHEIGHT ; y++)
1088 {
1089 #ifndef CRISPY_TRUECOLOR
1090 for (x=0 ; x<SCREENWIDTH/64 ; x++)
1091 {
1092 memcpy (dest, src+((y&63)<<6), 64);
1093 dest += 64;
1094 }
1095
1096 if (SCREENWIDTH&63)
1097 {
1098 memcpy (dest, src+((y&63)<<6), SCREENWIDTH&63);
1099 dest += (SCREENWIDTH&63);
1100 }
1101 #else
1102 for (x=0 ; x<SCREENWIDTH ; x++)
1103 {
1104 *dest++ = colormaps[src[((y&63)<<6) + (x&63)]];
1105 }
1106 #endif
1107 }
1108
1109 // Draw screen and bezel; this is done to a separate screen buffer.
1110
1111 V_UseBuffer(background_buffer);
1112
1113 patch = W_CacheLumpName(DEH_String("brdr_t"),PU_CACHE);
1114
1115 for (x=0 ; x<(scaledviewwidth >> crispy->hires) ; x+=8)
1116 V_DrawPatch((viewwindowx >> crispy->hires)+x-WIDESCREENDELTA, (viewwindowy >> crispy->hires)-8, patch);
1117 patch = W_CacheLumpName(DEH_String("brdr_b"),PU_CACHE);
1118
1119 for (x=0 ; x<(scaledviewwidth >> crispy->hires) ; x+=8)
1120 V_DrawPatch((viewwindowx >> crispy->hires)+x-WIDESCREENDELTA, (viewwindowy >> crispy->hires)+(viewheight >> crispy->hires), patch);
1121 patch = W_CacheLumpName(DEH_String("brdr_l"),PU_CACHE);
1122
1123 for (y=0 ; y<(viewheight >> crispy->hires) ; y+=8)
1124 V_DrawPatch((viewwindowx >> crispy->hires)-8-WIDESCREENDELTA, (viewwindowy >> crispy->hires)+y, patch);
1125 patch = W_CacheLumpName(DEH_String("brdr_r"),PU_CACHE);
1126
1127 for (y=0 ; y<(viewheight >> crispy->hires) ; y+=8)
1128 V_DrawPatch((viewwindowx >> crispy->hires)+(scaledviewwidth >> crispy->hires)-WIDESCREENDELTA, (viewwindowy >> crispy->hires)+y, patch);
1129
1130 // Draw beveled edge.
1131 V_DrawPatch((viewwindowx >> crispy->hires)-8-WIDESCREENDELTA,
1132 (viewwindowy >> crispy->hires)-8,
1133 W_CacheLumpName(DEH_String("brdr_tl"),PU_CACHE));
1134
1135 V_DrawPatch((viewwindowx >> crispy->hires)+(scaledviewwidth >> crispy->hires)-WIDESCREENDELTA,
1136 (viewwindowy >> crispy->hires)-8,
1137 W_CacheLumpName(DEH_String("brdr_tr"),PU_CACHE));
1138
1139 V_DrawPatch((viewwindowx >> crispy->hires)-8-WIDESCREENDELTA,
1140 (viewwindowy >> crispy->hires)+(viewheight >> crispy->hires),
1141 W_CacheLumpName(DEH_String("brdr_bl"),PU_CACHE));
1142
1143 V_DrawPatch((viewwindowx >> crispy->hires)+(scaledviewwidth >> crispy->hires)-WIDESCREENDELTA,
1144 (viewwindowy >> crispy->hires)+(viewheight >> crispy->hires),
1145 W_CacheLumpName(DEH_String("brdr_br"),PU_CACHE));
1146
1147 V_RestoreBuffer();
1148 }
1149
1150
1151 //
1152 // Copy a screen buffer.
1153 //
1154 void
R_VideoErase(unsigned ofs,int count)1155 R_VideoErase
1156 ( unsigned ofs,
1157 int count )
1158 {
1159 // LFB copy.
1160 // This might not be a good idea if memcpy
1161 // is not optiomal, e.g. byte by byte on
1162 // a 32bit CPU, as GNU GCC/Linux libc did
1163 // at one point.
1164
1165 if (background_buffer != NULL)
1166 {
1167 memcpy(I_VideoBuffer + ofs, background_buffer + ofs, count * sizeof(*I_VideoBuffer));
1168 }
1169 }
1170
1171
1172 //
1173 // R_DrawViewBorder
1174 // Draws the border around the view
1175 // for different size windows?
1176 //
R_DrawViewBorder(void)1177 void R_DrawViewBorder (void)
1178 {
1179 int top;
1180 int side;
1181 int ofs;
1182 int i;
1183
1184 if (scaledviewwidth == SCREENWIDTH)
1185 return;
1186
1187 top = ((SCREENHEIGHT-SBARHEIGHT)-viewheight)/2;
1188 side = (SCREENWIDTH-scaledviewwidth)/2;
1189
1190 // copy top and one line of left side
1191 R_VideoErase (0, top*SCREENWIDTH+side);
1192
1193 // copy one line of right side and bottom
1194 ofs = (viewheight+top)*SCREENWIDTH-side;
1195 R_VideoErase (ofs, top*SCREENWIDTH+side);
1196
1197 // copy sides using wraparound
1198 ofs = top*SCREENWIDTH + SCREENWIDTH-side;
1199 side <<= 1;
1200
1201 for (i=1 ; i<viewheight ; i++)
1202 {
1203 R_VideoErase (ofs, side);
1204 ofs += SCREENWIDTH;
1205 }
1206
1207 // ?
1208 V_MarkRect (0,0,SCREENWIDTH, SCREENHEIGHT-SBARHEIGHT);
1209 }
1210
1211
1212