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