1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: hw_cache.c 1546 2020-09-02 13:24:02Z wesleyjohnson $
5 //
6 // Copyright (C) 1998-2016 by DooM Legacy Team.
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
17 //
18 //
19 // $Log: hw_cache.c,v $
20 // Revision 1.39 2003/06/11 04:33:46 ssntails
21 // 256x256 size limit removal for textures. Possible 'compatibility' cvar commented.
22 //
23 // Revision 1.38 2003/06/10 21:48:06 ssntails
24 // Variable flat size support (32x32 to 2048x2048)
25 //
26 // Revision 1.37 2002/07/28 20:29:18 hurdler
27 // "Fix" holes in the sky
28 //
29 // Revision 1.36 2001/12/26 15:56:12 hurdler
30 // Manage transparent wall a little better
31 //
32 // Revision 1.35 2001/03/03 06:17:34 bpereira
33 // Revision 1.34 2001/02/28 17:50:56 bpereira
34 // Revision 1.33 2001/02/24 13:35:22 bpereira
35 // Revision 1.32 2001/01/25 18:56:27 bpereira
36 // Revision 1.31 2000/11/04 16:23:44 bpereira
37 // Revision 1.30 2000/11/02 22:16:03 bpereira
38 // Revision 1.29 2000/11/02 21:54:26 bpereira
39 // Revision 1.28 2000/11/02 19:49:39 bpereira
40 // Revision 1.27 2000/10/04 16:21:57 hurdler
41 // Revision 1.26 2000/09/28 20:57:20 bpereira
42 // Revision 1.25 2000/08/31 14:30:57 bpereira
43 // Revision 1.24 2000/08/11 19:11:57 metzgermeister
44 // Revision 1.23 2000/08/03 17:57:42 bpereira
45 //
46 // Revision 1.22 2000/07/13 21:07:47 metzgermeister
47 // fixed memory leak
48 //
49 // Revision 1.21 2000/07/01 09:23:50 bpereira
50 //
51 // Revision 1.20 2000/05/30 18:01:53 kegetys
52 // Added the chromakey flag to sprites
53 //
54 // Revision 1.19 2000/05/09 22:08:53 hurdler
55 // fix large sky problem
56 //
57 // Revision 1.18 2000/05/09 20:57:31 hurdler
58 // use my own code for colormap (next time, join with Boris own code)
59 // (necessary due to a small bug in Boris' code (not found) which shows strange effects under linux)
60 //
61 // Revision 1.17 2000/04/30 10:30:10 bpereira
62 //
63 // Revision 1.16 2000/04/27 17:48:47 hurdler
64 // colormap code in hardware mode is now the default
65 //
66 // Revision 1.15 2000/04/24 20:24:38 bpereira
67 //
68 // Revision 1.14 2000/04/24 17:23:26 hurdler
69 // Better support of colormap
70 //
71 // Revision 1.13 2000/04/24 15:46:34 hurdler
72 // Support colormap for text
73 //
74 // Revision 1.12 2000/04/23 16:19:52 bpereira
75 //
76 // Revision 1.11 2000/04/23 00:30:47 hurdler
77 // fix a small bug in skin color
78 //
79 // Revision 1.10 2000/04/22 21:08:23 hurdler
80 // Revision 1.9 2000/04/22 20:16:30 hurdler
81 //
82 // Revision 1.8 2000/04/22 19:12:50 hurdler
83 // support skin color in hardware mode
84 //
85 // Revision 1.7 2000/04/22 16:09:14 hurdler
86 // support skin color in hardware mode
87 //
88 // Revision 1.6 2000/04/18 12:52:21 hurdler
89 // Revision 1.5 2000/04/16 18:38:07 bpereira
90 //
91 // Revision 1.4 2000/04/09 17:18:01 hurdler
92 // modified coronas' code for 16 bits video mode
93 //
94 // Revision 1.3 2000/04/06 20:50:23 hurdler
95 // add Boris' changes for coronas in doom3.wad
96 //
97 // Revision 1.2 2000/02/27 00:42:11 hurdler
98 // Revision 1.1.1.1 2000/02/22 20:32:33 hurdler
99 // Initial import into CVS (v1.29 pr3)
100 //
101 //
102 // DESCRIPTION:
103 // load and convert graphics to the hardware format
104 //
105 //-----------------------------------------------------------------------------
106
107 #include "doomincl.h"
108
109 #include "hw_glob.h"
110 #include "hw_drv.h"
111
112 #include "doomstat.h"
113 //gamemode
114 #include "i_video.h"
115 //rendermode
116 #include "m_swap.h"
117 #include "r_data.h"
118 #include "w_wad.h"
119 #include "z_zone.h"
120 #include "v_video.h"
121
122 #if 0
123 // [WDJ] Replaced global cache draw flags with drawflags parameter and TF_ flags
124 //Hurdler: 25/04/2000: used for new colormap code in hardware mode
125 //unused
126 byte *gr_colormap = NULL; // by default it must be NULL ! (because colormap tables are not initialized)
127 #endif
128
129 // --------------------------------------------------------------------------
130 // Values set after a call to HWR_ResizeBlock()
131 // --------------------------------------------------------------------------
132 static int blocksize;
133 static int blockwidth;
134 static int blockheight;
135
136 extern byte * translucenttables; // set of translucent tables
137
138 int patchformat = GR_TEXFMT_AP_88; // use alpha for holes
139 int textureformat = GR_TEXFMT_P_8; // use chromakey for hole
140
141 // [WDJ] a strange palette pixel format with alpha
142 // to replace an endian swap within inner draw loop
143 // *((unsigned short*)dest) = LE_SWAP16( (alpha<<8) | texel );
144 typedef struct {
145 byte pixel; // paletted color
146 byte alpha;
147 } pixelalpha_t;
148
149 #if 0
150 typedef union {
151 uint16_t ui16;
152 pixelalpha_t s16;
153 } pixelunion16a_t;
154 #endif
155
156 // sprite, use alpha and chroma key for hole
157 // draw flags in mipmap->tfflags
158 // Called from HWR_GetTexture->HWR_GenerateTexture
159 // Called from HWR_MakePatch
160 static
HWR_DrawPatchInCache(Mipmap_t * mipmap,int blockwidth,int blockheight,int blocklinebyte,int texturewidth,int textureheight,int originx,int originy,patch_t * sw_patch,int bytepp)161 void HWR_DrawPatchInCache (Mipmap_t* mipmap,
162 int blockwidth, int blockheight, int blocklinebyte,
163 int texturewidth, int textureheight,
164 int originx, int originy, //where to draw the patch in the surface block
165 patch_t* sw_patch, int bytepp )
166 {
167 int x,x1,x2;
168 int col,ncols;
169 fixed_t xfrac, xfracstep;
170 fixed_t yfrac, yfracstep, ypos, count;
171 fixed_t scale_y;
172
173 // also can be called before translucenttables are setup
174 byte *fx1trans = // only one opaque trans so far
175 ((mipmap->tfflags & TF_Opaquetrans) && translucenttables)?
176 & translucenttables[ TRANSLU_TABLE_fx1 ]
177 : NULL;
178 byte chromakey_mapped = (mipmap->tfflags & TF_CHROMAKEYED)? 1:0;
179 byte alpha;
180 byte *colormap = mipmap->colormap;
181 byte *block = mipmap->grInfo.data;
182 column_t *patchcol;
183 byte *source;
184 byte *dest;
185
186 x1 = originx;
187 x2 = x1 + sw_patch->width;
188
189 if (x1<0)
190 x = 0;
191 else
192 x = x1;
193
194 if (x2 > texturewidth)
195 x2 = texturewidth;
196
197 if( !texturewidth )
198 return;
199
200 col = x * blockwidth / texturewidth;
201 ncols= ((x2-x) * blockwidth) / texturewidth;
202
203 #if 0
204 CONS_Printf("patch %dx%d texture %dx%d block %dx%d\n",
205 sw_patch->width, sw_patch->height,
206 texturewidth, textureheight, blockwidth, blockheight);
207 CONS_Printf(" col %d ncols %d x %d\n", col, ncols, x);
208 #endif
209
210 // source advance
211 xfrac = 0;
212 if (x1<0)
213 xfrac = -x1<<16;
214
215 xfracstep = (texturewidth << 16) / blockwidth;
216 yfracstep = (textureheight<< 16) / blockheight;
217 if( bytepp<1 || bytepp > 4 )
218 I_Error("HWR_DrawPatchInCache: no drawer defined for this bytepp (%d)\n",bytepp);
219
220 for (block += col*bytepp; ncols--; block+=bytepp, xfrac+=xfracstep)
221 {
222 #ifdef DEEPSEA_TALL_PATCH
223 // [MB (M. Bauerle), from crispy Doom] Support for DeePsea tall patches, [WDJ]
224 int cur_topdelta = -1;
225 #endif
226 patchcol = (column_t *)((byte *)sw_patch
227 + sw_patch->columnofs[xfrac>>16]);
228
229 scale_y = (blockheight << 16) / textureheight;
230
231 while (patchcol->topdelta != 0xff)
232 {
233 #ifdef DEEPSEA_TALL_PATCH
234 // [MB] [WDJ] DeePsea tall patch.
235 // DeepSea allows the patch to exceed 254 height.
236 // A Doom patch has monotonic ascending topdelta values, 0..254.
237 // DeePsea tall patches have an optional relative topdelta.
238 // When the column topdelta is <= the current topdelta,
239 // it is a DeePsea tall patch relative topdelta.
240 if( patchcol->topdelta <= cur_topdelta )
241 {
242 cur_topdelta += patchcol->topdelta;
243 }
244 else
245 {
246 cur_topdelta = patchcol->topdelta;
247 }
248 #endif
249
250 source = (byte *)patchcol + 3;
251 count = ((patchcol->length * scale_y) + (FRACUNIT/2)) >> 16;
252
253 #ifdef DEEPSEA_TALL_PATCH
254 ypos = originy + cur_topdelta;
255 #else
256 ypos = originy + patchcol->topdelta;
257 #endif
258
259 yfrac = 0;
260 //yfracstep = (patchcol->length << 16) / count;
261 if (ypos < 0)
262 {
263 // [WDJ] Original doom had a bug in clipping.
264 // To reproduce that bug, comment out the next line.
265 yfrac = -ypos<<16; // skip pixels in patch (not in original doom)
266
267 count += (((ypos * scale_y) + (FRACUNIT/2)) >> 16);
268 ypos = 0;
269 }
270
271 ypos = ((ypos * scale_y) + (FRACUNIT/2)) >> 16;
272 if (ypos + count >= blockheight )
273 count = blockheight - ypos;
274
275 dest = block + (ypos*blocklinebyte);
276 while (count>0)
277 {
278 byte texel = source[yfrac>>16];
279 count--;
280
281 // [WDJ] Fixed, this is fx1 not fire
282 // Verified that 0x40000 is the fx1 translucent table.
283 if( fx1trans && (fx1trans[(texel<<8)] != texel) )
284 alpha = 0x80;
285 else
286 alpha = 0xff;
287
288 //Hurdler: not perfect, but better than holes
289 // Move pixels conflicting with chromakey to a similar color
290 if( chromakey_mapped && texel == HWR_PATCHES_CHROMAKEY_COLORINDEX )
291 texel = HWR_CHROMAKEY_EQUIVALENTCOLORINDEX;
292 //Hurdler: 25/04/2000: now support colormap in hardware mode
293 else if (colormap)
294 texel = colormap[texel];
295
296 // hope compiler will get this switch out of the loops (dreams...)
297 // gcc do it ! but vcc not ! (why don't use cygnus gcc for win32 ?)
298 switch (bytepp) {
299 case 2 :
300 ((pixelalpha_t*)dest)->pixel = texel;
301 ((pixelalpha_t*)dest)->alpha = alpha;
302 break;
303 case 3 :
304 ((RGBA_t*)dest)->s.red = V_GetColor(texel).s.red;
305 ((RGBA_t*)dest)->s.green = V_GetColor(texel).s.green;
306 ((RGBA_t*)dest)->s.blue = V_GetColor(texel).s.blue;
307 break;
308 case 4 :
309 *((RGBA_t*)dest) = V_GetColor(texel);
310 ((RGBA_t*)dest)->s.alpha = alpha;
311 break;
312 default: // default is 1
313 *dest = texel;
314 break;
315 }
316
317 dest += blocklinebyte;
318 yfrac += yfracstep;
319 }
320 patchcol = (column_t *)( (byte *)patchcol + patchcol->length + 4);
321 }
322 }
323 }
324
325
326 // resize the patch to be 3dfx complient
327 // set : blocksize = blockwidth * blockheight (no bpp used)
328 // blockwidth
329 // blockheight
330 //note : 8bit (1 byte per pixel) palettized format
HWR_ResizeBlock(int originalwidth,int originalheight,GrTexInfo * grInfo)331 static void HWR_ResizeBlock ( int originalwidth,
332 int originalheight,
333 GrTexInfo* grInfo )
334 {
335 // Build the full textures from patches.
336 static const GrLOD_t gr_lods[9] = {
337 GR_LOD_LOG2_256,
338 GR_LOD_LOG2_128,
339 GR_LOD_LOG2_64,
340 GR_LOD_LOG2_32,
341 GR_LOD_LOG2_16,
342 GR_LOD_LOG2_8,
343 GR_LOD_LOG2_4,
344 GR_LOD_LOG2_2,
345 GR_LOD_LOG2_1
346 };
347
348 typedef struct {
349 GrAspectRatio_t aspect;
350 float max_s;
351 float max_t;
352 } booring_aspect_t;
353
354 static const booring_aspect_t gr_aspects[8] = {
355 {GR_ASPECT_LOG2_1x1, 255, 255},
356 {GR_ASPECT_LOG2_2x1, 255, 127},
357 {GR_ASPECT_LOG2_4x1, 255, 63},
358 {GR_ASPECT_LOG2_8x1, 255, 31},
359
360 {GR_ASPECT_LOG2_1x1, 255, 255},
361 {GR_ASPECT_LOG2_1x2, 127, 255},
362 {GR_ASPECT_LOG2_1x4, 63, 255},
363 {GR_ASPECT_LOG2_1x8, 31, 255}
364 };
365
366 int j,k;
367 int max,min;
368
369 // find a power of 2 width/height
370 if (cv_grrounddown.value)
371 {
372 blockwidth = 256;
373 while (originalwidth < blockwidth)
374 blockwidth >>= 1;
375 if (blockwidth<1)
376 I_Error ("3D GenerateTexture : too small");
377
378 blockheight = 256;
379 while (originalheight < blockheight)
380 blockheight >>= 1;
381 if (blockheight<1)
382 I_Error ("3D GenerateTexture : too small");
383 }
384 /* else if (cv_voodoocompatibility.value)
385 {
386 if(originalwidth > 256 || originalheight > 256)
387 {
388 blockwidth = 256;
389 while (originalwidth < blockwidth)
390 blockwidth >>= 1;
391 if (blockwidth<1)
392 I_Error ("3D GenerateTexture : too small");
393
394 blockheight = 256;
395 while (originalheight < blockheight)
396 blockheight >>= 1;
397 if (blockheight<1)
398 I_Error ("3D GenerateTexture : too small");
399 }
400 else
401 {
402 //size up to nearest power of 2
403 blockwidth = 1;
404 while (blockwidth < originalwidth)
405 blockwidth <<= 1;
406 // scale down the original graphics to fit in 256
407 if (blockwidth>256)
408 blockwidth = 256;
409 //I_Error ("3D GenerateTexture : too big");
410
411 //size up to nearest power of 2
412 blockheight = 1;
413 while (blockheight < originalheight)
414 blockheight <<= 1;
415 // scale down the original graphics to fit in 256
416 if (blockheight>256)
417 blockheight = 255;
418 //I_Error ("3D GenerateTexture : too big");
419 }
420 }*/
421 else
422 {
423 //size up to nearest power of 2
424 blockwidth = 1;
425 while (blockwidth < originalwidth)
426 blockwidth <<= 1;
427 // scale down the original graphics to fit in 256
428 if (blockwidth>2048)
429 blockwidth = 2048;
430 //I_Error ("3D GenerateTexture : too big");
431
432 //size up to nearest power of 2
433 blockheight = 1;
434 while (blockheight < originalheight)
435 blockheight <<= 1;
436 // scale down the original graphics to fit in 256
437 if (blockheight>2048)
438 blockheight = 2048;
439 //I_Error ("3D GenerateTexture : too big");
440 }
441
442 // do the boring LOD stuff.. blech!
443 if (blockwidth >= blockheight)
444 {
445 max = blockwidth;
446 min = blockheight;
447 }else{
448 max = blockheight;
449 min = blockwidth;
450 }
451
452 for (k=256, j=0; k > max; j++)
453 k>>=1;
454 grInfo->smallLodLog2 = gr_lods[j];
455 grInfo->largeLodLog2 = gr_lods[j];
456
457 for (k=max, j=0; k>min && j<4; j++)
458 k>>=1;
459 // aspect ratio too small for 3Dfx (eg: 8x128 is 1x16 : use 1x8)
460 if (j==4)
461 {
462 j=3;
463 //CONS_Printf ("HWR_ResizeBlock : bad aspect ratio %dx%d\n", blockwidth,blockheight);
464 if (blockwidth<blockheight)
465 blockwidth = max>>3;
466 else
467 blockheight = max>>3;
468 }
469 if (blockwidth<blockheight)
470 j+=4;
471 grInfo->aspectRatioLog2 = gr_aspects[j].aspect;
472
473 blocksize = blockwidth * blockheight;
474 }
475
476
477 // bytes per pixel, index by GrTextureFormat
478 static const int format2bpp[16] = {
479 0, //0
480 0, //1
481 1, //2 GR_TEXFMT_ALPHA_8
482 1, //3 GR_TEXFMT_INTENSITY_8
483 1, //4 GR_TEXFMT_ALPHA_INTENSITY_44
484 1, //5 GR_TEXFMT_P_8
485 4, //6 GR_RGBA
486 0, //7
487 0, //8
488 0, //9
489 2, //10 GR_TEXFMT_RGB_565
490 2, //11 GR_TEXFMT_ARGB_1555
491 2, //12 GR_TEXFMT_ARGB_4444
492 2, //13 GR_TEXFMT_ALPHA_INTENSITY_88
493 2, //14 GR_TEXFMT_AP_88
494 };
495
Make_Mip_Block(Mipmap_t * mipmap)496 static byte * Make_Mip_Block( Mipmap_t * mipmap )
497 {
498 int bytepp = format2bpp[mipmap->grInfo.format];
499 byte * block;
500
501 if( mipmap->grInfo.data != NULL ) // free any existing data
502 Z_Free(mipmap->grInfo.data);
503
504 // set grInfo.data
505 block = Z_Malloc (blocksize*bytepp, PU_STATIC, &(mipmap->grInfo.data));
506
507 switch (bytepp)
508 {
509 case 1:
510 memset(block, HWR_PATCHES_CHROMAKEY_COLORINDEX, blocksize );
511 break;
512 case 2:
513 {
514 // fill background with chromakey, alpha=0
515 pixelalpha_t alphachr = {HWR_PATCHES_CHROMAKEY_COLORINDEX, 0};
516 pixelalpha_t * blka = (pixelalpha_t*) block;
517 int i;
518 for( i=0; i<blocksize; i++ )
519 blka[i] = alphachr;
520 }
521 break;
522 case 4:
523 memset(block,0,blocksize*4);
524 break;
525 }
526
527 return block;
528 }
529
release_Mip_Block(Mipmap_t * mipmap)530 static void release_Mip_Block( Mipmap_t * mipmap )
531 {
532 if( mipmap->grInfo.data != NULL )
533 {
534 // free existing data
535 Z_Free(mipmap->grInfo.data);
536 // some Z_Free methods will clear owner, but not all
537 mipmap->grInfo.data = NULL; // mark as empty
538 }
539 }
540
541 //
542 // Create a composite texture from patches,
543 // adapt the texture size to a power of 2
544 // height and width for the hardware texture cache.
545 // Usually called with mipmap from grtex, there are cases where it may
546 // use another mipmap.
547 //
548 // drawflags: TF_Opaquetrans
549 // Called from HWR_GetTexture
HWR_GenerateTexture(int texnum,MipTexture_t * grtex,Mipmap_t * mipmap,uint32_t drawflags)550 static void HWR_GenerateTexture (int texnum, MipTexture_t* grtex,
551 Mipmap_t * mipmap, uint32_t drawflags)
552 {
553 byte* block;
554 texture_t* texture;
555 texpatch_t* texpatch;
556 patch_t* sw_patch;
557
558 int i;
559 int bytepp; // bytes per pixel
560 boolean skyspecial = false; //poor hack for Legacy large skies..
561
562 texture = textures[texnum];
563
564 // hack the Legacy skies.. texture size is 256x128 but patch size is larger..
565 if ( texture->name[0] == 'S' &&
566 texture->name[1] == 'K' &&
567 texture->name[2] == 'Y' &&
568 texture->name[4] == 0 )
569 {
570 skyspecial = true;
571 mipmap->tfflags = TF_WRAPXY; // don't use the chromakey for sky
572 }
573 else
574 mipmap->tfflags = TF_CHROMAKEYED | TF_WRAPXY;
575 mipmap->tfflags |= drawflags; // TF_Opaquetrans
576
577 HWR_ResizeBlock (texture->width, texture->height, &mipmap->grInfo);
578 mipmap->width = blockwidth;
579 mipmap->height = blockheight;
580 mipmap->grInfo.format = textureformat;
581 bytepp = format2bpp[mipmap->grInfo.format];
582
583 block = Make_Mip_Block( mipmap ); // sets grInfo.data
584
585 if (skyspecial) //Hurdler: not efficient, but better than holes in the sky (and it's done only at level loading)
586 {
587 int i, j;
588 RGBA_t col = V_GetColor(HWR_CHROMAKEY_EQUIVALENTCOLORINDEX);
589 // init sky with col so composite cannot leave any transparent holes,
590 // must be 32bit
591 for (j=0; j<blockheight; j++)
592 {
593 #if 1
594 for (i=0; i<blockwidth; i++)
595 {
596 ((RGBA_t*)block)[(j*blockwidth)+i] = col; // endian tolerant
597 }
598 #else
599 for (i=0; i<blockwidth; i++)
600 {
601 block[4*(j*blockwidth+i)+0] = col.s.red;
602 block[4*(j*blockwidth+i)+1] = col.s.green;
603 block[4*(j*blockwidth+i)+2] = col.s.blue;
604 block[4*(j*blockwidth+i)+3] = 0xff;
605 }
606 #endif
607 }
608 }
609
610 // Composite the columns together.
611 texpatch = texture->patches;
612 for (i=0 ;
613 i<texture->patchcount;
614 i++, texpatch++)
615 {
616 sw_patch = W_CachePatchNum_Endian( texpatch->lumpnum, PU_CACHE );
617 // correct texture size for Legacy's large skies
618 if (skyspecial) {
619 //CONS_Printf("sky %d, %d\n",texture->width,sw_patch->width);
620 //texture->width = sw_patch->width;
621 texture->height = sw_patch->height;
622 }
623 HWR_DrawPatchInCache( mipmap,
624 blockwidth, blockheight, blockwidth*bytepp,
625 texture->width, texture->height,
626 texpatch->originx, texpatch->originy,
627 sw_patch, bytepp );
628 }
629 //Hurdler: not efficient at all but I don't remember exactly how HWR_DrawPatchInCache works :(
630 if (bytepp==4)
631 {
632 // if any pixel is left unwritten (still init to 0), then TF_TRANSPARENT
633 for (i=3; i<blocksize; i+=4)
634 {
635 if (block[i] == 0)
636 {
637 mipmap->tfflags |= TF_TRANSPARENT;
638 break;
639 }
640 }
641 }
642
643 // make it purgable from zone memory
644 // use PU_PURGELEVEL so we can Z_FreeTags all at once
645 Z_ChangeTag (block, PU_HWRCACHE);
646
647 // to convert fixed_t ceilingheight and floorheight, and x, to texture
648 grtex->scaleX = FIXED_TO_FLOAT_MULT / (float)texture->width;
649 grtex->scaleY = FIXED_TO_FLOAT_MULT / (float)texture->height;
650 }
651
652
653
654 // [WDJ] Generate a foggy texture from base texture as an alternate
HWR_GenerateFogTexture(int texnum,Mipmap_t * mipmap,uint32_t drawflags)655 static void HWR_GenerateFogTexture (int texnum, Mipmap_t * mipmap,
656 uint32_t drawflags)
657 {
658 RGBA_t* rgbablock;
659 RGBA_t* fb;
660 RGBA_t* endpixel;
661 RGBA_t* cp;
662
663 int srcsize, si_line3, si, si_endx;
664 int i, x, y, zc;
665 unsigned int fc_g, fc_r, fc_b;
666 RGBA_t fc, fc_avg;
667 RGBA_t fogcolor = {.rgba=0x10101010}; // any endian
668 fogcolor.s.alpha = 0xFF;
669
670 // must have original texture first
671 MipTexture_t* base = HWR_GetTexture (texnum, 0);
672 RGBA_t * src = (RGBA_t*) base->mipmap.grInfo.data;
673 srcsize = base->mipmap.height * base->mipmap.width;
674
675 mipmap->tfflags = TF_WRAPXY | TF_Fogsheet | drawflags;
676
677 HWR_ResizeBlock (FOG_WIDTH, FOG_HEIGHT, &mipmap->grInfo);
678 mipmap->width = blockwidth;
679 mipmap->height = blockheight;
680 mipmap->grInfo.format = GR_RGBA;
681
682 rgbablock = (RGBA_t*) Make_Mip_Block( mipmap ); // sets grInfo.data
683 fb = rgbablock;
684 endpixel = rgbablock + ((blockheight * blockwidth) - 1);
685
686 // Emulate column blend of other drawers
687 si_line3 = 3 * base->mipmap.height;
688 // average 16 pixels
689 fc_r = fc_g = fc_b = 0;
690 si = 0;
691 for( i=0; i<16; i++ )
692 {
693 // find non-transparent pixel
694 for( zc = srcsize; zc > 0; zc-- )
695 {
696 si += si_line3 + 17; // 3 lines + 17 pixels
697 if( si >= srcsize ) si -= srcsize;
698 fc.rgba = src[si].rgba;
699 if( fc.s.alpha > 0x20 ) break;
700 // if all transparent, will avg random pixel noise
701 }
702 fc_r += fc.s.red;
703 fc_g += fc.s.green;
704 fc_b += fc.s.blue;
705 }
706 fc_avg.s.red = fc_r >> 4; // avg
707 fc_avg.s.green = fc_g >> 4;
708 fc_avg.s.blue = fc_b >> 4;
709 fc_avg.s.alpha = 0xff;
710 fogcolor.rgba = fc_avg.rgba; // init
711 // make a fog texture from averaged colors of linedef texture
712 for( x=0; x<blockwidth+32; x++ ) // wrap around width to smooth
713 {
714 if( x > blockwidth )
715 {
716 // reduce visible artifact by smoothing over x wrap edge
717 fb = & rgbablock[ x - blockwidth ];
718 fc_r = fb->s.red * 3;
719 fc_g = fb->s.green * 3;
720 fc_b = fb->s.blue * 3;
721 }
722 else
723 {
724 si = x % base->mipmap.width; // top of column
725 // always average three pixels of source texture
726 fc_r = fc_g = fc_b = 0;
727 for( i=0; i<3; i++ )
728 {
729 for( zc = 32; ; )
730 {
731 fc.rgba = src[si].rgba;
732 if( fc.s.alpha > 0x20 ) break;
733 // skip transparent pixels
734 si += base->mipmap.width; // down column
735 if( si >= srcsize ) si -= srcsize; // wrap source
736 if( --zc < 0 ) // too many transparent pixel
737 {
738 fc.rgba = fc_avg.rgba;
739 break;
740 }
741 }
742 fc_r += fc.s.red;
743 fc_g += fc.s.green;
744 fc_b += fc.s.blue;
745 si += si_line3;
746 if( si > srcsize ) si -= srcsize; // wrap source
747 }
748 }
749 // blend 61 and 3 = 4.6875%
750 fogcolor.s.red = ((((uint16_t)fogcolor.s.red)*61) + fc_r) >> 6;
751 fogcolor.s.green = ((((uint16_t)fogcolor.s.green)*61) + fc_g) >> 6;
752 fogcolor.s.blue = ((((uint16_t)fogcolor.s.blue)*61) + fc_b) >> 6;
753
754 // place fog down entire column
755 for( cp=fb; cp<=endpixel; cp+=blockwidth )
756 {
757 cp->rgba = fogcolor.rgba;
758 }
759 fb++;
760 }
761 // copy any masked outline into fog
762 for( y=0; y<blockheight; y++ )
763 {
764 si= (y % base->mipmap.height) * base->mipmap.width; // wrap
765 si_endx = si + base->mipmap.width;
766 fb= & rgbablock[y * blockwidth];
767 for( x=0; x<blockwidth; x++ )
768 {
769 // Draw masked only recognizes alpha != 0
770 fb->s.alpha = src[si].s.alpha;
771 fb++;
772 si++;
773 if( si >= si_endx ) // wrap source, larger than fog
774 si = si_endx - base->mipmap.width;
775 }
776 }
777
778 // make it purgable from zone memory
779 // use PU_PURGELEVEL so we can Z_FreeTags all at once
780 Z_ChangeTag (rgbablock, PU_HWRCACHE);
781 }
782
783
784 // grTex : Hardware texture cache info
785 // .data : address of converted patch in heap memory
786 // user for Z_Malloc(), becomes NULL if it is purged from the cache
787 // drawflags can be TF_Opaquetrans
788 // Called from HWR_Draw* -> HWR_LoadMappedPatch
789 // Called from HWR_GetPatch
790 // Called from W_CachePatchNum, W_CacheMappedPatchNum
HWR_MakePatch(patch_t * patch,MipPatch_t * grPatch,Mipmap_t * grMipmap,uint32_t drawflags)791 void HWR_MakePatch (patch_t* patch, MipPatch_t* grPatch, Mipmap_t *grMipmap,
792 uint32_t drawflags)
793 {
794 byte* block;
795 int newwidth, newheight;
796 int bytepp;
797
798 // don't do it twice (like a cache)
799 if(grMipmap->width==0)
800 {
801 // save the original patch header so that the MipPatch can be casted
802 // into a standard patch_t struct and the existing code can get the
803 // orginal patch dimensions and offsets.
804 grPatch->width = patch->width;
805 grPatch->height = patch->height;
806 grPatch->leftoffset = patch->leftoffset;
807 grPatch->topoffset = patch->topoffset;
808
809 // find the good 3dfx size (boring spec)
810 HWR_ResizeBlock (patch->width, patch->height, &grMipmap->grInfo);
811 grMipmap->width = blockwidth;
812 grMipmap->height = blockheight;
813
814 // no wrap around, no chroma key
815 grMipmap->tfflags = drawflags; // TF_Opaquetrans
816 // setup the texture info
817 grMipmap->grInfo.format = patchformat;
818 }
819 else
820 {
821 blockwidth = grMipmap->width;
822 blockheight = grMipmap->height;
823 blocksize = blockwidth * blockheight;
824 }
825
826 block = Make_Mip_Block(grMipmap); // set grInfo.data
827
828 // if rounddown, rounddown patches as well as textures
829 if (cv_grrounddown.value)
830 {
831 newwidth = blockwidth;
832 newheight = blockheight;
833 }
834 /* else if(cv_voodoocompatibility.value) // Only scales down textures that exceed 256x256.
835 {
836 // no rounddown, do not size up patches, so they don't look 'scaled'
837 newwidth = min( patch->width , blockwidth );
838 newheight = min( patch->height, blockheight);
839
840 if(newwidth > 256 || newheight > 256)
841 {
842 newwidth = blockwidth;
843 newheight = blockheight;
844 }
845 }*/
846 else
847 {
848 // no rounddown, do not size up patches, so they don't look 'scaled'
849 newwidth = min( patch->width , blockwidth );
850 newheight = min( patch->height, blockheight);
851 }
852
853 bytepp = format2bpp[grMipmap->grInfo.format];
854 HWR_DrawPatchInCache( grMipmap,
855 newwidth, newheight, blockwidth*bytepp,
856 patch->width, patch->height,
857 0, 0,
858 patch, bytepp );
859
860 grPatch->max_s = (float)newwidth / (float)blockwidth;
861 grPatch->max_t = (float)newheight / (float)blockheight;
862
863 // Now that the texture has been built in cache, it is purgable from zone memory.
864 Z_ChangeTag (block, PU_HWRCACHE);
865 }
866
867
868 // This releases the allocation made with HWR_MakePatch
HWR_release_Patch(MipPatch_t * grPatch,Mipmap_t * grMipmap)869 void HWR_release_Patch ( MipPatch_t* grPatch, Mipmap_t *grMipmap )
870 {
871 release_Mip_Block( grMipmap );
872 grMipmap->width = 0;
873 }
874
875
876
877 // =================================================
878 // CACHING HANDLING
879 // =================================================
880
881 static int gr_numtextures = 0;
882 static MipTexture_t* gr_textures = NULL; // for ALL Doom textures
883
HWR_Init_TextureCache(void)884 void HWR_Init_TextureCache (void)
885 {
886 gr_numtextures = 0;
887 gr_textures = NULL;
888 }
889
890 // Called from P_SetupLevel->HWR_PrepLevelCache
891 // Coordinate with malloc in HWR_GetMappedPatch
HWR_Free_TextureCache(void)892 void HWR_Free_TextureCache (void)
893 {
894 int i,j;
895
896 if( HWD.pfnClearMipMapCache == NULL ) return; // cache never set
897
898 // free references to the textures
899 HWD.pfnClearMipMapCache ();
900
901 // free grInfo.data before freeing mipmaps that Z_FreeTags will write
902 // free all hardware-converted graphics cached in the heap
903 // our goal is only the textures since user of the texture is the texture cache
904 Z_FreeTags (PU_HWRCACHE, PU_HWRCACHE);
905
906 // free all skin after each level: must be done after pfnClearMipMapCache!
907 for (j=0; j<numwadfiles; j++)
908 {
909 for (i=0; i<wadfiles[j]->numlumps; i++)
910 {
911 MipPatch_t *grpatch = &(wadfiles[j]->hwrcache[i]);
912 while (grpatch->mipmap.nextcolormap)
913 {
914 Mipmap_t *grmip = grpatch->mipmap.nextcolormap;
915 grpatch->mipmap.nextcolormap = grmip->nextcolormap;
916 free(grmip);
917 }
918 }
919 }
920
921 // now the heap don't have any 'user' pointing to our
922 // texturecache info, we can free it
923 if (gr_textures)
924 {
925 // destroy all of gr_textures
926 for( i=0; i<gr_numtextures; i++ )
927 {
928 // free alternate texture mipmap used for TF_Opaquetrans
929 Mipmap_t * altmip = gr_textures[i].mipmap.nextcolormap;
930 while( altmip )
931 {
932 register Mipmap_t * nxt = altmip->nextcolormap;
933 free(altmip);
934 altmip = nxt;
935 }
936 }
937 free (gr_textures);
938 gr_textures = NULL;
939 }
940 }
941
942 // Called from P_SetupLevel->HWR_Preload_Graphics
HWR_Prep_LevelCache(int numtextures)943 void HWR_Prep_LevelCache (int numtextures)
944 {
945 // problem: the mipmap cache management hold a list of mipmaps.. but they are
946 // reallocated on each level..
947 //sub-optimal, but
948 // 1) just need re-download stuff in hardware cache VERY fast
949 // 2) sprite/menu stuff mixed with level textures so can't do anything else
950
951 // we must free it since numtextures changed
952 HWR_Free_TextureCache ();
953
954 gr_numtextures = numtextures;
955 gr_textures = malloc (sizeof(MipTexture_t) * numtextures);
956 if (!gr_textures)
957 I_Error ("3D can't alloc gr_textures");
958 memset (gr_textures, 0, sizeof(MipTexture_t) * numtextures);
959 }
960
HWR_SetPalette(RGBA_t * palette)961 void HWR_SetPalette( RGBA_t *palette )
962 {
963 if( HWD.pfnSetPalette )
964 {
965 //Hurdler: 16/10/99: added for OpenGL gamma correction
966 RGBA_t gamma_correction = {0x7F7F7F7F};
967
968 gamma_correction.s.red = cv_grgammared.value;
969 gamma_correction.s.green = cv_grgammagreen.value;
970 gamma_correction.s.blue = cv_grgammablue.value;
971 HWD.pfnSetPalette( palette, &gamma_correction );
972 }
973
974 // hardware driver will flush their own cache if cache is non paletized
975 // now flush data texture cache so 32 bit texture are recomputed
976 if( patchformat == GR_RGBA || textureformat == GR_RGBA )
977 Z_FreeTags (PU_HWRCACHE, PU_HWRCACHE);
978 }
979
980
981 // Imitate the special object screen tints for each special palette.
982 // Corresponding to Doom special effect palettes.
983 // These seem to be the same for Doom and Heretic.
984 static uint32_t palette_to_tint[16] =
985 {
986 0x0, // 00 normal
987 0xff373797, // 01 red
988 0xff373797, // 02 red
989 0xff3030a7, // 03 red
990 0xff2727b7, // 04 red
991 0xff2020c7, // 05 red
992 0xff1717d7, // 06 red
993 0xff1010e7, // 07 red
994 0xff0707f7, // 08 red
995 0xffff6060, // 09 blue
996 0xff70a090, // 0A light green
997 0xff67b097, // 0B light green
998 0xff60c0a0, // 0C light green
999 0xff60ff60, // 0D green
1000 0xffff6060, // 0E blue
1001 0xffff6060 // 0F blue
1002 };
1003
1004
1005 // Enables flash palette.
1006 byte EN_HWR_flashpalette = 0;
1007
1008 // Faster palette flashes using tints.
1009 // palette_num : 0..15
HWR_SetFlashPalette(byte palette_num)1010 void HWR_SetFlashPalette( byte palette_num )
1011 {
1012
1013 //faB - NOW DO ONLY IN SOFTWARE MODE, LETS FIX THIS FOR GOOD OR NEVER
1014 // idea : use a true color gradient from frame to frame, because we
1015 // are in true color in HW3D, we can have smoother palette change
1016 // than the palettes defined in the wad
1017
1018 //Hurdler: TODO: see if all heretic palettes are properly managed
1019
1020 // Could change the HW palette used for paletted textures, but
1021 // that would require conversion of textures to RGB again.
1022 // This sets a tint that is averaged with the surface color
1023 // by the drawing engine.
1024 HWD.pfnSetSpecialState(HWD_SET_TINT_COLOR, palette_to_tint[palette_num] );
1025 }
1026
1027
1028 // --------------------------------------------------------------------------
1029 // Make sure texture is downloaded and set it as the source
1030 // --------------------------------------------------------------------------
1031 // drawflags: TF_Opaquetrans
1032 // Called from HWR_RenderSkyPlane // commented out
1033 // Called from HWR_DrawSkyBackground
1034 // Called from HWR_SplitWall
1035 // Called from HWR_StoreWallRange
1036 // Called from HWR_RenderTransparentWalls
HWR_GetTexture(int tex,uint32_t drawflags)1037 MipTexture_t* HWR_GetTexture (int tex, uint32_t drawflags)
1038 {
1039 MipTexture_t * miptex;
1040 Mipmap_t * mipmap;
1041 #ifdef PARANOIA
1042 if( tex>=gr_numtextures )
1043 I_Error(" HWR_GetTexture : tex>=numtextures\n");
1044 #endif
1045 miptex = &gr_textures[tex];
1046 mipmap = &(miptex->mipmap); // mipmap in miptex
1047 if ( miptex->mipmap.grInfo.data || miptex->mipmap.downloaded )
1048 {
1049 uint32_t tstflags = drawflags & (TF_Opaquetrans|TF_Fogsheet);
1050 // mipmap already in use, find matching flags
1051 for(; ; mipmap = mipmap->nextcolormap)
1052 {
1053 if ((mipmap->tfflags & (TF_Opaquetrans|TF_Fogsheet)) == tstflags)
1054 goto found_mipmap;
1055 if( ! mipmap->nextcolormap ) break;
1056 }
1057 {
1058 // no matching mipmap found, make new one as alternate
1059 Mipmap_t * newmip = malloc(sizeof(Mipmap_t));
1060 if( newmip == NULL )
1061 I_Error(" HWR_GetTexture : mipmap alloc failed\n");
1062 mipmap->nextcolormap = newmip; // link
1063 memset(newmip, 0, sizeof(Mipmap_t));
1064
1065 mipmap = newmip;
1066 }
1067 }
1068 else if (drawflags & TF_Fogsheet)
1069 {
1070 // Do not have base texture, base mipmap must go to base texture.
1071 // These cannot overlap, otherwise wrong mipmap gets used
1072 HWR_GetTexture (tex, 0); // get base texture first
1073 miptex = HWR_GetTexture (tex, drawflags); // gen fog texture mipmap
1074 return miptex;
1075 }
1076 if( drawflags & TF_Fogsheet )
1077 {
1078 // generate mipmap with foggy texture as alternate
1079 HWR_GenerateFogTexture (tex, mipmap, drawflags);
1080 }
1081 else
1082 {
1083 // generate mipmap with texture
1084 HWR_GenerateTexture (tex, miptex, mipmap, drawflags);
1085 }
1086
1087 found_mipmap:
1088 HWD.pfnSetTexture (mipmap);
1089 return miptex;
1090 }
1091
1092
HWR_CacheFlat(Mipmap_t * grMipmap,int flatlumpnum)1093 static void HWR_CacheFlat (Mipmap_t* grMipmap, int flatlumpnum)
1094 {
1095 byte *block;
1096 int size, flatsize;
1097
1098 // setup the texture info
1099 grMipmap->grInfo.smallLodLog2 = GR_LOD_LOG2_64;
1100 grMipmap->grInfo.largeLodLog2 = GR_LOD_LOG2_64;
1101 grMipmap->grInfo.aspectRatioLog2 = GR_ASPECT_LOG2_1x1;
1102 grMipmap->grInfo.format = GR_TEXFMT_P_8;
1103 grMipmap->tfflags = TF_WRAPXY;
1104
1105 size = W_LumpLength(flatlumpnum);
1106
1107 switch(size)
1108 {
1109 case 4194304: // 2048x2048 lump
1110 flatsize = 2048;
1111 break;
1112 case 1048576: // 1024x1024 lump
1113 flatsize = 1024;
1114 break;
1115 case 262144:// 512x512 lump
1116 flatsize = 512;
1117 break;
1118 case 65536: // 256x256 lump
1119 flatsize = 256;
1120 break;
1121 case 16384: // 128x128 lump
1122 flatsize = 128;
1123 break;
1124 case 1024: // 32x32 lump
1125 flatsize = 32;
1126 break;
1127 default: // 64x64 lump
1128 flatsize = 64;
1129 break;
1130 }
1131 grMipmap->width = flatsize;
1132 grMipmap->height = flatsize;
1133
1134 // the flat raw data needn't be converted with palettized textures
1135 block = Z_Malloc (W_LumpLength(flatlumpnum),
1136 PU_HWRCACHE,
1137 &grMipmap->grInfo.data);
1138
1139 W_ReadLump (flatlumpnum, block);
1140 }
1141
1142
1143 // Download a Doom 'flat' to the hardware cache and make it ready for use
HWR_GetFlat(lumpnum_t flatlumpnum)1144 void HWR_GetFlat (lumpnum_t flatlumpnum)
1145 {
1146 Mipmap_t * grmip;
1147
1148 grmip = &(wadfiles[ WADFILENUM(flatlumpnum) ]->hwrcache[ LUMPNUM(flatlumpnum) ].mipmap);
1149
1150 if (!grmip->downloaded &&
1151 !grmip->grInfo.data)
1152 HWR_CacheFlat (grmip, flatlumpnum);
1153
1154 HWD.pfnSetTexture (grmip);
1155 }
1156
1157 //
1158 // HWR_LoadMappedPatch(): replace the skin color of the sprite in cache
1159 // : load it first in doom cache if not already
1160 //
1161 // grmip.tfflags can have TF_Opaquetrans
1162 // Called from HWR_Draw* ->HWR_GetMappedPatch
HWR_LoadMappedPatch(Mipmap_t * grmip,MipPatch_t * gpatch)1163 static void HWR_LoadMappedPatch(Mipmap_t *grmip, MipPatch_t *gpatch)
1164 {
1165 if( !grmip->downloaded &&
1166 !grmip->grInfo.data )
1167 {
1168 // Load patch to temp, free it afterwards
1169 patch_t* pp = W_CachePatchNum_Endian(gpatch->patch_lumpnum, PU_IN_USE);
1170 HWR_MakePatch( pp, gpatch, grmip, grmip->tfflags);
1171
1172 Z_Free(pp);
1173 }
1174
1175 HWD.pfnSetTexture(grmip);
1176 }
1177
1178 // -----------------+
1179 // HWR_GetPatch : Download a patch to the hardware cache and make it ready for use
1180 // -----------------+
1181 // Called from HWR_Draw* -> HWR_DrawSegsSplats, HWR_DrawPSprite, HWR_DrawPatch
HWR_GetPatch(MipPatch_t * gpatch)1182 void HWR_GetPatch( MipPatch_t* gpatch )
1183 {
1184 // is it in hardware cache
1185 if ( !gpatch->mipmap.downloaded &&
1186 !gpatch->mipmap.grInfo.data )
1187 {
1188 // load the software patch, PU_STATIC or the Z_Malloc for hardware patch will
1189 // flush the software patch before the conversion! oh yeah I suffered
1190 patch_t * swpatch = W_CachePatchNum_Endian(gpatch->patch_lumpnum, PU_IN_USE);
1191
1192 #ifdef PARANOIA
1193 if( swpatch->width != gpatch->width || swpatch->height != gpatch->height
1194 || swpatch->leftoffset != gpatch->leftoffset || swpatch->topoffset != gpatch->topoffset ) {
1195 printf("HWR_GetPatch, bad patch: patch_lumpnum = %i\n", gpatch->patch_lumpnum);
1196 }
1197 #endif
1198
1199 HWR_MakePatch ( swpatch, gpatch, &gpatch->mipmap, 0);
1200
1201 // this is inefficient.. but the hardware patch in heap is purgeable so it should
1202 // not fragment memory, and besides the REAL cache here is the hardware memory
1203 Z_Free(swpatch);
1204 }
1205
1206 HWD.pfnSetTexture( &gpatch->mipmap );
1207 }
1208
1209
1210 // -------------------+
1211 // HWR_GetMappedPatch : Same as HWR_GetPatch for sprite color
1212 // -------------------+
1213 // colormap variations only, drawflags are fixed for whole sprite
1214 // Called from HWR_DrawSmallPatch, HWR_DrawMappedPatch, HWR_DrawSprite, HWR_DrawMD2
HWR_GetMappedPatch(MipPatch_t * gpatch,byte * colormap)1215 void HWR_GetMappedPatch(MipPatch_t* gpatch, byte *colormap)
1216 {
1217 Mipmap_t *grmip, *newmip;
1218
1219 if( (colormap==NULL) || (colormap==reg_colormaps) )
1220 {
1221 // Load the default (green) color in doom cache (temporary?) AND hardware cache
1222 HWR_GetPatch(gpatch);
1223 return;
1224 }
1225
1226 // search for the mipmap
1227 // skip the first (no colormap translated)
1228 for(grmip = &gpatch->mipmap ; grmip->nextcolormap ;)
1229 {
1230 grmip = grmip->nextcolormap;
1231 if (grmip->colormap==colormap)
1232 {
1233 HWR_LoadMappedPatch( grmip, gpatch );
1234 return;
1235 }
1236 }
1237 // not found, create it !
1238 // If we are here, the sprite with the current colormap is not already in hardware memory
1239
1240 //BP: WARNING : don't free it manually without clearing the cache of hardware renderer
1241 // (it have a list of mipmap)
1242 // this malloc is cleared in HWR_FreeTextureCache
1243 // (...) unfortunately z_malloc fragment alot the memory :( so malloc is better
1244 newmip = malloc(sizeof(Mipmap_t));
1245 memset(newmip, 0, sizeof(Mipmap_t));
1246 grmip->nextcolormap = newmip;
1247
1248 newmip->colormap = colormap;
1249 HWR_LoadMappedPatch( newmip, gpatch );
1250 }
1251
1252 #if 0
1253 // [WDJ] Not needed until a patch needs both with and without TF_Opaquetrans
1254 // May be called with drawflags = TF_Opaquetrans
1255 void HWR_GetMappedPatch(MipPatch_t* gpatch, byte *colormap, uint32_t drawflags)
1256 {
1257 Mipmap_t *grmip, *newmip;
1258
1259 if( !drawflags && ((colormap==NULL) || (colormap==reg_colormaps)) )
1260 {
1261 // Load the default (green) color in doom cache (temporary?) AND hardware cache
1262 HWR_GetPatch(gpatch);
1263 return;
1264 }
1265
1266 // search for the mipmap
1267 // skip the first (no colormap translated)
1268 for(grmip = &gpatch->mipmap ; grmip->nextcolormap ;)
1269 {
1270 grmip = grmip->nextcolormap;
1271 if (grmip->colormap==colormap
1272 && ((grmip->tfflags & TF_Opaquetrans)==drawflags) )
1273 {
1274 HWR_LoadMappedPatch( grmip, gpatch );
1275 return;
1276 }
1277 }
1278 // not found, create it !
1279 // If we are here, the sprite with the current colormap is not already in hardware memory
1280
1281 //BP: WARNING : don't free it manually without clearing the cache of hardware renderer
1282 // (it have a list of mipmap)
1283 // this malloc is cleared in HWR_FreeTextureCache
1284 // (...) unfortunately z_malloc fragment alot the memory :( so malloc is better
1285 newmip = malloc(sizeof(Mipmap_t));
1286 grmip->nextcolormap = newmip;
1287 memset(newmip, 0, sizeof(Mipmap_t));
1288
1289 newmip->tfflags = drawflags;
1290 HWR_LoadMappedPatch( newmip, gpatch );
1291 }
1292 #endif
1293
1294 static const int picmode2GR[] = {
1295 GR_TEXFMT_P_8, // PALETTE
1296 0, // INTENSITY (unsuported yet)
1297 GR_TEXFMT_ALPHA_INTENSITY_88, // INTENSITY_ALPHA (corona use this)
1298 0, // RGB24 (unsuported yet)
1299 GR_RGBA, // RGBA32 (opengl only)
1300 };
1301
1302 // Called from HWR_GetPic
1303 static
HWR_DrawPicInCache(byte * block,int blockwidth,int blockheight,int blocklinebyte,pic_t * pic,int dest_bytepp)1304 void HWR_DrawPicInCache (byte* block,
1305 int blockwidth, int blockheight, int blocklinebyte,
1306 pic_t* pic, int dest_bytepp)
1307 {
1308 int i,j;
1309 int picbytepp;
1310 int srcindex;
1311 fixed_t posx,posy,stepx,stepy;
1312 byte *dest,*src,texel;
1313
1314 stepy = ((int)pic->height<<16)/blockheight;
1315 stepx = ((int)pic->width<<16)/blockwidth;
1316 picbytepp = format2bpp[picmode2GR[pic->mode]];
1317 posy = 0;
1318 for( j=0 ;j<blockheight;j++)
1319 {
1320 posx = 0;
1321 dest = &block[j*blocklinebyte];
1322 src = &pic->data[(posy>>16)*pic->width*picbytepp];
1323 for( i=0 ;i<blockwidth;i++)
1324 {
1325 srcindex = (posx+FRACUNIT/2)>>16; // rounded to int
1326 switch (pic->mode) { // source bpp
1327 case PALETTE :
1328 texel = src[srcindex];
1329 switch( dest_bytepp ) { // destination bpp
1330 case 1 :
1331 *dest++ = texel;
1332 break;
1333 case 2 :
1334 ((pixelalpha_t*)dest)->pixel = texel;
1335 ((pixelalpha_t*)dest)->alpha = 0xff;
1336 dest +=2;
1337 break;
1338 case 3 :
1339 ((RGBA_t*)dest)->s.red = V_GetColor(texel).s.red;
1340 ((RGBA_t*)dest)->s.green = V_GetColor(texel).s.green;
1341 ((RGBA_t*)dest)->s.blue = V_GetColor(texel).s.blue;
1342 dest += 3;
1343 break;
1344 case 4 :
1345 *(RGBA_t*)dest = V_GetColor(texel);
1346 dest += 4;
1347 break;
1348 }
1349 break;
1350 case INTENSITY :
1351 *dest++ = src[srcindex];
1352 break;
1353 case INTENSITY_ALPHA : // assume dest bpp = 2
1354 *(uint16_t*)dest = ((uint16_t*)src)[ srcindex ];
1355 dest+=2;
1356 break;
1357 case RGB24 :
1358 break; // not supported yet
1359 case RGBA32 : // assume dest bpp = 4
1360 // [WDJ] without some note, must assume the inc should be after, not before
1361 // dest += 4;
1362 *(uint32_t*)dest = ((uint32_t*)src)[ srcindex ];
1363 dest += 4;
1364 break;
1365 }
1366 posx += stepx;
1367 }
1368 posy += stepy;
1369 }
1370 }
1371
1372 // -----------------+
1373 // HWR_GetPic : Download a Doom pic (raw row encoded with no 'holes')
1374 // Returns :
1375 // -----------------+
HWR_GetPic(lumpnum_t lumpnum)1376 MipPatch_t * HWR_GetPic( lumpnum_t lumpnum )
1377 {
1378 MipPatch_t *grpatch;
1379
1380 grpatch = &(wadfiles[ WADFILENUM(lumpnum) ]->hwrcache[ LUMPNUM(lumpnum) ]);
1381
1382 if( !grpatch->mipmap.downloaded
1383 && !grpatch->mipmap.grInfo.data )
1384 {
1385 pic_t *pic;
1386 int len;
1387 byte *block;
1388 int newwidth,newheight;
1389
1390 if( grpatch->mipmap.tfflags & TF_Her_Raw_Pic )
1391 {
1392 // raw pic : so get size from grpatch since it is save in v_drawrawscreen
1393 // [WDJ] CacheRawAsPic is correct endian
1394 // Will change to PU_CACHE before end of function
1395 pic = W_CacheRawAsPic( lumpnum, grpatch->width, grpatch->height, PU_IN_USE );
1396 len = W_LumpLength(lumpnum);
1397 }
1398 else
1399 {
1400 // Will change to PU_CACHE before end of function
1401 pic = W_CachePicNum( lumpnum, PU_IN_USE ); // endian fixed
1402 grpatch->width = pic->width;
1403 grpatch->height = pic->height;
1404 len = W_LumpLength(lumpnum) - sizeof(pic_t);
1405 }
1406
1407 grpatch->leftoffset = 0;
1408 grpatch->topoffset = 0;
1409
1410 // find the good 3dfx size (boring spec)
1411 HWR_ResizeBlock (grpatch->width, grpatch->height, &grpatch->mipmap.grInfo);
1412 grpatch->mipmap.width = blockwidth;
1413 grpatch->mipmap.height = blockheight;
1414
1415 if( pic->mode == PALETTE )
1416 grpatch->mipmap.grInfo.format = textureformat; // can be set by driver
1417 else
1418 grpatch->mipmap.grInfo.format = picmode2GR[pic->mode];
1419
1420 // allocate block
1421 block = Make_Mip_Block(&grpatch->mipmap);
1422
1423 // if rounddown, rounddown patches as well as textures
1424 if (cv_grrounddown.value)
1425 {
1426 newwidth = blockwidth;
1427 newheight = blockheight;
1428 }
1429 /* else if(cv_voodoocompatibility.value) // Only scales down textures that exceed 256x256.
1430 {
1431 // no rounddown, do not size up patches, so they don't look 'scaled'
1432 newwidth = min(pic->width,blockwidth);
1433 newheight = min(pic->height,blockheight);
1434
1435 if(newwidth > 256 || newheight > 256)
1436 {
1437 newwidth = blockwidth;
1438 newheight = blockheight;
1439 }
1440 }*/
1441 else
1442 {
1443 // no rounddown, do not size up patches, so they don't look 'scaled'
1444 newwidth = min(pic->width,blockwidth);
1445 newheight = min(pic->height,blockheight);
1446 }
1447
1448
1449 if( grpatch->width == blockwidth &&
1450 grpatch->height == blockheight &&
1451 format2bpp[grpatch->mipmap.grInfo.format] == format2bpp[picmode2GR[pic->mode]] )
1452 {
1453 // no conversion needed
1454 memcpy(grpatch->mipmap.grInfo.data, pic->data,len);
1455 }
1456 else
1457 {
1458 HWR_DrawPicInCache(block, newwidth, newheight,
1459 blockwidth*format2bpp[grpatch->mipmap.grInfo.format],
1460 pic,
1461 format2bpp[grpatch->mipmap.grInfo.format]);
1462 }
1463
1464 // Release PU_IN_USE
1465 Z_ChangeTag(pic, PU_CACHE);
1466 Z_ChangeTag(block, PU_HWRCACHE);
1467
1468 grpatch->mipmap.tfflags &= TF_Her_Raw_Pic;
1469 grpatch->max_s = (float)newwidth / (float)blockwidth;
1470 grpatch->max_t = (float)newheight / (float)blockheight;
1471 }
1472 HWD.pfnSetTexture( &grpatch->mipmap );
1473 //CONS_Printf("picloaded at %x as texture %d\n",grpatch->mipmap.grInfo.data, grpatch->mipmap.downloaded);
1474
1475 return grpatch;
1476 }
1477