All this texture load blocking var does is cause issues due to order of operations and what not. Lets just kill it. Thanks Alug for looking at this stuff for me!
1829 lines
49 KiB
C
1829 lines
49 KiB
C
// BLANKART
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
|
// Copyright (C) 1999-2020 by Sonic Team Junior.
|
|
//
|
|
// This program is free software distributed under the
|
|
// terms of the GNU General Public License, version 2.
|
|
// See the 'LICENSE' file for more details.
|
|
//-----------------------------------------------------------------------------
|
|
/// \file hw_cache.c
|
|
/// \brief load and convert graphics to the hardware format
|
|
|
|
#include "../doomdef.h"
|
|
|
|
#ifdef HWRENDER
|
|
#include "hw_main.h"
|
|
#include "hw_glob.h"
|
|
#include "hw_drv.h"
|
|
#include "hw_batching.h"
|
|
|
|
#include "../doomstat.h" //gamemode
|
|
#include "../i_video.h" //rendermode
|
|
#include "../r_data.h"
|
|
#include "../r_textures.h"
|
|
#include "../w_wad.h"
|
|
#include "../z_zone.h"
|
|
#include "../v_video.h"
|
|
#include "../r_draw.h"
|
|
#include "../r_patch.h"
|
|
#include "../r_main.h"
|
|
#include "../r_bsp.h"
|
|
#include "../r_picformats.h"
|
|
#include "../p_setup.h"
|
|
#include "../p_setup.h" // levelflats
|
|
#include "../p_spec.h" // anim_t
|
|
#include "../r_sky.h"
|
|
#include "../p_local.h"
|
|
|
|
INT32 patchformat = GL_TEXFMT_AP_88; // use alpha for holes
|
|
INT32 textureformat = GL_TEXFMT_P_8; // use chromakey for hole
|
|
|
|
RGBA_t mapPalette[256] = {0}; // the palette for the currently loaded level or menu etc.
|
|
|
|
// Returns a pointer to the palette which should be used for caching textures.
|
|
RGBA_t *HWR_GetTexturePalette(void)
|
|
{
|
|
return HWR_ShouldUsePaletteRendering() ? mapPalette : pLocalPalette;
|
|
}
|
|
|
|
static INT32 format2bpp(GLTextureFormat_t format)
|
|
{
|
|
if (format == GL_TEXFMT_RGBA)
|
|
return 4;
|
|
else if (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, RGBA_t *palette)
|
|
{
|
|
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];
|
|
alpha = 0xFF;
|
|
// Make pixel transparent if chroma keyed
|
|
if ((mipmap->flags & TF_CHROMAKEYED) && (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX))
|
|
alpha = 0x00;
|
|
|
|
//Hurdler: 25/04/2000: now support colormap in hardware mode
|
|
if (mipmap->colormap)
|
|
texel = mipmap->colormap->data[texel];
|
|
|
|
// 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)
|
|
{
|
|
case 2 : // uhhhhhhhh..........
|
|
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
|
|
texel = ASTBlendPaletteIndexes(*(dest+1), texel, originPatch->style, originPatch->alpha);
|
|
texelu16 = (UINT16)((alpha<<8) | texel);
|
|
memcpy(dest, &texelu16, sizeof(UINT16));
|
|
break;
|
|
case 3 : colortemp = palette[texel];
|
|
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
|
|
{
|
|
RGBA_t rgbatexel;
|
|
rgbatexel.rgba = *(UINT32 *)dest;
|
|
colortemp.rgba = ASTBlendTexturePixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha);
|
|
}
|
|
memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8));
|
|
break;
|
|
case 4 : colortemp = palette[texel];
|
|
colortemp.s.alpha = alpha;
|
|
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
|
|
{
|
|
RGBA_t rgbatexel;
|
|
rgbatexel.rgba = *(UINT32 *)dest;
|
|
colortemp.rgba = ASTBlendTexturePixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha);
|
|
}
|
|
memcpy(dest, &colortemp, sizeof(RGBA_t));
|
|
break;
|
|
// default is 1
|
|
default:
|
|
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
|
|
*dest = ASTBlendPaletteIndexes(*dest, texel, originPatch->style, originPatch->alpha);
|
|
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, RGBA_t *palette)
|
|
{
|
|
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];
|
|
alpha = 0xFF;
|
|
// Make pixel transparent if chroma keyed
|
|
if ((mipmap->flags & TF_CHROMAKEYED) && (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX))
|
|
alpha = 0x00;
|
|
|
|
//Hurdler: 25/04/2000: now support colormap in hardware mode
|
|
if (mipmap->colormap)
|
|
texel = mipmap->colormap->data[texel];
|
|
|
|
// 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)
|
|
{
|
|
case 2 : // uhhhhhhhh..........
|
|
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
|
|
texel = ASTBlendPaletteIndexes(*(dest+1), texel, originPatch->style, originPatch->alpha);
|
|
texelu16 = (UINT16)((alpha<<8) | texel);
|
|
memcpy(dest, &texelu16, sizeof(UINT16));
|
|
break;
|
|
case 3 : colortemp = palette[texel];
|
|
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
|
|
{
|
|
RGBA_t rgbatexel;
|
|
rgbatexel.rgba = *(UINT32 *)dest;
|
|
colortemp.rgba = ASTBlendTexturePixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha);
|
|
}
|
|
memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8));
|
|
break;
|
|
case 4 : colortemp = palette[texel];
|
|
colortemp.s.alpha = alpha;
|
|
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
|
|
{
|
|
RGBA_t rgbatexel;
|
|
rgbatexel.rgba = *(UINT32 *)dest;
|
|
colortemp.rgba = ASTBlendTexturePixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha);
|
|
}
|
|
memcpy(dest, &colortemp, sizeof(RGBA_t));
|
|
break;
|
|
// default is 1
|
|
default:
|
|
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
|
|
*dest = ASTBlendPaletteIndexes(*dest, texel, originPatch->style, originPatch->alpha);
|
|
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)
|
|
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;
|
|
UINT8 *block = mipmap->data;
|
|
INT32 bpp;
|
|
INT32 blockmodulo;
|
|
RGBA_t *palette;
|
|
|
|
if (pwidth <= 0 || pheight <= 0)
|
|
return;
|
|
|
|
palette = HWR_GetTexturePalette();
|
|
|
|
ncols = pwidth;
|
|
|
|
// source advance
|
|
xfrac = 0;
|
|
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?
|
|
blockmodulo = pblockwidth*bpp;
|
|
|
|
// Draw each column to the block cache
|
|
for (; ncols--; block += bpp, xfrac += xfracstep)
|
|
{
|
|
patchcol = (const column_t *)((const UINT8 *)realpatch->columns + (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, palette);
|
|
}
|
|
}
|
|
|
|
// 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 softwarepatch_t *realpatch)
|
|
{
|
|
INT32 x, x1, x2;
|
|
INT32 col, ncols;
|
|
fixed_t xfrac, xfracstep;
|
|
fixed_t yfracstep, scale_y;
|
|
const column_t *patchcol;
|
|
UINT8 *block = mipmap->data;
|
|
INT32 bpp;
|
|
INT32 blockmodulo;
|
|
INT32 width, height;
|
|
RGBA_t *palette;
|
|
|
|
// 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, RGBA_t *palette);
|
|
|
|
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;
|
|
|
|
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
|
|
|
|
palette = HWR_GetTexturePalette();
|
|
|
|
// patch is actually inside the texture!
|
|
// now check if texture is partly off-screen and adjust accordingly
|
|
|
|
// left edge
|
|
if (x1 < 0)
|
|
x = 0;
|
|
else
|
|
x = x1;
|
|
|
|
// right edge
|
|
if (x2 > texture->width)
|
|
x2 = texture->width;
|
|
|
|
|
|
col = x * pblockwidth / texture->width;
|
|
ncols = ((x2 - x) * pblockwidth) / texture->width;
|
|
|
|
/*
|
|
CONS_Debug(DBG_RENDER, "patch %dx%d texture %dx%d block %dx%d\n",
|
|
width, height,
|
|
texture->width, texture->height,
|
|
pblockwidth, pblockheight);
|
|
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);
|
|
|
|
if (bpp < 1 || bpp > 4)
|
|
I_Error("HWR_DrawTexturePatchInCache: no drawer defined for this bpp (%d)\n",bpp);
|
|
|
|
// NOTE: should this actually be pblockwidth*bpp?
|
|
blockmodulo = pblockwidth*bpp;
|
|
|
|
// Draw each column to the block cache
|
|
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, palette);
|
|
}
|
|
}
|
|
|
|
static UINT8 *MakeBlock(GLMipmap_t *grMipmap)
|
|
{
|
|
UINT8 *block;
|
|
INT32 bpp, i;
|
|
UINT16 bu16 = ((0x00 <<8) | HWR_PATCHES_CHROMAKEY_COLORINDEX);
|
|
INT32 blocksize = (grMipmap->width * grMipmap->height);
|
|
|
|
bpp = format2bpp(grMipmap->format);
|
|
block = Z_Malloc(blocksize*bpp, PU_HWRCACHE, &(grMipmap->data));
|
|
|
|
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++)
|
|
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(GLMapTexture_t *grtex, INT32 texnum, boolean noencoremap)
|
|
{
|
|
UINT8 *block;
|
|
texture_t *texture;
|
|
texpatch_t *patch;
|
|
softwarepatch_t *realpatch;
|
|
UINT8 *pdata;
|
|
INT32 blockwidth, blockheight, blocksize;
|
|
|
|
UINT8 *colormap = colormaps;
|
|
|
|
INT32 i, idx;
|
|
boolean skyspecial = false; //poor hack for Legacy large skies..
|
|
|
|
RGBA_t *palette;
|
|
palette = HWR_GetTexturePalette();
|
|
|
|
texture = textures[texnum];
|
|
|
|
grtex->mipmap.flags = TF_CHROMAKEYED | TF_WRAPXY;
|
|
grtex->mipmap.format = textureformat;
|
|
|
|
// hack the Legacy skies..
|
|
if (UNLIKELY(memcmp(texture->name, "SKY", 3) == 0 &&
|
|
(texture->name[4] == 0 || texture->name[5] == 0)))
|
|
{
|
|
skyspecial = true;
|
|
grtex->mipmap.flags &= ~TF_CHROMAKEYED; // don't use the chromakey for sky
|
|
grtex->mipmap.format = GL_TEXFMT_RGBA; // that skyspecial code below assumes this format ...
|
|
}
|
|
|
|
grtex->mipmap.width = (UINT16)texture->width;
|
|
grtex->mipmap.height = (UINT16)texture->height;
|
|
if (skyspecial)
|
|
grtex->mipmap.format = GL_TEXFMT_RGBA; // that skyspecial code below assumes this format ...
|
|
else
|
|
grtex->mipmap.format = textureformat;
|
|
|
|
if (!noencoremap && encoremap)
|
|
colormap += COLORMAP_REMAPOFFSET;
|
|
|
|
grtex->mipmap.colormap = Z_Calloc(sizeof(*grtex->mipmap.colormap), PU_HWRPATCHCOLMIPMAP, NULL);
|
|
grtex->mipmap.colormap->source = colormap;
|
|
memcpy(grtex->mipmap.colormap->data, colormap, 256 * sizeof(UINT8));
|
|
|
|
blockwidth = texture->width;
|
|
blockheight = texture->height;
|
|
blocksize = (blockwidth * blockheight);
|
|
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;
|
|
|
|
col = palette[HWR_PATCHES_CHROMAKEY_COLORINDEX];
|
|
for (idx = 0, j = 0; j < blockheight; j++)
|
|
{
|
|
for (i = 0; i < blockwidth; i++, idx++)
|
|
{
|
|
block[4*idx+0] = col.s.red;
|
|
block[4*idx+1] = col.s.green;
|
|
block[4*idx+2] = col.s.blue;
|
|
block[4*idx+3] = 0xff;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Composite the columns together.
|
|
for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++)
|
|
{
|
|
boolean dealloc = true;
|
|
boolean doremap = W_NeedPaletteRemapPwad(patch->wad, patch->lump, false);
|
|
size_t lumplength = W_LumpLengthPwad(patch->wad, patch->lump);
|
|
pdata = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE);
|
|
realpatch = (softwarepatch_t *)pdata;
|
|
|
|
#ifndef NO_PNG_LUMPS
|
|
if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength))
|
|
realpatch = (softwarepatch_t *)Picture_PNGConvert(pdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0);
|
|
else
|
|
#endif
|
|
if (texture->type == TEXTURETYPE_FLAT)
|
|
{
|
|
if (doremap)
|
|
R_DoPaletteRemapFlat(pdata, lumplength);
|
|
realpatch = (softwarepatch_t *)Picture_Convert(PICFMT_FLAT, pdata, PICFMT_DOOMPATCH, 0, NULL, texture->width, texture->height, 0, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
dealloc = false;
|
|
if (doremap)
|
|
R_DoPaletteRemapPatch(realpatch, lumplength);
|
|
}
|
|
|
|
HWR_DrawTexturePatchInCache(&grtex->mipmap, blockwidth, blockheight, texture, patch, realpatch);
|
|
|
|
if (dealloc)
|
|
Z_Unlock(realpatch);
|
|
}
|
|
//Hurdler: not efficient at all but I don't remember exactly how HWR_DrawPatchInCache works :(
|
|
if (format2bpp(grtex->mipmap.format)==4)
|
|
{
|
|
for (i = 3; i < blocksize*4; i += 4) // blocksize*4 because blocksize doesn't include the bpp
|
|
{
|
|
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)
|
|
{
|
|
if (grMipmap->width == 0)
|
|
{
|
|
grMipmap->width = grMipmap->height = 1;
|
|
while (grMipmap->width < patch->width) grMipmap->width <<= 1;
|
|
while (grMipmap->height < patch->height) grMipmap->height <<= 1;
|
|
|
|
// no wrap around, no chroma key
|
|
grMipmap->flags = 0;
|
|
|
|
// setup the texture info
|
|
grMipmap->format = patchformat;
|
|
|
|
grPatch->max_s = (float)patch->width / (float)grMipmap->width;
|
|
grPatch->max_t = (float)patch->height / (float)grMipmap->height;
|
|
}
|
|
|
|
Z_Free(grMipmap->data);
|
|
grMipmap->data = NULL;
|
|
|
|
if (makebitmap)
|
|
{
|
|
MakeBlock(grMipmap);
|
|
HWR_DrawPatchInCache(grMipmap,
|
|
grMipmap->width, grMipmap->height,
|
|
patch->width, patch->height,
|
|
patch);
|
|
}
|
|
}
|
|
|
|
// =================================================
|
|
// CACHING HANDLING
|
|
// =================================================
|
|
|
|
static size_t gl_numtextures = 0; // Texture count
|
|
static GLMapTexture_t *gl_textures; // For all textures
|
|
static GLMapTexture_t *gl_flats; // For all (texture) flats, as normal flats don't need to be cached
|
|
|
|
void HWR_FreeTextureData(patch_t *patch)
|
|
{
|
|
GLPatch_t *grPatch;
|
|
|
|
if (!patch || !patch->hardware)
|
|
return;
|
|
|
|
grPatch = patch->hardware;
|
|
|
|
if (vid.glstate == VID_GL_LIBRARY_LOADED)
|
|
HWD.pfnDeleteTexture(grPatch->mipmap);
|
|
if (grPatch->mipmap->data)
|
|
Z_Free(grPatch->mipmap->data);
|
|
}
|
|
|
|
void HWR_FreeTexture(patch_t *patch)
|
|
{
|
|
if (!patch)
|
|
return;
|
|
|
|
if (patch->hardware)
|
|
{
|
|
GLPatch_t *grPatch = patch->hardware;
|
|
|
|
HWR_FreeTextureColormaps(patch);
|
|
|
|
if (grPatch->mipmap)
|
|
{
|
|
HWR_FreeTextureData(patch);
|
|
Z_Free(grPatch->mipmap);
|
|
}
|
|
|
|
Z_Free(patch->hardware);
|
|
}
|
|
|
|
patch->hardware = NULL;
|
|
}
|
|
|
|
// Called by HWR_FreePatchCache.
|
|
void HWR_FreeTextureColormaps(patch_t *patch)
|
|
{
|
|
GLPatch_t *pat;
|
|
|
|
// The patch must be valid, obviously
|
|
if (!patch)
|
|
return;
|
|
|
|
pat = patch->hardware;
|
|
if (!pat)
|
|
return;
|
|
|
|
// The mipmap must be valid, obviously
|
|
while (pat->mipmap)
|
|
{
|
|
// Confusing at first, but pat->mipmap->nextcolormap
|
|
// at the beginning of the loop is the first colormap
|
|
// from the linked list of colormaps.
|
|
GLMipmap_t *next = NULL;
|
|
|
|
// No mipmap in this patch, break out of the loop.
|
|
if (!pat->mipmap)
|
|
break;
|
|
|
|
// No colormap mipmaps either.
|
|
if (!pat->mipmap->nextcolormap)
|
|
break;
|
|
|
|
// Set the first colormap to the one that comes after it.
|
|
next = pat->mipmap->nextcolormap;
|
|
pat->mipmap->nextcolormap = next->nextcolormap;
|
|
|
|
// Free image data from memory.
|
|
if (next->data)
|
|
Z_Free(next->data);
|
|
if (next->colormap)
|
|
Z_Free(next->colormap);
|
|
next->data = NULL;
|
|
next->colormap = NULL;
|
|
HWD.pfnDeleteTexture(next);
|
|
|
|
// Free the old colormap mipmap from memory.
|
|
free(next);
|
|
}
|
|
}
|
|
|
|
static boolean FreeTextureCallback(void *mem)
|
|
{
|
|
patch_t *patch = (patch_t *)mem;
|
|
HWR_FreeTexture(patch);
|
|
return false;
|
|
}
|
|
|
|
static boolean FreeColormapsCallback(void *mem)
|
|
{
|
|
patch_t *patch = (patch_t *)mem;
|
|
HWR_FreeTextureColormaps(patch);
|
|
return false;
|
|
}
|
|
|
|
static void HWR_FreePatchCache(boolean freeall)
|
|
{
|
|
boolean (*callback)(void *mem) = FreeTextureCallback;
|
|
|
|
if (!freeall)
|
|
callback = FreeColormapsCallback;
|
|
|
|
Z_IterateTags(PU_PATCH, PU_PATCH_ROTATED, callback);
|
|
Z_IterateTags(PU_SPRITE, PU_HUDGFX, callback);
|
|
}
|
|
|
|
// free all textures after each level
|
|
void HWR_ClearAllTextures(void)
|
|
{
|
|
HWD.pfnClearMipMapCache(); // free references to the textures
|
|
HWR_FreePatchCache(true);
|
|
}
|
|
|
|
void HWR_FreeColormapCache(void)
|
|
{
|
|
HWR_FreePatchCache(false);
|
|
}
|
|
|
|
void HWR_InitMapTextures(void)
|
|
{
|
|
gl_textures = NULL;
|
|
gl_flats = NULL;
|
|
}
|
|
|
|
static void FreeMapTexture(GLMapTexture_t *tex)
|
|
{
|
|
HWD.pfnDeleteTexture(&tex->mipmap);
|
|
if (tex->mipmap.data)
|
|
Z_Free(tex->mipmap.data);
|
|
tex->mipmap.data = NULL;
|
|
}
|
|
|
|
void HWR_FreeMapTextures(void)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < gl_numtextures*2; i++)
|
|
{
|
|
FreeMapTexture(&gl_textures[i]);
|
|
FreeMapTexture(&gl_flats[i]);
|
|
}
|
|
|
|
// now the heap don't have any 'user' pointing to our
|
|
// texturecache info, we can free it
|
|
if (gl_textures)
|
|
free(gl_textures);
|
|
if (gl_flats)
|
|
free(gl_flats);
|
|
gl_textures = NULL;
|
|
gl_flats = NULL;
|
|
gl_numtextures = 0;
|
|
}
|
|
|
|
static void HWR_PrecacheLevelFlats(void)
|
|
{
|
|
levelflat_t levelflat;
|
|
size_t i, j;
|
|
|
|
// special case for encore
|
|
if (encoremap)
|
|
{
|
|
// go through all sectors to determine if it should be remapped for encore
|
|
for (i = 0; i < numsectors; i++)
|
|
{
|
|
sector_t *sec = §ors[i];
|
|
|
|
// sector checked already?
|
|
if (sec->validcount == validcount)
|
|
continue;
|
|
|
|
sec->validcount = validcount;
|
|
|
|
// gotta check sector floor and ceiling
|
|
for (j = 0; j < 2; j++)
|
|
{
|
|
const boolean ceiling = (j == 0);
|
|
INT32 pic = ceiling ? sec->ceilingpic : sec->floorpic;
|
|
|
|
levelflat = levelflats[pic];
|
|
|
|
HWR_GetLevelFlat(&levelflat, R_NoEncore(sec, &levelflat, ceiling));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// on non encore we have it simple
|
|
// just load every flat in the level
|
|
for (i = 0; i < numlevelflats; i++)
|
|
{
|
|
levelflat = levelflats[i];
|
|
|
|
HWR_GetLevelFlat(&levelflat, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void HWR_PrecacheLevelTextures(void)
|
|
{
|
|
char *texturepresent;
|
|
anim_t *anim;
|
|
size_t i, j;
|
|
INT32 h;
|
|
|
|
texturepresent = calloc(numtextures, sizeof (*texturepresent));
|
|
if (texturepresent == NULL) I_Error("%s: Out of memory looking up textures", "HWR_PrecacheLevel");
|
|
|
|
for (i = 0; i < numlines; i++)
|
|
{
|
|
line_t *line = &lines[i];
|
|
const int noencoremap = ((line->flags & ML_TFERLINE) ? 2 : 1);
|
|
|
|
// line checked already?
|
|
if (line->validcount == validcount)
|
|
continue;
|
|
|
|
line->validcount = validcount;
|
|
|
|
// two sides
|
|
for (j = 0; j < 2; j++)
|
|
{
|
|
side_t *side = &sides[line->sidenum[j]];
|
|
|
|
// Single-side linedef
|
|
if (line->sidenum[j] == 0xffff)
|
|
continue;
|
|
|
|
if (side->toptexture >= 0 && side->toptexture < numtextures)
|
|
{
|
|
texturepresent[side->toptexture] = 1|noencoremap;
|
|
}
|
|
if (side->midtexture >= 0 && side->midtexture < numtextures)
|
|
{
|
|
texturepresent[side->midtexture] = 1|noencoremap;
|
|
}
|
|
if (side->bottomtexture >= 0 && side->bottomtexture < numtextures)
|
|
{
|
|
texturepresent[side->bottomtexture] = 1|noencoremap;
|
|
}
|
|
}
|
|
}
|
|
|
|
// check for animated textures
|
|
for (anim = anims; anim < lastanim; anim++)
|
|
{
|
|
if (!texturepresent[anim->basepic])
|
|
continue;
|
|
|
|
const char texpresent = texturepresent[anim->basepic];
|
|
|
|
if (!texpresent)
|
|
continue;
|
|
|
|
if (texpresent & 1)
|
|
{
|
|
for (h = 1; h < anim->numpics; h++)
|
|
{
|
|
HWR_GetTexture(anim->basepic+h, false);
|
|
}
|
|
}
|
|
|
|
if (texpresent & 2)
|
|
{
|
|
for (h = 1; h < anim->numpics; h++)
|
|
{
|
|
HWR_GetTexture(anim->basepic+h, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sky texture is always present.
|
|
// Note that F_SKY1 is the name used to indicate a sky floor/ceiling as a flat,
|
|
// while the sky texture is stored like a wall texture, with a skynum dependent name.
|
|
texturepresent[skytexture] = 1;
|
|
|
|
for (i = 0; i < (unsigned)numtextures; i++)
|
|
{
|
|
const char texpresent = texturepresent[i];
|
|
|
|
if (!texpresent)
|
|
continue;
|
|
|
|
if (texpresent & 1)
|
|
{
|
|
HWR_GetTexture(i, false);
|
|
}
|
|
|
|
if (texpresent & 2)
|
|
{
|
|
HWR_GetTexture(i, true);
|
|
}
|
|
}
|
|
free(texturepresent);
|
|
}
|
|
|
|
/*static void HWR_PrecacheLevelSprites(void)
|
|
{
|
|
GLPatch_t *spritepatch;
|
|
char *spritepresent;
|
|
size_t i, j, k;
|
|
lumpnum_t lump;
|
|
|
|
thinker_t *th;
|
|
mobj_t *mo;
|
|
spriteframe_t *sf;
|
|
|
|
spritepresent = calloc(numsprites, sizeof (*spritepresent));
|
|
if (spritepresent == NULL) I_Error("%s: Out of memory looking up sprites", "HWR_PrecacheLevel");
|
|
|
|
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
|
{
|
|
if (th->function != (actionf_p1)P_MobjThinker)
|
|
continue;
|
|
|
|
mo = (mobj_t *)th;
|
|
|
|
// ogl is weird
|
|
// for some reason it does not want to preload sprites with colormaps
|
|
// so just save us the work
|
|
if (mo->color || mo->colorized)
|
|
continue;
|
|
|
|
spritepresent[mo->sprite] = 1;
|
|
}
|
|
|
|
for (i = 0; i < numsprites; i++)
|
|
{
|
|
if (!spritepresent[i])
|
|
continue;
|
|
|
|
for (j = 0; j < sprites[i].numframes; j++)
|
|
{
|
|
sf = &sprites[i].spriteframes[j];
|
|
|
|
#define cacheang(a) {\
|
|
lump = sf->lumppat[a];\
|
|
spritepatch = W_CachePatchNum(lump, PU_CACHE);\
|
|
if (spritepatch != NULL)\
|
|
HWR_GetPatch((patch_t *)spritepatch);\
|
|
}
|
|
// see R_InitSprites for more about lumppat,lumpid
|
|
switch (sf->rotate)
|
|
{
|
|
case SRF_SINGLE:
|
|
cacheang(0);
|
|
break;
|
|
case SRF_2D:
|
|
cacheang(2);
|
|
cacheang(6);
|
|
break;
|
|
default:
|
|
k = 8;
|
|
while (k--)
|
|
cacheang(k);
|
|
break;
|
|
}
|
|
#undef cacheang
|
|
}
|
|
}
|
|
free(spritepresent);
|
|
}*/
|
|
|
|
void HWR_PrecacheLevel(void)
|
|
{
|
|
if (rendermode != render_opengl)
|
|
return;
|
|
|
|
// Precache flats.
|
|
HWR_PrecacheLevelFlats();
|
|
|
|
// prevent timeouts
|
|
NetKeepAlive();
|
|
|
|
// Precache textures.
|
|
HWR_PrecacheLevelTextures();
|
|
|
|
// prevent timeouts
|
|
NetKeepAlive();
|
|
|
|
// Precache sprites.
|
|
//HWR_PrecacheLevelSprites();
|
|
|
|
// prevent timeouts
|
|
//NetKeepAlive();
|
|
}
|
|
|
|
void HWR_LoadMapTextures(size_t pnumtextures)
|
|
{
|
|
// we must free it since numtextures may have changed
|
|
HWR_FreeMapTextures();
|
|
|
|
gl_numtextures = pnumtextures;
|
|
gl_textures = calloc(gl_numtextures, sizeof (*gl_textures)*2); // *2 - 1 for encore-remapped texture and another for noencore texture (unused when not in encore)
|
|
gl_flats = calloc(gl_numtextures, sizeof(*gl_flats)*2);
|
|
|
|
if (gl_textures == NULL || gl_flats == NULL)
|
|
I_Error("HWR_LoadMapTextures: ran out of memory for OpenGL textures");
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// Make sure texture is downloaded and set it as the source
|
|
// --------------------------------------------------------------------------
|
|
GLMapTexture_t *HWR_GetTexture(INT32 tex, boolean noencoremap)
|
|
{
|
|
GLMapTexture_t *grtex;
|
|
#ifdef PARANOIA
|
|
if ((unsigned)tex >= gl_numtextures)
|
|
I_Error("HWR_GetTexture: tex >= numtextures\n");
|
|
#endif
|
|
|
|
grtex = &gl_textures[tex*2 + (encoremap && !noencoremap ? 0 : 1)];
|
|
|
|
// Generate texture if missing from the cache
|
|
if (!grtex->mipmap.data && !grtex->mipmap.downloaded)
|
|
HWR_GenerateTexture(grtex, tex, noencoremap || !R_TextureCanRemap(tex));
|
|
|
|
// If hardware does not have the texture, then call pfnSetTexture to upload it
|
|
if (!grtex->mipmap.downloaded)
|
|
HWD.pfnSetTexture(&grtex->mipmap);
|
|
HWR_SetCurrentTexture(&grtex->mipmap);
|
|
|
|
// The system-memory data can be purged now.
|
|
Z_ChangeTag(grtex->mipmap.data, PU_HWRCACHE_UNLOCKED);
|
|
|
|
INT32 brightmapnum = R_GetTextureBrightmap(tex);
|
|
|
|
if (brightmapnum)
|
|
{
|
|
GLMapTexture_t *grtexbright;
|
|
|
|
// Every texture in memory, stored in the
|
|
// hardware renderer's bit depth format. Wow!
|
|
grtexbright = &gl_textures[brightmapnum*2 + (encoremap && !noencoremap ? 0 : 1)];
|
|
|
|
// Generate texture if missing from the cache
|
|
if (!grtexbright->mipmap.data && !grtexbright->mipmap.downloaded)
|
|
HWR_GenerateTexture(grtexbright, brightmapnum, true);
|
|
|
|
grtexbright->mipmap.flags |= TF_BRIGHTMAP;
|
|
|
|
// If hardware does not have the texture, then call pfnSetTexture to upload it
|
|
if (!grtexbright->mipmap.downloaded)
|
|
HWD.pfnSetTexture(&grtexbright->mipmap);
|
|
HWR_SetCurrentTexture(&grtexbright->mipmap);
|
|
|
|
// The system-memory data can be purged now.
|
|
Z_ChangeTag(grtexbright->mipmap.data, PU_HWRCACHE_UNLOCKED);
|
|
}
|
|
|
|
return grtex;
|
|
}
|
|
|
|
static void HWR_CacheFlat(GLMipmap_t *grMipmap, lumpnum_t flatlumpnum)
|
|
{
|
|
UINT8 *flat;
|
|
size_t steppy;
|
|
size_t size, pflatsize;
|
|
boolean doremap;
|
|
|
|
|
|
// setup the texture info
|
|
grMipmap->format = GL_TEXFMT_P_8;
|
|
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;
|
|
}
|
|
|
|
grMipmap->width = (UINT16)pflatsize;
|
|
grMipmap->height = (UINT16)pflatsize;
|
|
|
|
doremap = W_NeedPaletteRemap(flatlumpnum, true);
|
|
|
|
// the flat raw data needn't be converted with palettized textures
|
|
W_ReadLump(flatlumpnum, Z_Malloc(W_LumpLength(flatlumpnum),
|
|
PU_HWRCACHE, &grMipmap->data));
|
|
|
|
if (doremap)
|
|
R_DoPaletteRemapFlat(grMipmap->data, size);
|
|
|
|
flat = grMipmap->data;
|
|
for (steppy = 0; steppy < size; steppy++)
|
|
if (flat[steppy] != HWR_PATCHES_CHROMAKEY_COLORINDEX)
|
|
flat[steppy] = grMipmap->colormap->source[flat[steppy]];
|
|
}
|
|
|
|
// Download a Doom 'flat' to the hardware cache and make it ready for use
|
|
void HWR_GetRawFlat(lumpnum_t flatlumpnum, boolean noencoremap)
|
|
{
|
|
GLMipmap_t *grmip;
|
|
patch_t *patch;
|
|
|
|
UINT8 *colormap = colormaps;
|
|
|
|
if (flatlumpnum == LUMPERROR)
|
|
return;
|
|
|
|
patch = HWR_GetCachedGLPatch(flatlumpnum);
|
|
grmip = ((GLPatch_t *)Patch_AllocateHardwarePatch(patch))->mipmap;
|
|
|
|
if (!grmip->colormap)
|
|
{
|
|
if (!noencoremap && encoremap)
|
|
colormap += COLORMAP_REMAPOFFSET;
|
|
|
|
grmip->colormap = Z_Calloc(sizeof(*grmip->colormap), PU_HWRPATCHCOLMIPMAP, NULL);
|
|
grmip->colormap->source = colormap;
|
|
memcpy(grmip->colormap->data, colormap, 256 * sizeof(UINT8));
|
|
}
|
|
|
|
if (!grmip->downloaded && !grmip->data)
|
|
{
|
|
HWR_CacheFlat(grmip, flatlumpnum);
|
|
}
|
|
|
|
// If hardware does not have the texture, then call pfnSetTexture to upload it
|
|
if (!grmip->downloaded)
|
|
HWD.pfnSetTexture(grmip);
|
|
HWR_SetCurrentTexture(grmip);
|
|
|
|
// The system-memory data can be purged now.
|
|
Z_ChangeTag(grmip->data, PU_HWRCACHE_UNLOCKED);
|
|
}
|
|
|
|
void HWR_GetLevelFlat(levelflat_t *levelflat, boolean noencoremap)
|
|
{
|
|
if (levelflat->type == LEVELFLAT_NONE)
|
|
{
|
|
HWR_SetCurrentTexture(NULL);
|
|
return;
|
|
}
|
|
|
|
INT32 texturenum = texturetranslation[levelflat->texture_id];
|
|
INT32 brightmapnum = R_GetTextureBrightmap(texturenum);
|
|
|
|
if (texturenum <= 0)
|
|
{
|
|
HWR_SetCurrentTexture(NULL);
|
|
return;
|
|
}
|
|
|
|
GLMapTexture_t *grtex = &gl_flats[texturenum*2 + (encoremap && !noencoremap ? 0 : 1)];
|
|
GLMipmap_t *grMipmap = &grtex->mipmap;
|
|
|
|
if (!grMipmap->data && !grMipmap->downloaded)
|
|
{
|
|
UINT8 *flat;
|
|
UINT8 *colormap = colormaps;
|
|
|
|
grMipmap->format = GL_TEXFMT_P_8;
|
|
grMipmap->flags = TF_WRAPXY|TF_CHROMAKEYED;
|
|
|
|
grMipmap->width = (UINT16)textures[texturenum]->width;
|
|
grMipmap->height = (UINT16)textures[texturenum]->height;
|
|
|
|
size_t size = grMipmap->width * grMipmap->height;
|
|
flat = Picture_TextureToFlat(texturenum);
|
|
Z_ChangeTag(flat, PU_HWRCACHE);
|
|
Z_SetUser(flat, &grMipmap->data);
|
|
|
|
if (!noencoremap && encoremap)
|
|
colormap += COLORMAP_REMAPOFFSET;
|
|
|
|
grtex->mipmap.colormap = Z_Calloc(sizeof(*grtex->mipmap.colormap), PU_HWRPATCHCOLMIPMAP, NULL);
|
|
grtex->mipmap.colormap->source = colormap;
|
|
memcpy(grtex->mipmap.colormap->data, colormap, 256);
|
|
|
|
for (size_t steppy = 0; steppy < size; steppy++)
|
|
if (flat[steppy] != HWR_PATCHES_CHROMAKEY_COLORINDEX)
|
|
flat[steppy] = grtex->mipmap.colormap->source[flat[steppy]];
|
|
}
|
|
|
|
if (!grMipmap->downloaded)
|
|
HWD.pfnSetTexture(&grtex->mipmap);
|
|
|
|
HWR_SetCurrentTexture(&grtex->mipmap);
|
|
|
|
Z_ChangeTag(grMipmap->data, PU_HWRCACHE_UNLOCKED);
|
|
|
|
if (brightmapnum)
|
|
{
|
|
grtex = &gl_flats[brightmapnum*2 + (encoremap && !noencoremap ? 0 : 1)];
|
|
grMipmap = &grtex->mipmap;
|
|
|
|
if (!grMipmap->data && !grMipmap->downloaded)
|
|
{
|
|
grMipmap->format = GL_TEXFMT_P_8;
|
|
grMipmap->flags = TF_WRAPXY|TF_CHROMAKEYED;
|
|
|
|
grMipmap->width = (UINT16)textures[brightmapnum]->width;
|
|
grMipmap->height = (UINT16)textures[brightmapnum]->height;
|
|
|
|
size_t size = grMipmap->width * grMipmap->height;
|
|
memcpy(Z_Malloc(size, PU_HWRCACHE, &grMipmap->data), R_GetFlatForTexture(brightmapnum), size);
|
|
}
|
|
|
|
grtex->mipmap.flags |= TF_BRIGHTMAP;
|
|
|
|
if (!grMipmap->downloaded)
|
|
HWD.pfnSetTexture(&grtex->mipmap);
|
|
|
|
HWR_SetCurrentTexture(&grtex->mipmap);
|
|
|
|
Z_ChangeTag(grMipmap->data, PU_HWRCACHE_UNLOCKED);
|
|
}
|
|
}
|
|
|
|
// --------------------+
|
|
// HWR_LoadPatchMipmap : Generates a patch into a mipmap, usually the mipmap inside the patch itself
|
|
// --------------------+
|
|
static void HWR_LoadPatchMipmap(patch_t *patch, GLMipmap_t *grMipmap)
|
|
{
|
|
GLPatch_t *grPatch = patch->hardware;
|
|
if (!grMipmap->downloaded && !grMipmap->data)
|
|
HWR_MakePatch(patch, grPatch, grMipmap, true);
|
|
|
|
// If hardware does not have the texture, then call pfnSetTexture to upload it
|
|
if (!grMipmap->downloaded)
|
|
HWD.pfnSetTexture(grMipmap);
|
|
HWR_SetCurrentTexture(grMipmap);
|
|
|
|
// The system-memory data can be purged now.
|
|
Z_ChangeTag(grMipmap->data, PU_HWRCACHE_UNLOCKED);
|
|
}
|
|
|
|
// ----------------------+
|
|
// HWR_UpdatePatchMipmap : Updates a mipmap.
|
|
// ----------------------+
|
|
static void HWR_UpdatePatchMipmap(patch_t *patch, GLMipmap_t *grMipmap)
|
|
{
|
|
GLPatch_t *grPatch = patch->hardware;
|
|
HWR_MakePatch(patch, grPatch, grMipmap, true);
|
|
|
|
// If hardware does not have the texture, then call pfnSetTexture to upload it
|
|
// If it does have the texture, then call pfnUpdateTexture to update it
|
|
if (!grMipmap->downloaded)
|
|
HWD.pfnSetTexture(grMipmap);
|
|
else
|
|
HWD.pfnUpdateTexture(grMipmap);
|
|
HWR_SetCurrentTexture(grMipmap);
|
|
|
|
// The system-memory data can be purged now.
|
|
Z_ChangeTag(grMipmap->data, PU_HWRCACHE_UNLOCKED);
|
|
}
|
|
|
|
// -----------------+
|
|
// HWR_GetPatch : Downloads a patch to the hardware cache and make it ready for use
|
|
// -----------------+
|
|
void HWR_GetPatch(patch_t *patch)
|
|
{
|
|
if (!patch->hardware)
|
|
Patch_CreateGL(patch);
|
|
HWR_LoadPatchMipmap(patch, ((GLPatch_t *)patch->hardware)->mipmap);
|
|
}
|
|
|
|
// -------------------+
|
|
// HWR_GetMappedPatch : Same as HWR_GetPatch for sprite color
|
|
// -------------------+
|
|
void HWR_GetMappedPatch(patch_t *patch, const UINT8 *colormap)
|
|
{
|
|
GLPatch_t *grPatch;
|
|
GLMipmap_t *grMipmap, *newMipmap;
|
|
|
|
if (!patch->hardware)
|
|
Patch_CreateGL(patch);
|
|
grPatch = patch->hardware;
|
|
|
|
// Blatant hack for encore colormapping aside...
|
|
if (colormap == colormaps || colormap == NULL || colormap == (const UINT8*)(COLORMAP_REMAPOFFSET))
|
|
{
|
|
// Load the default (green) color in hardware cache
|
|
HWR_GetPatch(patch);
|
|
return;
|
|
}
|
|
|
|
// search for the mipmap
|
|
// skip the first (no colormap translated)
|
|
for (grMipmap = grPatch->mipmap; LIKELY(grMipmap->nextcolormap); )
|
|
{
|
|
grMipmap = grMipmap->nextcolormap;
|
|
if (UNLIKELY(grMipmap->colormap && grMipmap->colormap->source == colormap))
|
|
{
|
|
if (memcmp(grMipmap->colormap->data, colormap, 256 * sizeof(UINT8)))
|
|
{
|
|
memcpy(grMipmap->colormap->data, colormap, 256 * sizeof(UINT8));
|
|
HWR_UpdatePatchMipmap(patch, grMipmap);
|
|
}
|
|
else
|
|
HWR_LoadPatchMipmap(patch, grMipmap);
|
|
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_FreeColormapCache
|
|
// (...) unfortunately z_malloc fragment alot the memory :(so malloc is better
|
|
newMipmap = calloc(1, sizeof (*newMipmap));
|
|
if (newMipmap == NULL)
|
|
I_Error("%s: Out of memory", "HWR_GetMappedPatch");
|
|
grMipmap->nextcolormap = newMipmap;
|
|
|
|
newMipmap->colormap = Z_Calloc(sizeof(*newMipmap->colormap), PU_HWRPATCHCOLMIPMAP, NULL);
|
|
newMipmap->colormap->source = colormap;
|
|
memcpy(newMipmap->colormap->data, colormap, 256 * sizeof(UINT8));
|
|
|
|
HWR_LoadPatchMipmap(patch, newMipmap);
|
|
}
|
|
|
|
void HWR_UnlockCachedPatch(GLPatch_t *gpatch)
|
|
{
|
|
if (!gpatch)
|
|
return;
|
|
|
|
Z_ChangeTag(gpatch->mipmap->data, PU_HWRCACHE_UNLOCKED);
|
|
}
|
|
|
|
static const INT32 picmode2GR[] =
|
|
{
|
|
GL_TEXFMT_P_8, // PALETTE
|
|
0, // INTENSITY (unsupported yet)
|
|
GL_TEXFMT_ALPHA_INTENSITY_88, // INTENSITY_ALPHA (corona use this)
|
|
0, // RGB24 (unsupported yet)
|
|
GL_TEXFMT_RGBA, // RGBA32 (opengl only)
|
|
};
|
|
|
|
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;
|
|
RGBA_t *palette = HWR_GetTexturePalette();
|
|
|
|
stepy = ((INT32)SHORT(pic->height)<<FRACBITS)/pblockheight;
|
|
stepx = ((INT32)SHORT(pic->width)<<FRACBITS)/pblockwidth;
|
|
picbpp = format2bpp(picmode2GR[pic->mode]);
|
|
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 = palette[texel];
|
|
memcpy(dest, &col, sizeof(RGBA_t)-sizeof(UINT8));
|
|
dest += sizeof(RGBA_t)-sizeof(UINT8);
|
|
break;
|
|
case 4 :
|
|
memcpy(dest, &palette[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 :
|
|
// -----------------+
|
|
patch_t *HWR_GetPic(lumpnum_t lumpnum)
|
|
{
|
|
patch_t *patch = HWR_GetCachedGLPatch(lumpnum);
|
|
GLPatch_t *grPatch = (GLPatch_t *)(patch->hardware);
|
|
|
|
if (!grPatch->mipmap->downloaded && !grPatch->mipmap->data)
|
|
{
|
|
pic_t *pic;
|
|
UINT8 *block;
|
|
size_t len;
|
|
|
|
pic = W_CacheLumpNum(lumpnum, PU_CACHE);
|
|
patch->width = SHORT(pic->width);
|
|
patch->height = SHORT(pic->height);
|
|
len = W_LumpLength(lumpnum) - sizeof (pic_t);
|
|
|
|
grPatch->mipmap->width = (UINT16)patch->width;
|
|
grPatch->mipmap->height = (UINT16)patch->height;
|
|
|
|
if (pic->mode == PALETTE)
|
|
grPatch->mipmap->format = textureformat; // can be set by driver
|
|
else
|
|
grPatch->mipmap->format = picmode2GR[pic->mode];
|
|
|
|
Z_Free(grPatch->mipmap->data);
|
|
|
|
// allocate block
|
|
block = MakeBlock(grPatch->mipmap);
|
|
|
|
if (patch->width == SHORT(pic->width) &&
|
|
patch->height == SHORT(pic->height) &&
|
|
format2bpp(grPatch->mipmap->format) == format2bpp(picmode2GR[pic->mode]))
|
|
{
|
|
// no conversion needed
|
|
memcpy(grPatch->mipmap->data, pic->data,len);
|
|
}
|
|
else
|
|
HWR_DrawPicInCache(block, SHORT(pic->width), SHORT(pic->height),
|
|
SHORT(pic->width)*format2bpp(grPatch->mipmap->format),
|
|
pic,
|
|
format2bpp(grPatch->mipmap->format));
|
|
|
|
Z_Unlock(pic);
|
|
Z_ChangeTag(block, PU_HWRCACHE_UNLOCKED);
|
|
|
|
grPatch->mipmap->flags = 0;
|
|
grPatch->max_s = grPatch->max_t = 1.0f;
|
|
}
|
|
HWD.pfnSetTexture(grPatch->mipmap);
|
|
//CONS_Debug(DBG_RENDER, "picloaded at %x as texture %d\n",grPatch->mipmap->data, grPatch->mipmap->downloaded);
|
|
|
|
return patch;
|
|
}
|
|
|
|
patch_t *HWR_GetCachedGLPatchPwad(UINT16 wadnum, UINT16 lumpnum)
|
|
{
|
|
lumpcache_t *lumpcache = wadfiles[wadnum]->patchcache;
|
|
if (!lumpcache[lumpnum])
|
|
{
|
|
void *ptr = Z_Calloc(sizeof(patch_t), PU_PATCH, &lumpcache[lumpnum]);
|
|
Patch_Create(NULL, 0, ptr);
|
|
Patch_AllocateHardwarePatch(ptr);
|
|
}
|
|
return (patch_t *)(lumpcache[lumpnum]);
|
|
}
|
|
|
|
patch_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;
|
|
UINT8 *block = mipmap->data; // places the data directly into here
|
|
UINT8 *flat;
|
|
UINT8 *dest, *src, texel;
|
|
RGBA_t col;
|
|
RGBA_t *palette = HWR_GetTexturePalette();
|
|
|
|
// Place the flats data into flat
|
|
W_ReadLump(fademasklumpnum, Z_Malloc(W_LumpLength(fademasklumpnum),
|
|
PU_HWRCACHE, &flat));
|
|
|
|
stepy = ((INT32)fmheight<<FRACBITS)/pblockheight;
|
|
stepx = ((INT32)fmwidth<<FRACBITS)/pblockwidth;
|
|
posy = 0;
|
|
for (j = 0; j < pblockheight; j++)
|
|
{
|
|
posx = 0;
|
|
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 = palette[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
|
|
fmwidth = 0;
|
|
fmheight = 0;
|
|
return;
|
|
}
|
|
|
|
// Thankfully, this will still work for this scenario
|
|
grMipmap->width = fmwidth;
|
|
grMipmap->height = fmheight;
|
|
|
|
MakeBlock(grMipmap);
|
|
|
|
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)
|
|
{
|
|
patch_t *patch = HWR_GetCachedGLPatch(fademasklumpnum);
|
|
GLMipmap_t *grmip = ((GLPatch_t *)Patch_AllocateHardwarePatch(patch))->mipmap;
|
|
if (!grmip->downloaded && !grmip->data)
|
|
HWR_CacheFadeMask(grmip, fademasklumpnum);
|
|
|
|
HWD.pfnSetTexture(grmip);
|
|
|
|
// The system-memory data can be purged now.
|
|
Z_ChangeTag(grmip->data, PU_HWRCACHE_UNLOCKED);
|
|
}
|
|
|
|
// =================================================
|
|
// PALETTE HANDLING
|
|
// =================================================
|
|
|
|
void HWR_SetPalette(RGBA_t *palette)
|
|
{
|
|
if (HWR_ShouldUsePaletteRendering())
|
|
{
|
|
// set the palette for palette postprocessing
|
|
|
|
if (cv_glpalettedepth.value == 16)
|
|
{
|
|
// crush to 16-bit rgb565, like software currently does in the standard configuration
|
|
// Note: Software's screenshots have the 24-bit palette, but the screen gets
|
|
// the 16-bit version! For making comparison screenshots either use an external screenshot
|
|
// tool or set the palette depth to 24 bits.
|
|
RGBA_t crushed_palette[256];
|
|
int i;
|
|
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
float fred = (float)(palette[i].s.red >> 3);
|
|
float fgreen = (float)(palette[i].s.green >> 2);
|
|
float fblue = (float)(palette[i].s.blue >> 3);
|
|
crushed_palette[i].s.red = (UINT8)(fred / 31.0f * 255.0f);
|
|
crushed_palette[i].s.green = (UINT8)(fgreen / 63.0f * 255.0f);
|
|
crushed_palette[i].s.blue = (UINT8)(fblue / 31.0f * 255.0f);
|
|
crushed_palette[i].s.alpha = 255;
|
|
}
|
|
|
|
HWD.pfnSetScreenPalette(crushed_palette);
|
|
}
|
|
else
|
|
{
|
|
HWD.pfnSetScreenPalette(palette);
|
|
}
|
|
|
|
// this part is responsible for keeping track of the palette OUTSIDE of a level.
|
|
if (!(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction)))
|
|
HWR_SetMapPalette();
|
|
}
|
|
else
|
|
{
|
|
// set the palette for the textures
|
|
HWD.pfnSetTexturePalette(palette);
|
|
// reset mapPalette so next call to HWR_SetMapPalette will update everything correctly
|
|
memset(mapPalette, 0, sizeof(mapPalette));
|
|
// 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)
|
|
{
|
|
Z_FreeTag(PU_HWRCACHE);
|
|
Z_FreeTag(PU_HWRCACHE_UNLOCKED);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void HWR_SetPaletteLookup(RGBA_t *palette)
|
|
{
|
|
int r, g, b;
|
|
UINT8 *lut = Z_Malloc(
|
|
HWR_PALETTE_LUT_SIZE*HWR_PALETTE_LUT_SIZE*HWR_PALETTE_LUT_SIZE*sizeof(UINT8),
|
|
PU_STATIC, NULL);
|
|
#define STEP_SIZE (256/HWR_PALETTE_LUT_SIZE)
|
|
for (b = 0; b < HWR_PALETTE_LUT_SIZE; b++)
|
|
{
|
|
for (g = 0; g < HWR_PALETTE_LUT_SIZE; g++)
|
|
{
|
|
for (r = 0; r < HWR_PALETTE_LUT_SIZE; r++)
|
|
{
|
|
lut[b*HWR_PALETTE_LUT_SIZE*HWR_PALETTE_LUT_SIZE+g*HWR_PALETTE_LUT_SIZE+r] =
|
|
NearestPaletteColor(r*STEP_SIZE, g*STEP_SIZE, b*STEP_SIZE, palette);
|
|
}
|
|
}
|
|
}
|
|
#undef STEP_SIZE
|
|
HWD.pfnSetPaletteLookup(lut);
|
|
Z_Free(lut);
|
|
}
|
|
|
|
// Updates mapPalette to reflect the loaded level or other game state.
|
|
// Textures are flushed if needed.
|
|
// Call this function only in palette rendering mode.
|
|
void HWR_SetMapPalette(void)
|
|
{
|
|
RGBA_t RGBA_converted[256];
|
|
RGBA_t *palette;
|
|
int i;
|
|
|
|
if (!(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction)))
|
|
{
|
|
// outside of a level, pMasterPalette should have PLAYPAL ready for us
|
|
palette = pMasterPalette;
|
|
}
|
|
else
|
|
{
|
|
// in a level pMasterPalette might have a flash palette, but we
|
|
// want the map's original palette.
|
|
lumpnum_t lumpnum = W_GetNumForName(GetPalette());
|
|
size_t palsize = W_LumpLength(lumpnum);
|
|
UINT8 *RGB_data;
|
|
|
|
if (palsize < 768) // 256 * 3
|
|
I_Error("HWR_SetMapPalette: A programmer assumed palette lumps are at least 768 bytes long, but apparently this was a wrong assumption!\n");
|
|
|
|
RGB_data = W_CacheLumpNum(lumpnum, PU_CACHE);
|
|
// we got the RGB palette now, but we need it in RGBA format.
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
RGBA_converted[i].s.red = *(RGB_data++);
|
|
RGBA_converted[i].s.green = *(RGB_data++);
|
|
RGBA_converted[i].s.blue = *(RGB_data++);
|
|
RGBA_converted[i].s.alpha = 255;
|
|
}
|
|
|
|
// remap the palette from 2.1 to 2.2 indices in compatmode
|
|
RGBA_t *palcopy = NULL;
|
|
|
|
if (wadfiles[WADFILENUM(lumpnum)]->compatmode)
|
|
{
|
|
palcopy = malloc(sizeof(*palcopy)*256);
|
|
memcpy(palcopy, RGBA_converted, sizeof(*palcopy)*256);
|
|
}
|
|
|
|
if (palcopy)
|
|
{
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
RGBA_converted[i].rgba = palcopy[R_InvPaletteRemap(i)].rgba;
|
|
}
|
|
|
|
free(palcopy);
|
|
}
|
|
|
|
palette = RGBA_converted;
|
|
}
|
|
|
|
// check if the palette has changed from the previous one
|
|
if (memcmp(mapPalette, palette, sizeof(mapPalette)))
|
|
{
|
|
memcpy(mapPalette, palette, sizeof(mapPalette));
|
|
|
|
// in palette rendering mode, this means that all rgba textures now have wrong colors
|
|
// and the lookup table is outdated
|
|
HWR_SetPaletteLookup(mapPalette);
|
|
HWD.pfnSetTexturePalette(mapPalette);
|
|
|
|
if (patchformat == GL_TEXFMT_RGBA || textureformat == GL_TEXFMT_RGBA)
|
|
{
|
|
Z_FreeTag(PU_HWRCACHE);
|
|
Z_FreeTag(PU_HWRCACHE_UNLOCKED);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Creates a hardware lighttable from the supplied lighttable.
|
|
// Returns the id of the hw lighttable, usable in FSurfaceInfo.
|
|
UINT32 HWR_CreateLightTable(UINT8 *lighttable)
|
|
{
|
|
UINT32 i, id;
|
|
RGBA_t *palette = HWR_GetTexturePalette();
|
|
RGBA_t *hw_lighttable = Z_Malloc(256 * 32 * sizeof(RGBA_t), PU_STATIC, NULL);
|
|
|
|
// To make the palette index -> RGBA mapping easier for the shader,
|
|
// the hardware lighttable is composed of RGBA colors instead of palette indices.
|
|
for (i = 0; i < 256 * 32; i++)
|
|
hw_lighttable[i] = palette[lighttable[i]];
|
|
|
|
id = HWD.pfnCreateLightTable(hw_lighttable);
|
|
Z_Free(hw_lighttable);
|
|
return id;
|
|
}
|
|
|
|
// get hwr lighttable id for colormap, create it if it doesn't already exist
|
|
UINT32 HWR_GetLightTableID(extracolormap_t *colormap)
|
|
{
|
|
boolean default_colormap = false;
|
|
if (!colormap)
|
|
{
|
|
colormap = R_GetDefaultColormap(); // a place to store the hw lighttable id
|
|
// alternatively could just store the id in a global variable if there are issues
|
|
default_colormap = true;
|
|
}
|
|
|
|
// create hw lighttable if there isn't one
|
|
if (!colormap->gl_lighttable_id)
|
|
{
|
|
UINT8 *colormap_pointer;
|
|
|
|
if (default_colormap)
|
|
colormap_pointer = colormaps; // don't actually use the data from the "default colormap"
|
|
else
|
|
colormap_pointer = colormap->colormap;
|
|
colormap->gl_lighttable_id = HWR_CreateLightTable(colormap_pointer);
|
|
}
|
|
|
|
return colormap->gl_lighttable_id;
|
|
}
|
|
|
|
// Note: all hardware lighttable ids assigned before this
|
|
// call become invalid and must not be used.
|
|
void HWR_ClearLightTables(void)
|
|
{
|
|
if (vid.glstate == VID_GL_LIBRARY_LOADED)
|
|
HWD.pfnClearLightTables();
|
|
}
|
|
|
|
#endif //HWRENDER
|