OpenGL palette rendering and related things

This commit is contained in:
Hannu Hanhi 2021-05-16 01:38:23 +03:00
parent 118fc58192
commit ac1b5ae546
14 changed files with 719 additions and 122 deletions

View file

@ -32,6 +32,14 @@
INT32 patchformat = GL_TEXFMT_AP_88; // use alpha for holes INT32 patchformat = GL_TEXFMT_AP_88; // use alpha for holes
INT32 textureformat = GL_TEXFMT_P_8; // use chromakey for hole 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.
static RGBA_t *HWR_GetTexturePalette(void)
{
return HWR_ShouldUsePaletteRendering() ? mapPalette : pLocalPalette;
}
static INT32 format2bpp(GLTextureFormat_t format) static INT32 format2bpp(GLTextureFormat_t format)
{ {
if (format == GL_TEXFMT_RGBA) if (format == GL_TEXFMT_RGBA)
@ -49,7 +57,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm
INT32 pblockheight, INT32 blockmodulo, INT32 pblockheight, INT32 blockmodulo,
fixed_t yfracstep, fixed_t scale_y, fixed_t yfracstep, fixed_t scale_y,
texpatch_t *originPatch, INT32 patchheight, texpatch_t *originPatch, INT32 patchheight,
INT32 bpp) INT32 bpp, RGBA_t *palette)
{ {
fixed_t yfrac, position, count; fixed_t yfrac, position, count;
UINT8 *dest; UINT8 *dest;
@ -121,7 +129,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm
texelu16 = (UINT16)((alpha<<8) | texel); texelu16 = (UINT16)((alpha<<8) | texel);
memcpy(dest, &texelu16, sizeof(UINT16)); memcpy(dest, &texelu16, sizeof(UINT16));
break; break;
case 3 : colortemp = V_GetColor(texel); case 3 : colortemp = palette[texel];
if ((originPatch != NULL) && (originPatch->style != AST_COPY)) if ((originPatch != NULL) && (originPatch->style != AST_COPY))
{ {
RGBA_t rgbatexel; RGBA_t rgbatexel;
@ -130,7 +138,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm
} }
memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8)); memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8));
break; break;
case 4 : colortemp = V_GetColor(texel); case 4 : colortemp = palette[texel];
colortemp.s.alpha = alpha; colortemp.s.alpha = alpha;
if ((originPatch != NULL) && (originPatch->style != AST_COPY)) if ((originPatch != NULL) && (originPatch->style != AST_COPY))
{ {
@ -160,7 +168,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block,
INT32 pblockheight, INT32 blockmodulo, INT32 pblockheight, INT32 blockmodulo,
fixed_t yfracstep, fixed_t scale_y, fixed_t yfracstep, fixed_t scale_y,
texpatch_t *originPatch, INT32 patchheight, texpatch_t *originPatch, INT32 patchheight,
INT32 bpp) INT32 bpp, RGBA_t *palette)
{ {
fixed_t yfrac, position, count; fixed_t yfrac, position, count;
UINT8 *dest; UINT8 *dest;
@ -231,7 +239,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block,
texelu16 = (UINT16)((alpha<<8) | texel); texelu16 = (UINT16)((alpha<<8) | texel);
memcpy(dest, &texelu16, sizeof(UINT16)); memcpy(dest, &texelu16, sizeof(UINT16));
break; break;
case 3 : colortemp = V_GetColor(texel); case 3 : colortemp = palette[texel];
if ((originPatch != NULL) && (originPatch->style != AST_COPY)) if ((originPatch != NULL) && (originPatch->style != AST_COPY))
{ {
RGBA_t rgbatexel; RGBA_t rgbatexel;
@ -240,7 +248,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block,
} }
memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8)); memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8));
break; break;
case 4 : colortemp = V_GetColor(texel); case 4 : colortemp = palette[texel];
colortemp.s.alpha = alpha; colortemp.s.alpha = alpha;
if ((originPatch != NULL) && (originPatch->style != AST_COPY)) if ((originPatch != NULL) && (originPatch->style != AST_COPY))
{ {
@ -284,10 +292,13 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap,
UINT8 *block = mipmap->data; UINT8 *block = mipmap->data;
INT32 bpp; INT32 bpp;
INT32 blockmodulo; INT32 blockmodulo;
RGBA_t *palette;
if (pwidth <= 0 || pheight <= 0) if (pwidth <= 0 || pheight <= 0)
return; return;
palette = HWR_GetTexturePalette();
ncols = pwidth; ncols = pwidth;
// source advance // source advance
@ -313,7 +324,7 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap,
pblockheight, blockmodulo, pblockheight, blockmodulo,
yfracstep, scale_y, yfracstep, scale_y,
NULL, pheight, // not that pheight is going to get used anyway... NULL, pheight, // not that pheight is going to get used anyway...
bpp); bpp, palette);
} }
} }
@ -332,16 +343,19 @@ static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap,
INT32 bpp; INT32 bpp;
INT32 blockmodulo; INT32 blockmodulo;
INT32 width, height; INT32 width, height;
RGBA_t *palette;
// Column drawing function pointer. // Column drawing function pointer.
static void (*ColumnDrawerPointer)(const column_t *patchcol, UINT8 *block, GLMipmap_t *mipmap, static void (*ColumnDrawerPointer)(const column_t *patchcol, UINT8 *block, GLMipmap_t *mipmap,
INT32 pblockheight, INT32 blockmodulo, INT32 pblockheight, INT32 blockmodulo,
fixed_t yfracstep, fixed_t scale_y, fixed_t yfracstep, fixed_t scale_y,
texpatch_t *originPatch, INT32 patchheight, texpatch_t *originPatch, INT32 patchheight,
INT32 bpp); INT32 bpp, RGBA_t *palette);
if (texture->width <= 0 || texture->height <= 0) if (texture->width <= 0 || texture->height <= 0)
return; return;
palette = HWR_GetTexturePalette();
ColumnDrawerPointer = (patch->flip & 2) ? HWR_DrawFlippedColumnInCache : HWR_DrawColumnInCache; ColumnDrawerPointer = (patch->flip & 2) ? HWR_DrawFlippedColumnInCache : HWR_DrawColumnInCache;
x1 = patch->originx; x1 = patch->originx;
@ -409,7 +423,7 @@ static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap,
pblockheight, blockmodulo, pblockheight, blockmodulo,
yfracstep, scale_y, yfracstep, scale_y,
patch, height, patch, height,
bpp); bpp, palette);
} }
} }
@ -454,6 +468,9 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex)
INT32 i; INT32 i;
boolean skyspecial = false; //poor hack for Legacy large skies.. boolean skyspecial = false; //poor hack for Legacy large skies..
RGBA_t *palette;
palette = HWR_GetTexturePalette();
texture = textures[texnum]; texture = textures[texnum];
// hack the Legacy skies.. // hack the Legacy skies..
@ -472,7 +489,10 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex)
grtex->mipmap.width = (UINT16)texture->width; grtex->mipmap.width = (UINT16)texture->width;
grtex->mipmap.height = (UINT16)texture->height; grtex->mipmap.height = (UINT16)texture->height;
grtex->mipmap.format = textureformat; if (skyspecial)
grtex->mipmap.format = GL_TEXFMT_RGBA; // that skyspecial code below assumes this format ...
else
grtex->mipmap.format = textureformat;
blockwidth = texture->width; blockwidth = texture->width;
blockheight = texture->height; blockheight = texture->height;
@ -484,7 +504,7 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex)
INT32 j; INT32 j;
RGBA_t col; RGBA_t col;
col = V_GetColor(HWR_PATCHES_CHROMAKEY_COLORINDEX); col = palette[HWR_PATCHES_CHROMAKEY_COLORINDEX];
for (j = 0; j < blockheight; j++) for (j = 0; j < blockheight; j++)
{ {
for (i = 0; i < blockwidth; i++) for (i = 0; i < blockwidth; i++)
@ -759,19 +779,6 @@ void HWR_LoadMapTextures(size_t pnumtextures)
gl_maptexturesloaded = true; gl_maptexturesloaded = true;
} }
void HWR_SetPalette(RGBA_t *palette)
{
HWD.pfnSetPalette(palette);
// 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);
}
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// Make sure texture is downloaded and set it as the source // Make sure texture is downloaded and set it as the source
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -1111,6 +1118,7 @@ static void HWR_DrawPicInCache(UINT8 *block, INT32 pblockwidth, INT32 pblockheig
UINT16 texelu16; UINT16 texelu16;
INT32 picbpp; INT32 picbpp;
RGBA_t col; RGBA_t col;
RGBA_t *palette = HWR_GetTexturePalette();
stepy = ((INT32)SHORT(pic->height)<<FRACBITS)/pblockheight; stepy = ((INT32)SHORT(pic->height)<<FRACBITS)/pblockheight;
stepx = ((INT32)SHORT(pic->width)<<FRACBITS)/pblockwidth; stepx = ((INT32)SHORT(pic->width)<<FRACBITS)/pblockwidth;
@ -1137,12 +1145,12 @@ static void HWR_DrawPicInCache(UINT8 *block, INT32 pblockwidth, INT32 pblockheig
dest += sizeof(UINT16); dest += sizeof(UINT16);
break; break;
case 3 : case 3 :
col = V_GetColor(texel); col = palette[texel];
memcpy(dest, &col, sizeof(RGBA_t)-sizeof(UINT8)); memcpy(dest, &col, sizeof(RGBA_t)-sizeof(UINT8));
dest += sizeof(RGBA_t)-sizeof(UINT8); dest += sizeof(RGBA_t)-sizeof(UINT8);
break; break;
case 4 : case 4 :
memcpy(dest, &V_GetColor(texel), sizeof(RGBA_t)); memcpy(dest, &palette[texel], sizeof(RGBA_t));
dest += sizeof(RGBA_t); dest += sizeof(RGBA_t);
break; break;
} }
@ -1252,6 +1260,7 @@ static void HWR_DrawFadeMaskInCache(GLMipmap_t *mipmap, INT32 pblockwidth, INT32
UINT8 *flat; UINT8 *flat;
UINT8 *dest, *src, texel; UINT8 *dest, *src, texel;
RGBA_t col; RGBA_t col;
RGBA_t *palette = HWR_GetTexturePalette();
// Place the flats data into flat // Place the flats data into flat
W_ReadLump(fademasklumpnum, Z_Malloc(W_LumpLength(fademasklumpnum), W_ReadLump(fademasklumpnum, Z_Malloc(W_LumpLength(fademasklumpnum),
@ -1269,7 +1278,7 @@ static void HWR_DrawFadeMaskInCache(GLMipmap_t *mipmap, INT32 pblockwidth, INT32
{ {
// fademask bpp is always 1, and is used just for alpha // fademask bpp is always 1, and is used just for alpha
texel = src[(posx)>>FRACBITS]; texel = src[(posx)>>FRACBITS];
col = V_GetColor(texel); col = palette[texel];
*dest = col.s.red; // take the red level of the colour and use it for alpha, as fademasks do *dest = col.s.red; // take the red level of the colour and use it for alpha, as fademasks do
dest++; dest++;
@ -1341,4 +1350,159 @@ void HWR_GetFadeMask(lumpnum_t fademasklumpnum)
Z_ChangeTag(grmip->data, PU_HWRCACHE_UNLOCKED); 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;
}
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;
}
// 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 #endif //HWRENDER

View file

@ -18,6 +18,12 @@
#define ZCLIP_PLANE 4.0f // Used for the actual game drawing #define ZCLIP_PLANE 4.0f // Used for the actual game drawing
#define NZCLIP_PLANE 0.9f // Seems to be only used for the HUD and screen textures #define NZCLIP_PLANE 0.9f // Seems to be only used for the HUD and screen textures
// The width/height/depth of the palette lookup table used by palette rendering.
// Changing this also requires changing the shader code!
// Also assumed to be a power of two in some parts of the code.
// 64 seems to work perfectly for the vanilla palette.
#define HWR_PALETTE_LUT_SIZE 64
// ========================================================================== // ==========================================================================
// SIMPLE TYPES // SIMPLE TYPES
// ========================================================================== // ==========================================================================
@ -146,6 +152,7 @@ enum
SHADER_WATER, SHADER_WATER,
SHADER_FOG, SHADER_FOG,
SHADER_SKY, SHADER_SKY,
SHADER_PALETTE_POSTPROCESS,
NUMSHADERTARGETS, NUMSHADERTARGETS,
}; };
@ -275,6 +282,7 @@ struct FSurfaceInfo
RGBA_t PolyColor; RGBA_t PolyColor;
RGBA_t TintColor; RGBA_t TintColor;
RGBA_t FadeColor; RGBA_t FadeColor;
UINT32 LightTableId;
FLightInfo LightInfo; FLightInfo LightInfo;
}; };
typedef struct FSurfaceInfo FSurfaceInfo; typedef struct FSurfaceInfo FSurfaceInfo;
@ -282,7 +290,7 @@ typedef struct FSurfaceInfo FSurfaceInfo;
#define GL_DEFAULTMIX 0x00000000 #define GL_DEFAULTMIX 0x00000000
#define GL_DEFAULTFOG 0xFF000000 #define GL_DEFAULTFOG 0xFF000000
//Hurdler: added for backward compatibility // Various settings and states for the rendering backend.
enum hwdsetspecialstate enum hwdsetspecialstate
{ {
HWD_SET_MODEL_LIGHTING = 1, HWD_SET_MODEL_LIGHTING = 1,

View file

@ -32,7 +32,7 @@ EXPORT void HWRAPI(Shutdown) (void);
#ifdef _WINDOWS #ifdef _WINDOWS
EXPORT void HWRAPI(GetModeList) (vmode_t **pvidmodes, INT32 *numvidmodes); EXPORT void HWRAPI(GetModeList) (vmode_t **pvidmodes, INT32 *numvidmodes);
#endif #endif
EXPORT void HWRAPI(SetPalette) (RGBA_t *ppal); EXPORT void HWRAPI(SetTexturePalette) (RGBA_t *ppal);
EXPORT void HWRAPI(FinishUpdate) (INT32 waitvbl); EXPORT void HWRAPI(FinishUpdate) (INT32 waitvbl);
EXPORT void HWRAPI(Draw2DLine) (F2DCoord *v1, F2DCoord *v2, RGBA_t Color); EXPORT void HWRAPI(Draw2DLine) (F2DCoord *v1, F2DCoord *v2, RGBA_t Color);
EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags); EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags);
@ -47,10 +47,8 @@ EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32
EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip); EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip);
EXPORT void HWRAPI(ClearMipMapCache) (void); EXPORT void HWRAPI(ClearMipMapCache) (void);
//Hurdler: added for backward compatibility
EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value); EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value);
//Hurdler: added for new development
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface); EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface);
EXPORT void HWRAPI(CreateModelVBOs) (model_t *model); EXPORT void HWRAPI(CreateModelVBOs) (model_t *model);
EXPORT void HWRAPI(SetTransform) (FTransform *ptransform); EXPORT void HWRAPI(SetTransform) (FTransform *ptransform);
@ -76,6 +74,11 @@ EXPORT void HWRAPI(UnSetShader) (void);
EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value); EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value);
EXPORT void HWRAPI(SetPaletteLookup)(UINT8 *lut);
EXPORT UINT32 HWRAPI(CreateLightTable)(RGBA_t *hw_lighttable);
EXPORT void HWRAPI(ClearLightTables)(void);
EXPORT void HWRAPI(SetScreenPalette)(RGBA_t *palette);
// ========================================================================== // ==========================================================================
// HWR DRIVER OBJECT, FOR CLIENT PROGRAM // HWR DRIVER OBJECT, FOR CLIENT PROGRAM
// ========================================================================== // ==========================================================================
@ -85,7 +88,7 @@ EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value);
struct hwdriver_s struct hwdriver_s
{ {
Init pfnInit; Init pfnInit;
SetPalette pfnSetPalette; SetTexturePalette pfnSetTexturePalette;
FinishUpdate pfnFinishUpdate; FinishUpdate pfnFinishUpdate;
Draw2DLine pfnDraw2DLine; Draw2DLine pfnDraw2DLine;
DrawPolygon pfnDrawPolygon; DrawPolygon pfnDrawPolygon;
@ -99,7 +102,7 @@ struct hwdriver_s
ReadRect pfnReadRect; ReadRect pfnReadRect;
GClipRect pfnGClipRect; GClipRect pfnGClipRect;
ClearMipMapCache pfnClearMipMapCache; ClearMipMapCache pfnClearMipMapCache;
SetSpecialState pfnSetSpecialState;//Hurdler: added for backward compatibility SetSpecialState pfnSetSpecialState;
DrawModel pfnDrawModel; DrawModel pfnDrawModel;
CreateModelVBOs pfnCreateModelVBOs; CreateModelVBOs pfnCreateModelVBOs;
SetTransform pfnSetTransform; SetTransform pfnSetTransform;
@ -127,6 +130,11 @@ struct hwdriver_s
UnSetShader pfnUnSetShader; UnSetShader pfnUnSetShader;
SetShaderInfo pfnSetShaderInfo; SetShaderInfo pfnSetShaderInfo;
SetPaletteLookup pfnSetPaletteLookup;
CreateLightTable pfnCreateLightTable;
ClearLightTables pfnClearLightTables;
SetScreenPalette pfnSetScreenPalette;
}; };
extern struct hwdriver_s hwdriver; extern struct hwdriver_s hwdriver;

