diff options
Diffstat (limited to 'src/v_video.c')
-rw-r--r-- | src/v_video.c | 1037 |
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]; | ||
49 | screeninfo_t screens[NUM_SCREENS]; | ||
50 | |||
51 | /* jff 4/24/98 initialize this at runtime */ | ||
52 | const byte *colrngs[CR_LIMIT]; | ||
53 | |||
54 | int 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 | |||
71 | typedef struct { | ||
72 | const char *name; | ||
73 | const byte **map; | ||
74 | } crdef_t; | ||
75 | |||
76 | // killough 5/2/98: table-driven approach | ||
77 | static 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 | ||
93 | void 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 | // | ||
112 | static 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 | */ | ||
157 | static 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 | |||
228 | void 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 | // | ||
256 | static 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 | |||
490 | static 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 | |||
497 | unsigned short *V_Palette15 = NULL; | ||
498 | unsigned short *V_Palette16 = NULL; | ||
499 | unsigned int *V_Palette32 = NULL; | ||
500 | static unsigned short *Palettes15 = NULL; | ||
501 | static unsigned short *Palettes16 = NULL; | ||
502 | static unsigned int *Palettes32 = NULL; | ||
503 | static int currentPaletteIndex = 0; | ||
504 | |||
505 | // | ||
506 | // V_UpdateTrueColorPalette | ||
507 | // | ||
508 | void 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 | //--------------------------------------------------------------------------- | ||
638 | static 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 | |||
656 | void 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 | |||
668 | void 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 | ||
692 | static 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 | |||
701 | static 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 | |||
714 | static 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 | |||
727 | static 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 | |||
740 | static void WRAP_V_DrawLine(fline_t* fl, int color); | ||
741 | static void V_PlotPixel8(int scrn, int x, int y, byte color); | ||
742 | static void V_PlotPixel15(int scrn, int x, int y, byte color); | ||
743 | static void V_PlotPixel16(int scrn, int x, int y, byte color); | ||
744 | static void V_PlotPixel32(int scrn, int x, int y, byte color); | ||
745 | |||
746 | #ifdef GL_DOOM | ||
747 | static 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 | } | ||
751 | static 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 | } | ||
754 | static void WRAP_gld_DrawBackground(const char *flatname, int n) | ||
755 | { | ||
756 | gld_DrawBackground(flatname); | ||
757 | } | ||
758 | static 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 | } | ||
762 | static void WRAP_gld_DrawBlock(int x, int y, int scrn, int width, int height, const byte *src, enum patch_translation_e flags) | ||
763 | { | ||
764 | } | ||
765 | static 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 | } | ||
769 | static 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 | |||
775 | static void NULL_FillRect(int scrn, int x, int y, int width, int height, byte colour) {} | ||
776 | static void NULL_CopyRect(int srcx, int srcy, int srcscrn, int width, int height, int destx, int desty, int destscrn, enum patch_translation_e flags) {} | ||
777 | static void NULL_DrawBackground(const char *flatname, int n) {} | ||
778 | static void NULL_DrawNumPatch(int x, int y, int scrn, int lump, int cm, enum patch_translation_e flags) {} | ||
779 | static void NULL_DrawBlock(int x, int y, int scrn, int width, int height, const byte *src, enum patch_translation_e flags) {} | ||
780 | static void NULL_PlotPixel(int scrn, int x, int y, byte color) {} | ||
781 | static void NULL_DrawLine(fline_t* fl, int color) {} | ||
782 | |||
783 | const char *default_videomode; | ||
784 | static video_mode_t current_videomode = VID_MODE8; | ||
785 | |||
786 | V_CopyRect_f V_CopyRect = NULL_CopyRect; | ||
787 | V_FillRect_f V_FillRect = NULL_FillRect; | ||
788 | V_DrawNumPatch_f V_DrawNumPatch = NULL_DrawNumPatch; | ||
789 | V_DrawBackground_f V_DrawBackground = NULL_DrawBackground; | ||
790 | V_PlotPixel_f V_PlotPixel = NULL_PlotPixel; | ||
791 | V_DrawLine_f V_DrawLine = NULL_DrawLine; | ||
792 | |||
793 | // | ||
794 | // V_InitMode | ||
795 | // | ||
796 | void 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 | // | ||
861 | video_mode_t V_GetMode(void) { | ||
862 | return current_videomode; | ||
863 | } | ||
864 | |||
865 | // | ||
866 | // V_GetModePixelDepth | ||
867 | // | ||
868 | int 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 | // | ||
881 | int 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 | // | ||
894 | int V_GetPixelDepth(void) { | ||
895 | return V_GetModePixelDepth(current_videomode); | ||
896 | } | ||
897 | |||
898 | // | ||
899 | // V_AllocScreen | ||
900 | // | ||
901 | void 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 | // | ||
910 | void 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 | // | ||
920 | void 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 | // | ||
930 | void V_FreeScreens(void) { | ||
931 | int i; | ||
932 | |||
933 | for (i=0; i<NUM_SCREENS; i++) | ||
934 | V_FreeScreen(&screens[i]); | ||
935 | } | ||
936 | |||
937 | static void V_PlotPixel8(int scrn, int x, int y, byte color) { | ||
938 | screens[scrn].data[x+screens[scrn].byte_pitch*y] = color; | ||
939 | } | ||
940 | |||
941 | static 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 | |||
945 | static 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 | |||
949 | static 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 | // | ||
962 | static 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 | } | ||