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