View file

@ -128,6 +128,9 @@ void HWR_FreeColormapCache(void);
void HWR_UnlockCachedPatch(GLPatch_t *gpatch); void HWR_UnlockCachedPatch(GLPatch_t *gpatch);
void HWR_SetPalette(RGBA_t *palette); void HWR_SetPalette(RGBA_t *palette);
void HWR_SetMapPalette(void);
UINT32 HWR_CreateLightTable(UINT8 *lighttable);
void HWR_ClearLightTables(void);
// -------- // --------

View file

@ -126,26 +126,6 @@ static line_t *gl_linedef;
static sector_t *gl_frontsector; static sector_t *gl_frontsector;
static sector_t *gl_backsector; static sector_t *gl_backsector;
// --------------------------------------------------------------------------
// STUFF FOR THE PROJECTION CODE
// --------------------------------------------------------------------------
FTransform atransform;
// duplicates of the main code, set after R_SetupFrame() passed them into sharedstruct,
// copied here for local use
static fixed_t dup_viewx, dup_viewy, dup_viewz;
static angle_t dup_viewangle;
static float gl_viewx, gl_viewy, gl_viewz;
static float gl_viewsin, gl_viewcos;
// Maybe not necessary with the new T&L code (needs to be checked!)
static float gl_viewludsin, gl_viewludcos; // look up down kik test
static float gl_fovlud;
static angle_t gl_aimingangle;
static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox);
// Render stats // Render stats
precise_t ps_hw_skyboxtime = 0; precise_t ps_hw_skyboxtime = 0;
precise_t ps_hw_nodesorttime = 0; precise_t ps_hw_nodesorttime = 0;
@ -170,6 +150,29 @@ boolean gl_sessioncommandsadded = false;
// false if shaders have not been initialized yet, or if shaders are not available // false if shaders have not been initialized yet, or if shaders are not available
boolean gl_shadersavailable = false; boolean gl_shadersavailable = false;
// Whether the internal state is set to palette rendering or not.
static boolean gl_palette_rendering_state = false;
// --------------------------------------------------------------------------
// STUFF FOR THE PROJECTION CODE
// --------------------------------------------------------------------------
FTransform atransform;
// duplicates of the main code, set after R_SetupFrame() passed them into sharedstruct,
// copied here for local use
static fixed_t dup_viewx, dup_viewy, dup_viewz;
static angle_t dup_viewangle;
static float gl_viewx, gl_viewy, gl_viewz;
static float gl_viewsin, gl_viewcos;
// Maybe not necessary with the new T&L code (needs to be checked!)
static float gl_viewludsin, gl_viewludcos; // look up down kik test
static float gl_fovlud;
static angle_t gl_aimingangle;
static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox);
// ========================================================================== // ==========================================================================
// Lighting // Lighting
// ========================================================================== // ==========================================================================
@ -234,6 +237,33 @@ void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *col
Surface->LightInfo.light_level = light_level; Surface->LightInfo.light_level = light_level;
Surface->LightInfo.fade_start = (colormap != NULL) ? colormap->fadestart : 0; Surface->LightInfo.fade_start = (colormap != NULL) ? colormap->fadestart : 0;
Surface->LightInfo.fade_end = (colormap != NULL) ? colormap->fadeend : 31; Surface->LightInfo.fade_end = (colormap != NULL) ? colormap->fadeend : 31;
if (HWR_ShouldUsePaletteRendering())
{
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);
}
Surface->LightTableId = colormap->gl_lighttable_id;
}
else
{
Surface->LightTableId = 0;
}
} }
UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap) // Let's see if this can work UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap) // Let's see if this can work
@ -905,13 +935,15 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum,
{ {
if (pfloor && (pfloor->flags & FF_FOG)) if (pfloor && (pfloor->flags & FF_FOG))
{ {
lightnum = HWR_CalcWallLight(pfloor->master->frontsector->lightlevel, v1x, v1y, v2x, v2y); lightnum = pfloor->master->frontsector->lightlevel;
colormap = pfloor->master->frontsector->extra_colormap; colormap = pfloor->master->frontsector->extra_colormap;
lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, v1x, v1y, v2x, v2y);
} }
else else
{ {
lightnum = HWR_CalcWallLight(*list[i].lightlevel, v1x, v1y, v2x, v2y); lightnum = *list[i].lightlevel;
colormap = *list[i].extra_colormap; colormap = *list[i].extra_colormap;
lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, v1x, v1y, v2x, v2y);
} }
} }
@ -1113,8 +1145,9 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
cliphigh = (float)(texturehpeg + (gl_curline->flength*FRACUNIT)); cliphigh = (float)(texturehpeg + (gl_curline->flength*FRACUNIT));
} }
lightnum = HWR_CalcWallLight(gl_frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); lightnum = gl_frontsector->lightlevel;
colormap = gl_frontsector->extra_colormap; colormap = gl_frontsector->extra_colormap;
lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y);
if (gl_frontsector) if (gl_frontsector)
Surf.PolyColor.s.alpha = 255; Surf.PolyColor.s.alpha = 255;
@ -1739,8 +1772,9 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
blendmode = PF_Fog|PF_NoTexture; blendmode = PF_Fog|PF_NoTexture;
lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); lightnum = rover->master->frontsector->lightlevel;
colormap = rover->master->frontsector->extra_colormap; colormap = rover->master->frontsector->extra_colormap;
lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y);
Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap); Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap);
@ -1851,8 +1885,9 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
blendmode = PF_Fog|PF_NoTexture; blendmode = PF_Fog|PF_NoTexture;
lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); lightnum = rover->master->frontsector->lightlevel;
colormap = rover->master->frontsector->extra_colormap; colormap = rover->master->frontsector->extra_colormap;
lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y);
Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap); Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap);
@ -5867,6 +5902,7 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
else else
type = &postimgtype; type = &postimgtype;
if (!HWR_ShouldUsePaletteRendering())
{ {
// do we really need to save player (is it not the same)? // do we really need to save player (is it not the same)?
player_t *saved_player = stplyr; player_t *saved_player = stplyr;
@ -6080,6 +6116,7 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
HWR_RenderSkyboxView(viewnumber, player); // This is drawn before everything else so it is placed behind HWR_RenderSkyboxView(viewnumber, player); // This is drawn before everything else so it is placed behind
ps_hw_skyboxtime = I_GetPreciseTime() - ps_hw_skyboxtime; ps_hw_skyboxtime = I_GetPreciseTime() - ps_hw_skyboxtime;
if (!HWR_ShouldUsePaletteRendering())
{ {
// do we really need to save player (is it not the same)? // do we really need to save player (is it not the same)?
player_t *saved_player = stplyr; player_t *saved_player = stplyr;
@ -6277,6 +6314,56 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
HWD.pfnGClipRect(0, 0, vid.width, vid.height, NZCLIP_PLANE); HWD.pfnGClipRect(0, 0, vid.width, vid.height, NZCLIP_PLANE);
} }
// Returns whether palette rendering is "actually enabled."
// Can't have palette rendering if shaders are disabled.
boolean HWR_ShouldUsePaletteRendering(void)
{
return (cv_glpaletterendering.value && HWR_UseShader());
}
// enable or disable palette rendering state depending on settings and availability
// called when relevant settings change
// shader recompilation is done in the cvar callback
static void HWR_TogglePaletteRendering(void)
{
// which state should we go to?
if (HWR_ShouldUsePaletteRendering())
{
// are we not in that state already?
if (!gl_palette_rendering_state)
{
gl_palette_rendering_state = true;
// The textures will still be converted to RGBA by r_opengl.
// This however makes hw_cache use paletted blending for composite textures!
// (patchformat is not touched)
textureformat = GL_TEXFMT_P_8;
HWR_SetMapPalette();
HWR_SetPalette(pLocalPalette);
// If the r_opengl "texture palette" stays the same during this switch, the textures
// will not be cleared out. However they are still out of date since the
// composite texture blending method has changed. Therefore they need to be cleared.
HWD.pfnClearMipMapCache();
}
}
else
{
// are we not in that state already?
if (gl_palette_rendering_state)
{
gl_palette_rendering_state = false;
textureformat = GL_TEXFMT_RGBA;
HWR_SetPalette(pLocalPalette);
// If the r_opengl "texture palette" stays the same during this switch, the textures
// will not be cleared out. However they are still out of date since the
// composite texture blending method has changed. Therefore they need to be cleared.
HWD.pfnClearMipMapCache();
}
}
}
void HWR_LoadLevel(void) void HWR_LoadLevel(void)
{ {
#ifdef ALAM_LIGHTING #ifdef ALAM_LIGHTING
@ -6290,6 +6377,9 @@ void HWR_LoadLevel(void)
HWR_ClearSkyDome(); HWR_ClearSkyDome();
HWR_BuildSkyDome(); HWR_BuildSkyDome();
if (HWR_ShouldUsePaletteRendering())
HWR_SetMapPalette();
gl_maploaded = true; gl_maploaded = true;
} }
@ -6305,6 +6395,9 @@ static CV_PossibleValue_t glshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Thi
static void CV_glfiltermode_OnChange(void); static void CV_glfiltermode_OnChange(void);
static void CV_glanisotropic_OnChange(void); static void CV_glanisotropic_OnChange(void);
static void CV_glmodellighting_OnChange(void); static void CV_glmodellighting_OnChange(void);
static void CV_glpaletterendering_OnChange(void);
static void CV_glpalettedepth_OnChange(void);
static void CV_glshaders_OnChange(void);
static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"}, static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"},
{HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"}, {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"}, {HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"}, {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"},
@ -6314,7 +6407,7 @@ static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSA
{0, NULL}}; {0, NULL}};
CV_PossibleValue_t glanisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}}; CV_PossibleValue_t glanisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}};
consvar_t cv_glshaders = CVAR_INIT ("gr_shaders", "On", CV_SAVE, glshaders_cons_t, NULL); consvar_t cv_glshaders = CVAR_INIT ("gr_shaders", "On", CV_SAVE|CV_CALL, glshaders_cons_t, CV_glshaders_OnChange);
consvar_t cv_glallowshaders = CVAR_INIT ("gr_allowclientshaders", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_glallowshaders = CVAR_INIT ("gr_allowclientshaders", "On", CV_NETVAR, CV_OnOff, NULL);
consvar_t cv_fovchange = CVAR_INIT ("gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL); consvar_t cv_fovchange = CVAR_INIT ("gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL);
@ -6342,6 +6435,11 @@ consvar_t cv_glsolvetjoin = CVAR_INIT ("gr_solvetjoin", "On", 0, CV_OnOff, NULL)
consvar_t cv_glbatching = CVAR_INIT ("gr_batching", "On", 0, CV_OnOff, NULL); consvar_t cv_glbatching = CVAR_INIT ("gr_batching", "On", 0, CV_OnOff, NULL);
static CV_PossibleValue_t glpalettedepth_cons_t[] = {{16, "16 bits"}, {24, "24 bits"}, {0, NULL}};
consvar_t cv_glpaletterendering = CVAR_INIT ("gr_paletterendering", "Off", CV_SAVE|CV_CALL, CV_OnOff, CV_glpaletterendering_OnChange);
consvar_t cv_glpalettedepth = CVAR_INIT ("gr_palettedepth", "16 bits", CV_SAVE|CV_CALL, glpalettedepth_cons_t, CV_glpalettedepth_OnChange);
static void CV_glfiltermode_OnChange(void) static void CV_glfiltermode_OnChange(void)
{ {
if (rendermode == render_opengl) if (rendermode == render_opengl)
@ -6361,6 +6459,31 @@ static void CV_glmodellighting_OnChange(void)
HWR_CompileShaders(); HWR_CompileShaders();
} }
static void CV_glpaletterendering_OnChange(void)
{
if (gl_shadersavailable)
{
HWR_CompileShaders();
HWR_TogglePaletteRendering();
}
}
static void CV_glpalettedepth_OnChange(void)
{
// refresh the screen palette
if (HWR_ShouldUsePaletteRendering())
HWR_SetPalette(pLocalPalette);
}
static void CV_glshaders_OnChange(void)
{
if (cv_glpaletterendering.value)
{
// can't do palette rendering without shaders, so update the state if needed
HWR_TogglePaletteRendering();
}
}
//added by Hurdler: console varibale that are saved //added by Hurdler: console varibale that are saved
void HWR_AddCommands(void) void HWR_AddCommands(void)
{ {
@ -6389,6 +6512,9 @@ void HWR_AddCommands(void)
CV_RegisterVar(&cv_glbatching); CV_RegisterVar(&cv_glbatching);
CV_RegisterVar(&cv_glpaletterendering);
CV_RegisterVar(&cv_glpalettedepth);
#ifndef NEWCLIP #ifndef NEWCLIP
CV_RegisterVar(&cv_glclipwalls); CV_RegisterVar(&cv_glclipwalls);
#endif #endif
@ -6411,6 +6537,8 @@ void HWR_Startup(void)
{ {
CONS_Printf("HWR_Startup()...\n"); CONS_Printf("HWR_Startup()...\n");
textureformat = patchformat = GL_TEXFMT_RGBA;
HWR_InitPolyPool(); HWR_InitPolyPool();
HWR_AddSessionCommands(); HWR_AddSessionCommands();
HWR_InitMapTextures(); HWR_InitMapTextures();
@ -6421,11 +6549,9 @@ void HWR_Startup(void)
gl_shadersavailable = HWR_InitShaders(); gl_shadersavailable = HWR_InitShaders();
HWR_LoadAllCustomShaders(); HWR_LoadAllCustomShaders();
HWR_TogglePaletteRendering();
} }
if (rendermode == render_opengl)
textureformat = patchformat = GL_TEXFMT_RGBA;
gl_init = true; gl_init = true;
} }
@ -6564,7 +6690,7 @@ void HWR_DoPostProcessor(player_t *player)
// Armageddon Blast Flash! // Armageddon Blast Flash!
// Could this even be considered postprocessor? // Could this even be considered postprocessor?
if (player->flashcount) if (player->flashcount && !HWR_ShouldUsePaletteRendering())
{ {
FOutVector v[4]; FOutVector v[4];
FSurfaceInfo Surf; FSurfaceInfo Surf;

View file

@ -74,6 +74,8 @@ FBITFIELD HWR_GetBlendModeFlag(INT32 ast);
FBITFIELD HWR_SurfaceBlend(INT32 style, INT32 transtablenum, FSurfaceInfo *pSurf); FBITFIELD HWR_SurfaceBlend(INT32 style, INT32 transtablenum, FSurfaceInfo *pSurf);
FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf); FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf);
boolean HWR_ShouldUsePaletteRendering(void);
extern CV_PossibleValue_t glanisotropicmode_cons_t[]; extern CV_PossibleValue_t glanisotropicmode_cons_t[];
#ifdef ALAM_LIGHTING #ifdef ALAM_LIGHTING
@ -96,8 +98,9 @@ extern consvar_t cv_glspritebillboarding;
extern consvar_t cv_glskydome; extern consvar_t cv_glskydome;
extern consvar_t cv_glfakecontrast; extern consvar_t cv_glfakecontrast;
extern consvar_t cv_glslopecontrast; extern consvar_t cv_glslopecontrast;
extern consvar_t cv_glbatching; extern consvar_t cv_glbatching;
extern consvar_t cv_glpaletterendering;
extern consvar_t cv_glpalettedepth;
extern float gl_viewwidth, gl_viewheight, gl_baseviewwindowy; extern float gl_viewwidth, gl_viewheight, gl_baseviewwindowy;

View file

@ -38,7 +38,7 @@
#define GLSL_MODEL_VERTEX_SHADER \ #define GLSL_MODEL_VERTEX_SHADER \
"void main()\n" \ "void main()\n" \
"{\n" \ "{\n" \
"#ifdef MODEL_LIGHTING\n" \ "#ifdef SRB2_MODEL_LIGHTING\n" \
"float nDotVP = dot(gl_Normal, vec3(0, 1, 0));\n" \ "float nDotVP = dot(gl_Normal, vec3(0, 1, 0));\n" \
"float light = 0.75 + max(nDotVP, 0.0);\n" \ "float light = 0.75 + max(nDotVP, 0.0);\n" \
"gl_FrontColor = vec4(light, light, light, 1.0);\n" \ "gl_FrontColor = vec4(light, light, light, 1.0);\n" \
@ -69,6 +69,7 @@
// Software fragment shader // Software fragment shader
// //
// Include GLSL_FLOOR_FUDGES or GLSL_WALL_FUDGES or define the fudges in shaders that use this macro.
#define GLSL_DOOM_COLORMAP \ #define GLSL_DOOM_COLORMAP \
"float R_DoomColormap(float light, float z)\n" \ "float R_DoomColormap(float light, float z)\n" \
"{\n" \ "{\n" \
@ -76,8 +77,12 @@
"float lightz = clamp(z / 16.0, 0.0, 127.0);\n" \ "float lightz = clamp(z / 16.0, 0.0, 127.0);\n" \
"float startmap = (15.0 - lightnum) * 4.0;\n" \ "float startmap = (15.0 - lightnum) * 4.0;\n" \
"float scale = 160.0 / (lightz + 1.0);\n" \ "float scale = 160.0 / (lightz + 1.0);\n" \
"return startmap - scale * 0.5;\n" \ "float cap = (155.0 - light) * 0.26;\n" \
"return max(startmap * STARTMAP_FUDGE - scale * 0.5 * SCALE_FUDGE, cap);\n" \
"}\n" "}\n"
// lighting cap adjustment:
// first num (155.0), increase to make it start to go dark sooner
// second num (0.26), increase to make it go dark faster
#define GLSL_DOOM_LIGHT_EQUATION \ #define GLSL_DOOM_LIGHT_EQUATION \
"float R_DoomLightingEquation(float light)\n" \ "float R_DoomLightingEquation(float light)\n" \
@ -106,7 +111,28 @@
"}\n" \ "}\n" \
"final_color = mix(final_color, fade_color, darkness);\n" "final_color = mix(final_color, fade_color, darkness);\n"
#define GLSL_PALETTE_RENDERING \
"float tex_pal_idx = texture3D(palette_lookup_tex, vec3((texel * 63.0 + 0.5) / 64.0))[0] * 255.0;\n" \
"float z = gl_FragCoord.z / gl_FragCoord.w;\n" \
"float light_y = clamp(floor(R_DoomColormap(lighting, z)), 0.0, 31.0);\n" \
"vec2 lighttable_coord = vec2((tex_pal_idx + 0.5) / 256.0, (light_y + 0.5) / 32.0);\n" \
"vec4 final_color = texture2D(lighttable_tex, lighttable_coord);\n" \
"final_color.a = texel.a * poly_color.a;\n" \
"gl_FragColor = final_color;\n" \
#define GLSL_SOFTWARE_FRAGMENT_SHADER \ #define GLSL_SOFTWARE_FRAGMENT_SHADER \
"#ifdef SRB2_PALETTE_RENDERING\n" \
"uniform sampler2D tex;\n" \
"uniform sampler3D palette_lookup_tex;\n" \
"uniform sampler2D lighttable_tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform float lighting;\n" \
GLSL_DOOM_COLORMAP \
"void main(void) {\n" \
"vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
GLSL_PALETTE_RENDERING \
"}\n" \
"#else\n" \
"uniform sampler2D tex;\n" \ "uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \ "uniform vec4 poly_color;\n" \
"uniform vec4 tint_color;\n" \ "uniform vec4 tint_color;\n" \
@ -124,11 +150,45 @@
GLSL_SOFTWARE_FADE_EQUATION \ GLSL_SOFTWARE_FADE_EQUATION \
"final_color.a = texel.a * poly_color.a;\n" \ "final_color.a = texel.a * poly_color.a;\n" \
"gl_FragColor = final_color;\n" \ "gl_FragColor = final_color;\n" \
"}\0" "}\n" \
"#endif\0"
// hand tuned adjustments for light level calculation
#define GLSL_FLOOR_FUDGES \
"#define STARTMAP_FUDGE 1.06\n" \
"#define SCALE_FUDGE 1.15\n"
#define GLSL_WALL_FUDGES \
"#define STARTMAP_FUDGE 1.05\n" \
"#define SCALE_FUDGE 2.2\n"
#define GLSL_SOFTWARE_FRAGMENT_SHADER_FLOORS \
GLSL_FLOOR_FUDGES \
GLSL_SOFTWARE_FRAGMENT_SHADER
#define GLSL_SOFTWARE_FRAGMENT_SHADER_WALLS \
GLSL_WALL_FUDGES \
GLSL_SOFTWARE_FRAGMENT_SHADER
// same as above but multiplies results with the lighting value from the // same as above but multiplies results with the lighting value from the
// accompanying vertex shader (stored in gl_Color) // accompanying vertex shader (stored in gl_Color) if model lighting is enabled
#define GLSL_SOFTWARE_MODEL_FRAGMENT_SHADER \ #define GLSL_SOFTWARE_MODEL_FRAGMENT_SHADER \
GLSL_WALL_FUDGES \
"#ifdef SRB2_PALETTE_RENDERING\n" \
"uniform sampler2D tex;\n" \
"uniform sampler3D palette_lookup_tex;\n" \
"uniform sampler2D lighttable_tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform float lighting;\n" \
GLSL_DOOM_COLORMAP \
"void main(void) {\n" \
"vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
"#ifdef SRB2_MODEL_LIGHTING\n" \
"texel *= gl_Color;\n" \
"#endif\n" \
GLSL_PALETTE_RENDERING \
"}\n" \
"#else\n" \
"uniform sampler2D tex;\n" \ "uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \ "uniform vec4 poly_color;\n" \
"uniform vec4 tint_color;\n" \ "uniform vec4 tint_color;\n" \
@ -144,12 +204,13 @@
"vec4 final_color = base_color;\n" \ "vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \ GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \ GLSL_SOFTWARE_FADE_EQUATION \
"#ifdef MODEL_LIGHTING\n" \ "#ifdef SRB2_MODEL_LIGHTING\n" \
"final_color *= gl_Color;\n" \ "final_color *= gl_Color;\n" \
"#endif\n" \ "#endif\n" \
"final_color.a = texel.a * poly_color.a;\n" \ "final_color.a = texel.a * poly_color.a;\n" \
"gl_FragColor = final_color;\n" \ "gl_FragColor = final_color;\n" \
"}\0" "}\n" \
"#endif\0"
// //
// Water surface shader // Water surface shader
@ -158,7 +219,32 @@
// Still needs to distort things underneath/around the water... // Still needs to distort things underneath/around the water...
// //
#define GLSL_WATER_TEXEL \
"float water_z = (gl_FragCoord.z / gl_FragCoord.w) / 2.0;\n" \
"float a = -pi * (water_z * freq) + (leveltime * speed);\n" \
"float sdistort = sin(a) * amp;\n" \
"float cdistort = cos(a) * amp;\n" \
"vec4 texel = texture2D(tex, vec2(gl_TexCoord[0].s - sdistort, gl_TexCoord[0].t - cdistort));\n"
#define GLSL_WATER_FRAGMENT_SHADER \ #define GLSL_WATER_FRAGMENT_SHADER \
GLSL_FLOOR_FUDGES \
"const float freq = 0.025;\n" \
"const float amp = 0.025;\n" \
"const float speed = 2.0;\n" \
"const float pi = 3.14159;\n" \
"#ifdef SRB2_PALETTE_RENDERING\n" \
"uniform sampler2D tex;\n" \
"uniform sampler3D palette_lookup_tex;\n" \
"uniform sampler2D lighttable_tex;\n" \
"uniform vec4 poly_color;\n" \
"uniform float lighting;\n" \
"uniform float leveltime;\n" \
GLSL_DOOM_COLORMAP \
"void main(void) {\n" \
GLSL_WATER_TEXEL \
GLSL_PALETTE_RENDERING \
"}\n" \
"#else\n" \
"uniform sampler2D tex;\n" \ "uniform sampler2D tex;\n" \
"uniform vec4 poly_color;\n" \ "uniform vec4 poly_color;\n" \
"uniform vec4 tint_color;\n" \ "uniform vec4 tint_color;\n" \
@ -167,25 +253,18 @@
"uniform float fade_start;\n" \ "uniform float fade_start;\n" \
"uniform float fade_end;\n" \ "uniform float fade_end;\n" \
"uniform float leveltime;\n" \ "uniform float leveltime;\n" \
"const float freq = 0.025;\n" \
"const float amp = 0.025;\n" \
"const float speed = 2.0;\n" \
"const float pi = 3.14159;\n" \
GLSL_DOOM_COLORMAP \ GLSL_DOOM_COLORMAP \
GLSL_DOOM_LIGHT_EQUATION \ GLSL_DOOM_LIGHT_EQUATION \
"void main(void) {\n" \ "void main(void) {\n" \
"float z = (gl_FragCoord.z / gl_FragCoord.w) / 2.0;\n" \ GLSL_WATER_TEXEL \
"float a = -pi * (z * freq) + (leveltime * speed);\n" \
"float sdistort = sin(a) * amp;\n" \
"float cdistort = cos(a) * amp;\n" \
"vec4 texel = texture2D(tex, vec2(gl_TexCoord[0].s - sdistort, gl_TexCoord[0].t - cdistort));\n" \
"vec4 base_color = texel * poly_color;\n" \ "vec4 base_color = texel * poly_color;\n" \
"vec4 final_color = base_color;\n" \ "vec4 final_color = base_color;\n" \
GLSL_SOFTWARE_TINT_EQUATION \ GLSL_SOFTWARE_TINT_EQUATION \
GLSL_SOFTWARE_FADE_EQUATION \ GLSL_SOFTWARE_FADE_EQUATION \
"final_color.a = texel.a * poly_color.a;\n" \ "final_color.a = texel.a * poly_color.a;\n" \
"gl_FragColor = final_color;\n" \ "gl_FragColor = final_color;\n" \
"}\0" "}\n" \
"#endif\0"
// //
// Fog block shader // Fog block shader
@ -193,7 +272,10 @@
// Alpha of the planes themselves are still slightly off -- see HWR_FogBlockAlpha // Alpha of the planes themselves are still slightly off -- see HWR_FogBlockAlpha
// //
// The floor fudges are used, but should the wall fudges be used instead? or something inbetween?
// or separate values for floors and walls? (need to change more than this shader for that)
#define GLSL_FOG_FRAGMENT_SHADER \ #define GLSL_FOG_FRAGMENT_SHADER \
GLSL_FLOOR_FUDGES \
"uniform vec4 tint_color;\n" \ "uniform vec4 tint_color;\n" \
"uniform vec4 fade_color;\n" \ "uniform vec4 fade_color;\n" \
"uniform float lighting;\n" \ "uniform float lighting;\n" \
@ -220,6 +302,19 @@
"gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * gl_Color * poly_color;\n" \ "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * gl_Color * poly_color;\n" \
"}\0" "}\0"
// Shader for the palette rendering postprocess step
#define GLSL_PALETTE_POSTPROCESS_SHADER \
"uniform sampler2D tex;\n" \
"uniform sampler3D palette_lookup_tex;\n" \
"uniform sampler1D screen_palette_tex;\n" \
"void main(void) {\n" \
"vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \
"float tex_pal_idx = texture3D(palette_lookup_tex, vec3((texel * 63.0 + 0.5) / 64.0))[0] * 255.0;\n" \
"float palette_coord = (tex_pal_idx + 0.5) / 256.0;\n" \
"vec4 final_color = texture1D(screen_palette_tex, palette_coord);\n" \
"gl_FragColor = final_color;\n" \
"}\0"
// ================ // ================
// Shader sources // Shader sources
// ================ // ================
@ -229,13 +324,13 @@ static struct {
const char *fragment; const char *fragment;
} const gl_shadersources[] = { } const gl_shadersources[] = {
// Floor shader // Floor shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER_FLOORS},
// Wall shader // Wall shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER_WALLS},
// Sprite shader // Sprite shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER_WALLS},
// Model shader // Model shader
{GLSL_MODEL_VERTEX_SHADER, GLSL_SOFTWARE_MODEL_FRAGMENT_SHADER}, {GLSL_MODEL_VERTEX_SHADER, GLSL_SOFTWARE_MODEL_FRAGMENT_SHADER},
@ -249,6 +344,9 @@ static struct {
// Sky shader // Sky shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_SKY_FRAGMENT_SHADER}, {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SKY_FRAGMENT_SHADER},
// Palette postprocess shader
{GLSL_DEFAULT_VERTEX_SHADER, GLSL_PALETTE_POSTPROCESS_SHADER},
{NULL, NULL}, {NULL, NULL},
}; };
@ -272,7 +370,8 @@ static shader_t gl_shaders[NUMSHADERTARGETS*2];
static shadertarget_t gl_shadertargets[NUMSHADERTARGETS]; static shadertarget_t gl_shadertargets[NUMSHADERTARGETS];
#define MODEL_LIGHTING_DEFINE "#define MODEL_LIGHTING" #define MODEL_LIGHTING_DEFINE "#define SRB2_MODEL_LIGHTING"
#define PALETTE_RENDERING_DEFINE "#define SRB2_PALETTE_RENDERING"
// Initialize shader variables and the backend's shader system. Load the base shaders. // Initialize shader variables and the backend's shader system. Load the base shaders.
// Returns false if shaders cannot be used. // Returns false if shaders cannot be used.
@ -446,6 +545,8 @@ static char *HWR_PreprocessShader(char *original)
new_len = original_len; new_len = original_len;
if (cv_glmodellighting.value) if (cv_glmodellighting.value)
new_len += sizeof(MODEL_LIGHTING_DEFINE) - 1 + 2 * line_ending_len; new_len += sizeof(MODEL_LIGHTING_DEFINE) - 1 + 2 * line_ending_len;
if (cv_glpaletterendering.value)
new_len += sizeof(PALETTE_RENDERING_DEFINE) - 1 + 2 * line_ending_len;
// Allocate memory for modified shader. // Allocate memory for modified shader.
new_shader = Z_Malloc(new_len + 1, PU_STATIC, NULL); new_shader = Z_Malloc(new_len + 1, PU_STATIC, NULL);
@ -458,16 +559,23 @@ static char *HWR_PreprocessShader(char *original)
read_pos += insertion_pos; read_pos += insertion_pos;
write_pos += insertion_pos; write_pos += insertion_pos;
#define WRITE_DEFINE(define) \
{ \
strcpy(write_pos, line_ending); \
write_pos += line_ending_len; \
strcpy(write_pos, define); \
write_pos += sizeof(define) - 1; \
strcpy(write_pos, line_ending); \
write_pos += line_ending_len; \
}
// Write the additions. // Write the additions.
if (cv_glmodellighting.value) if (cv_glmodellighting.value)
{ WRITE_DEFINE(MODEL_LIGHTING_DEFINE)
strcpy(write_pos, line_ending); if (cv_glpaletterendering.value)
write_pos += line_ending_len; WRITE_DEFINE(PALETTE_RENDERING_DEFINE)
strcpy(write_pos, MODEL_LIGHTING_DEFINE);
write_pos += sizeof(MODEL_LIGHTING_DEFINE) - 1; #undef WRITE_DEFINE
strcpy(write_pos, line_ending);
write_pos += line_ending_len;
}
// Copy the part after our additions. // Copy the part after our additions.
M_Memcpy(write_pos, read_pos, original_len - insertion_pos); M_Memcpy(write_pos, read_pos, original_len - insertion_pos);
@ -557,6 +665,7 @@ customshaderxlat_t shaderxlat[] =
{"WaterRipple", SHADER_WATER}, {"WaterRipple", SHADER_WATER},
{"Fog", SHADER_FOG}, {"Fog", SHADER_FOG},
{"Sky", SHADER_SKY}, {"Sky", SHADER_SKY},
{"PalettePostprocess", SHADER_PALETTE_POSTPROCESS},
{NULL, 0}, {NULL, 0},
}; };
@ -739,18 +848,13 @@ const char *HWR_GetShaderName(INT32 shader)
{ {
INT32 i; INT32 i;
if (shader) for (i = 0; shaderxlat[i].type; i++)
{ {
for (i = 0; shaderxlat[i].type; i++) if (shaderxlat[i].id == shader)
{ return shaderxlat[i].type;
if (shaderxlat[i].id == shader)
return shaderxlat[i].type;
}
return "Unknown";
} }
return "Default"; return "Unknown";
} }
#endif // HWRENDER #endif // HWRENDER

