aboutsummaryrefslogtreecommitdiff
path: root/src/v_video.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/v_video.c')
-rw-r--r--src/v_video.c1037
1 files changed, 1037 insertions, 0 deletions
diff --git a/src/v_video.c b/src/v_video.c
new file mode 100644
index 0000000..0921fe5
--- /dev/null
+++ b/src/v_video.c
@@ -0,0 +1,1037 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
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
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Gamma correction LUT stuff.
31 * Color range translation support
32 * Functions to draw patches (by post) directly to screen.
33 * Functions to blit a block to the screen.
34 *
35 *-----------------------------------------------------------------------------
36 */
37
38#include "doomdef.h"
39#include "r_main.h"
40#include "r_draw.h"
41#include "m_bbox.h"
42#include "w_wad.h" /* needed for color translation lump lookup */
43#include "v_video.h"
44#include "i_video.h"
45#include "r_filter.h"
46#include "lprintf.h"
47
48// Each screen is [SCREENWIDTH*SCREENHEIGHT];
49screeninfo_t screens[NUM_SCREENS];
50
51/* jff 4/24/98 initialize this at runtime */
52const byte *colrngs[CR_LIMIT];
53
54int usegamma;
55
56/*
57 * V_InitColorTranslation
58 *
59 * Loads the color translation tables from predefined lumps at game start
60 * No return
61 *
62 * Used for translating text colors from the red palette range
63 * to other colors. The first nine entries can be used to dynamically
64 * switch the output of text color thru the HUlib_drawText routine
65 * by embedding ESCn in the text to obtain color n. Symbols for n are
66 * provided in v_video.h.
67 *
68 * cphipps - constness of crdef_t stuff fixed
69 */
70
71typedef struct {
72 const char *name;
73 const byte **map;
74} crdef_t;
75
76// killough 5/2/98: table-driven approach
77static const crdef_t crdefs[] = {
78 {"CRBRICK", &colrngs[CR_BRICK ]},
79 {"CRTAN", &colrngs[CR_TAN ]},
80 {"CRGRAY", &colrngs[CR_GRAY ]},
81 {"CRGREEN", &colrngs[CR_GREEN ]},
82 {"CRBROWN", &colrngs[CR_BROWN ]},
83 {"CRGOLD", &colrngs[CR_GOLD ]},
84 {"CRRED", &colrngs[CR_RED ]},
85 {"CRBLUE", &colrngs[CR_BLUE ]},
86 {"CRORANGE", &colrngs[CR_ORANGE]},
87 {"CRYELLOW", &colrngs[CR_YELLOW]},
88 {"CRBLUE2", &colrngs[CR_BLUE2]},
89 {NULL}
90};
91
92// killough 5/2/98: tiny engine driven by table above
93void V_InitColorTranslation(void)
94{
95 register const crdef_t *p;
96 for (p=crdefs; p->name; p++)
97 *p->map = W_CacheLumpName(p->name);
98}
99
100//
101// V_CopyRect
102//
103// Copies a source rectangle in a screen buffer to a destination
104// rectangle in another screen buffer. Source origin in srcx,srcy,
105// destination origin in destx,desty, common size in width and height.
106// Source buffer specfified by srcscrn, destination buffer by destscrn.
107//
108// Marks the destination rectangle on the screen dirty.
109//
110// No return.
111//
112static void FUNC_V_CopyRect(int srcx, int srcy, int srcscrn, int width,
113 int height, int destx, int desty, int destscrn,
114 enum patch_translation_e flags)
115{
116 byte *src;
117 byte *dest;
118
119 if (flags & VPT_STRETCH)
120 {
121 srcx=srcx*SCREENWIDTH/320;
122 srcy=srcy*SCREENHEIGHT/200;
123 width=width*SCREENWIDTH/320;
124 height=height*SCREENHEIGHT/200;
125 destx=destx*SCREENWIDTH/320;
126 desty=desty*SCREENHEIGHT/200;
127 }
128
129#ifdef RANGECHECK
130 if (srcx<0
131 ||srcx+width >SCREENWIDTH
132 || srcy<0
133 || srcy+height>SCREENHEIGHT
134 ||destx<0||destx+width >SCREENWIDTH
135 || desty<0
136 || desty+height>SCREENHEIGHT)
137 I_Error ("V_CopyRect: Bad arguments");
138#endif
139
140 src = screens[srcscrn].data+screens[srcscrn].byte_pitch*srcy+srcx*V_GetPixelDepth();
141 dest = screens[destscrn].data+screens[destscrn].byte_pitch*desty+destx*V_GetPixelDepth();
142
143 for ( ; height>0 ; height--)
144 {
145 memcpy (dest, src, width*V_GetPixelDepth());
146 src += screens[srcscrn].byte_pitch;
147 dest += screens[destscrn].byte_pitch;
148 }
149}
150
151/*
152 * V_DrawBackground tiles a 64x64 patch over the entire screen, providing the
153 * background for the Help and Setup screens, and plot text betwen levels.
154 * cphipps - used to have M_DrawBackground, but that was used the framebuffer
155 * directly, so this is my code from the equivalent function in f_finale.c
156 */
157static void FUNC_V_DrawBackground(const char* flatname, int scrn)
158{
159 /* erase the entire screen to a tiled background */
160 const byte *src;
161 int x,y;
162 int width,height;
163 int lump;
164
165 // killough 4/17/98:
166 src = W_CacheLumpNum(lump = firstflat + R_FlatNumForName(flatname));
167
168 /* V_DrawBlock(0, 0, scrn, 64, 64, src, 0); */
169 width = height = 64;
170 if (V_GetMode() == VID_MODE8) {
171 byte *dest = screens[scrn].data;
172
173 while (height--) {
174 memcpy (dest, src, width);
175 src += width;
176 dest += screens[scrn].byte_pitch;
177 }
178 } else if (V_GetMode() == VID_MODE15) {
179 unsigned short *dest = (unsigned short *)screens[scrn].data;
180
181 while (height--) {
182 int i;
183 for (i=0; i<width; i++) {
184 dest[i] = VID_PAL15(src[i], VID_COLORWEIGHTMASK);
185 }
186 src += width;
187 dest += screens[scrn].short_pitch;
188 }
189 } else if (V_GetMode() == VID_MODE16) {
190 unsigned short *dest = (unsigned short *)screens[scrn].data;
191
192 while (height--) {
193 int i;
194 for (i=0; i<width; i++) {
195 dest[i] = VID_PAL16(src[i], VID_COLORWEIGHTMASK);
196 }
197 src += width;
198 dest += screens[scrn].short_pitch;
199 }
200 } else if (V_GetMode() == VID_MODE32) {
201 unsigned int *dest = (unsigned int *)screens[scrn].data;
202
203 while (height--) {
204 int i;
205 for (i=0; i<width; i++) {
206 dest[i] = VID_PAL32(src[i], VID_COLORWEIGHTMASK);
207 }
208 src += width;
209 dest += screens[scrn].int_pitch;
210 }
211 }
212 /* end V_DrawBlock */
213
214 for (y=0 ; y<SCREENHEIGHT ; y+=64)
215 for (x=y ? 0 : 64; x<SCREENWIDTH ; x+=64)
216 V_CopyRect(0, 0, scrn, ((SCREENWIDTH-x) < 64) ? (SCREENWIDTH-x) : 64,
217 ((SCREENHEIGHT-y) < 64) ? (SCREENHEIGHT-y) : 64, x, y, scrn, VPT_NONE);
218 W_UnlockLumpNum(lump);
219}
220
221//
222// V_Init
223//
224// Allocates the 4 full screen buffers in low DOS memory
225// No return
226//
227
228void V_Init (void)
229{
230 int i;
231
232 // reset the all
233 for (i = 0; i<NUM_SCREENS; i++) {
234 screens[i].data = NULL;
235 screens[i].not_on_heap = false;
236 screens[i].width = 0;
237 screens[i].height = 0;
238 screens[i].byte_pitch = 0;
239 screens[i].short_pitch = 0;
240 screens[i].int_pitch = 0;
241 }
242}
243
244//
245// V_DrawMemPatch
246//
247// CPhipps - unifying patch drawing routine, handles all cases and combinations
248// of stretching, flipping and translating
249//
250// This function is big, hopefully not too big that gcc can't optimise it well.
251// In fact it packs pretty well, there is no big performance lose for all this merging;
252// the inner loops themselves are just the same as they always were
253// (indeed, laziness of the people who wrote the 'clones' of the original V_DrawPatch
254// means that their inner loops weren't so well optimised, so merging code may even speed them).
255//
256static void V_DrawMemPatch(int x, int y, int scrn, const rpatch_t *patch,
257 int cm, enum patch_translation_e flags)
258{
259 const byte *trans;
260
261 if (cm<CR_LIMIT)
262 trans=colrngs[cm];
263 else
264 trans=translationtables + 256*((cm-CR_LIMIT)-1);
265 y -= patch->topoffset;
266 x -= patch->leftoffset;
267
268 // CPhipps - auto-no-stretch if not high-res
269 if (flags & VPT_STRETCH)
270 if ((SCREENWIDTH==320) && (SCREENHEIGHT==200))
271 flags &= ~VPT_STRETCH;
272
273 // CPhipps - null translation pointer => no translation
274 if (!trans)
275 flags &= ~VPT_TRANS;
276
277 if (V_GetMode() == VID_MODE8 && !(flags & VPT_STRETCH)) {
278 int col;
279 byte *desttop = screens[scrn].data+y*screens[scrn].byte_pitch+x*V_GetPixelDepth();
280 unsigned int w = patch->width;
281
282 if (y<0 || y+patch->height > ((flags & VPT_STRETCH) ? 200 : SCREENHEIGHT)) {
283 // killough 1/19/98: improved error message:
284 lprintf(LO_WARN, "V_DrawMemPatch8: Patch (%d,%d)-(%d,%d) exceeds LFB in vertical direction (horizontal is clipped)\n"
285 "Bad V_DrawMemPatch8 (flags=%u)", x, y, x+patch->width, y+patch->height, flags);
286 return;
287 }
288
289 w--; // CPhipps - note: w = width-1 now, speeds up flipping
290
291 for (col=0 ; (unsigned int)col<=w ; desttop++, col++, x++) {
292 int i;
293 const int colindex = (flags & VPT_FLIP) ? (w - col) : (col);
294 const rcolumn_t *column = R_GetPatchColumn(patch, colindex);
295
296 if (x < 0)
297 continue;
298 if (x >= SCREENWIDTH)
299 break;
300
301 // step through the posts in a column
302 for (i=0; i<column->numPosts; i++) {
303 const rpost_t *post = &column->posts[i];
304 // killough 2/21/98: Unrolled and performance-tuned
305
306 const byte *source = column->pixels + post->topdelta;
307 byte *dest = desttop + post->topdelta*screens[scrn].byte_pitch;
308 int count = post->length;
309
310 if (!(flags & VPT_TRANS)) {
311 if ((count-=4)>=0)
312 do {
313 register byte s0,s1;
314 s0 = source[0];
315 s1 = source[1];
316 dest[0] = s0;
317 dest[screens[scrn].byte_pitch] = s1;
318 dest += screens[scrn].byte_pitch*2;
319 s0 = source[2];
320 s1 = source[3];
321 source += 4;
322 dest[0] = s0;
323 dest[screens[scrn].byte_pitch] = s1;
324 dest += screens[scrn].byte_pitch*2;
325 } while ((count-=4)>=0);
326 if (count+=4)
327 do {
328 *dest = *source++;
329 dest += screens[scrn].byte_pitch;
330 } while (--count);
331 } else {
332 // CPhipps - merged translation code here
333 if ((count-=4)>=0)
334 do {
335 register byte s0,s1;
336 s0 = source[0];
337 s1 = source[1];
338 s0 = trans[s0];
339 s1 = trans[s1];
340 dest[0] = s0;
341 dest[screens[scrn].byte_pitch] = s1;
342 dest += screens[scrn].byte_pitch*2;
343 s0 = source[2];
344 s1 = source[3];
345 s0 = trans[s0];
346 s1 = trans[s1];
347 source += 4;
348 dest[0] = s0;
349 dest[screens[scrn].byte_pitch] = s1;
350 dest += screens[scrn].byte_pitch*2;
351 } while ((count-=4)>=0);
352 if (count+=4)
353 do {
354 *dest = trans[*source++];
355 dest += screens[scrn].byte_pitch;
356 } while (--count);
357 }
358 }
359 }
360 }
361 else {
362 // CPhipps - move stretched patch drawing code here
363 // - reformat initialisers, move variables into inner blocks
364
365 int col;
366 int w = (patch->width << 16) - 1; // CPhipps - -1 for faster flipping
367 int left, right, top, bottom;
368 int DX = (SCREENWIDTH<<16) / 320;
369 int DXI = (320<<16) / SCREENWIDTH;
370 int DY = (SCREENHEIGHT<<16) / 200;
371 int DYI = (200<<16) / SCREENHEIGHT;
372 R_DrawColumn_f colfunc;
373 draw_column_vars_t dcvars;
374 draw_vars_t olddrawvars = drawvars;
375
376 R_SetDefaultDrawColumnVars(&dcvars);
377
378 drawvars.byte_topleft = screens[scrn].data;
379 drawvars.short_topleft = (unsigned short *)screens[scrn].data;
380 drawvars.int_topleft = (unsigned int *)screens[scrn].data;
381 drawvars.byte_pitch = screens[scrn].byte_pitch;
382 drawvars.short_pitch = screens[scrn].short_pitch;
383 drawvars.int_pitch = screens[scrn].int_pitch;
384
385 if (!(flags & VPT_STRETCH)) {
386 DX = 1 << 16;
387 DXI = 1 << 16;
388 DY = 1 << 16;
389 DYI = 1 << 16;
390 }
391
392 if (flags & VPT_TRANS) {
393 colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_TRANSLATED, drawvars.filterpatch, RDRAW_FILTER_NONE);
394 dcvars.translation = trans;
395 } else {
396 colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, drawvars.filterpatch, RDRAW_FILTER_NONE);
397 }
398
399 left = ( x * DX ) >> FRACBITS;
400 top = ( y * DY ) >> FRACBITS;
401 right = ( (x + patch->width) * DX ) >> FRACBITS;
402 bottom = ( (y + patch->height) * DY ) >> FRACBITS;
403
404 dcvars.texheight = patch->height;
405 dcvars.iscale = DYI;
406 dcvars.drawingmasked = MAX(patch->width, patch->height) > 8;
407 dcvars.edgetype = drawvars.patch_edges;
408
409 if (drawvars.filterpatch == RDRAW_FILTER_LINEAR) {
410 // bias the texture u coordinate
411 if (patch->isNotTileable)
412 col = -(FRACUNIT>>1);
413 else
414 col = (patch->width<<FRACBITS)-(FRACUNIT>>1);
415 }
416 else {
417 col = 0;
418 }
419
420 for (dcvars.x=left; dcvars.x<right; dcvars.x++, col+=DXI) {
421 int i;
422 const int colindex = (flags & VPT_FLIP) ? ((w - col)>>16): (col>>16);
423 const rcolumn_t *column = R_GetPatchColumn(patch, colindex);
424 const rcolumn_t *prevcolumn = R_GetPatchColumn(patch, colindex-1);
425 const rcolumn_t *nextcolumn = R_GetPatchColumn(patch, colindex+1);
426
427 // ignore this column if it's to the left of our clampRect
428 if (dcvars.x < 0)
429 continue;
430 if (dcvars.x >= SCREENWIDTH)
431 break;
432
433 dcvars.texu = ((flags & VPT_FLIP) ? ((patch->width<<FRACBITS)-col) : col) % (patch->width<<FRACBITS);
434
435 // step through the posts in a column
436 for (i=0; i<column->numPosts; i++) {
437 const rpost_t *post = &column->posts[i];
438 int yoffset = 0;
439
440 dcvars.yl = (((y + post->topdelta) * DY)>>FRACBITS);
441 dcvars.yh = (((y + post->topdelta + post->length) * DY - (FRACUNIT>>1))>>FRACBITS);
442 dcvars.edgeslope = post->slope;
443
444 if ((dcvars.yh < 0) || (dcvars.yh < top))
445 continue;
446 if ((dcvars.yl >= SCREENHEIGHT) || (dcvars.yl >= bottom))
447 continue;
448
449 if (dcvars.yh >= bottom) {
450 dcvars.yh = bottom-1;
451 dcvars.edgeslope &= ~RDRAW_EDGESLOPE_BOT_MASK;
452 }
453 if (dcvars.yh >= SCREENHEIGHT) {
454 dcvars.yh = SCREENHEIGHT-1;
455 dcvars.edgeslope &= ~RDRAW_EDGESLOPE_BOT_MASK;
456 }
457
458 if (dcvars.yl < 0) {
459 yoffset = 0-dcvars.yl;
460 dcvars.yl = 0;
461 dcvars.edgeslope &= ~RDRAW_EDGESLOPE_TOP_MASK;
462 }
463 if (dcvars.yl < top) {
464 yoffset = top-dcvars.yl;
465 dcvars.yl = top;
466 dcvars.edgeslope &= ~RDRAW_EDGESLOPE_TOP_MASK;
467 }
468
469 dcvars.source = column->pixels + post->topdelta + yoffset;
470 dcvars.prevsource = prevcolumn ? prevcolumn->pixels + post->topdelta + yoffset: dcvars.source;
471 dcvars.nextsource = nextcolumn ? nextcolumn->pixels + post->topdelta + yoffset: dcvars.source;
472
473 dcvars.texturemid = -((dcvars.yl-centery)*dcvars.iscale);
474
475 colfunc(&dcvars);
476 }
477 }
478
479 R_ResetColumnBuffer();
480 drawvars = olddrawvars;
481 }
482}
483
484// CPhipps - some simple, useful wrappers for that function, for drawing patches from wads
485
486// CPhipps - GNU C only suppresses generating a copy of a function if it is
487// static inline; other compilers have different behaviour.
488// This inline is _only_ for the function below
489
490static void FUNC_V_DrawNumPatch(int x, int y, int scrn, int lump,
491 int cm, enum patch_translation_e flags)
492{
493 V_DrawMemPatch(x, y, scrn, R_CachePatchNum(lump), cm, flags);
494 R_UnlockPatchNum(lump);
495}
496
497unsigned short *V_Palette15 = NULL;
498unsigned short *V_Palette16 = NULL;
499unsigned int *V_Palette32 = NULL;
500static unsigned short *Palettes15 = NULL;
501static unsigned short *Palettes16 = NULL;
502static unsigned int *Palettes32 = NULL;
503static int currentPaletteIndex = 0;
504
505//
506// V_UpdateTrueColorPalette
507//
508void V_UpdateTrueColorPalette(video_mode_t mode) {
509 int i, w, p;
510 byte r,g,b;
511 int nr,ng,nb;
512 float t;
513 int paletteNum = (V_GetMode() == VID_MODEGL ? 0 : currentPaletteIndex);
514 static int usegammaOnLastPaletteGeneration = -1;
515
516 int pplump = W_GetNumForName("PLAYPAL");
517 int gtlump = (W_CheckNumForName)("GAMMATBL",ns_prboom);
518 const byte *pal = W_CacheLumpNum(pplump);
519 // opengl doesn't use the gamma
520 const byte *const gtable =
521 (const byte *)W_CacheLumpNum(gtlump) +
522 (V_GetMode() == VID_MODEGL ? 0 : 256*(usegamma))
523 ;
524
525 int numPals = W_LumpLength(pplump) / (3*256);
526 const float dontRoundAbove = 220;
527 float roundUpR, roundUpG, roundUpB;
528
529 if (usegammaOnLastPaletteGeneration != usegamma) {
530 if (Palettes15) free(Palettes15);
531 if (Palettes16) free(Palettes16);
532 if (Palettes32) free(Palettes32);
533 Palettes15 = NULL;
534 Palettes16 = NULL;
535 Palettes32 = NULL;
536 usegammaOnLastPaletteGeneration = usegamma;
537 }
538
539 if (mode == VID_MODE32) {
540 if (!Palettes32) {
541 // set int palette
542 Palettes32 = (int*)malloc(numPals*256*sizeof(int)*VID_NUMCOLORWEIGHTS);
543 for (p=0; p<numPals; p++) {
544 for (i=0; i<256; i++) {
545 r = gtable[pal[(256*p+i)*3+0]];
546 g = gtable[pal[(256*p+i)*3+1]];
547 b = gtable[pal[(256*p+i)*3+2]];
548
549 // ideally, we should always round up, but very bright colors
550 // overflow the blending adds, so they don't get rounded.
551 roundUpR = (r > dontRoundAbove) ? 0 : 0.5f;
552 roundUpG = (g > dontRoundAbove) ? 0 : 0.5f;
553 roundUpB = (b > dontRoundAbove) ? 0 : 0.5f;
554
555 for (w=0; w<VID_NUMCOLORWEIGHTS; w++) {
556 t = (float)(w)/(float)(VID_NUMCOLORWEIGHTS-1);
557 nr = (int)(r*t+roundUpR);
558 ng = (int)(g*t+roundUpG);
559 nb = (int)(b*t+roundUpB);
560 Palettes32[((p*256+i)*VID_NUMCOLORWEIGHTS)+w] = (
561 (nr<<16) | (ng<<8) | nb
562 );
563 }
564 }
565 }
566 }
567 V_Palette32 = Palettes32 + paletteNum*256*VID_NUMCOLORWEIGHTS;
568 }
569 else if (mode == VID_MODE16) {
570 if (!Palettes16) {
571 // set short palette
572 Palettes16 = (short*)malloc(numPals*256*sizeof(short)*VID_NUMCOLORWEIGHTS);
573 for (p=0; p<numPals; p++) {
574 for (i=0; i<256; i++) {
575 r = gtable[pal[(256*p+i)*3+0]];
576 g = gtable[pal[(256*p+i)*3+1]];
577 b = gtable[pal[(256*p+i)*3+2]];
578
579 // ideally, we should always round up, but very bright colors
580 // overflow the blending adds, so they don't get rounded.
581 roundUpR = (r > dontRoundAbove) ? 0 : 0.5f;
582 roundUpG = (g > dontRoundAbove) ? 0 : 0.5f;
583 roundUpB = (b > dontRoundAbove) ? 0 : 0.5f;
584
585 for (w=0; w<VID_NUMCOLORWEIGHTS; w++) {
586 t = (float)(w)/(float)(VID_NUMCOLORWEIGHTS-1);
587 nr = (int)((r>>3)*t+roundUpR);
588 ng = (int)((g>>2)*t+roundUpG);
589 nb = (int)((b>>3)*t+roundUpB);
590 Palettes16[((p*256+i)*VID_NUMCOLORWEIGHTS)+w] = (
591 (nr<<11) | (ng<<5) | nb
592 );
593 }
594 }
595 }
596 }
597 V_Palette16 = Palettes16 + paletteNum*256*VID_NUMCOLORWEIGHTS;
598 }
599 else if (mode == VID_MODE15) {
600 if (!Palettes15) {
601 // set short palette
602 Palettes15 = (short*)malloc(numPals*256*sizeof(short)*VID_NUMCOLORWEIGHTS);
603 for (p=0; p<numPals; p++) {
604 for (i=0; i<256; i++) {
605 r = gtable[pal[(256*p+i)*3+0]];
606 g = gtable[pal[(256*p+i)*3+1]];
607 b = gtable[pal[(256*p+i)*3+2]];
608
609 // ideally, we should always round up, but very bright colors
610 // overflow the blending adds, so they don't get rounded.
611 roundUpR = (r > dontRoundAbove) ? 0 : 0.5f;
612 roundUpG = (g > dontRoundAbove) ? 0 : 0.5f;
613 roundUpB = (b > dontRoundAbove) ? 0 : 0.5f;
614
615 for (w=0; w<VID_NUMCOLORWEIGHTS; w++) {
616 t = (float)(w)/(float)(VID_NUMCOLORWEIGHTS-1);
617 nr = (int)((r>>3)*t+roundUpR);
618 ng = (int)((g>>3)*t+roundUpG);
619 nb = (int)((b>>3)*t+roundUpB);
620 Palettes15[((p*256+i)*VID_NUMCOLORWEIGHTS)+w] = (
621 (nr<<10) | (ng<<5) | nb
622 );
623 }
624 }
625 }
626 }
627 V_Palette15 = Palettes15 + paletteNum*256*VID_NUMCOLORWEIGHTS;
628 }
629
630 W_UnlockLumpNum(pplump);
631 W_UnlockLumpNum(gtlump);
632}
633
634
635//---------------------------------------------------------------------------
636// V_DestroyTrueColorPalette
637//---------------------------------------------------------------------------
638static void V_DestroyTrueColorPalette(video_mode_t mode) {
639 if (mode == VID_MODE15) {
640 if (Palettes15) free(Palettes15);
641 Palettes15 = NULL;
642 V_Palette15 = NULL;
643 }
644 if (mode == VID_MODE16) {
645 if (Palettes16) free(Palettes16);
646 Palettes16 = NULL;
647 V_Palette16 = NULL;
648 }
649 if (mode == VID_MODE32) {
650 if (Palettes32) free(Palettes32);
651 Palettes32 = NULL;
652 V_Palette32 = NULL;
653 }
654}
655
656void V_DestroyUnusedTrueColorPalettes(void) {
657 if (V_GetMode() != VID_MODE15) V_DestroyTrueColorPalette(VID_MODE15);
658 if (V_GetMode() != VID_MODE16) V_DestroyTrueColorPalette(VID_MODE16);
659 if (V_GetMode() != VID_MODE32) V_DestroyTrueColorPalette(VID_MODE32);
660}
661
662//
663// V_SetPalette
664//
665// CPhipps - New function to set the palette to palette number pal.
666// Handles loading of PLAYPAL and calls I_SetPalette
667
668void V_SetPalette(int pal)
669{
670 currentPaletteIndex = pal;
671
672 if (V_GetMode() == VID_MODEGL) {
673#ifdef GL_DOOM
674 gld_SetPalette(pal);
675#endif
676 } else {
677 I_SetPalette(pal);
678 if (V_GetMode() == VID_MODE15 || V_GetMode() == VID_MODE16 || V_GetMode() == VID_MODE32) {
679 // V_SetPalette can be called as part of the gamma setting before
680 // we've loaded any wads, which prevents us from reading the palette - POPE
681 if (W_CheckNumForName("PLAYPAL") >= 0) {
682 V_UpdateTrueColorPalette(V_GetMode());
683 }
684 }
685 }
686}
687
688//
689// V_FillRect
690//
691// CPhipps - New function to fill a rectangle with a given colour
692static void V_FillRect8(int scrn, int x, int y, int width, int height, byte colour)
693{
694 byte* dest = screens[scrn].data + x + y*screens[scrn].byte_pitch;
695 while (height--) {
696 memset(dest, colour, width);
697 dest += screens[scrn].byte_pitch;
698 }
699}
700
701static void V_FillRect15(int scrn, int x, int y, int width, int height, byte colour)
702{
703 unsigned short* dest = (unsigned short *)screens[scrn].data + x + y*screens[scrn].short_pitch;
704 int w;
705 short c = VID_PAL15(colour, VID_COLORWEIGHTMASK);
706 while (height--) {
707 for (w=0; w<width; w++) {
708 dest[w] = c;
709 }
710 dest += screens[scrn].short_pitch;
711 }
712}
713
714static void V_FillRect16(int scrn, int x, int y, int width, int height, byte colour)
715{
716 unsigned short* dest = (unsigned short *)screens[scrn].data + x + y*screens[scrn].short_pitch;
717 int w;
718 short c = VID_PAL16(colour, VID_COLORWEIGHTMASK);
719 while (height--) {
720 for (w=0; w<width; w++) {
721 dest[w] = c;
722 }
723 dest += screens[scrn].short_pitch;
724 }
725}
726
727static void V_FillRect32(int scrn, int x, int y, int width, int height, byte colour)
728{
729 unsigned int* dest = (unsigned int *)screens[scrn].data + x + y*screens[scrn].int_pitch;
730 int w;
731 int c = VID_PAL32(colour, VID_COLORWEIGHTMASK);
732 while (height--) {
733 for (w=0; w<width; w++) {
734 dest[w] = c;
735 }
736 dest += screens[scrn].int_pitch;
737 }
738}
739
740static void WRAP_V_DrawLine(fline_t* fl, int color);
741static void V_PlotPixel8(int scrn, int x, int y, byte color);
742static void V_PlotPixel15(int scrn, int x, int y, byte color);
743static void V_PlotPixel16(int scrn, int x, int y, byte color);
744static void V_PlotPixel32(int scrn, int x, int y, byte color);
745
746#ifdef GL_DOOM
747static void WRAP_gld_FillRect(int scrn, int x, int y, int width, int height, byte colour)
748{
749 gld_FillBlock(x,y,width,height,colour);
750}
751static void WRAP_gld_CopyRect(int srcx, int srcy, int srcscrn, int width, int height, int destx, int desty, int destscrn, enum patch_translation_e flags)
752{
753}
754static void WRAP_gld_DrawBackground(const char *flatname, int n)
755{
756 gld_DrawBackground(flatname);
757}
758static void WRAP_gld_DrawNumPatch(int x, int y, int scrn, int lump, int cm, enum patch_translation_e flags)
759{
760 gld_DrawNumPatch(x,y,lump,cm,flags);
761}
762static void WRAP_gld_DrawBlock(int x, int y, int scrn, int width, int height, const byte *src, enum patch_translation_e flags)
763{
764}
765static void V_PlotPixelGL(int scrn, int x, int y, byte color) {
766 gld_DrawLine(x-1, y, x+1, y, color);
767 gld_DrawLine(x, y-1, x, y+1, color);
768}
769static void WRAP_gld_DrawLine(fline_t* fl, int color)
770{
771 gld_DrawLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, color);
772}
773#endif
774
775static void NULL_FillRect(int scrn, int x, int y, int width, int height, byte colour) {}
776static void NULL_CopyRect(int srcx, int srcy, int srcscrn, int width, int height, int destx, int desty, int destscrn, enum patch_translation_e flags) {}
777static void NULL_DrawBackground(const char *flatname, int n) {}
778static void NULL_DrawNumPatch(int x, int y, int scrn, int lump, int cm, enum patch_translation_e flags) {}
779static void NULL_DrawBlock(int x, int y, int scrn, int width, int height, const byte *src, enum patch_translation_e flags) {}
780static void NULL_PlotPixel(int scrn, int x, int y, byte color) {}
781static void NULL_DrawLine(fline_t* fl, int color) {}
782
783const char *default_videomode;
784static video_mode_t current_videomode = VID_MODE8;
785
786V_CopyRect_f V_CopyRect = NULL_CopyRect;
787V_FillRect_f V_FillRect = NULL_FillRect;
788V_DrawNumPatch_f V_DrawNumPatch = NULL_DrawNumPatch;
789V_DrawBackground_f V_DrawBackground = NULL_DrawBackground;
790V_PlotPixel_f V_PlotPixel = NULL_PlotPixel;
791V_DrawLine_f V_DrawLine = NULL_DrawLine;
792
793//
794// V_InitMode
795//
796void V_InitMode(video_mode_t mode) {
797#ifndef GL_DOOM
798 if (mode == VID_MODEGL)
799 mode = VID_MODE8;
800#endif
801 switch (mode) {
802 case VID_MODE8:
803 lprintf(LO_INFO, "V_InitMode: using 8 bit video mode\n");
804 V_CopyRect = FUNC_V_CopyRect;
805 V_FillRect = V_FillRect8;
806 V_DrawNumPatch = FUNC_V_DrawNumPatch;
807 V_DrawBackground = FUNC_V_DrawBackground;
808 V_PlotPixel = V_PlotPixel8;
809 V_DrawLine = WRAP_V_DrawLine;
810 current_videomode = VID_MODE8;
811 break;
812 case VID_MODE15:
813 lprintf(LO_INFO, "V_InitMode: using 15 bit video mode\n");
814 V_CopyRect = FUNC_V_CopyRect;
815 V_FillRect = V_FillRect15;
816 V_DrawNumPatch = FUNC_V_DrawNumPatch;
817 V_DrawBackground = FUNC_V_DrawBackground;
818 V_PlotPixel = V_PlotPixel15;
819 V_DrawLine = WRAP_V_DrawLine;
820 current_videomode = VID_MODE15;
821 break;
822 case VID_MODE16:
823 lprintf(LO_INFO, "V_InitMode: using 16 bit video mode\n");
824 V_CopyRect = FUNC_V_CopyRect;
825 V_FillRect = V_FillRect16;
826 V_DrawNumPatch = FUNC_V_DrawNumPatch;
827 V_DrawBackground = FUNC_V_DrawBackground;
828 V_PlotPixel = V_PlotPixel16;
829 V_DrawLine = WRAP_V_DrawLine;
830 current_videomode = VID_MODE16;
831 break;
832 case VID_MODE32:
833 lprintf(LO_INFO, "V_InitMode: using 32 bit video mode\n");
834 V_CopyRect = FUNC_V_CopyRect;
835 V_FillRect = V_FillRect32;
836 V_DrawNumPatch = FUNC_V_DrawNumPatch;
837 V_DrawBackground = FUNC_V_DrawBackground;
838 V_PlotPixel = V_PlotPixel32;
839 V_DrawLine = WRAP_V_DrawLine;
840 current_videomode = VID_MODE32;
841 break;
842#ifdef GL_DOOM
843 case VID_MODEGL:
844 lprintf(LO_INFO, "V_InitMode: using OpenGL video mode\n");
845 V_CopyRect = WRAP_gld_CopyRect;
846 V_FillRect = WRAP_gld_FillRect;
847 V_DrawNumPatch = WRAP_gld_DrawNumPatch;
848 V_DrawBackground = WRAP_gld_DrawBackground;
849 V_PlotPixel = V_PlotPixelGL;
850 V_DrawLine = WRAP_gld_DrawLine;
851 current_videomode = VID_MODEGL;
852 break;
853#endif
854 }
855 R_FilterInit();
856}
857
858//
859// V_GetMode
860//
861video_mode_t V_GetMode(void) {
862 return current_videomode;
863}
864
865//
866// V_GetModePixelDepth
867//
868int V_GetModePixelDepth(video_mode_t mode) {
869 switch (mode) {
870 case VID_MODE8: return 1;
871 case VID_MODE15: return 2;
872 case VID_MODE16: return 2;
873 case VID_MODE32: return 4;
874 default: return 0;
875 }
876}
877
878//
879// V_GetNumPixelBits
880//
881int V_GetNumPixelBits(void) {
882 switch (current_videomode) {
883 case VID_MODE8: return 8;
884 case VID_MODE15: return 15;
885 case VID_MODE16: return 16;
886 case VID_MODE32: return 32;
887 default: return 0;
888 }
889}
890
891//
892// V_GetPixelDepth
893//
894int V_GetPixelDepth(void) {
895 return V_GetModePixelDepth(current_videomode);
896}
897
898//
899// V_AllocScreen
900//
901void V_AllocScreen(screeninfo_t *scrn) {
902 if (!scrn->not_on_heap)
903 if ((scrn->byte_pitch * scrn->height) > 0)
904 scrn->data = malloc(scrn->byte_pitch*scrn->height);
905}
906
907//
908// V_AllocScreens
909//
910void V_AllocScreens(void) {
911 int i;
912
913 for (i=0; i<NUM_SCREENS; i++)
914 V_AllocScreen(&screens[i]);
915}
916
917//
918// V_FreeScreen
919//
920void V_FreeScreen(screeninfo_t *scrn) {
921 if (!scrn->not_on_heap) {
922 free(scrn->data);
923 scrn->data = NULL;
924 }
925}
926
927//
928// V_FreeScreens
929//
930void V_FreeScreens(void) {
931 int i;
932
933 for (i=0; i<NUM_SCREENS; i++)
934 V_FreeScreen(&screens[i]);
935}
936
937static void V_PlotPixel8(int scrn, int x, int y, byte color) {
938 screens[scrn].data[x+screens[scrn].byte_pitch*y] = color;
939}
940
941static void V_PlotPixel15(int scrn, int x, int y, byte color) {
942 ((unsigned short *)screens[scrn].data)[x+screens[scrn].short_pitch*y] = VID_PAL15(color, VID_COLORWEIGHTMASK);
943}
944
945static void V_PlotPixel16(int scrn, int x, int y, byte color) {
946 ((unsigned short *)screens[scrn].data)[x+screens[scrn].short_pitch*y] = VID_PAL16(color, VID_COLORWEIGHTMASK);
947}
948
949static void V_PlotPixel32(int scrn, int x, int y, byte color) {
950 ((unsigned int *)screens[scrn].data)[x+screens[scrn].int_pitch*y] = VID_PAL32(color, VID_COLORWEIGHTMASK);
951}
952
953//
954// WRAP_V_DrawLine()
955//
956// Draw a line in the frame buffer.
957// Classic Bresenham w/ whatever optimizations needed for speed
958//
959// Passed the frame coordinates of line, and the color to be drawn
960// Returns nothing
961//
962static void WRAP_V_DrawLine(fline_t* fl, int color)
963{
964 register int x;
965 register int y;
966 register int dx;
967 register int dy;
968 register int sx;
969 register int sy;
970 register int ax;
971 register int ay;
972 register int d;
973
974#ifdef RANGECHECK // killough 2/22/98
975 static int fuck = 0;
976
977 // For debugging only
978 if
979 (
980 fl->a.x < 0 || fl->a.x >= SCREENWIDTH
981 || fl->a.y < 0 || fl->a.y >= SCREENHEIGHT
982 || fl->b.x < 0 || fl->b.x >= SCREENWIDTH
983 || fl->b.y < 0 || fl->b.y >= SCREENHEIGHT
984 )
985 {
986 //jff 8/3/98 use logical output routine
987 lprintf(LO_DEBUG, "fuck %d \r", fuck++);
988 return;
989 }
990#endif
991
992#define PUTDOT(xx,yy,cc) V_PlotPixel(0,xx,yy,(byte)cc)
993
994 dx = fl->b.x - fl->a.x;
995 ax = 2 * (dx<0 ? -dx : dx);
996 sx = dx<0 ? -1 : 1;
997
998 dy = fl->b.y - fl->a.y;
999 ay = 2 * (dy<0 ? -dy : dy);
1000 sy = dy<0 ? -1 : 1;
1001
1002 x = fl->a.x;
1003 y = fl->a.y;
1004
1005 if (ax > ay)
1006 {
1007 d = ay - ax/2;
1008 while (1)
1009 {
1010 PUTDOT(x,y,color);
1011 if (x == fl->b.x) return;
1012 if (d>=0)
1013 {
1014 y += sy;
1015 d -= ax;
1016 }
1017 x += sx;
1018 d += ay;
1019 }
1020 }
1021 else
1022 {
1023 d = ax - ay/2;
1024 while (1)
1025 {
1026 PUTDOT(x, y, color);
1027 if (y == fl->b.y) return;
1028 if (d >= 0)
1029 {
1030 x += sx;
1031 d -= ay;
1032 }
1033 y += sy;
1034 d += ax;
1035 }
1036 }
1037}