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