View file

@ -34,12 +34,21 @@ struct GLRGBAFloat
GLfloat alpha; GLfloat alpha;
}; };
typedef struct GLRGBAFloat GLRGBAFloat; typedef struct GLRGBAFloat GLRGBAFloat;
static const GLubyte white[4] = { 255, 255, 255, 255 };
// lighttable list item
struct LTListItem
{
UINT32 id;
struct LTListItem *next;
};
typedef struct LTListItem LTListItem;
// ========================================================================== // ==========================================================================
// CONSTANTS // CONSTANTS
// ========================================================================== // ==========================================================================
static const GLubyte white[4] = { 255, 255, 255, 255 };
// With OpenGL 1.1+, the first texture should be 1 // With OpenGL 1.1+, the first texture should be 1
static GLuint NOTEXTURE_NUM = 0; static GLuint NOTEXTURE_NUM = 0;
@ -55,6 +64,7 @@ static float NEAR_CLIPPING_PLANE = NZCLIP_PLANE;
static GLuint tex_downloaded = 0; static GLuint tex_downloaded = 0;
static GLuint lt_downloaded = 0; // currently bound lighttable texture
static GLfloat fov = 90.0f; static GLfloat fov = 90.0f;
static FBITFIELD CurrentPolyFlags; static FBITFIELD CurrentPolyFlags;
@ -62,7 +72,14 @@ static FBITFIELD CurrentPolyFlags;
static FTextureInfo *TexCacheTail = NULL; static FTextureInfo *TexCacheTail = NULL;
static FTextureInfo *TexCacheHead = NULL; static FTextureInfo *TexCacheHead = NULL;
RGBA_t myPaletteData[256]; // Linked list of all lighttables.
static LTListItem *LightTablesTail = NULL;
static LTListItem *LightTablesHead = NULL;
static RGBA_t screenPalette[256] = {0}; // the palette for the postprocessing step in palette rendering
static GLuint screenPaletteTex = 0; // 1D texture containing the screen palette
static GLuint paletteLookupTex = 0; // 3D texture containing RGB -> palette index lookup table
RGBA_t myPaletteData[256]; // the palette for converting textures to RGBA
GLint screen_width = 0; // used by Draw2DLine() GLint screen_width = 0; // used by Draw2DLine()
GLint screen_height = 0; GLint screen_height = 0;
GLbyte screen_depth = 0; GLbyte screen_depth = 0;
@ -377,6 +394,8 @@ typedef void (APIENTRY * PFNglTexEnvi) (GLenum target, GLenum pname, GLint param
static PFNglTexEnvi pglTexEnvi; static PFNglTexEnvi pglTexEnvi;
typedef void (APIENTRY * PFNglTexParameteri) (GLenum target, GLenum pname, GLint param); typedef void (APIENTRY * PFNglTexParameteri) (GLenum target, GLenum pname, GLint param);
static PFNglTexParameteri pglTexParameteri; static PFNglTexParameteri pglTexParameteri;
typedef void (APIENTRY * PFNglTexImage1D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
static PFNglTexImage1D pglTexImage1D;
typedef void (APIENTRY * PFNglTexImage2D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRY * PFNglTexImage2D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
static PFNglTexImage2D pglTexImage2D; static PFNglTexImage2D pglTexImage2D;
typedef void (APIENTRY * PFNglTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRY * PFNglTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
@ -400,6 +419,10 @@ static PFNglCopyTexSubImage2D pglCopyTexSubImage2D;
typedef GLint (APIENTRY * PFNgluBuild2DMipmaps) (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data); typedef GLint (APIENTRY * PFNgluBuild2DMipmaps) (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
static PFNgluBuild2DMipmaps pgluBuild2DMipmaps; static PFNgluBuild2DMipmaps pgluBuild2DMipmaps;
/* 1.2 functions for 3D textures */
typedef void (APIENTRY * PFNglTexImage3D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
static PFNglTexImage3D pglTexImage3D;
/* 1.3 functions for multitexturing */ /* 1.3 functions for multitexturing */
typedef void (APIENTRY *PFNglActiveTexture) (GLenum); typedef void (APIENTRY *PFNglActiveTexture) (GLenum);
static PFNglActiveTexture pglActiveTexture; static PFNglActiveTexture pglActiveTexture;
@ -444,6 +467,9 @@ static PFNglBlendEquation pglBlendEquation;
#ifndef GL_TEXTURE1 #ifndef GL_TEXTURE1
#define GL_TEXTURE1 0x84C1 #define GL_TEXTURE1 0x84C1
#endif #endif
#ifndef GL_TEXTURE2
#define GL_TEXTURE2 0x84C2
#endif
/* 1.5 Parms */ /* 1.5 Parms */
#ifndef GL_ARRAY_BUFFER #ifndef GL_ARRAY_BUFFER
@ -515,6 +541,7 @@ boolean SetupGLfunc(void)
GETOPENGLFUNC(pglTexEnvi, glTexEnvi) GETOPENGLFUNC(pglTexEnvi, glTexEnvi)
GETOPENGLFUNC(pglTexParameteri, glTexParameteri) GETOPENGLFUNC(pglTexParameteri, glTexParameteri)
GETOPENGLFUNC(pglTexImage1D, glTexImage1D)
GETOPENGLFUNC(pglTexImage2D, glTexImage2D) GETOPENGLFUNC(pglTexImage2D, glTexImage2D)
GETOPENGLFUNC(pglTexSubImage2D, glTexSubImage2D) GETOPENGLFUNC(pglTexSubImage2D, glTexSubImage2D)
@ -590,7 +617,12 @@ typedef enum
gluniform_fade_start, gluniform_fade_start,
gluniform_fade_end, gluniform_fade_end,
// misc. (custom shaders) // palette rendering
gluniform_screen_palette_tex,
gluniform_palette_lookup_tex,
gluniform_lighttable_tex,
// misc.
gluniform_leveltime, gluniform_leveltime,
gluniform_max, gluniform_max,
@ -656,6 +688,9 @@ static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f};
void SetupGLFunc4(void) void SetupGLFunc4(void)
{ {
/* 1.2 funcs */
pglTexImage3D = GetGLFunc("glTexImage3D");
/* 1.3 funcs */
pglActiveTexture = GetGLFunc("glActiveTexture"); pglActiveTexture = GetGLFunc("glActiveTexture");
pglMultiTexCoord2f = GetGLFunc("glMultiTexCoord2f"); pglMultiTexCoord2f = GetGLFunc("glMultiTexCoord2f");
pglClientActiveTexture = GetGLFunc("glClientActiveTexture"); pglClientActiveTexture = GetGLFunc("glClientActiveTexture");
@ -1496,6 +1531,9 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
w = pTexInfo->width; w = pTexInfo->width;
h = pTexInfo->height; h = pTexInfo->height;
if (w*h > 2048*2048 && pTexInfo->format != GL_TEXFMT_RGBA)
I_Error("Tried to convert too big texture: %dx%d", w, h);
if ((pTexInfo->format == GL_TEXFMT_P_8) || if ((pTexInfo->format == GL_TEXFMT_P_8) ||
(pTexInfo->format == GL_TEXFMT_AP_88)) (pTexInfo->format == GL_TEXFMT_AP_88))
{ {
@ -1889,11 +1927,31 @@ static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i)
shader->uniforms[gluniform_fade_start] = GETUNI("fade_start"); shader->uniforms[gluniform_fade_start] = GETUNI("fade_start");
shader->uniforms[gluniform_fade_end] = GETUNI("fade_end"); shader->uniforms[gluniform_fade_end] = GETUNI("fade_end");
// misc. (custom shaders) // palette rendering
shader->uniforms[gluniform_leveltime] = GETUNI("leveltime"); shader->uniforms[gluniform_screen_palette_tex] = GETUNI("screen_palette_tex");
shader->uniforms[gluniform_palette_lookup_tex] = GETUNI("palette_lookup_tex");
shader->uniforms[gluniform_lighttable_tex] = GETUNI("lighttable_tex");
// misc.
shader->uniforms[gluniform_leveltime] = GETUNI("leveltime");
#undef GETUNI #undef GETUNI
// set permanent uniform values
#define UNIFORM_1(uniform, a, function) \
if (uniform != -1) \
function (uniform, a);
pglUseProgram(shader->program);
// texture unit numbers for the samplers used for palette rendering
UNIFORM_1(shader->uniforms[gluniform_screen_palette_tex], 2, pglUniform1i);
UNIFORM_1(shader->uniforms[gluniform_palette_lookup_tex], 1, pglUniform1i);
UNIFORM_1(shader->uniforms[gluniform_lighttable_tex], 2, pglUniform1i);
// restore gl shader state
pglUseProgram(gl_shaderstate.program);
#undef UNIFORM_1
return true; return true;
} }
@ -1956,6 +2014,14 @@ static void PreparePolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FBITFIELD
fade.green = byte2float[pSurf->FadeColor.s.green]; fade.green = byte2float[pSurf->FadeColor.s.green];
fade.blue = byte2float[pSurf->FadeColor.s.blue]; fade.blue = byte2float[pSurf->FadeColor.s.blue];
fade.alpha = byte2float[pSurf->FadeColor.s.alpha]; fade.alpha = byte2float[pSurf->FadeColor.s.alpha];
if (pSurf->LightTableId && pSurf->LightTableId != lt_downloaded)
{
pglActiveTexture(GL_TEXTURE2);
pglBindTexture(GL_TEXTURE_2D, pSurf->LightTableId);
pglActiveTexture(GL_TEXTURE0);
lt_downloaded = pSurf->LightTableId;
}
} }
} }
@ -2148,9 +2214,6 @@ EXPORT void HWRAPI(RenderSkyDome) (gl_sky_t *sky)
pglDisableClientState(GL_COLOR_ARRAY); pglDisableClientState(GL_COLOR_ARRAY);
} }
// ==========================================================================
//
// ==========================================================================
EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value) EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
{ {
switch (IdState) switch (IdState)
@ -2514,6 +2577,14 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
else if (Surface->PolyColor.s.alpha == 0xFF) else if (Surface->PolyColor.s.alpha == 0xFF)
flags |= (PF_Occlude | PF_Masked); flags |= (PF_Occlude | PF_Masked);
if (Surface->LightTableId && Surface->LightTableId != lt_downloaded)
{
pglActiveTexture(GL_TEXTURE2);
pglBindTexture(GL_TEXTURE_2D, Surface->LightTableId);
pglActiveTexture(GL_TEXTURE0);
lt_downloaded = Surface->LightTableId;
}
SetBlend(flags); SetBlend(flags);
Shader_SetUniforms(Surface, &poly, &tint, &fade); Shader_SetUniforms(Surface, &poly, &tint, &fade);
@ -3249,6 +3320,9 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height)
ClearBuffer(true, false, &clearColour); ClearBuffer(true, false, &clearColour);
pglBindTexture(GL_TEXTURE_2D, finalScreenTexture); pglBindTexture(GL_TEXTURE_2D, finalScreenTexture);
// prepare shader, if it is enabled
Shader_SetUniforms(NULL, NULL, NULL, NULL);
pglColor4ubv(white); pglColor4ubv(white);
pglTexCoordPointer(2, GL_FLOAT, 0, fix); pglTexCoordPointer(2, GL_FLOAT, 0, fix);
@ -3258,4 +3332,76 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height)
tex_downloaded = finalScreenTexture; tex_downloaded = finalScreenTexture;
} }
EXPORT void HWRAPI(SetPaletteLookup)(UINT8 *lut)
{
if (!paletteLookupTex)
pglGenTextures(1, &paletteLookupTex);
pglActiveTexture(GL_TEXTURE1);
pglBindTexture(GL_TEXTURE_3D, paletteLookupTex);
pglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
pglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
pglTexImage3D(GL_TEXTURE_3D, 0, GL_R8, HWR_PALETTE_LUT_SIZE, HWR_PALETTE_LUT_SIZE, HWR_PALETTE_LUT_SIZE,
0, GL_RED, GL_UNSIGNED_BYTE, lut);
pglActiveTexture(GL_TEXTURE0);
}
EXPORT UINT32 HWRAPI(CreateLightTable)(RGBA_t *hw_lighttable)
{
LTListItem *item = malloc(sizeof(LTListItem));
if (!LightTablesTail)
{
LightTablesHead = LightTablesTail = item;
}
else
{
LightTablesTail->next = item;
LightTablesTail = item;
}
item->next = NULL;
pglGenTextures(1, &item->id);
pglBindTexture(GL_TEXTURE_2D, item->id);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
pglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, hw_lighttable);
// restore previously bound texture
pglBindTexture(GL_TEXTURE_2D, tex_downloaded);
return item->id;
}
// Delete light table textures, ids given before become invalid and must not be used.
EXPORT void HWRAPI(ClearLightTables)(void)
{
while (LightTablesHead)
{
LTListItem *item = LightTablesHead;
pglDeleteTextures(1, (GLuint *)&item->id);
LightTablesHead = item->next;
free(item);
}
LightTablesTail = NULL;
// we no longer have a bound light table (if we had one), we just deleted it!
lt_downloaded = 0;
}
// This palette is used for the palette rendering postprocessing step.
EXPORT void HWRAPI(SetScreenPalette)(RGBA_t *palette)
{
if (memcmp(screenPalette, palette, sizeof(screenPalette)))
{
memcpy(screenPalette, palette, sizeof(screenPalette));
if (!screenPaletteTex)
pglGenTextures(1, &screenPaletteTex);
pglActiveTexture(GL_TEXTURE2);
pglBindTexture(GL_TEXTURE_1D, screenPaletteTex);
pglTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
pglTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
pglTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, palette);
pglActiveTexture(GL_TEXTURE0);
}
}
#endif //HWRENDER #endif //HWRENDER

