1 // SONIC ROBO BLAST 2
2 //-----------------------------------------------------------------------------
3 // Copyright (C) 1998-2000 by DooM Legacy Team.
4 // Copyright (C) 1999-2020 by Sonic Team Junior.
5 //
6 // This program is free software distributed under the
7 // terms of the GNU General Public License, version 2.
8 // See the 'LICENSE' file for more details.
9 //-----------------------------------------------------------------------------
10 /// \file hw_cache.c
11 /// \brief load and convert graphics to the hardware format
12
13 #include "../doomdef.h"
14
15 #ifdef HWRENDER
16 #include "hw_glob.h"
17 #include "hw_drv.h"
18 #include "hw_batching.h"
19
20 #include "../doomstat.h" //gamemode
21 #include "../i_video.h" //rendermode
22 #include "../r_data.h"
23 #include "../r_textures.h"
24 #include "../w_wad.h"
25 #include "../z_zone.h"
26 #include "../v_video.h"
27 #include "../r_draw.h"
28 #include "../r_patch.h"
29 #include "../r_picformats.h"
30 #include "../p_setup.h"
31
32 INT32 patchformat = GL_TEXFMT_AP_88; // use alpha for holes
33 INT32 textureformat = GL_TEXFMT_P_8; // use chromakey for hole
34
format2bpp(GLTextureFormat_t format)35 static INT32 format2bpp(GLTextureFormat_t format)
36 {
37 if (format == GL_TEXFMT_RGBA)
38 return 4;
39 else if (format == GL_TEXFMT_ALPHA_INTENSITY_88 || format == GL_TEXFMT_AP_88)
40 return 2;
41 else
42 return 1;
43 }
44
45 // This code was originally placed directly in HWR_DrawPatchInCache.
46 // It is now split from it for my sanity! (and the sanity of others)
47 // -- Monster Iestyn (13/02/19)
HWR_DrawColumnInCache(const column_t * patchcol,UINT8 * block,GLMipmap_t * mipmap,INT32 pblockheight,INT32 blockmodulo,fixed_t yfracstep,fixed_t scale_y,texpatch_t * originPatch,INT32 patchheight,INT32 bpp)48 static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipmap_t *mipmap,
49 INT32 pblockheight, INT32 blockmodulo,
50 fixed_t yfracstep, fixed_t scale_y,
51 texpatch_t *originPatch, INT32 patchheight,
52 INT32 bpp)
53 {
54 fixed_t yfrac, position, count;
55 UINT8 *dest;
56 const UINT8 *source;
57 INT32 topdelta, prevdelta = -1;
58 INT32 originy = 0;
59
60 // for writing a pixel to dest
61 RGBA_t colortemp;
62 UINT8 alpha;
63 UINT8 texel;
64 UINT16 texelu16;
65
66 (void)patchheight; // This parameter is unused
67
68 if (originPatch) // originPatch can be NULL here, unlike in the software version
69 originy = originPatch->originy;
70
71 while (patchcol->topdelta != 0xff)
72 {
73 topdelta = patchcol->topdelta;
74 if (topdelta <= prevdelta)
75 topdelta += prevdelta;
76 prevdelta = topdelta;
77 source = (const UINT8 *)patchcol + 3;
78 count = ((patchcol->length * scale_y) + (FRACUNIT/2)) >> FRACBITS;
79 position = originy + topdelta;
80
81 yfrac = 0;
82 //yfracstep = (patchcol->length << FRACBITS) / count;
83 if (position < 0)
84 {
85 yfrac = -position<<FRACBITS;
86 count += (((position * scale_y) + (FRACUNIT/2)) >> FRACBITS);
87 position = 0;
88 }
89
90 position = ((position * scale_y) + (FRACUNIT/2)) >> FRACBITS;
91
92 if (position < 0)
93 position = 0;
94
95 if (position + count >= pblockheight)
96 count = pblockheight - position;
97
98 dest = block + (position*blockmodulo);
99 while (count > 0)
100 {
101 count--;
102
103 texel = source[yfrac>>FRACBITS];
104 alpha = 0xFF;
105 // Make pixel transparent if chroma keyed
106 if ((mipmap->flags & TF_CHROMAKEYED) && (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX))
107 alpha = 0x00;
108
109 //Hurdler: 25/04/2000: now support colormap in hardware mode
110 if (mipmap->colormap)
111 texel = mipmap->colormap->data[texel];
112
113 // hope compiler will get this switch out of the loops (dreams...)
114 // gcc do it ! but vcc not ! (why don't use cygwin gcc for win32 ?)
115 // Alam: SRB2 uses Mingw, HUGS
116 switch (bpp)
117 {
118 case 2 : // uhhhhhhhh..........
119 if ((originPatch != NULL) && (originPatch->style != AST_COPY))
120 texel = ASTBlendPaletteIndexes(*(dest+1), texel, originPatch->style, originPatch->alpha);
121 texelu16 = (UINT16)((alpha<<8) | texel);
122 memcpy(dest, &texelu16, sizeof(UINT16));
123 break;
124 case 3 : colortemp = V_GetColor(texel);
125 if ((originPatch != NULL) && (originPatch->style != AST_COPY))
126 {
127 RGBA_t rgbatexel;
128 rgbatexel.rgba = *(UINT32 *)dest;
129 colortemp.rgba = ASTBlendTexturePixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha);
130 }
131 memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8));
132 break;
133 case 4 : colortemp = V_GetColor(texel);
134 colortemp.s.alpha = alpha;
135 if ((originPatch != NULL) && (originPatch->style != AST_COPY))
136 {
137 RGBA_t rgbatexel;
138 rgbatexel.rgba = *(UINT32 *)dest;
139 colortemp.rgba = ASTBlendTexturePixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha);
140 }
141 memcpy(dest, &colortemp, sizeof(RGBA_t));
142 break;
143 // default is 1
144 default:
145 if ((originPatch != NULL) && (originPatch->style != AST_COPY))
146 *dest = ASTBlendPaletteIndexes(*dest, texel, originPatch->style, originPatch->alpha);
147 else
148 *dest = texel;
149 break;
150 }
151
152 dest += blockmodulo;
153 yfrac += yfracstep;
154 }
155 patchcol = (const column_t *)((const UINT8 *)patchcol + patchcol->length + 4);
156 }
157 }
158
HWR_DrawFlippedColumnInCache(const column_t * patchcol,UINT8 * block,GLMipmap_t * mipmap,INT32 pblockheight,INT32 blockmodulo,fixed_t yfracstep,fixed_t scale_y,texpatch_t * originPatch,INT32 patchheight,INT32 bpp)159 static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, GLMipmap_t *mipmap,
160 INT32 pblockheight, INT32 blockmodulo,
161 fixed_t yfracstep, fixed_t scale_y,
162 texpatch_t *originPatch, INT32 patchheight,
163 INT32 bpp)
164 {
165 fixed_t yfrac, position, count;
166 UINT8 *dest;
167 const UINT8 *source;
168 INT32 topdelta, prevdelta = -1;
169 INT32 originy = 0;
170
171 // for writing a pixel to dest
172 RGBA_t colortemp;
173 UINT8 alpha;
174 UINT8 texel;
175 UINT16 texelu16;
176
177 if (originPatch) // originPatch can be NULL here, unlike in the software version
178 originy = originPatch->originy;
179
180 while (patchcol->topdelta != 0xff)
181 {
182 topdelta = patchcol->topdelta;
183 if (topdelta <= prevdelta)
184 topdelta += prevdelta;
185 prevdelta = topdelta;
186 topdelta = patchheight-patchcol->length-topdelta;
187 source = (const UINT8 *)patchcol + 3;
188 count = ((patchcol->length * scale_y) + (FRACUNIT/2)) >> FRACBITS;
189 position = originy + topdelta;
190
191 yfrac = (patchcol->length-1) << FRACBITS;
192
193 if (position < 0)
194 {
195 yfrac += position<<FRACBITS;
196 count += (((position * scale_y) + (FRACUNIT/2)) >> FRACBITS);
197 position = 0;
198 }
199
200 position = ((position * scale_y) + (FRACUNIT/2)) >> FRACBITS;
201
202 if (position < 0)
203 position = 0;
204
205 if (position + count >= pblockheight)
206 count = pblockheight - position;
207
208 dest = block + (position*blockmodulo);
209 while (count > 0)
210 {
211 count--;
212
213 texel = source[yfrac>>FRACBITS];
214 alpha = 0xFF;
215 // Make pixel transparent if chroma keyed
216 if ((mipmap->flags & TF_CHROMAKEYED) && (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX))
217 alpha = 0x00;
218
219 //Hurdler: 25/04/2000: now support colormap in hardware mode
220 if (mipmap->colormap)
221 texel = mipmap->colormap->data[texel];
222
223 // hope compiler will get this switch out of the loops (dreams...)
224 // gcc do it ! but vcc not ! (why don't use cygwin gcc for win32 ?)
225 // Alam: SRB2 uses Mingw, HUGS
226 switch (bpp)
227 {
228 case 2 : // uhhhhhhhh..........
229 if ((originPatch != NULL) && (originPatch->style != AST_COPY))
230 texel = ASTBlendPaletteIndexes(*(dest+1), texel, originPatch->style, originPatch->alpha);
231 texelu16 = (UINT16)((alpha<<8) | texel);
232 memcpy(dest, &texelu16, sizeof(UINT16));
233 break;
234 case 3 : colortemp = V_GetColor(texel);
235 if ((originPatch != NULL) && (originPatch->style != AST_COPY))
236 {
237 RGBA_t rgbatexel;
238 rgbatexel.rgba = *(UINT32 *)dest;
239 colortemp.rgba = ASTBlendTexturePixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha);
240 }
241 memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8));
242 break;
243 case 4 : colortemp = V_GetColor(texel);
244 colortemp.s.alpha = alpha;
245 if ((originPatch != NULL) && (originPatch->style != AST_COPY))
246 {
247 RGBA_t rgbatexel;
248 rgbatexel.rgba = *(UINT32 *)dest;
249 colortemp.rgba = ASTBlendTexturePixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha);
250 }
251 memcpy(dest, &colortemp, sizeof(RGBA_t));
252 break;
253 // default is 1
254 default:
255 if ((originPatch != NULL) && (originPatch->style != AST_COPY))
256 *dest = ASTBlendPaletteIndexes(*dest, texel, originPatch->style, originPatch->alpha);
257 else
258 *dest = texel;
259 break;
260 }
261
262 dest += blockmodulo;
263 yfrac -= yfracstep;
264 }
265 patchcol = (const column_t *)((const UINT8 *)patchcol + patchcol->length + 4);
266 }
267 }
268
269
270 // Simplified patch caching function
271 // for use by sprites and other patches that are not part of a wall texture
272 // no alpha or flipping should be present since we do not want non-texture graphics to have them
273 // no offsets are used either
274 // -- Monster Iestyn (13/02/19)
HWR_DrawPatchInCache(GLMipmap_t * mipmap,INT32 pblockwidth,INT32 pblockheight,INT32 pwidth,INT32 pheight,const patch_t * realpatch)275 static void HWR_DrawPatchInCache(GLMipmap_t *mipmap,
276 INT32 pblockwidth, INT32 pblockheight,
277 INT32 pwidth, INT32 pheight,
278 const patch_t *realpatch)
279 {
280 INT32 ncols;
281 fixed_t xfrac, xfracstep;
282 fixed_t yfracstep, scale_y;
283 const column_t *patchcol;
284 UINT8 *block = mipmap->data;
285 INT32 bpp;
286 INT32 blockmodulo;
287
288 if (pwidth <= 0 || pheight <= 0)
289 return;
290
291 ncols = pwidth;
292
293 // source advance
294 xfrac = 0;
295 xfracstep = FRACUNIT;
296 yfracstep = FRACUNIT;
297 scale_y = FRACUNIT;
298
299 bpp = format2bpp(mipmap->format);
300
301 if (bpp < 1 || bpp > 4)
302 I_Error("HWR_DrawPatchInCache: no drawer defined for this bpp (%d)\n",bpp);
303
304 // NOTE: should this actually be pblockwidth*bpp?
305 blockmodulo = pblockwidth*bpp;
306
307 // Draw each column to the block cache
308 for (; ncols--; block += bpp, xfrac += xfracstep)
309 {
310 patchcol = (const column_t *)((const UINT8 *)realpatch->columns + (realpatch->columnofs[xfrac>>FRACBITS]));
311
312 HWR_DrawColumnInCache(patchcol, block, mipmap,
313 pblockheight, blockmodulo,
314 yfracstep, scale_y,
315 NULL, pheight, // not that pheight is going to get used anyway...
316 bpp);
317 }
318 }
319
320 // This function we use for caching patches that belong to textures
HWR_DrawTexturePatchInCache(GLMipmap_t * mipmap,INT32 pblockwidth,INT32 pblockheight,texture_t * texture,texpatch_t * patch,const softwarepatch_t * realpatch)321 static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap,
322 INT32 pblockwidth, INT32 pblockheight,
323 texture_t *texture, texpatch_t *patch,
324 const softwarepatch_t *realpatch)
325 {
326 INT32 x, x1, x2;
327 INT32 col, ncols;
328 fixed_t xfrac, xfracstep;
329 fixed_t yfracstep, scale_y;
330 const column_t *patchcol;
331 UINT8 *block = mipmap->data;
332 INT32 bpp;
333 INT32 blockmodulo;
334 INT32 width, height;
335 // Column drawing function pointer.
336 static void (*ColumnDrawerPointer)(const column_t *patchcol, UINT8 *block, GLMipmap_t *mipmap,
337 INT32 pblockheight, INT32 blockmodulo,
338 fixed_t yfracstep, fixed_t scale_y,
339 texpatch_t *originPatch, INT32 patchheight,
340 INT32 bpp);
341
342 if (texture->width <= 0 || texture->height <= 0)
343 return;
344
345 ColumnDrawerPointer = (patch->flip & 2) ? HWR_DrawFlippedColumnInCache : HWR_DrawColumnInCache;
346
347 x1 = patch->originx;
348 width = SHORT(realpatch->width);
349 height = SHORT(realpatch->height);
350 x2 = x1 + width;
351
352 if (x1 > texture->width || x2 < 0)
353 return; // patch not located within texture's x bounds, ignore
354
355 if (patch->originy > texture->height || (patch->originy + height) < 0)
356 return; // patch not located within texture's y bounds, ignore
357
358 // patch is actually inside the texture!
359 // now check if texture is partly off-screen and adjust accordingly
360
361 // left edge
362 if (x1 < 0)
363 x = 0;
364 else
365 x = x1;
366
367 // right edge
368 if (x2 > texture->width)
369 x2 = texture->width;
370
371
372 col = x * pblockwidth / texture->width;
373 ncols = ((x2 - x) * pblockwidth) / texture->width;
374
375 /*
376 CONS_Debug(DBG_RENDER, "patch %dx%d texture %dx%d block %dx%d\n",
377 width, height,
378 texture->width, texture->height,
379 pblockwidth, pblockheight);
380 CONS_Debug(DBG_RENDER, " col %d ncols %d x %d\n", col, ncols, x);
381 */
382
383 // source advance
384 xfrac = 0;
385 if (x1 < 0)
386 xfrac = -x1<<FRACBITS;
387
388 xfracstep = (texture->width << FRACBITS) / pblockwidth;
389 yfracstep = (texture->height<< FRACBITS) / pblockheight;
390 scale_y = (pblockheight << FRACBITS) / texture->height;
391
392 bpp = format2bpp(mipmap->format);
393
394 if (bpp < 1 || bpp > 4)
395 I_Error("HWR_DrawTexturePatchInCache: no drawer defined for this bpp (%d)\n",bpp);
396
397 // NOTE: should this actually be pblockwidth*bpp?
398 blockmodulo = pblockwidth*bpp;
399
400 // Draw each column to the block cache
401 for (block += col*bpp; ncols--; block += bpp, xfrac += xfracstep)
402 {
403 if (patch->flip & 1)
404 patchcol = (const column_t *)((const UINT8 *)realpatch + LONG(realpatch->columnofs[(width-1)-(xfrac>>FRACBITS)]));
405 else
406 patchcol = (const column_t *)((const UINT8 *)realpatch + LONG(realpatch->columnofs[xfrac>>FRACBITS]));
407
408 ColumnDrawerPointer(patchcol, block, mipmap,
409 pblockheight, blockmodulo,
410 yfracstep, scale_y,
411 patch, height,
412 bpp);
413 }
414 }
415
MakeBlock(GLMipmap_t * grMipmap)416 static UINT8 *MakeBlock(GLMipmap_t *grMipmap)
417 {
418 UINT8 *block;
419 INT32 bpp, i;
420 UINT16 bu16 = ((0x00 <<8) | HWR_PATCHES_CHROMAKEY_COLORINDEX);
421 INT32 blocksize = (grMipmap->width * grMipmap->height);
422
423 bpp = format2bpp(grMipmap->format);
424 block = Z_Malloc(blocksize*bpp, PU_HWRCACHE, &(grMipmap->data));
425
426 switch (bpp)
427 {
428 case 1: memset(block, HWR_PATCHES_CHROMAKEY_COLORINDEX, blocksize); break;
429 case 2:
430 // fill background with chromakey, alpha = 0
431 for (i = 0; i < blocksize; i++)
432 //[segabor]
433 memcpy(block+i*sizeof(UINT16), &bu16, sizeof(UINT16));
434 break;
435 case 4: memset(block, 0x00, blocksize*sizeof(UINT32)); break;
436 }
437
438 return block;
439 }
440
441 //
442 // Create a composite texture from patches, adapt the texture size to a power of 2
443 // height and width for the hardware texture cache.
444 //
HWR_GenerateTexture(INT32 texnum,GLMapTexture_t * grtex)445 static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex)
446 {
447 UINT8 *block;
448 texture_t *texture;
449 texpatch_t *patch;
450 softwarepatch_t *realpatch;
451 UINT8 *pdata;
452 INT32 blockwidth, blockheight, blocksize;
453
454 INT32 i;
455 boolean skyspecial = false; //poor hack for Legacy large skies..
456
457 texture = textures[texnum];
458
459 // hack the Legacy skies..
460 if (texture->name[0] == 'S' &&
461 texture->name[1] == 'K' &&
462 texture->name[2] == 'Y' &&
463 (texture->name[4] == 0 ||
464 texture->name[5] == 0)
465 )
466 {
467 skyspecial = true;
468 grtex->mipmap.flags = TF_WRAPXY; // don't use the chromakey for sky
469 }
470 else
471 grtex->mipmap.flags = TF_CHROMAKEYED | TF_WRAPXY;
472
473 grtex->mipmap.width = (UINT16)texture->width;
474 grtex->mipmap.height = (UINT16)texture->height;
475 grtex->mipmap.format = textureformat;
476
477 blockwidth = texture->width;
478 blockheight = texture->height;
479 blocksize = (blockwidth * blockheight);
480 block = MakeBlock(&grtex->mipmap);
481
482 if (skyspecial) //Hurdler: not efficient, but better than holes in the sky (and it's done only at level loading)
483 {
484 INT32 j;
485 RGBA_t col;
486
487 col = V_GetColor(HWR_PATCHES_CHROMAKEY_COLORINDEX);
488 for (j = 0; j < blockheight; j++)
489 {
490 for (i = 0; i < blockwidth; i++)
491 {
492 block[4*(j*blockwidth+i)+0] = col.s.red;
493 block[4*(j*blockwidth+i)+1] = col.s.green;
494 block[4*(j*blockwidth+i)+2] = col.s.blue;
495 block[4*(j*blockwidth+i)+3] = 0xff;
496 }
497 }
498 }
499
500 // Composite the columns together.
501 for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++)
502 {
503 boolean dealloc = true;
504 size_t lumplength = W_LumpLengthPwad(patch->wad, patch->lump);
505 pdata = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE);
506 realpatch = (softwarepatch_t *)pdata;
507
508 #ifndef NO_PNG_LUMPS
509 if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength))
510 realpatch = (softwarepatch_t *)Picture_PNGConvert(pdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0);
511 else
512 #endif
513 #ifdef WALLFLATS
514 if (texture->type == TEXTURETYPE_FLAT)
515 realpatch = (softwarepatch_t *)Picture_Convert(PICFMT_FLAT, pdata, PICFMT_DOOMPATCH, 0, NULL, texture->width, texture->height, 0, 0, 0);
516 else
517 #endif
518 {
519 (void)lumplength;
520 dealloc = false;
521 }
522
523 HWR_DrawTexturePatchInCache(&grtex->mipmap, blockwidth, blockheight, texture, patch, realpatch);
524
525 if (dealloc)
526 Z_Unlock(realpatch);
527 }
528 //Hurdler: not efficient at all but I don't remember exactly how HWR_DrawPatchInCache works :(
529 if (format2bpp(grtex->mipmap.format)==4)
530 {
531 for (i = 3; i < blocksize*4; i += 4) // blocksize*4 because blocksize doesn't include the bpp
532 {
533 if (block[i] == 0)
534 {
535 grtex->mipmap.flags |= TF_TRANSPARENT;
536 break;
537 }
538 }
539 }
540
541 grtex->scaleX = 1.0f/(texture->width*FRACUNIT);
542 grtex->scaleY = 1.0f/(texture->height*FRACUNIT);
543 }
544
545 // patch may be NULL if grMipmap has been initialised already and makebitmap is false
HWR_MakePatch(const patch_t * patch,GLPatch_t * grPatch,GLMipmap_t * grMipmap,boolean makebitmap)546 void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap)
547 {
548 if (grMipmap->width == 0)
549 {
550 grMipmap->width = grMipmap->height = 1;
551 while (grMipmap->width < patch->width) grMipmap->width <<= 1;
552 while (grMipmap->height < patch->height) grMipmap->height <<= 1;
553
554 // no wrap around, no chroma key
555 grMipmap->flags = 0;
556
557 // setup the texture info
558 grMipmap->format = patchformat;
559
560 grPatch->max_s = (float)patch->width / (float)grMipmap->width;
561 grPatch->max_t = (float)patch->height / (float)grMipmap->height;
562 }
563
564 Z_Free(grMipmap->data);
565 grMipmap->data = NULL;
566
567 if (makebitmap)
568 {
569 MakeBlock(grMipmap);
570
571 HWR_DrawPatchInCache(grMipmap,
572 grMipmap->width, grMipmap->height,
573 patch->width, patch->height,
574 patch);
575 }
576 }
577
578
579 // =================================================
580 // CACHING HANDLING
581 // =================================================
582
583 static size_t gl_numtextures = 0; // Texture count
584 static GLMapTexture_t *gl_textures; // For all textures
585 static GLMapTexture_t *gl_flats; // For all (texture) flats, as normal flats don't need to be cached
586 boolean gl_maptexturesloaded = false;
587
HWR_FreeTextureData(patch_t * patch)588 void HWR_FreeTextureData(patch_t *patch)
589 {
590 GLPatch_t *grPatch;
591
592 if (!patch || !patch->hardware)
593 return;
594
595 grPatch = patch->hardware;
596
597 if (vid.glstate == VID_GL_LIBRARY_LOADED)
598 HWD.pfnDeleteTexture(grPatch->mipmap);
599 if (grPatch->mipmap->data)
600 Z_Free(grPatch->mipmap->data);
601 }
602
HWR_FreeTexture(patch_t * patch)603 void HWR_FreeTexture(patch_t *patch)
604 {
605 if (!patch)
606 return;
607
608 if (patch->hardware)
609 {
610 GLPatch_t *grPatch = patch->hardware;
611
612 HWR_FreeTextureColormaps(patch);
613
614 if (grPatch->mipmap)
615 {
616 HWR_FreeTextureData(patch);
617 Z_Free(grPatch->mipmap);
618 }
619
620 Z_Free(patch->hardware);
621 }
622
623 patch->hardware = NULL;
624 }
625
626 // Called by HWR_FreePatchCache.
HWR_FreeTextureColormaps(patch_t * patch)627 void HWR_FreeTextureColormaps(patch_t *patch)
628 {
629 GLPatch_t *pat;
630
631 // The patch must be valid, obviously
632 if (!patch)
633 return;
634
635 pat = patch->hardware;
636 if (!pat)
637 return;
638
639 // The mipmap must be valid, obviously
640 while (pat->mipmap)
641 {
642 // Confusing at first, but pat->mipmap->nextcolormap
643 // at the beginning of the loop is the first colormap
644 // from the linked list of colormaps.
645 GLMipmap_t *next = NULL;
646
647 // No mipmap in this patch, break out of the loop.
648 if (!pat->mipmap)
649 break;
650
651 // No colormap mipmaps either.
652 if (!pat->mipmap->nextcolormap)
653 break;
654
655 // Set the first colormap to the one that comes after it.
656 next = pat->mipmap->nextcolormap;
657 pat->mipmap->nextcolormap = next->nextcolormap;
658
659 // Free image data from memory.
660 if (next->data)
661 Z_Free(next->data);
662 if (next->colormap)
663 Z_Free(next->colormap);
664 next->data = NULL;
665 next->colormap = NULL;
666 HWD.pfnDeleteTexture(next);
667
668 // Free the old colormap mipmap from memory.
669 free(next);
670 }
671 }
672
FreeTextureCallback(void * mem)673 static boolean FreeTextureCallback(void *mem)
674 {
675 patch_t *patch = (patch_t *)mem;
676 HWR_FreeTexture(patch);
677 return false;
678 }
679
FreeColormapsCallback(void * mem)680 static boolean FreeColormapsCallback(void *mem)
681 {
682 patch_t *patch = (patch_t *)mem;
683 HWR_FreeTextureColormaps(patch);
684 return false;
685 }
686
HWR_FreePatchCache(boolean freeall)687 static void HWR_FreePatchCache(boolean freeall)
688 {
689 boolean (*callback)(void *mem) = FreeTextureCallback;
690
691 if (!freeall)
692 callback = FreeColormapsCallback;
693
694 Z_IterateTags(PU_PATCH, PU_PATCH_ROTATED, callback);
695 Z_IterateTags(PU_SPRITE, PU_HUDGFX, callback);
696 }
697
698 // free all textures after each level
HWR_ClearAllTextures(void)699 void HWR_ClearAllTextures(void)
700 {
701 HWD.pfnClearMipMapCache(); // free references to the textures
702 HWR_FreePatchCache(true);
703 }
704
HWR_FreeColormapCache(void)705 void HWR_FreeColormapCache(void)
706 {
707 HWR_FreePatchCache(false);
708 }
709
HWR_InitMapTextures(void)710 void HWR_InitMapTextures(void)
711 {
712 gl_textures = NULL;
713 gl_flats = NULL;
714 gl_maptexturesloaded = false;
715 }
716
FreeMapTexture(GLMapTexture_t * tex)717 static void FreeMapTexture(GLMapTexture_t *tex)
718 {
719 HWD.pfnDeleteTexture(&tex->mipmap);
720 if (tex->mipmap.data)
721 Z_Free(tex->mipmap.data);
722 tex->mipmap.data = NULL;
723 }
724
HWR_FreeMapTextures(void)725 void HWR_FreeMapTextures(void)
726 {
727 size_t i;
728
729 for (i = 0; i < gl_numtextures; i++)
730 {
731 FreeMapTexture(&gl_textures[i]);
732 FreeMapTexture(&gl_flats[i]);
733 }
734
735 // now the heap don't have any 'user' pointing to our
736 // texturecache info, we can free it
737 if (gl_textures)
738 free(gl_textures);
739 if (gl_flats)
740 free(gl_flats);
741 gl_textures = NULL;
742 gl_flats = NULL;
743 gl_numtextures = 0;
744 gl_maptexturesloaded = false;
745 }
746
HWR_LoadMapTextures(size_t pnumtextures)747 void HWR_LoadMapTextures(size_t pnumtextures)
748 {
749 // we must free it since numtextures may have changed
750 HWR_FreeMapTextures();
751
752 gl_numtextures = pnumtextures;
753 gl_textures = calloc(gl_numtextures, sizeof(*gl_textures));
754 gl_flats = calloc(gl_numtextures, sizeof(*gl_flats));
755
756 if ((gl_textures == NULL) || (gl_flats == NULL))
757 I_Error("HWR_LoadMapTextures: ran out of memory for OpenGL textures");
758
759 gl_maptexturesloaded = true;
760 }
761
HWR_SetPalette(RGBA_t * palette)762 void HWR_SetPalette(RGBA_t *palette)
763 {
764 HWD.pfnSetPalette(palette);
765
766 // hardware driver will flush there own cache if cache is non paletized
767 // now flush data texture cache so 32 bit texture are recomputed
768 if (patchformat == GL_TEXFMT_RGBA || textureformat == GL_TEXFMT_RGBA)
769 {
770 Z_FreeTag(PU_HWRCACHE);
771 Z_FreeTag(PU_HWRCACHE_UNLOCKED);
772 }
773 }
774
775 // --------------------------------------------------------------------------
776 // Make sure texture is downloaded and set it as the source
777 // --------------------------------------------------------------------------
HWR_GetTexture(INT32 tex)778 GLMapTexture_t *HWR_GetTexture(INT32 tex)
779 {
780 GLMapTexture_t *grtex;
781 #ifdef PARANOIA
782 if ((unsigned)tex >= gl_numtextures)
783 I_Error("HWR_GetTexture: tex >= numtextures\n");
784 #endif
785
786 // Every texture in memory, stored in the
787 // hardware renderer's bit depth format. Wow!
788 grtex = &gl_textures[tex];
789
790 // Generate texture if missing from the cache
791 if (!grtex->mipmap.data && !grtex->mipmap.downloaded)
792 HWR_GenerateTexture(tex, grtex);
793
794 // If hardware does not have the texture, then call pfnSetTexture to upload it
795 if (!grtex->mipmap.downloaded)
796 HWD.pfnSetTexture(&grtex->mipmap);
797 HWR_SetCurrentTexture(&grtex->mipmap);
798
799 // The system-memory data can be purged now.
800 Z_ChangeTag(grtex->mipmap.data, PU_HWRCACHE_UNLOCKED);
801
802 return grtex;
803 }
804
HWR_CacheFlat(GLMipmap_t * grMipmap,lumpnum_t flatlumpnum)805 static void HWR_CacheFlat(GLMipmap_t *grMipmap, lumpnum_t flatlumpnum)
806 {
807 size_t size, pflatsize;
808
809 // setup the texture info
810 grMipmap->format = GL_TEXFMT_P_8;
811 grMipmap->flags = TF_WRAPXY|TF_CHROMAKEYED;
812
813 size = W_LumpLength(flatlumpnum);
814
815 switch (size)
816 {
817 case 4194304: // 2048x2048 lump
818 pflatsize = 2048;
819 break;
820 case 1048576: // 1024x1024 lump
821 pflatsize = 1024;
822 break;
823 case 262144:// 512x512 lump
824 pflatsize = 512;
825 break;
826 case 65536: // 256x256 lump
827 pflatsize = 256;
828 break;
829 case 16384: // 128x128 lump
830 pflatsize = 128;
831 break;
832 case 1024: // 32x32 lump
833 pflatsize = 32;
834 break;
835 default: // 64x64 lump
836 pflatsize = 64;
837 break;
838 }
839
840 grMipmap->width = (UINT16)pflatsize;
841 grMipmap->height = (UINT16)pflatsize;
842
843 // the flat raw data needn't be converted with palettized textures
844 W_ReadLump(flatlumpnum, Z_Malloc(W_LumpLength(flatlumpnum),
845 PU_HWRCACHE, &grMipmap->data));
846 }
847
HWR_CacheTextureAsFlat(GLMipmap_t * grMipmap,INT32 texturenum)848 static void HWR_CacheTextureAsFlat(GLMipmap_t *grMipmap, INT32 texturenum)
849 {
850 UINT8 *flat;
851 UINT8 *converted;
852 size_t size;
853
854 // setup the texture info
855 grMipmap->format = GL_TEXFMT_P_8;
856 grMipmap->flags = TF_WRAPXY|TF_CHROMAKEYED;
857
858 grMipmap->width = (UINT16)textures[texturenum]->width;
859 grMipmap->height = (UINT16)textures[texturenum]->height;
860 size = (grMipmap->width * grMipmap->height);
861
862 flat = Z_Malloc(size, PU_HWRCACHE, &grMipmap->data);
863 converted = (UINT8 *)Picture_TextureToFlat(texturenum);
864 M_Memcpy(flat, converted, size);
865 Z_Free(converted);
866 }
867
868 // Download a Doom 'flat' to the hardware cache and make it ready for use
HWR_GetRawFlat(lumpnum_t flatlumpnum)869 void HWR_GetRawFlat(lumpnum_t flatlumpnum)
870 {
871 GLMipmap_t *grmip;
872 patch_t *patch;
873
874 if (flatlumpnum == LUMPERROR)
875 return;
876
877 patch = HWR_GetCachedGLPatch(flatlumpnum);
878 grmip = ((GLPatch_t *)Patch_AllocateHardwarePatch(patch))->mipmap;
879 if (!grmip->downloaded && !grmip->data)
880 HWR_CacheFlat(grmip, flatlumpnum);
881
882 // If hardware does not have the texture, then call pfnSetTexture to upload it
883 if (!grmip->downloaded)
884 HWD.pfnSetTexture(grmip);
885 HWR_SetCurrentTexture(grmip);
886
887 // The system-memory data can be purged now.
888 Z_ChangeTag(grmip->data, PU_HWRCACHE_UNLOCKED);
889 }
890
HWR_GetLevelFlat(levelflat_t * levelflat)891 void HWR_GetLevelFlat(levelflat_t *levelflat)
892 {
893 // Who knows?
894 if (levelflat == NULL)
895 return;
896
897 if (levelflat->type == LEVELFLAT_FLAT)
898 HWR_GetRawFlat(levelflat->u.flat.lumpnum);
899 else if (levelflat->type == LEVELFLAT_TEXTURE)
900 {
901 GLMapTexture_t *grtex;
902 INT32 texturenum = levelflat->u.texture.num;
903 #ifdef PARANOIA
904 if ((unsigned)texturenum >= gl_numtextures)
905 I_Error("HWR_GetLevelFlat: texturenum >= numtextures");
906 #endif
907
908 // Who knows?
909 if (texturenum == 0 || texturenum == -1)
910 return;
911
912 // Every texture in memory, stored as a 8-bit flat. Wow!
913 grtex = &gl_flats[texturenum];
914
915 // Generate flat if missing from the cache
916 if (!grtex->mipmap.data && !grtex->mipmap.downloaded)
917 HWR_CacheTextureAsFlat(&grtex->mipmap, texturenum);
918
919 // If hardware does not have the texture, then call pfnSetTexture to upload it
920 if (!grtex->mipmap.downloaded)
921 HWD.pfnSetTexture(&grtex->mipmap);
922 HWR_SetCurrentTexture(&grtex->mipmap);
923
924 // The system-memory data can be purged now.
925 Z_ChangeTag(grtex->mipmap.data, PU_HWRCACHE_UNLOCKED);
926 }
927 else if (levelflat->type == LEVELFLAT_PATCH)
928 {
929 patch_t *patch = W_CachePatchNum(levelflat->u.flat.lumpnum, PU_CACHE);
930 levelflat->width = (UINT16)(patch->width);
931 levelflat->height = (UINT16)(patch->height);
932 HWR_GetPatch(patch);
933 }
934 #ifndef NO_PNG_LUMPS
935 else if (levelflat->type == LEVELFLAT_PNG)
936 {
937 GLMipmap_t *mipmap = levelflat->mipmap;
938
939 // Cache the picture.
940 if (!levelflat->mippic)
941 {
942 INT32 pngwidth = 0, pngheight = 0;
943 void *pic = Picture_PNGConvert(W_CacheLumpNum(levelflat->u.flat.lumpnum, PU_CACHE), PICFMT_FLAT, &pngwidth, &pngheight, NULL, NULL, W_LumpLength(levelflat->u.flat.lumpnum), NULL, 0);
944
945 Z_ChangeTag(pic, PU_LEVEL);
946 Z_SetUser(pic, &levelflat->mippic);
947
948 levelflat->width = (UINT16)pngwidth;
949 levelflat->height = (UINT16)pngheight;
950 }
951
952 // Make the mipmap.
953 if (mipmap == NULL)
954 {
955 mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_STATIC, NULL);
956 mipmap->format = GL_TEXFMT_P_8;
957 mipmap->flags = TF_WRAPXY|TF_CHROMAKEYED;
958 levelflat->mipmap = mipmap;
959 }
960
961 if (!mipmap->data && !mipmap->downloaded)
962 {
963 UINT8 *flat;
964 size_t size;
965
966 if (levelflat->mippic == NULL)
967 I_Error("HWR_GetLevelFlat: levelflat->mippic == NULL");
968
969 mipmap->width = levelflat->width;
970 mipmap->height = levelflat->height;
971
972 size = (mipmap->width * mipmap->height);
973 flat = Z_Malloc(size, PU_LEVEL, &mipmap->data);
974 M_Memcpy(flat, levelflat->mippic, size);
975 }
976
977 // Tell the hardware driver to bind the current texture to the flat's mipmap
978 HWR_SetCurrentTexture(mipmap);
979 }
980 #endif
981 else // set no texture
982 HWR_SetCurrentTexture(NULL);
983 }
984
985 // --------------------+
986 // HWR_LoadPatchMipmap : Generates a patch into a mipmap, usually the mipmap inside the patch itself
987 // --------------------+
HWR_LoadPatchMipmap(patch_t * patch,GLMipmap_t * grMipmap)988 static void HWR_LoadPatchMipmap(patch_t *patch, GLMipmap_t *grMipmap)
989 {
990 GLPatch_t *grPatch = patch->hardware;
991 if (!grMipmap->downloaded && !grMipmap->data)
992 HWR_MakePatch(patch, grPatch, grMipmap, true);
993
994 // If hardware does not have the texture, then call pfnSetTexture to upload it
995 if (!grMipmap->downloaded)
996 HWD.pfnSetTexture(grMipmap);
997 HWR_SetCurrentTexture(grMipmap);
998
999 // The system-memory data can be purged now.
1000 Z_ChangeTag(grMipmap->data, PU_HWRCACHE_UNLOCKED);
1001 }
1002
1003 // ----------------------+
1004 // HWR_UpdatePatchMipmap : Updates a mipmap.
1005 // ----------------------+
HWR_UpdatePatchMipmap(patch_t * patch,GLMipmap_t * grMipmap)1006 static void HWR_UpdatePatchMipmap(patch_t *patch, GLMipmap_t *grMipmap)
1007 {
1008 GLPatch_t *grPatch = patch->hardware;
1009 HWR_MakePatch(patch, grPatch, grMipmap, true);
1010
1011 // If hardware does not have the texture, then call pfnSetTexture to upload it
1012 // If it does have the texture, then call pfnUpdateTexture to update it
1013 if (!grMipmap->downloaded)
1014 HWD.pfnSetTexture(grMipmap);
1015 else
1016 HWD.pfnUpdateTexture(grMipmap);
1017 HWR_SetCurrentTexture(grMipmap);
1018
1019 // The system-memory data can be purged now.
1020 Z_ChangeTag(grMipmap->data, PU_HWRCACHE_UNLOCKED);
1021 }
1022
1023 // -----------------+
1024 // HWR_GetPatch : Downloads a patch to the hardware cache and make it ready for use
1025 // -----------------+
HWR_GetPatch(patch_t * patch)1026 void HWR_GetPatch(patch_t *patch)
1027 {
1028 if (!patch->hardware)
1029 Patch_CreateGL(patch);
1030 HWR_LoadPatchMipmap(patch, ((GLPatch_t *)patch->hardware)->mipmap);
1031 }
1032
1033 // -------------------+
1034 // HWR_GetMappedPatch : Same as HWR_GetPatch for sprite color
1035 // -------------------+
HWR_GetMappedPatch(patch_t * patch,const UINT8 * colormap)1036 void HWR_GetMappedPatch(patch_t *patch, const UINT8 *colormap)
1037 {
1038 GLPatch_t *grPatch;
1039 GLMipmap_t *grMipmap, *newMipmap;
1040
1041 if (!patch->hardware)
1042 Patch_CreateGL(patch);
1043 grPatch = patch->hardware;
1044
1045 if (colormap == colormaps || colormap == NULL)
1046 {
1047 // Load the default (green) color in hardware cache
1048 HWR_GetPatch(patch);
1049 return;
1050 }
1051
1052 // search for the mipmap
1053 // skip the first (no colormap translated)
1054 for (grMipmap = grPatch->mipmap; grMipmap->nextcolormap; )
1055 {
1056 grMipmap = grMipmap->nextcolormap;
1057 if (grMipmap->colormap && grMipmap->colormap->source == colormap)
1058 {
1059 if (memcmp(grMipmap->colormap->data, colormap, 256 * sizeof(UINT8)))
1060 {
1061 M_Memcpy(grMipmap->colormap->data, colormap, 256 * sizeof(UINT8));
1062 HWR_UpdatePatchMipmap(patch, grMipmap);
1063 }
1064 else
1065 HWR_LoadPatchMipmap(patch, grMipmap);
1066 return;
1067 }
1068 }
1069 // not found, create it!
1070 // If we are here, the sprite with the current colormap is not already in hardware memory
1071
1072 //BP: WARNING: don't free it manually without clearing the cache of harware renderer
1073 // (it have a liste of mipmap)
1074 // this malloc is cleared in HWR_FreeColormapCache
1075 // (...) unfortunately z_malloc fragment alot the memory :(so malloc is better
1076 newMipmap = calloc(1, sizeof (*newMipmap));
1077 if (newMipmap == NULL)
1078 I_Error("%s: Out of memory", "HWR_GetMappedPatch");
1079 grMipmap->nextcolormap = newMipmap;
1080
1081 newMipmap->colormap = Z_Calloc(sizeof(*newMipmap->colormap), PU_HWRPATCHCOLMIPMAP, NULL);
1082 newMipmap->colormap->source = colormap;
1083 M_Memcpy(newMipmap->colormap->data, colormap, 256 * sizeof(UINT8));
1084
1085 HWR_LoadPatchMipmap(patch, newMipmap);
1086 }
1087
HWR_UnlockCachedPatch(GLPatch_t * gpatch)1088 void HWR_UnlockCachedPatch(GLPatch_t *gpatch)
1089 {
1090 if (!gpatch)
1091 return;
1092
1093 Z_ChangeTag(gpatch->mipmap->data, PU_HWRCACHE_UNLOCKED);
1094 }
1095
1096 static const INT32 picmode2GR[] =
1097 {
1098 GL_TEXFMT_P_8, // PALETTE
1099 0, // INTENSITY (unsupported yet)
1100 GL_TEXFMT_ALPHA_INTENSITY_88, // INTENSITY_ALPHA (corona use this)
1101 0, // RGB24 (unsupported yet)
1102 GL_TEXFMT_RGBA, // RGBA32 (opengl only)
1103 };
1104
HWR_DrawPicInCache(UINT8 * block,INT32 pblockwidth,INT32 pblockheight,INT32 blockmodulo,pic_t * pic,INT32 bpp)1105 static void HWR_DrawPicInCache(UINT8 *block, INT32 pblockwidth, INT32 pblockheight,
1106 INT32 blockmodulo, pic_t *pic, INT32 bpp)
1107 {
1108 INT32 i,j;
1109 fixed_t posx, posy, stepx, stepy;
1110 UINT8 *dest, *src, texel;
1111 UINT16 texelu16;
1112 INT32 picbpp;
1113 RGBA_t col;
1114
1115 stepy = ((INT32)SHORT(pic->height)<<FRACBITS)/pblockheight;
1116 stepx = ((INT32)SHORT(pic->width)<<FRACBITS)/pblockwidth;
1117 picbpp = format2bpp(picmode2GR[pic->mode]);
1118 posy = 0;
1119 for (j = 0; j < pblockheight; j++)
1120 {
1121 posx = 0;
1122 dest = &block[j*blockmodulo];
1123 src = &pic->data[(posy>>FRACBITS)*SHORT(pic->width)*picbpp];
1124 for (i = 0; i < pblockwidth;i++)
1125 {
1126 switch (pic->mode)
1127 { // source bpp
1128 case PALETTE :
1129 texel = src[(posx+FRACUNIT/2)>>FRACBITS];
1130 switch (bpp)
1131 { // destination bpp
1132 case 1 :
1133 *dest++ = texel; break;
1134 case 2 :
1135 texelu16 = (UINT16)(texel | 0xff00);
1136 memcpy(dest, &texelu16, sizeof(UINT16));
1137 dest += sizeof(UINT16);
1138 break;
1139 case 3 :
1140 col = V_GetColor(texel);
1141 memcpy(dest, &col, sizeof(RGBA_t)-sizeof(UINT8));
1142 dest += sizeof(RGBA_t)-sizeof(UINT8);
1143 break;
1144 case 4 :
1145 memcpy(dest, &V_GetColor(texel), sizeof(RGBA_t));
1146 dest += sizeof(RGBA_t);
1147 break;
1148 }
1149 break;
1150 case INTENSITY :
1151 *dest++ = src[(posx+FRACUNIT/2)>>FRACBITS];
1152 break;
1153 case INTENSITY_ALPHA : // assume dest bpp = 2
1154 memcpy(dest, src + ((posx+FRACUNIT/2)>>FRACBITS)*sizeof(UINT16), sizeof(UINT16));
1155 dest += sizeof(UINT16);
1156 break;
1157 case RGB24 :
1158 break; // not supported yet
1159 case RGBA32 : // assume dest bpp = 4
1160 dest += sizeof(UINT32);
1161 memcpy(dest, src + ((posx+FRACUNIT/2)>>FRACBITS)*sizeof(UINT32), sizeof(UINT32));
1162 break;
1163 }
1164 posx += stepx;
1165 }
1166 posy += stepy;
1167 }
1168 }
1169
1170 // -----------------+
1171 // HWR_GetPic : Download a Doom pic (raw row encoded with no 'holes')
1172 // Returns :
1173 // -----------------+
HWR_GetPic(lumpnum_t lumpnum)1174 patch_t *HWR_GetPic(lumpnum_t lumpnum)
1175 {
1176 patch_t *patch = HWR_GetCachedGLPatch(lumpnum);
1177 GLPatch_t *grPatch = (GLPatch_t *)(patch->hardware);
1178
1179 if (!grPatch->mipmap->downloaded && !grPatch->mipmap->data)
1180 {
1181 pic_t *pic;
1182 UINT8 *block;
1183 size_t len;
1184
1185 pic = W_CacheLumpNum(lumpnum, PU_CACHE);
1186 patch->width = SHORT(pic->width);
1187 patch->height = SHORT(pic->height);
1188 len = W_LumpLength(lumpnum) - sizeof (pic_t);
1189
1190 grPatch->mipmap->width = (UINT16)patch->width;
1191 grPatch->mipmap->height = (UINT16)patch->height;
1192
1193 if (pic->mode == PALETTE)
1194 grPatch->mipmap->format = textureformat; // can be set by driver
1195 else
1196 grPatch->mipmap->format = picmode2GR[pic->mode];
1197
1198 Z_Free(grPatch->mipmap->data);
1199
1200 // allocate block
1201 block = MakeBlock(grPatch->mipmap);
1202
1203 if (patch->width == SHORT(pic->width) &&
1204 patch->height == SHORT(pic->height) &&
1205 format2bpp(grPatch->mipmap->format) == format2bpp(picmode2GR[pic->mode]))
1206 {
1207 // no conversion needed
1208 M_Memcpy(grPatch->mipmap->data, pic->data,len);
1209 }
1210 else
1211 HWR_DrawPicInCache(block, SHORT(pic->width), SHORT(pic->height),
1212 SHORT(pic->width)*format2bpp(grPatch->mipmap->format),
1213 pic,
1214 format2bpp(grPatch->mipmap->format));
1215
1216 Z_Unlock(pic);
1217 Z_ChangeTag(block, PU_HWRCACHE_UNLOCKED);
1218
1219 grPatch->mipmap->flags = 0;
1220 grPatch->max_s = grPatch->max_t = 1.0f;
1221 }
1222 HWD.pfnSetTexture(grPatch->mipmap);
1223 //CONS_Debug(DBG_RENDER, "picloaded at %x as texture %d\n",grPatch->mipmap->data, grPatch->mipmap->downloaded);
1224
1225 return patch;
1226 }
1227
HWR_GetCachedGLPatchPwad(UINT16 wadnum,UINT16 lumpnum)1228 patch_t *HWR_GetCachedGLPatchPwad(UINT16 wadnum, UINT16 lumpnum)
1229 {
1230 lumpcache_t *lumpcache = wadfiles[wadnum]->patchcache;
1231 if (!lumpcache[lumpnum])
1232 {
1233 void *ptr = Z_Calloc(sizeof(patch_t), PU_PATCH, &lumpcache[lumpnum]);
1234 Patch_Create(NULL, 0, ptr);
1235 Patch_AllocateHardwarePatch(ptr);
1236 }
1237 return (patch_t *)(lumpcache[lumpnum]);
1238 }
1239
HWR_GetCachedGLPatch(lumpnum_t lumpnum)1240 patch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum)
1241 {
1242 return HWR_GetCachedGLPatchPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum));
1243 }
1244
1245 // Need to do this because they aren't powers of 2
HWR_DrawFadeMaskInCache(GLMipmap_t * mipmap,INT32 pblockwidth,INT32 pblockheight,lumpnum_t fademasklumpnum,UINT16 fmwidth,UINT16 fmheight)1246 static void HWR_DrawFadeMaskInCache(GLMipmap_t *mipmap, INT32 pblockwidth, INT32 pblockheight,
1247 lumpnum_t fademasklumpnum, UINT16 fmwidth, UINT16 fmheight)
1248 {
1249 INT32 i,j;
1250 fixed_t posx, posy, stepx, stepy;
1251 UINT8 *block = mipmap->data; // places the data directly into here
1252 UINT8 *flat;
1253 UINT8 *dest, *src, texel;
1254 RGBA_t col;
1255
1256 // Place the flats data into flat
1257 W_ReadLump(fademasklumpnum, Z_Malloc(W_LumpLength(fademasklumpnum),
1258 PU_HWRCACHE, &flat));
1259
1260 stepy = ((INT32)fmheight<<FRACBITS)/pblockheight;
1261 stepx = ((INT32)fmwidth<<FRACBITS)/pblockwidth;
1262 posy = 0;
1263 for (j = 0; j < pblockheight; j++)
1264 {
1265 posx = 0;
1266 dest = &block[j*(mipmap->width)]; // 1bpp
1267 src = &flat[(posy>>FRACBITS)*SHORT(fmwidth)];
1268 for (i = 0; i < pblockwidth;i++)
1269 {
1270 // fademask bpp is always 1, and is used just for alpha
1271 texel = src[(posx)>>FRACBITS];
1272 col = V_GetColor(texel);
1273 *dest = col.s.red; // take the red level of the colour and use it for alpha, as fademasks do
1274
1275 dest++;
1276 posx += stepx;
1277 }
1278 posy += stepy;
1279 }
1280
1281 Z_Free(flat);
1282 }
1283
HWR_CacheFadeMask(GLMipmap_t * grMipmap,lumpnum_t fademasklumpnum)1284 static void HWR_CacheFadeMask(GLMipmap_t *grMipmap, lumpnum_t fademasklumpnum)
1285 {
1286 size_t size;
1287 UINT16 fmheight = 0, fmwidth = 0;
1288
1289 // setup the texture info
1290 grMipmap->format = GL_TEXFMT_ALPHA_8; // put the correct alpha levels straight in so I don't need to convert it later
1291 grMipmap->flags = 0;
1292
1293 size = W_LumpLength(fademasklumpnum);
1294
1295 switch (size)
1296 {
1297 // None of these are powers of 2, so I'll need to do what is done for textures and make them powers of 2 before they can be used
1298 case 256000: // 640x400
1299 fmwidth = 640;
1300 fmheight = 400;
1301 break;
1302 case 64000: // 320x200
1303 fmwidth = 320;
1304 fmheight = 200;
1305 break;
1306 case 16000: // 160x100
1307 fmwidth = 160;
1308 fmheight = 100;
1309 break;
1310 case 4000: // 80x50 (minimum)
1311 fmwidth = 80;
1312 fmheight = 50;
1313 break;
1314 default: // Bad lump
1315 CONS_Alert(CONS_WARNING, "Fade mask lump of incorrect size, ignored\n"); // I should avoid this by checking the lumpnum in HWR_RunWipe
1316 break;
1317 }
1318
1319 // Thankfully, this will still work for this scenario
1320 grMipmap->width = fmwidth;
1321 grMipmap->height = fmheight;
1322
1323 MakeBlock(grMipmap);
1324
1325 HWR_DrawFadeMaskInCache(grMipmap, fmwidth, fmheight, fademasklumpnum, fmwidth, fmheight);
1326
1327 // I DO need to convert this because it isn't power of 2 and we need the alpha
1328 }
1329
1330
HWR_GetFadeMask(lumpnum_t fademasklumpnum)1331 void HWR_GetFadeMask(lumpnum_t fademasklumpnum)
1332 {
1333 patch_t *patch = HWR_GetCachedGLPatch(fademasklumpnum);
1334 GLMipmap_t *grmip = ((GLPatch_t *)Patch_AllocateHardwarePatch(patch))->mipmap;
1335 if (!grmip->downloaded && !grmip->data)
1336 HWR_CacheFadeMask(grmip, fademasklumpnum);
1337
1338 HWD.pfnSetTexture(grmip);
1339
1340 // The system-memory data can be purged now.
1341 Z_ChangeTag(grmip->data, PU_HWRCACHE_UNLOCKED);
1342 }
1343
1344 #endif //HWRENDER
1345