SRB2/src/hardware/hw_cache.c

1236 lines
35 KiB
C
Raw Normal View History

2020-01-23 23:12:15 +00:00
// SONIC ROBO BLAST 2
2014-03-15 16:59:03 +00:00
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
2020-01-23 23:12:15 +00:00
// Copyright (C) 1999-2020 by Sonic Team Junior.
2014-03-15 16:59:03 +00:00
//
2020-01-23 23:12:15 +00:00
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
2014-03-15 16:59:03 +00:00
//-----------------------------------------------------------------------------
2020-01-23 23:12:15 +00:00
/// \file hw_cache.c
2014-03-15 16:59:03 +00:00
/// \brief load and convert graphics to the hardware format
#include "../doomdef.h"
#ifdef HWRENDER
#include "hw_glob.h"
#include "hw_drv.h"
2020-06-07 18:20:52 +00:00
#include "hw_batching.h"
2014-03-15 16:59:03 +00:00
#include "../doomstat.h" //gamemode
#include "../i_video.h" //rendermode
#include "../r_data.h"
#include "../w_wad.h"
#include "../z_zone.h"
#include "../v_video.h"
#include "../r_draw.h"
2019-10-28 18:28:42 +00:00
#include "../r_patch.h"
#include "../p_setup.h"
2014-03-15 16:59:03 +00:00
INT32 patchformat = GL_TEXFMT_AP_88; // use alpha for holes
INT32 textureformat = GL_TEXFMT_P_8; // use chromakey for hole
2014-03-15 16:59:03 +00:00
static INT32 format2bpp(GLTextureFormat_t format)
{
if (format == GL_TEXFMT_RGBA)
return 4;
else if (format == GL_TEXFMT_RGB_565
|| format == GL_TEXFMT_ARGB_1555
|| format == GL_TEXFMT_ARGB_4444
|| format == GL_TEXFMT_ALPHA_INTENSITY_88
|| format == GL_TEXFMT_AP_88)
return 2;
else
return 1;
}
// This code was originally placed directly in HWR_DrawPatchInCache.
// It is now split from it for my sanity! (and the sanity of others)
// -- Monster Iestyn (13/02/19)
static void 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)
{
fixed_t yfrac, position, count;
UINT8 *dest;
const UINT8 *source;
INT32 topdelta, prevdelta = -1;
INT32 originy = 0;
// for writing a pixel to dest
RGBA_t colortemp;
UINT8 alpha;
UINT8 texel;
UINT16 texelu16;
(void)patchheight; // This parameter is unused
if (originPatch) // originPatch can be NULL here, unlike in the software version
originy = originPatch->originy;
while (patchcol->topdelta != 0xff)
{
topdelta = patchcol->topdelta;
if (topdelta <= prevdelta)
topdelta += prevdelta;
prevdelta = topdelta;
source = (const UINT8 *)patchcol + 3;
count = ((patchcol->length * scale_y) + (FRACUNIT/2)) >> FRACBITS;
position = originy + topdelta;
yfrac = 0;
//yfracstep = (patchcol->length << FRACBITS) / count;
if (position < 0)
{
yfrac = -position<<FRACBITS;
count += (((position * scale_y) + (FRACUNIT/2)) >> FRACBITS);
position = 0;
}
position = ((position * scale_y) + (FRACUNIT/2)) >> FRACBITS;
if (position < 0)
position = 0;
if (position + count >= pblockheight)
count = pblockheight - position;
dest = block + (position*blockmodulo);
while (count > 0)
{
count--;
texel = source[yfrac>>FRACBITS];
//Hurdler: 25/04/2000: now support colormap in hardware mode
2019-11-09 17:09:20 +00:00
if (mipmap->colormap)
texel = mipmap->colormap[texel];
2020-01-06 01:04:19 +00:00
// If the mipmap is chromakeyed, check if the texel's color
// is equivalent to the chroma key's color index.
alpha = 0xff;
if ((mipmap->flags & TF_CHROMAKEYED) && (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX))
2019-11-09 17:09:20 +00:00
alpha = 0x00;
// hope compiler will get this switch out of the loops (dreams...)
// gcc do it ! but vcc not ! (why don't use cygwin gcc for win32 ?)
// Alam: SRB2 uses Mingw, HUGS
switch (bpp)
{
2019-09-08 01:43:29 +00:00
case 2 : // uhhhhhhhh..........
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
texel = ASTBlendPixel_8bpp(*(dest+1), texel, originPatch->style, originPatch->alpha);
2019-09-08 01:43:29 +00:00
texelu16 = (UINT16)((alpha<<8) | texel);
memcpy(dest, &texelu16, sizeof(UINT16));
break;
case 3 : colortemp = V_GetColor(texel);
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
2019-09-08 01:43:29 +00:00
{
RGBA_t rgbatexel;
rgbatexel.rgba = *(UINT32 *)dest;
2019-09-18 01:29:53 +00:00
colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha);
2019-09-08 01:43:29 +00:00
}
memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8));
break;
case 4 : colortemp = V_GetColor(texel);
colortemp.s.alpha = alpha;
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
2019-09-08 01:43:29 +00:00
{
RGBA_t rgbatexel;
rgbatexel.rgba = *(UINT32 *)dest;
2019-09-18 01:29:53 +00:00
colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha);
2019-09-08 01:43:29 +00:00
}
memcpy(dest, &colortemp, sizeof(RGBA_t));
break;
// default is 1
2019-09-08 01:43:29 +00:00
default:
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
*dest = ASTBlendPixel_8bpp(*dest, texel, originPatch->style, originPatch->alpha);
2019-09-08 01:43:29 +00:00
else
*dest = texel;
break;
}
dest += blockmodulo;
yfrac += yfracstep;
}
patchcol = (const column_t *)((const UINT8 *)patchcol + patchcol->length + 4);
}
}
static void 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)
{
fixed_t yfrac, position, count;
UINT8 *dest;
const UINT8 *source;
INT32 topdelta, prevdelta = -1;
INT32 originy = 0;
// for writing a pixel to dest
RGBA_t colortemp;
UINT8 alpha;
UINT8 texel;
UINT16 texelu16;
if (originPatch) // originPatch can be NULL here, unlike in the software version
originy = originPatch->originy;
while (patchcol->topdelta != 0xff)
{
topdelta = patchcol->topdelta;
if (topdelta <= prevdelta)
topdelta += prevdelta;
prevdelta = topdelta;
topdelta = patchheight-patchcol->length-topdelta;
source = (const UINT8 *)patchcol + 3;
count = ((patchcol->length * scale_y) + (FRACUNIT/2)) >> FRACBITS;
position = originy + topdelta;
yfrac = (patchcol->length-1) << FRACBITS;
if (position < 0)
{
yfrac += position<<FRACBITS;
count += (((position * scale_y) + (FRACUNIT/2)) >> FRACBITS);
position = 0;
}
position = ((position * scale_y) + (FRACUNIT/2)) >> FRACBITS;
if (position < 0)
position = 0;
if (position + count >= pblockheight)
count = pblockheight - position;
dest = block + (position*blockmodulo);
while (count > 0)
{
count--;
texel = source[yfrac>>FRACBITS];
//Hurdler: 25/04/2000: now support colormap in hardware mode
2019-11-09 17:09:20 +00:00
if (mipmap->colormap)
texel = mipmap->colormap[texel];
// If the mipmap is chromakeyed, check if the texel's color
// is equivalent to the chroma key's color index.
alpha = 0xff;
if ((mipmap->flags & TF_CHROMAKEYED) && (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX))
2019-11-09 17:09:20 +00:00
alpha = 0x00;
// hope compiler will get this switch out of the loops (dreams...)
// gcc do it ! but vcc not ! (why don't use cygwin gcc for win32 ?)
// Alam: SRB2 uses Mingw, HUGS
switch (bpp)
{
2019-09-08 01:43:29 +00:00
case 2 : // uhhhhhhhh..........
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
texel = ASTBlendPixel_8bpp(*(dest+1), texel, originPatch->style, originPatch->alpha);
2019-09-08 01:43:29 +00:00
texelu16 = (UINT16)((alpha<<8) | texel);
memcpy(dest, &texelu16, sizeof(UINT16));
break;
case 3 : colortemp = V_GetColor(texel);
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
2019-09-08 01:43:29 +00:00
{
RGBA_t rgbatexel;
rgbatexel.rgba = *(UINT32 *)dest;
2019-09-18 01:29:53 +00:00
colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha);
2019-09-08 01:43:29 +00:00
}
memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8));
break;
case 4 : colortemp = V_GetColor(texel);
colortemp.s.alpha = alpha;
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
2019-09-08 01:43:29 +00:00
{
RGBA_t rgbatexel;
rgbatexel.rgba = *(UINT32 *)dest;
2019-09-18 01:29:53 +00:00
colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha);
2019-09-08 01:43:29 +00:00
}
memcpy(dest, &colortemp, sizeof(RGBA_t));
break;
// default is 1
2019-09-08 01:43:29 +00:00
default:
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
*dest = ASTBlendPixel_8bpp(*dest, texel, originPatch->style, originPatch->alpha);
2019-09-08 01:43:29 +00:00
else
*dest = texel;
break;
}
dest += blockmodulo;
yfrac -= yfracstep;
}
patchcol = (const column_t *)((const UINT8 *)patchcol + patchcol->length + 4);
}
}
// Simplified patch caching function
// for use by sprites and other patches that are not part of a wall texture
// no alpha or flipping should be present since we do not want non-texture graphics to have them
// no offsets are used either
// -- Monster Iestyn (13/02/19)
2014-03-15 16:59:03 +00:00
static void HWR_DrawPatchInCache(GLMipmap_t *mipmap,
INT32 pblockwidth, INT32 pblockheight,
INT32 pwidth, INT32 pheight,
const patch_t *realpatch)
{
INT32 ncols;
fixed_t xfrac, xfracstep;
fixed_t yfracstep, scale_y;
const column_t *patchcol;
2020-07-06 03:35:48 +00:00
UINT8 *block = mipmap->data;
INT32 bpp;
INT32 blockmodulo;
if (pwidth <= 0 || pheight <= 0)
return;
2020-03-14 20:52:25 +00:00
ncols = pwidth;
// source advance
xfrac = 0;
2020-03-14 20:52:25 +00:00
xfracstep = FRACUNIT;
yfracstep = FRACUNIT;
scale_y = FRACUNIT;
bpp = format2bpp(mipmap->format);
if (bpp < 1 || bpp > 4)
I_Error("HWR_DrawPatchInCache: no drawer defined for this bpp (%d)\n",bpp);
// NOTE: should this actually be pblockwidth*bpp?
2020-01-28 03:56:22 +00:00
blockmodulo = pblockwidth*bpp;
// Draw each column to the block cache
for (; ncols--; block += bpp, xfrac += xfracstep)
{
patchcol = (const column_t *)((const UINT8 *)realpatch + LONG(realpatch->columnofs[xfrac>>FRACBITS]));
HWR_DrawColumnInCache(patchcol, block, mipmap,
pblockheight, blockmodulo,
yfracstep, scale_y,
NULL, pheight, // not that pheight is going to get used anyway...
bpp);
}
}
// This function we use for caching patches that belong to textures
static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap,
INT32 pblockwidth, INT32 pblockheight,
texture_t *texture, texpatch_t *patch,
const patch_t *realpatch)
2014-03-15 16:59:03 +00:00
{
INT32 x, x1, x2;
INT32 col, ncols;
fixed_t xfrac, xfracstep;
fixed_t yfracstep, scale_y;
const column_t *patchcol;
2020-07-06 03:35:48 +00:00
UINT8 *block = mipmap->data;
INT32 bpp;
INT32 blockmodulo;
INT32 width, height;
// Column drawing function pointer.
static void (*ColumnDrawerPointer)(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);
2014-03-15 16:59:03 +00:00
if (texture->width <= 0 || texture->height <= 0)
return;
ColumnDrawerPointer = (patch->flip & 2) ? HWR_DrawFlippedColumnInCache : HWR_DrawColumnInCache;
x1 = patch->originx;
width = SHORT(realpatch->width);
height = SHORT(realpatch->height);
x2 = x1 + width;
2014-03-15 16:59:03 +00:00
if (x1 > texture->width || x2 < 0)
return; // patch not located within texture's x bounds, ignore
if (patch->originy > texture->height || (patch->originy + height) < 0)
return; // patch not located within texture's y bounds, ignore
// patch is actually inside the texture!
// now check if texture is partly off-screen and adjust accordingly
// left edge
2014-03-15 16:59:03 +00:00
if (x1 < 0)
x = 0;
else
x = x1;
// right edge
if (x2 > texture->width)
x2 = texture->width;
2014-03-15 16:59:03 +00:00
col = x * pblockwidth / texture->width;
ncols = ((x2 - x) * pblockwidth) / texture->width;
2014-03-15 16:59:03 +00:00
/*
CONS_Debug(DBG_RENDER, "patch %dx%d texture %dx%d block %dx%d\n",
width, height,
texture->width, texture->height,
pblockwidth, pblockheight);
2014-03-15 16:59:03 +00:00
CONS_Debug(DBG_RENDER, " col %d ncols %d x %d\n", col, ncols, x);
*/
// source advance
xfrac = 0;
if (x1 < 0)
xfrac = -x1<<FRACBITS;
xfracstep = (texture->width << FRACBITS) / pblockwidth;
yfracstep = (texture->height<< FRACBITS) / pblockheight;
scale_y = (pblockheight << FRACBITS) / texture->height;
bpp = format2bpp(mipmap->format);
2014-03-15 16:59:03 +00:00
if (bpp < 1 || bpp > 4)
I_Error("HWR_DrawPatchInCache: no drawer defined for this bpp (%d)\n",bpp);
// NOTE: should this actually be pblockwidth*bpp?
2020-01-28 03:56:22 +00:00
blockmodulo = pblockwidth*bpp;
// Draw each column to the block cache
2014-03-15 16:59:03 +00:00
for (block += col*bpp; ncols--; block += bpp, xfrac += xfracstep)
{
if (patch->flip & 1)
patchcol = (const column_t *)((const UINT8 *)realpatch + LONG(realpatch->columnofs[(width-1)-(xfrac>>FRACBITS)]));
else
patchcol = (const column_t *)((const UINT8 *)realpatch + LONG(realpatch->columnofs[xfrac>>FRACBITS]));
ColumnDrawerPointer(patchcol, block, mipmap,
pblockheight, blockmodulo,
yfracstep, scale_y,
patch, height,
bpp);
2014-03-15 16:59:03 +00:00
}
}
static UINT8 *MakeBlock(GLMipmap_t *grMipmap)
{
UINT8 *block;
INT32 bpp, i;
2019-11-09 17:09:20 +00:00
UINT16 bu16 = ((0x00 <<8) | HWR_PATCHES_CHROMAKEY_COLORINDEX);
2020-01-28 03:56:22 +00:00
INT32 blocksize = (grMipmap->width * grMipmap->height);
2014-03-15 16:59:03 +00:00
bpp = format2bpp(grMipmap->format);
2020-07-06 03:35:48 +00:00
block = Z_Malloc(blocksize*bpp, PU_HWRCACHE, &(grMipmap->data));
2014-03-15 16:59:03 +00:00
switch (bpp)
{
case 1: memset(block, HWR_PATCHES_CHROMAKEY_COLORINDEX, blocksize); break;
case 2:
// fill background with chromakey, alpha = 0
for (i = 0; i < blocksize; i++)
//[segabor]
memcpy(block+i*sizeof(UINT16), &bu16, sizeof(UINT16));
break;
case 4: memset(block, 0x00, blocksize*sizeof(UINT32)); break;
}
return block;
}
//
// Create a composite texture from patches, adapt the texture size to a power of 2
// height and width for the hardware texture cache.
//
static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex)
2014-03-15 16:59:03 +00:00
{
UINT8 *block;
texture_t *texture;
texpatch_t *patch;
patch_t *realpatch;
2019-11-09 16:28:56 +00:00
UINT8 *pdata;
2020-01-28 03:56:22 +00:00
INT32 blockwidth, blockheight, blocksize;
2014-03-15 16:59:03 +00:00
INT32 i;
boolean skyspecial = false; //poor hack for Legacy large skies..
texture = textures[texnum];
// hack the Legacy skies..
if (texture->name[0] == 'S' &&
texture->name[1] == 'K' &&
texture->name[2] == 'Y' &&
(texture->name[4] == 0 ||
texture->name[5] == 0)
)
{
skyspecial = true;
grtex->mipmap.flags = TF_WRAPXY; // don't use the chromakey for sky
}
else
grtex->mipmap.flags = TF_CHROMAKEYED | TF_WRAPXY;
2020-01-28 03:56:22 +00:00
grtex->mipmap.width = (UINT16)texture->width;
grtex->mipmap.height = (UINT16)texture->height;
2020-07-06 03:35:48 +00:00
grtex->mipmap.format = textureformat;
2014-03-15 16:59:03 +00:00
2020-01-28 03:56:22 +00:00
blockwidth = texture->width;
blockheight = texture->height;
blocksize = (blockwidth * blockheight);
2014-03-15 16:59:03 +00:00
block = MakeBlock(&grtex->mipmap);
if (skyspecial) //Hurdler: not efficient, but better than holes in the sky (and it's done only at level loading)
{
INT32 j;
RGBA_t col;
2019-11-09 17:09:20 +00:00
col = V_GetColor(HWR_PATCHES_CHROMAKEY_COLORINDEX);
2014-03-15 16:59:03 +00:00
for (j = 0; j < blockheight; j++)
{
for (i = 0; i < blockwidth; i++)
{
block[4*(j*blockwidth+i)+0] = col.s.red;
block[4*(j*blockwidth+i)+1] = col.s.green;
block[4*(j*blockwidth+i)+2] = col.s.blue;
block[4*(j*blockwidth+i)+3] = 0xff;
}
}
}
// Composite the columns together.
for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++)
{
2019-11-09 16:28:56 +00:00
boolean dealloc = true;
2019-05-27 02:37:23 +00:00
size_t lumplength = W_LumpLengthPwad(patch->wad, patch->lump);
2019-11-09 16:28:56 +00:00
pdata = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE);
realpatch = (patch_t *)pdata;
2019-09-06 22:41:29 +00:00
#ifndef NO_PNG_LUMPS
2019-05-27 02:37:23 +00:00
if (R_IsLumpPNG((UINT8 *)realpatch, lumplength))
2020-01-01 20:36:55 +00:00
realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL);
2019-11-09 16:28:56 +00:00
else
2019-09-06 22:41:29 +00:00
#endif
2019-11-09 16:28:56 +00:00
#ifdef WALLFLATS
if (texture->type == TEXTURETYPE_FLAT)
realpatch = R_FlatToPatch(pdata, texture->width, texture->height, 0, 0, NULL, false);
else
2019-09-06 22:41:29 +00:00
#endif
2019-11-09 16:28:56 +00:00
{
(void)lumplength;
dealloc = false;
}
HWR_DrawTexturePatchInCache(&grtex->mipmap, blockwidth, blockheight, texture, patch, realpatch);
if (dealloc)
Z_Unlock(realpatch);
2014-03-15 16:59:03 +00:00
}
//Hurdler: not efficient at all but I don't remember exactly how HWR_DrawPatchInCache works :(
if (format2bpp(grtex->mipmap.format)==4)
2014-03-15 16:59:03 +00:00
{
for (i = 3; i < blocksize*4; i += 4) // blocksize*4 because blocksize doesn't include the bpp
2014-03-15 16:59:03 +00:00
{
if (block[i] == 0)
{
grtex->mipmap.flags |= TF_TRANSPARENT;
break;
}
}
}
grtex->scaleX = 1.0f/(texture->width*FRACUNIT);
grtex->scaleY = 1.0f/(texture->height*FRACUNIT);
}
// patch may be NULL if grMipmap has been initialised already and makebitmap is false
void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap)
{
#ifndef NO_PNG_LUMPS
// lump is a png so convert it
size_t len = W_LumpLengthPwad(grPatch->wadnum, grPatch->lumpnum);
if ((patch != NULL) && R_IsLumpPNG((const UINT8 *)patch, len))
2020-01-01 20:36:55 +00:00
patch = R_PNGToPatch((const UINT8 *)patch, len, NULL);
#endif
2014-03-15 16:59:03 +00:00
// don't do it twice (like a cache)
if (grMipmap->width == 0)
{
// save the original patch header so that the GLPatch can be casted
// into a standard patch_t struct and the existing code can get the
// orginal patch dimensions and offsets.
grPatch->width = SHORT(patch->width);
grPatch->height = SHORT(patch->height);
grPatch->leftoffset = SHORT(patch->leftoffset);
grPatch->topoffset = SHORT(patch->topoffset);
2020-03-14 20:52:25 +00:00
grMipmap->width = grMipmap->height = 1;
while (grMipmap->width < grPatch->width) grMipmap->width <<= 1;
while (grMipmap->height < grPatch->height) grMipmap->height <<= 1;
2014-03-15 16:59:03 +00:00
// no wrap around, no chroma key
grMipmap->flags = 0;
// setup the texture info
2020-07-06 03:35:48 +00:00
grMipmap->format = patchformat;
2020-03-14 20:52:25 +00:00
//grPatch->max_s = grPatch->max_t = 1.0f;
grPatch->max_s = (float)grPatch->width / (float)grMipmap->width;
grPatch->max_t = (float)grPatch->height / (float)grMipmap->height;
2014-03-15 16:59:03 +00:00
}
2020-07-06 03:35:48 +00:00
Z_Free(grMipmap->data);
grMipmap->data = NULL;
2014-03-15 16:59:03 +00:00
if (makebitmap)
{
MakeBlock(grMipmap);
HWR_DrawPatchInCache(grMipmap,
2020-03-14 20:52:25 +00:00
grMipmap->width, grMipmap->height,
2014-03-15 16:59:03 +00:00
grPatch->width, grPatch->height,
patch);
2014-03-15 16:59:03 +00:00
}
}
// =================================================
// CACHING HANDLING
// =================================================
static size_t gr_numtextures = 0; // Texture count
static GLMapTexture_t *gr_textures; // For all textures
static GLMapTexture_t *gr_flats; // For all (texture) flats, as normal flats don't need to be cached
2014-03-15 16:59:03 +00:00
void HWR_InitTextureCache(void)
{
gr_textures = NULL;
2019-12-08 04:54:03 +00:00
gr_flats = NULL;
2014-03-15 16:59:03 +00:00
}
// Callback function for HWR_FreeTextureCache.
static void FreeMipmapColormap(INT32 patchnum, void *patch)
{
2019-11-24 20:37:11 +00:00
GLPatch_t* const pat = patch;
2014-03-15 16:59:03 +00:00
(void)patchnum; //unused
2019-12-08 02:46:05 +00:00
// The patch must be valid, obviously
if (!pat)
return;
// The mipmap must be valid, obviously
while (pat->mipmap)
2014-03-15 16:59:03 +00:00
{
2019-11-24 20:37:11 +00:00
// Confusing at first, but pat->mipmap->nextcolormap
// at the beginning of the loop is the first colormap
2019-12-08 02:46:05 +00:00
// from the linked list of colormaps.
GLMipmap_t *next = NULL;
// No mipmap in this patch, break out of the loop.
if (!pat->mipmap)
2019-12-04 18:50:17 +00:00
break;
2019-12-08 02:46:05 +00:00
// No colormap mipmap either.
if (!pat->mipmap->nextcolormap)
break;
// Set the first colormap to the one that comes after it.
next = pat->mipmap->nextcolormap;
2019-11-24 20:37:11 +00:00
pat->mipmap->nextcolormap = next->nextcolormap;
2019-12-08 02:46:05 +00:00
// Free image data from memory.
2020-07-06 03:35:48 +00:00
if (next->data)
Z_Free(next->data);
next->data = NULL;
2019-12-08 02:46:05 +00:00
2019-12-08 06:23:37 +00:00
// Free the old colormap mipmap from memory.
2019-11-24 20:37:11 +00:00
free(next);
2014-03-15 16:59:03 +00:00
}
}
2019-12-08 06:23:37 +00:00
void HWR_FreeMipmapCache(void)
2014-03-15 16:59:03 +00:00
{
INT32 i;
2019-09-09 00:37:24 +00:00
2014-03-15 16:59:03 +00:00
// free references to the textures
HWD.pfnClearMipMapCache();
// free all hardware-converted graphics cached in the heap
// our gool is only the textures since user of the texture is the texture cache
Z_FreeTag(PU_HWRCACHE);
Z_FreeTag(PU_HWRCACHE_UNLOCKED);
2014-03-15 16:59:03 +00:00
2019-09-09 00:37:24 +00:00
// Alam: free the Z_Blocks before freeing it's users
2019-11-24 20:37:11 +00:00
// free all patch colormaps after each level: must be done after ClearMipMapCache!
2019-09-09 00:37:24 +00:00
for (i = 0; i < numwadfiles; i++)
M_AATreeIterate(wadfiles[i]->hwrcache, FreeMipmapColormap);
}
void HWR_FreeTextureCache(void)
{
2014-03-15 16:59:03 +00:00
// free references to the textures
2019-12-08 06:23:37 +00:00
HWR_FreeMipmapCache();
2014-03-15 16:59:03 +00:00
// now the heap don't have any 'user' pointing to our
// texturecache info, we can free it
if (gr_textures)
free(gr_textures);
2019-12-08 04:54:03 +00:00
if (gr_flats)
free(gr_flats);
2014-03-15 16:59:03 +00:00
gr_textures = NULL;
2019-12-08 04:54:03 +00:00
gr_flats = NULL;
2014-03-15 16:59:03 +00:00
gr_numtextures = 0;
}
2019-12-08 06:23:37 +00:00
void HWR_LoadTextures(size_t pnumtextures)
2014-03-15 16:59:03 +00:00
{
// we must free it since numtextures changed
HWR_FreeTextureCache();
2019-12-08 04:54:03 +00:00
// Why not Z_Malloc?
2014-03-15 16:59:03 +00:00
gr_numtextures = pnumtextures;
2019-12-08 04:54:03 +00:00
gr_textures = calloc(gr_numtextures, sizeof(*gr_textures));
gr_flats = calloc(gr_numtextures, sizeof(*gr_flats));
// Doesn't tell you which it _is_, but hopefully
// should never ever happen (right?!)
if ((gr_textures == NULL) || (gr_flats == NULL))
2019-12-08 06:23:37 +00:00
I_Error("HWR_LoadTextures: ran out of memory for OpenGL textures. Sad!");
2014-03-15 16:59:03 +00:00
}
void HWR_SetPalette(RGBA_t *palette)
{
2019-12-09 01:12:56 +00:00
HWD.pfnSetPalette(palette);
2014-03-15 16:59:03 +00:00
// hardware driver will flush there own cache if cache is non paletized
// now flush data texture cache so 32 bit texture are recomputed
if (patchformat == GL_TEXFMT_RGBA || textureformat == GL_TEXFMT_RGBA)
2014-03-15 16:59:03 +00:00
{
Z_FreeTag(PU_HWRCACHE);
Z_FreeTag(PU_HWRCACHE_UNLOCKED);
2014-03-15 16:59:03 +00:00
}
}
// --------------------------------------------------------------------------
// Make sure texture is downloaded and set it as the source
// --------------------------------------------------------------------------
GLMapTexture_t *HWR_GetTexture(INT32 tex)
2014-03-15 16:59:03 +00:00
{
GLMapTexture_t *grtex;
2014-03-15 16:59:03 +00:00
#ifdef PARANOIA
if ((unsigned)tex >= gr_numtextures)
2019-09-08 21:27:35 +00:00
I_Error("HWR_GetTexture: tex >= numtextures\n");
2014-03-15 16:59:03 +00:00
#endif
2019-12-08 04:54:03 +00:00
// Every texture in memory, stored in the
// hardware renderer's bit depth format. Wow!
2014-03-15 16:59:03 +00:00
grtex = &gr_textures[tex];
2019-12-08 04:54:03 +00:00
// Generate texture if missing from the cache
2020-07-06 03:35:48 +00:00
if (!grtex->mipmap.data && !grtex->mipmap.downloaded)
2014-03-15 16:59:03 +00:00
HWR_GenerateTexture(tex, grtex);
2020-06-07 18:20:52 +00:00
// If hardware does not have the texture, then call pfnSetTexture to upload it
if (!grtex->mipmap.downloaded)
HWD.pfnSetTexture(&grtex->mipmap);
2020-07-06 03:35:48 +00:00
2020-06-07 18:20:52 +00:00
HWR_SetCurrentTexture(&grtex->mipmap);
2014-03-15 16:59:03 +00:00
// The system-memory data can be purged now.
2020-07-06 03:35:48 +00:00
Z_ChangeTag(grtex->mipmap.data, PU_HWRCACHE_UNLOCKED);
2014-03-15 16:59:03 +00:00
return grtex;
}
static void HWR_CacheFlat(GLMipmap_t *grMipmap, lumpnum_t flatlumpnum)
{
size_t size, pflatsize;
// setup the texture info
grMipmap->format = GL_TEXFMT_P_8;
2014-03-15 16:59:03 +00:00
grMipmap->flags = TF_WRAPXY|TF_CHROMAKEYED;
size = W_LumpLength(flatlumpnum);
switch (size)
{
case 4194304: // 2048x2048 lump
pflatsize = 2048;
break;
case 1048576: // 1024x1024 lump
pflatsize = 1024;
break;
case 262144:// 512x512 lump
pflatsize = 512;
break;
case 65536: // 256x256 lump
pflatsize = 256;
break;
case 16384: // 128x128 lump
pflatsize = 128;
break;
case 1024: // 32x32 lump
pflatsize = 32;
break;
default: // 64x64 lump
pflatsize = 64;
break;
}
2019-11-09 01:58:41 +00:00
grMipmap->width = (UINT16)pflatsize;
grMipmap->height = (UINT16)pflatsize;
2014-03-15 16:59:03 +00:00
2019-11-09 01:58:41 +00:00
// the flat raw data needn't be converted with palettized textures
W_ReadLump(flatlumpnum, Z_Malloc(W_LumpLength(flatlumpnum),
2020-07-06 03:35:48 +00:00
PU_HWRCACHE, &grMipmap->data));
}
2014-03-15 16:59:03 +00:00
2019-11-09 01:58:41 +00:00
static void HWR_CacheTextureAsFlat(GLMipmap_t *grMipmap, INT32 texturenum)
2014-03-15 16:59:03 +00:00
{
2019-09-07 19:54:26 +00:00
UINT8 *flat;
2014-03-15 16:59:03 +00:00
2019-05-26 19:22:33 +00:00
// setup the texture info
grMipmap->format = GL_TEXFMT_P_8;
2019-05-26 19:22:33 +00:00
grMipmap->flags = TF_WRAPXY|TF_CHROMAKEYED;
grMipmap->width = (UINT16)textures[texturenum]->width;
grMipmap->height = (UINT16)textures[texturenum]->height;
2020-07-06 03:35:48 +00:00
flat = Z_Malloc(grMipmap->width * grMipmap->height, PU_HWRCACHE, &grMipmap->data);
2019-09-07 19:54:26 +00:00
memset(flat, TRANSPARENTPIXEL, grMipmap->width * grMipmap->height);
R_TextureToFlat(texturenum, flat);
2019-05-26 19:22:33 +00:00
}
2019-11-09 01:58:41 +00:00
// Download a Doom 'flat' to the hardware cache and make it ready for use
void HWR_LiterallyGetFlat(lumpnum_t flatlumpnum)
{
GLMipmap_t *grmip;
if (flatlumpnum == LUMPERROR)
return;
grmip = HWR_GetCachedGLPatch(flatlumpnum)->mipmap;
2020-07-06 03:35:48 +00:00
if (!grmip->downloaded && !grmip->data)
2019-11-09 01:58:41 +00:00
HWR_CacheFlat(grmip, flatlumpnum);
2020-06-07 18:20:52 +00:00
// If hardware does not have the texture, then call pfnSetTexture to upload it
if (!grmip->downloaded)
HWD.pfnSetTexture(grmip);
2020-07-06 03:35:48 +00:00
2020-06-07 18:20:52 +00:00
HWR_SetCurrentTexture(grmip);
// The system-memory data can be purged now.
2020-07-06 03:35:48 +00:00
Z_ChangeTag(grmip->data, PU_HWRCACHE_UNLOCKED);
2019-11-09 01:58:41 +00:00
}
void HWR_GetLevelFlat(levelflat_t *levelflat)
2019-11-09 01:58:41 +00:00
{
// Who knows?
if (levelflat == NULL)
return;
2019-11-09 01:58:41 +00:00
if (levelflat->type == LEVELFLAT_FLAT)
HWR_LiterallyGetFlat(levelflat->u.flat.lumpnum);
else if (levelflat->type == LEVELFLAT_TEXTURE)
{
GLMapTexture_t *grtex;
2019-11-09 01:58:41 +00:00
INT32 texturenum = levelflat->u.texture.num;
#ifdef PARANOIA
2019-11-09 01:58:41 +00:00
if ((unsigned)texturenum >= gr_numtextures)
I_Error("HWR_GetLevelFlat: texturenum >= numtextures\n");
#endif
2019-12-08 04:54:03 +00:00
// Who knows?
2019-11-09 01:58:41 +00:00
if (texturenum == 0 || texturenum == -1)
return;
2019-12-08 04:54:03 +00:00
// Every texture in memory, stored as a 8-bit flat. Wow!
grtex = &gr_flats[texturenum];
// Generate flat if missing from the cache
2020-07-06 03:35:48 +00:00
if (!grtex->mipmap.data && !grtex->mipmap.downloaded)
2019-11-09 01:58:41 +00:00
HWR_CacheTextureAsFlat(&grtex->mipmap, texturenum);
2020-06-07 18:20:52 +00:00
// If hardware does not have the texture, then call pfnSetTexture to upload it
if (!grtex->mipmap.downloaded)
HWD.pfnSetTexture(&grtex->mipmap);
2020-07-06 03:35:48 +00:00
2020-06-07 18:20:52 +00:00
HWR_SetCurrentTexture(&grtex->mipmap);
2019-11-09 01:58:41 +00:00
// The system-memory data can be purged now.
2020-07-06 03:35:48 +00:00
Z_ChangeTag(grtex->mipmap.data, PU_HWRCACHE_UNLOCKED);
2019-11-09 01:58:41 +00:00
}
else // set no texture
2020-06-07 18:20:52 +00:00
HWR_SetCurrentTexture(NULL);
2014-03-15 16:59:03 +00:00
}
//
// HWR_LoadMappedPatch(): replace the skin color of the sprite in cache
// : load it first in doom cache if not already
//
static void HWR_LoadMappedPatch(GLMipmap_t *grmip, GLPatch_t *gpatch)
{
2020-07-06 03:35:48 +00:00
if (!grmip->downloaded && !grmip->data)
2014-03-15 16:59:03 +00:00
{
2019-08-18 17:16:48 +00:00
patch_t *patch = gpatch->rawpatch;
if (!patch)
patch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC);
2014-03-15 16:59:03 +00:00
HWR_MakePatch(patch, gpatch, grmip, true);
2019-08-18 17:16:48 +00:00
// You can't free rawpatch for some reason?
2019-12-08 04:54:03 +00:00
// (Obviously I can't, sprite rotation needs that...)
2019-08-18 17:16:48 +00:00
if (!gpatch->rawpatch)
Z_Free(patch);
2014-03-15 16:59:03 +00:00
}
2020-06-07 18:20:52 +00:00
// If hardware does not have the texture, then call pfnSetTexture to upload it
if (!grmip->downloaded)
HWD.pfnSetTexture(grmip);
2020-07-06 03:35:48 +00:00
2020-06-07 18:20:52 +00:00
HWR_SetCurrentTexture(grmip);
2014-03-15 16:59:03 +00:00
// The system-memory data can be purged now.
2020-07-06 03:35:48 +00:00
Z_ChangeTag(grmip->data, PU_HWRCACHE_UNLOCKED);
2014-03-15 16:59:03 +00:00
}
// -----------------+
// HWR_GetPatch : Download a patch to the hardware cache and make it ready for use
// -----------------+
void HWR_GetPatch(GLPatch_t *gpatch)
{
// is it in hardware cache
2020-07-06 03:35:48 +00:00
if (!gpatch->mipmap->downloaded && !gpatch->mipmap->data)
2014-03-15 16:59:03 +00:00
{
// load the software patch, PU_STATIC or the Z_Malloc for hardware patch will
// flush the software patch before the conversion! oh yeah I suffered
2019-08-18 17:16:48 +00:00
patch_t *ptr = gpatch->rawpatch;
if (!ptr)
ptr = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC);
HWR_MakePatch(ptr, gpatch, gpatch->mipmap, true);
2014-03-15 16:59:03 +00:00
// this is inefficient.. but the hardware patch in heap is purgeable so it should
// not fragment memory, and besides the REAL cache here is the hardware memory
2019-08-18 17:16:48 +00:00
if (!gpatch->rawpatch)
Z_Free(ptr);
2014-03-15 16:59:03 +00:00
}
2020-06-07 18:20:52 +00:00
// If hardware does not have the texture, then call pfnSetTexture to upload it
if (!gpatch->mipmap->downloaded)
HWD.pfnSetTexture(gpatch->mipmap);
HWR_SetCurrentTexture(gpatch->mipmap);
2014-03-15 16:59:03 +00:00
// The system-memory patch data can be purged now.
2020-07-06 03:35:48 +00:00
Z_ChangeTag(gpatch->mipmap->data, PU_HWRCACHE_UNLOCKED);
2014-03-15 16:59:03 +00:00
}
// -------------------+
// HWR_GetMappedPatch : Same as HWR_GetPatch for sprite color
// -------------------+
void HWR_GetMappedPatch(GLPatch_t *gpatch, const UINT8 *colormap)
{
GLMipmap_t *grmip, *newmip;
if (colormap == colormaps || colormap == NULL)
{
// Load the default (green) color in doom cache (temporary?) AND hardware cache
HWR_GetPatch(gpatch);
return;
}
// search for the mimmap
// skip the first (no colormap translated)
for (grmip = gpatch->mipmap; grmip->nextcolormap; )
2014-03-15 16:59:03 +00:00
{
grmip = grmip->nextcolormap;
if (grmip->colormap == colormap)
{
HWR_LoadMappedPatch(grmip, gpatch);
return;
}
}
// not found, create it!
// If we are here, the sprite with the current colormap is not already in hardware memory
//BP: WARNING: don't free it manually without clearing the cache of harware renderer
// (it have a liste of mipmap)
// this malloc is cleared in HWR_FreeTextureCache
// (...) unfortunately z_malloc fragment alot the memory :(so malloc is better
newmip = calloc(1, sizeof (*newmip));
if (newmip == NULL)
I_Error("%s: Out of memory", "HWR_GetMappedPatch");
grmip->nextcolormap = newmip;
newmip->colormap = colormap;
HWR_LoadMappedPatch(newmip, gpatch);
}
void HWR_UnlockCachedPatch(GLPatch_t *gpatch)
{
if (!gpatch)
return;
2020-07-06 03:35:48 +00:00
Z_ChangeTag(gpatch->mipmap->data, PU_HWRCACHE_UNLOCKED);
2014-03-15 16:59:03 +00:00
Z_ChangeTag(gpatch, PU_HWRPATCHINFO_UNLOCKED);
}
static const INT32 picmode2GR[] =
{
GL_TEXFMT_P_8, // PALETTE
2014-03-15 16:59:03 +00:00
0, // INTENSITY (unsupported yet)
GL_TEXFMT_ALPHA_INTENSITY_88, // INTENSITY_ALPHA (corona use this)
2014-03-15 16:59:03 +00:00
0, // RGB24 (unsupported yet)
GL_TEXFMT_RGBA, // RGBA32 (opengl only)
2014-03-15 16:59:03 +00:00
};
static void HWR_DrawPicInCache(UINT8 *block, INT32 pblockwidth, INT32 pblockheight,
INT32 blockmodulo, pic_t *pic, INT32 bpp)
{
INT32 i,j;
fixed_t posx, posy, stepx, stepy;
UINT8 *dest, *src, texel;
UINT16 texelu16;
INT32 picbpp;
RGBA_t col;
stepy = ((INT32)SHORT(pic->height)<<FRACBITS)/pblockheight;
stepx = ((INT32)SHORT(pic->width)<<FRACBITS)/pblockwidth;
picbpp = format2bpp(picmode2GR[pic->mode]);
2014-03-15 16:59:03 +00:00
posy = 0;
for (j = 0; j < pblockheight; j++)
{
posx = 0;
dest = &block[j*blockmodulo];
src = &pic->data[(posy>>FRACBITS)*SHORT(pic->width)*picbpp];
for (i = 0; i < pblockwidth;i++)
{
switch (pic->mode)
{ // source bpp
case PALETTE :
texel = src[(posx+FRACUNIT/2)>>FRACBITS];
switch (bpp)
{ // destination bpp
case 1 :
*dest++ = texel; break;
case 2 :
texelu16 = (UINT16)(texel | 0xff00);
memcpy(dest, &texelu16, sizeof(UINT16));
dest += sizeof(UINT16);
break;
case 3 :
col = V_GetColor(texel);
memcpy(dest, &col, sizeof(RGBA_t)-sizeof(UINT8));
dest += sizeof(RGBA_t)-sizeof(UINT8);
break;
case 4 :
memcpy(dest, &V_GetColor(texel), sizeof(RGBA_t));
dest += sizeof(RGBA_t);
break;
}
break;
case INTENSITY :
*dest++ = src[(posx+FRACUNIT/2)>>FRACBITS];
break;
case INTENSITY_ALPHA : // assume dest bpp = 2
memcpy(dest, src + ((posx+FRACUNIT/2)>>FRACBITS)*sizeof(UINT16), sizeof(UINT16));
dest += sizeof(UINT16);
break;
case RGB24 :
break; // not supported yet
case RGBA32 : // assume dest bpp = 4
dest += sizeof(UINT32);
memcpy(dest, src + ((posx+FRACUNIT/2)>>FRACBITS)*sizeof(UINT32), sizeof(UINT32));
break;
}
posx += stepx;
}
posy += stepy;
}
}
// -----------------+
// HWR_GetPic : Download a Doom pic (raw row encoded with no 'holes')
// Returns :
// -----------------+
GLPatch_t *HWR_GetPic(lumpnum_t lumpnum)
{
2020-02-08 21:19:27 +00:00
GLPatch_t *grpatch = HWR_GetCachedGLPatch(lumpnum);
2020-07-06 03:35:48 +00:00
if (!grpatch->mipmap->downloaded && !grpatch->mipmap->data)
2014-03-15 16:59:03 +00:00
{
pic_t *pic;
UINT8 *block;
size_t len;
pic = W_CacheLumpNum(lumpnum, PU_CACHE);
grpatch->width = SHORT(pic->width);
grpatch->height = SHORT(pic->height);
len = W_LumpLength(lumpnum) - sizeof (pic_t);
grpatch->leftoffset = 0;
grpatch->topoffset = 0;
2020-01-28 03:56:22 +00:00
grpatch->mipmap->width = (UINT16)grpatch->width;
grpatch->mipmap->height = (UINT16)grpatch->height;
2014-03-15 16:59:03 +00:00
if (pic->mode == PALETTE)
2020-07-06 03:35:48 +00:00
grpatch->mipmap->format = textureformat; // can be set by driver
2014-03-15 16:59:03 +00:00
else
2020-07-06 03:35:48 +00:00
grpatch->mipmap->format = picmode2GR[pic->mode];
2014-03-15 16:59:03 +00:00
2020-07-06 03:35:48 +00:00
Z_Free(grpatch->mipmap->data);
2014-03-15 16:59:03 +00:00
// allocate block
block = MakeBlock(grpatch->mipmap);
2014-03-15 16:59:03 +00:00
2020-01-28 03:56:22 +00:00
if (grpatch->width == SHORT(pic->width) &&
grpatch->height == SHORT(pic->height) &&
format2bpp(grpatch->mipmap->format) == format2bpp(picmode2GR[pic->mode]))
2014-03-15 16:59:03 +00:00
{
// no conversion needed
2020-07-06 03:35:48 +00:00
M_Memcpy(grpatch->mipmap->data, pic->data,len);
2014-03-15 16:59:03 +00:00
}
else
2020-01-28 03:56:22 +00:00
HWR_DrawPicInCache(block, SHORT(pic->width), SHORT(pic->height),
SHORT(pic->width)*format2bpp(grpatch->mipmap->format),
2014-03-15 16:59:03 +00:00
pic,
format2bpp(grpatch->mipmap->format));
2014-03-15 16:59:03 +00:00
Z_Unlock(pic);
Z_ChangeTag(block, PU_HWRCACHE_UNLOCKED);
grpatch->mipmap->flags = 0;
2020-01-28 03:56:22 +00:00
grpatch->max_s = grpatch->max_t = 1.0f;
2014-03-15 16:59:03 +00:00
}
HWD.pfnSetTexture(grpatch->mipmap);
2020-07-06 03:35:48 +00:00
//CONS_Debug(DBG_RENDER, "picloaded at %x as texture %d\n",grpatch->mipmap.data, grpatch->mipmap.downloaded);
2014-03-15 16:59:03 +00:00
return grpatch;
}
GLPatch_t *HWR_GetCachedGLPatchPwad(UINT16 wadnum, UINT16 lumpnum)
{
aatree_t *hwrcache = wadfiles[wadnum]->hwrcache;
GLPatch_t *grpatch;
if (!(grpatch = M_AATreeGet(hwrcache, lumpnum)))
{
grpatch = Z_Calloc(sizeof(GLPatch_t), PU_HWRPATCHINFO, NULL);
grpatch->wadnum = wadnum;
grpatch->lumpnum = lumpnum;
grpatch->mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_HWRPATCHINFO, NULL);
2014-03-15 16:59:03 +00:00
M_AATreeSet(hwrcache, lumpnum, grpatch);
}
return grpatch;
}
GLPatch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum)
{
return HWR_GetCachedGLPatchPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum));
}
// Need to do this because they aren't powers of 2
static void HWR_DrawFadeMaskInCache(GLMipmap_t *mipmap, INT32 pblockwidth, INT32 pblockheight,
lumpnum_t fademasklumpnum, UINT16 fmwidth, UINT16 fmheight)
{
INT32 i,j;
fixed_t posx, posy, stepx, stepy;
2020-07-06 03:35:48 +00:00
UINT8 *block = mipmap->data; // places the data directly into here
UINT8 *flat;
UINT8 *dest, *src, texel;
RGBA_t col;
// Place the flats data into flat
W_ReadLump(fademasklumpnum, Z_Malloc(W_LumpLength(fademasklumpnum),
PU_HWRCACHE, &flat));
stepy = ((INT32)SHORT(fmheight)<<FRACBITS)/pblockheight;
stepx = ((INT32)SHORT(fmwidth)<<FRACBITS)/pblockwidth;
posy = 0;
for (j = 0; j < pblockheight; j++)
{
posx = 0;
2020-01-28 03:56:22 +00:00
dest = &block[j*(mipmap->width)]; // 1bpp
src = &flat[(posy>>FRACBITS)*SHORT(fmwidth)];
for (i = 0; i < pblockwidth;i++)
{
// fademask bpp is always 1, and is used just for alpha
texel = src[(posx)>>FRACBITS];
col = V_GetColor(texel);
*dest = col.s.red; // take the red level of the colour and use it for alpha, as fademasks do
dest++;
posx += stepx;
}
posy += stepy;
}
Z_Free(flat);
}
static void HWR_CacheFadeMask(GLMipmap_t *grMipmap, lumpnum_t fademasklumpnum)
{
size_t size;
UINT16 fmheight = 0, fmwidth = 0;
// setup the texture info
grMipmap->format = GL_TEXFMT_ALPHA_8; // put the correct alpha levels straight in so I don't need to convert it later
grMipmap->flags = 0;
size = W_LumpLength(fademasklumpnum);
switch (size)
{
// 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
case 256000: // 640x400
fmwidth = 640;
fmheight = 400;
break;
case 64000: // 320x200
fmwidth = 320;
fmheight = 200;
break;
case 16000: // 160x100
fmwidth = 160;
fmheight = 100;
break;
case 4000: // 80x50 (minimum)
fmwidth = 80;
fmheight = 50;
break;
default: // Bad lump
CONS_Alert(CONS_WARNING, "Fade mask lump of incorrect size, ignored\n"); // I should avoid this by checking the lumpnum in HWR_RunWipe
break;
}
// Thankfully, this will still work for this scenario
2020-01-28 03:56:22 +00:00
grMipmap->width = fmwidth;
grMipmap->height = fmheight;
2014-11-02 04:15:05 +00:00
MakeBlock(grMipmap);
2020-01-28 03:56:22 +00:00
HWR_DrawFadeMaskInCache(grMipmap, fmwidth, fmheight, fademasklumpnum, fmwidth, fmheight);
// I DO need to convert this because it isn't power of 2 and we need the alpha
}
void HWR_GetFadeMask(lumpnum_t fademasklumpnum)
{
2020-02-08 21:19:27 +00:00
GLMipmap_t *grmip = HWR_GetCachedGLPatch(fademasklumpnum)->mipmap;
2020-07-06 03:35:48 +00:00
if (!grmip->downloaded && !grmip->data)
HWR_CacheFadeMask(grmip, fademasklumpnum);
HWD.pfnSetTexture(grmip);
// The system-memory data can be purged now.
2020-07-06 03:35:48 +00:00
Z_ChangeTag(grmip->data, PU_HWRCACHE_UNLOCKED);
}
2014-03-15 16:59:03 +00:00
#endif //HWRENDER