View file

@ -1443,18 +1443,20 @@ static menuitem_t OP_OpenGLOptionsMenu[] =
{IT_HEADER, NULL, "General", NULL, 51}, {IT_HEADER, NULL, "General", NULL, 51},
{IT_STRING|IT_CVAR, NULL, "Shaders", &cv_glshaders, 63}, {IT_STRING|IT_CVAR, NULL, "Shaders", &cv_glshaders, 63},
{IT_STRING|IT_CVAR, NULL, "Lack of perspective", &cv_glshearing, 73}, {IT_STRING|IT_CVAR, NULL, "Palette rendering", &cv_glpaletterendering, 73},
{IT_STRING|IT_CVAR, NULL, "Field of view", &cv_fov, 83}, {IT_STRING|IT_CVAR, NULL, "Palette bit depth", &cv_glpalettedepth, 83},
{IT_STRING|IT_CVAR, NULL, "Lack of perspective", &cv_glshearing, 93},
{IT_STRING|IT_CVAR, NULL, "Field of view", &cv_fov, 103},
{IT_HEADER, NULL, "Miscellaneous", NULL, 102}, {IT_HEADER, NULL, "Miscellaneous", NULL, 122},
{IT_STRING|IT_CVAR, NULL, "Bit depth", &cv_scr_depth, 114}, {IT_STRING|IT_CVAR, NULL, "Bit depth", &cv_scr_depth, 134},
{IT_STRING|IT_CVAR, NULL, "Texture filter", &cv_glfiltermode, 124}, {IT_STRING|IT_CVAR, NULL, "Texture filter", &cv_glfiltermode, 144},
{IT_STRING|IT_CVAR, NULL, "Anisotropic", &cv_glanisotropicmode, 134}, {IT_STRING|IT_CVAR, NULL, "Anisotropic", &cv_glanisotropicmode, 154},
#ifdef ALAM_LIGHTING #ifdef ALAM_LIGHTING
{IT_SUBMENU|IT_STRING, NULL, "Lighting...", &OP_OpenGLLightingDef, 144}, {IT_SUBMENU|IT_STRING, NULL, "Lighting...", &OP_OpenGLLightingDef, 164},
#endif #endif
#if defined (_WINDOWS) && (!((defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL))) #if defined (_WINDOWS) && (!((defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL)))
{IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 154}, {IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 174},
#endif #endif
}; };

View file

@ -30,6 +30,10 @@
#include "byteptr.h" #include "byteptr.h"
#include "dehacked.h" #include "dehacked.h"
#ifdef HWRENDER
#include "hardware/hw_glob.h" // HWR_ClearLightTables
#endif
// //
// Graphics. // Graphics.
// SRB2 graphics for walls and sprites // SRB2 graphics for walls and sprites
@ -425,6 +429,9 @@ void R_ClearColormaps(void)
{ {
// Purged by PU_LEVEL, just overwrite the pointer // Purged by PU_LEVEL, just overwrite the pointer
extra_colormaps = R_CreateDefaultColormap(true); extra_colormaps = R_CreateDefaultColormap(true);
#ifdef HWRENDER
HWR_ClearLightTables();
#endif
} }
// //

View file

@ -69,6 +69,11 @@ typedef struct extracolormap_s
lighttable_t *colormap; lighttable_t *colormap;
#ifdef HWRENDER
// The id of the hardware lighttable. Zero means it does not exist yet.
UINT32 gl_lighttable_id;
#endif
#ifdef EXTRACOLORMAPLUMPS #ifdef EXTRACOLORMAPLUMPS
lumpnum_t lump; // for colormap lump matching, init to LUMPERROR lumpnum_t lump; // for colormap lump matching, init to LUMPERROR
char lumpname[9]; // for netsyncing char lumpname[9]; // for netsyncing

View file

@ -74,7 +74,7 @@ void *hwSym(const char *funcName,void *handle)
{ {
void *funcPointer = NULL; void *funcPointer = NULL;
#ifdef HWRENDER #ifdef HWRENDER
if (0 == strcmp("SetPalette", funcName)) if (0 == strcmp("SetTexturePalette", funcName))
funcPointer = &OglSdlSetPalette; funcPointer = &OglSdlSetPalette;
GETFUNC(Init); GETFUNC(Init);
@ -113,6 +113,11 @@ void *hwSym(const char *funcName,void *handle)
GETFUNC(SetShaderInfo); GETFUNC(SetShaderInfo);
GETFUNC(SetPaletteLookup);
GETFUNC(CreateLightTable);
GETFUNC(ClearLightTables);
GETFUNC(SetScreenPalette);
#else //HWRENDER #else //HWRENDER
if (0 == strcmp("FinishUpdate", funcName)) if (0 == strcmp("FinishUpdate", funcName))
return funcPointer; //&FinishUpdate; return funcPointer; //&FinishUpdate;

View file

@ -1241,6 +1241,17 @@ void I_FinishUpdate(void)
#ifdef HWRENDER #ifdef HWRENDER
else if (rendermode == render_opengl) else if (rendermode == render_opengl)
{ {
// Final postprocess step of palette rendering, after everything else has been drawn.
if (HWR_ShouldUsePaletteRendering())
{
// not using the function for its original named purpose but can be used like this too
HWR_MakeScreenFinalTexture();
HWD.pfnSetSpecialState(HWD_SET_SHADERS, 1);
HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_PALETTE_POSTPROCESS));
HWR_DrawScreenFinalTexture(vid.width, vid.height);
HWD.pfnUnSetShader();
HWD.pfnSetSpecialState(HWD_SET_SHADERS, 0);
}
OglSdlFinishUpdate(cv_vidwait.value); OglSdlFinishUpdate(cv_vidwait.value);
} }
#endif #endif
@ -1863,7 +1874,7 @@ void VID_StartupOpenGL(void)
HWD.pfnGClipRect = hwSym("GClipRect",NULL); HWD.pfnGClipRect = hwSym("GClipRect",NULL);
HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL); HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL);
HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL); HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL);
HWD.pfnSetPalette = hwSym("SetPalette",NULL); HWD.pfnSetTexturePalette= hwSym("SetTexturePalette",NULL);
HWD.pfnGetTextureUsed = hwSym("GetTextureUsed",NULL); HWD.pfnGetTextureUsed = hwSym("GetTextureUsed",NULL);
HWD.pfnDrawModel = hwSym("DrawModel",NULL); HWD.pfnDrawModel = hwSym("DrawModel",NULL);
HWD.pfnCreateModelVBOs = hwSym("CreateModelVBOs",NULL); HWD.pfnCreateModelVBOs = hwSym("CreateModelVBOs",NULL);
@ -1886,6 +1897,11 @@ void VID_StartupOpenGL(void)
HWD.pfnSetShaderInfo = hwSym("SetShaderInfo",NULL); HWD.pfnSetShaderInfo = hwSym("SetShaderInfo",NULL);
HWD.pfnSetPaletteLookup = hwSym("SetPaletteLookup",NULL);
HWD.pfnCreateLightTable = hwSym("CreateLightTable",NULL);
HWD.pfnClearLightTables = hwSym("ClearLightTables",NULL);
HWD.pfnSetScreenPalette = hwSym("SetScreenPalette",NULL);
vid.glstate = HWD.pfnInit() ? VID_GL_LIBRARY_LOADED : VID_GL_LIBRARY_ERROR; // let load the OpenGL library vid.glstate = HWD.pfnInit() ? VID_GL_LIBRARY_LOADED : VID_GL_LIBRARY_ERROR; // let load the OpenGL library
if (vid.glstate == VID_GL_LIBRARY_ERROR) if (vid.glstate == VID_GL_LIBRARY_ERROR)

View file

@ -209,8 +209,8 @@ void ST_doPaletteStuff(void)
palette = 0; palette = 0;
#ifdef HWRENDER #ifdef HWRENDER
if (rendermode == render_opengl) if (rendermode == render_opengl && !HWR_ShouldUsePaletteRendering())
palette = 0; // No flashpals here in OpenGL palette = 0; // Don't set the palette to a flashpal in OpenGL's truecolor mode
#endif #endif
if (palette != st_palette) if (palette != st_palette)
@ -2786,7 +2786,7 @@ void ST_Drawer(void)
//25/08/99: Hurdler: palette changes is done for all players, //25/08/99: Hurdler: palette changes is done for all players,
// not only player1! That's why this part // not only player1! That's why this part
// of code is moved somewhere else. // of code is moved somewhere else.
if (rendermode == render_soft) if (rendermode == render_soft || HWR_ShouldUsePaletteRendering())
#endif #endif
if (rendermode != render_none) ST_doPaletteStuff(); if (rendermode != render_none) ST_doPaletteStuff();