From 6b81279e333b3a77d1780997aa05390f4f1d510c Mon Sep 17 00:00:00 2001 From: Alug Date: Mon, 15 Dec 2025 22:25:50 +0100 Subject: [PATCH] Revert "Merge pull request 'Revert Pal Render for fixing' (#199) from revertpalfornow into next" This reverts commit 68dc60eea289003e2851ce30a93533a84be050f9, reversing changes made to e4ce835acb0f6f1a64cb999c631a52dcafcd376d. --- src/hardware/CMakeLists.txt | 1 + src/hardware/hw_batching.c | 7 +- src/hardware/hw_cache.c | 265 +++++++- src/hardware/hw_defs.h | 60 +- src/hardware/hw_draw.c | 30 +- src/hardware/hw_drv.h | 54 +- src/hardware/hw_glob.h | 21 +- src/hardware/hw_main.c | 423 ++++++------- src/hardware/hw_main.h | 11 +- src/hardware/hw_md2.c | 23 +- src/hardware/hw_shaders.c | 7 +- src/hardware/hw_shaders.h | 432 +++++++++++++ src/hardware/r_opengl/r_opengl.c | 1022 +++++++++++++----------------- src/hardware/r_opengl/r_opengl.h | 9 +- src/r_data.c | 5 +- src/r_defs.h | 5 + src/sdl/hwsym_sdl.c | 23 +- src/sdl/i_video.cpp | 31 +- src/sdl/ogl_sdl.c | 4 +- src/st_stuff.c | 6 +- src/w_wad.cpp | 3 - src/y_inter.c | 2 +- 22 files changed, 1464 insertions(+), 980 deletions(-) create mode 100644 src/hardware/hw_shaders.h diff --git a/src/hardware/CMakeLists.txt b/src/hardware/CMakeLists.txt index a0a0f280c..8b00fa353 100644 --- a/src/hardware/CMakeLists.txt +++ b/src/hardware/CMakeLists.txt @@ -11,5 +11,6 @@ target_sources(SRB2SDL2 PRIVATE hw_model.c u_list.c hw_batching.c + hw_shaders.c r_opengl/r_opengl.c ) diff --git a/src/hardware/hw_batching.c b/src/hardware/hw_batching.c index 591a37349..1c1633894 100644 --- a/src/hardware/hw_batching.c +++ b/src/hardware/hw_batching.c @@ -93,7 +93,7 @@ void HWR_SetCurrentTexture(GLMipmap_t *texture) // If batching is enabled, this function collects the polygon data and the chosen texture // for later use in HWR_RenderBatches. Otherwise the rendering backend is used to // render the polygon immediately. -void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, int shader, boolean horizonSpecial) +void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, int shader_target, boolean horizonSpecial) { if (currently_batching) { @@ -132,7 +132,7 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt polygonArray[polygonArraySize].polyFlags = PolyFlags; polygonArray[polygonArraySize].texture = current_texture; polygonArray[polygonArraySize].brightmap = current_brightmap; - polygonArray[polygonArraySize].shader = shader; + polygonArray[polygonArraySize].shader = (shader_target != -1) ? HWR_GetShaderFromTarget(shader_target) : shader_target; polygonArray[polygonArraySize].horizonSpecial = horizonSpecial; polygonArraySize++; @@ -141,8 +141,7 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt } else { - if (shader) - HWD.pfnSetShader(shader); + HWD.pfnSetShader((shader_target != SHADER_NONE) ? HWR_GetShaderFromTarget(shader_target) : shader_target); HWD.pfnDrawPolygon(pSurf, pOutVerts, iNumPts, PolyFlags); } } diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 76536350d..45e4c443f 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -39,6 +39,14 @@ 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) @@ -56,7 +64,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm INT32 pblockheight, INT32 blockmodulo, fixed_t yfracstep, fixed_t scale_y, texpatch_t *originPatch, INT32 patchheight, - INT32 bpp) + INT32 bpp, RGBA_t *palette) { fixed_t yfrac, position, count; UINT8 *dest; @@ -128,7 +136,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm texelu16 = (UINT16)((alpha<<8) | texel); memcpy(dest, &texelu16, sizeof(UINT16)); break; - case 3 : colortemp = V_GetColor(texel); + case 3 : colortemp = palette[texel]; if ((originPatch != NULL) && (originPatch->style != AST_COPY)) { RGBA_t rgbatexel; @@ -137,7 +145,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm } memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8)); break; - case 4 : colortemp = V_GetColor(texel); + case 4 : colortemp = palette[texel]; colortemp.s.alpha = alpha; if ((originPatch != NULL) && (originPatch->style != AST_COPY)) { @@ -167,7 +175,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, INT32 pblockheight, INT32 blockmodulo, fixed_t yfracstep, fixed_t scale_y, texpatch_t *originPatch, INT32 patchheight, - INT32 bpp) + INT32 bpp, RGBA_t *palette) { fixed_t yfrac, position, count; UINT8 *dest; @@ -238,7 +246,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, texelu16 = (UINT16)((alpha<<8) | texel); memcpy(dest, &texelu16, sizeof(UINT16)); break; - case 3 : colortemp = V_GetColor(texel); + case 3 : colortemp = palette[texel]; if ((originPatch != NULL) && (originPatch->style != AST_COPY)) { RGBA_t rgbatexel; @@ -247,7 +255,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, } memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8)); break; - case 4 : colortemp = V_GetColor(texel); + case 4 : colortemp = palette[texel]; colortemp.s.alpha = alpha; if ((originPatch != NULL) && (originPatch->style != AST_COPY)) { @@ -291,10 +299,13 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap, UINT8 *block = mipmap->data; INT32 bpp; INT32 blockmodulo; + RGBA_t *palette; if (pwidth <= 0 || pheight <= 0) return; + palette = HWR_GetTexturePalette(); + ncols = pwidth; // source advance @@ -320,7 +331,7 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap, pblockheight, blockmodulo, yfracstep, scale_y, NULL, pheight, // not that pheight is going to get used anyway... - bpp); + bpp, palette); } } @@ -339,12 +350,14 @@ static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap, 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); + INT32 bpp, RGBA_t *palette); if (texture->width <= 0 || texture->height <= 0) return; @@ -362,6 +375,8 @@ static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap, 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 @@ -416,7 +431,7 @@ static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap, pblockheight, blockmodulo, yfracstep, scale_y, patch, height, - bpp); + bpp, palette); } } @@ -463,6 +478,9 @@ static void HWR_GenerateTexture(GLMapTexture_t *grtex, INT32 texnum, boolean noe 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; @@ -479,7 +497,10 @@ static void HWR_GenerateTexture(GLMapTexture_t *grtex, INT32 texnum, boolean noe grtex->mipmap.width = (UINT16)texture->width; 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; if (!noencoremap && encoremap) colormap += COLORMAP_REMAPOFFSET; @@ -498,7 +519,7 @@ static void HWR_GenerateTexture(GLMapTexture_t *grtex, INT32 texnum, boolean noe INT32 j; RGBA_t col; - col = V_GetColor(HWR_PATCHES_CHROMAKEY_COLORINDEX); + col = palette[HWR_PATCHES_CHROMAKEY_COLORINDEX]; for (idx = 0, j = 0; j < blockheight; j++) { for (i = 0; i < blockwidth; i++, idx++) @@ -1008,19 +1029,6 @@ void HWR_LoadMapTextures(size_t pnumtextures) 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 // -------------------------------------------------------------------------- @@ -1382,6 +1390,7 @@ static void HWR_DrawPicInCache(UINT8 *block, INT32 pblockwidth, INT32 pblockheig UINT16 texelu16; INT32 picbpp; RGBA_t col; + RGBA_t *palette = HWR_GetTexturePalette(); stepy = ((INT32)SHORT(pic->height)<width)<>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++; @@ -1614,4 +1624,205 @@ void HWR_GetFadeMask(lumpnum_t fademasklumpnum) 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 diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 5e30a6fc9..3a21c08cc 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -22,6 +22,12 @@ extern "C" { #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 +// 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 // ========================================================================== @@ -135,33 +141,30 @@ typedef struct } FOutVector; #ifdef GL_SHADERS -// Predefined shader types + +// Shader targets used to render specific types of geometry. +// A shader target is resolved to an actual shader with HWR_GetShaderFromTarget. +// The shader returned may be a base shader or a custom shader. enum { SHADER_NONE = -1, - SHADER_DEFAULT = 0, - SHADER_FLOOR, + SHADER_FLOOR = 0, SHADER_WALL, SHADER_SPRITE, - SHADER_MODEL, SHADER_MODEL_LIGHTING, + SHADER_MODEL, + SHADER_MODEL_LIGHTING, SHADER_WATER, SHADER_FOG, SHADER_SKY, + SHADER_PALETTE_POSTPROCESS, + SHADER_UI_COLORMAP_FADE, - NUMBASESHADERS, + NUMSHADERTARGETS }; -// Maximum amount of shader programs -// Must be higher than NUMBASESHADERS -#define HWR_MAXSHADERS 16 - -// Shader sources (vertex and fragment) -typedef struct -{ - char *vertex; - char *fragment; -} shadersource_t; +// Must be at least NUMSHADERTARGETS*2 to fit base and custom shaders for each shader target. +#define HWR_MAXSHADERS NUMSHADERTARGETS*2 // Custom shader reference table typedef struct @@ -290,6 +293,7 @@ struct FSurfaceInfo RGBA_t PolyColor; RGBA_t TintColor; RGBA_t FadeColor; + UINT32 LightTableId; FLightInfo LightInfo; }; typedef struct FSurfaceInfo FSurfaceInfo; @@ -297,7 +301,7 @@ typedef struct FSurfaceInfo FSurfaceInfo; #define GL_DEFAULTMIX 0x00000000 #define GL_DEFAULTFOG 0x19000000 -//Hurdler: added for backward compatibility +// Various settings and states for the rendering backend. enum hwdsetspecialstate { HWD_SET_MODEL_LIGHTING = 1, @@ -309,15 +313,13 @@ enum hwdsetspecialstate }; typedef enum hwdsetspecialstate hwdspecialstate_t; -// Lactozilla: Shader options -enum hwdshaderoption +enum hwdshaderstage { - HWD_SHADEROPTION_OFF, - HWD_SHADEROPTION_ON, - HWD_SHADEROPTION_NOCUSTOM, + HWD_SHADERSTAGE_VERTEX, + HWD_SHADERSTAGE_FRAGMENT, }; -typedef enum hwdshaderoption hwdshaderoption_t; +typedef enum hwdshaderstage hwdshaderstage_t; // Lactozilla: Shader info // Generally set at the start of the frame. @@ -343,6 +345,20 @@ enum hwdfiltermode HWD_SET_TEXTUREFILTER_MIXED3, }; +// Screen texture slots +enum hwdscreentexture +{ + HWD_SCREENTEXTURE_WIPE_START, // source image for the wipe/fade effect + HWD_SCREENTEXTURE_WIPE_END, // destination image for the wipe/fade effect + HWD_SCREENTEXTURE_GENERIC1, // underwater/heat effect, intermission background + HWD_SCREENTEXTURE_GENERIC2, // palette-based colormap fade, screen before palette rendering's postprocessing + HWD_SCREENTEXTURE_GENERIC3, // screen after palette rendering's postprocessing + HWD_SCREENTEXTURE_VHS, + NUMSCREENTEXTURES, // (generic3 is unused if palette rendering is disabled) +}; + +typedef enum hwdscreentexture hwdscreentexture_t; + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index f2e3cb95a..2c9fb6b75 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -534,12 +534,26 @@ void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength) if (color & 0xFF00) // Do COLORMAP fade. { + if (HWR_ShouldUsePaletteRendering()) + { + const hwdscreentexture_t scr_tex = HWD_SCREENTEXTURE_GENERIC2; + + Surf.LightTableId = HWR_GetLightTableID(NULL); + Surf.LightInfo.light_level = strength; + HWD.pfnMakeScreenTexture(scr_tex); + HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_UI_COLORMAP_FADE)); + HWD.pfnDrawScreenTexture(scr_tex, &Surf, PF_ColorMapped|PF_NoDepthTest); + HWD.pfnUnSetShader(); + + return; + } Surf.PolyColor.rgba = UINT2RGBA(0x01010160); Surf.PolyColor.s.alpha = (strength*8); } else // Do TRANSMAP** fade. { - Surf.PolyColor.rgba = V_GetColor(color).rgba; + RGBA_t *palette = HWR_GetTexturePalette(); + Surf.PolyColor.rgba = palette[color&0xFF].rgba; Surf.PolyColor.s.alpha = softwaretranstogl[strength]; } HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); @@ -620,7 +634,8 @@ void HWR_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT16 ac } else // Do TRANSMAP** fade. { - Surf.PolyColor.rgba = V_GetColor(actualcolor).rgba; + RGBA_t *palette = HWR_GetTexturePalette(); + Surf.PolyColor.rgba = palette[actualcolor&0xFF].rgba; Surf.PolyColor.s.alpha = softwaretranstogl[strength]; } HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); @@ -716,8 +731,9 @@ void HWR_drawAMline(const fline_t *fl, INT32 color) { F2DCoord v1, v2; RGBA_t color_rgba; + RGBA_t *palette = HWR_GetTexturePalette(); - color_rgba = V_GetColor(color); + color_rgba = palette[color&0xFF]; v1.x = ((float)fl->a.x-(vid.width/2.0f))*(2.0f/vid.width); v1.y = ((float)fl->a.y-(vid.height/2.0f))*(2.0f/vid.height); @@ -912,6 +928,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) float fx, fy, fw, fh; UINT8 alphalevel = ((color & V_ALPHAMASK) >> V_ALPHASHIFT); UINT8 blendmode = ((color & V_BLENDMASK) >> V_BLENDSHIFT); + RGBA_t *palette = HWR_GetTexturePalette(); // 3--2 // | /| @@ -927,7 +944,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) { if (x == 0 && y == 0 && w == BASEVIDWIDTH*FRACUNIT && h == BASEVIDHEIGHT*FRACUNIT) { - RGBA_t rgbaColour = V_GetColor(color); + RGBA_t rgbaColour = palette[color&0xFF]; FRGBAFloat clearColour; clearColour.red = (float)rgbaColour.s.red / 255; clearColour.green = (float)rgbaColour.s.green / 255; @@ -955,7 +972,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) v[0].t = v[1].t = 0.0f; v[2].t = v[3].t = 1.0f; - Surf.PolyColor = V_GetColor(color); + Surf.PolyColor = palette[color&0xFF]; flags = HWR_GetBlendModeFlag(blendmode+1)|PF_Modulated|PF_NoDepthTest|PF_NoTexture; @@ -1044,6 +1061,7 @@ static inline boolean saveTGA(const char *file_name, void *buffer, UINT8 *HWR_GetScreenshot(INT32 scale) { static UINT8 *buf = NULL; + int tex = HWR_ShouldUsePaletteRendering() ? HWD_SCREENTEXTURE_GENERIC3 : HWD_SCREENTEXTURE_GENERIC2; buf = realloc(buf, (vid.width/scale)*(vid.height/scale)*3); @@ -1051,7 +1069,7 @@ UINT8 *HWR_GetScreenshot(INT32 scale) return NULL; // returns 24bit 888 RGB - HWD.pfnReadScreenFinalTexture(buf, scale); + HWD.pfnReadScreenTexture(tex, (void *)buf, scale); return buf; } diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 63d78e549..246bd1d02 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -33,7 +33,7 @@ EXPORT boolean HWRAPI(Init) (void); #ifndef HAVE_SDL EXPORT void HWRAPI(Shutdown) (void); #endif -EXPORT void HWRAPI(SetPalette) (RGBA_t *ppal); +EXPORT void HWRAPI(SetTexturePalette) (RGBA_t *ppal); EXPORT void HWRAPI(FinishUpdate) (INT32 waitvbl); EXPORT void HWRAPI(Draw2DLine) (F2DCoord *v1, F2DCoord *v2, RGBA_t Color); EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags); @@ -44,7 +44,7 @@ EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFl EXPORT void HWRAPI(SetTexture) (GLMipmap_t *TexInfo); EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *TexInfo); EXPORT void HWRAPI(DeleteTexture) (GLMipmap_t *TexInfo); -EXPORT void HWRAPI(ReadScreenFinalTexture) (UINT8 * restrict dest, INT32 scale); +EXPORT void HWRAPI(ReadScreenTexture) (int tex, UINT8 *restrict dest, INT32 scale); EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip); EXPORT void HWRAPI(ClearMipMapCache) (void); @@ -58,26 +58,27 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform); EXPORT INT32 HWRAPI(GetTextureUsed) (void); EXPORT void HWRAPI(FlushScreenTextures) (void); -EXPORT void HWRAPI(StartScreenWipe) (void); -EXPORT void HWRAPI(EndScreenWipe) (void); -EXPORT void HWRAPI(DoScreenWipe) (void); -EXPORT void HWRAPI(MakeIntermissionBG) (void); -EXPORT void HWRAPI(DrawIntermissionBG) (void); -EXPORT void HWRAPI(MakeScreenTexture) (void); +EXPORT void HWRAPI(DoScreenWipe) (int wipeStart, int wipeEnd); +EXPORT void HWRAPI(DrawScreenTexture) (int tex, FSurfaceInfo *surf, FBITFIELD polyflags); EXPORT void HWRAPI(RenderVhsEffect) (INT16 upbary, INT16 downbary, UINT8 updistort, UINT8 downdistort, UINT8 barsize); -EXPORT void HWRAPI(MakeScreenFinalTexture) (void); -EXPORT void HWRAPI(DrawScreenFinalTexture) (int width, int height); +EXPORT void HWRAPI(MakeScreenTexture) (int tex); +EXPORT void HWRAPI(DrawScreenFinalTexture) (int tex, int width, int height); #define SCREENVERTS 10 EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]); -EXPORT boolean HWRAPI(CompileShaders) (void); -EXPORT void HWRAPI(CleanShaders) (void); -EXPORT void HWRAPI(SetShader) (int type); +EXPORT boolean HWRAPI(InitShaders) (void); +EXPORT void HWRAPI(LoadShader) (int slot, char *code, hwdshaderstage_t stage); +EXPORT boolean HWRAPI(CompileShader) (int slot); +EXPORT void HWRAPI(SetShader) (int slot); EXPORT void HWRAPI(UnSetShader) (void); EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value); -EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boolean isfragment); + +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 @@ -88,7 +89,7 @@ EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boole struct hwdriver_s { Init pfnInit; - SetPalette pfnSetPalette; + SetTexturePalette pfnSetTexturePalette; FinishUpdate pfnFinishUpdate; Draw2DLine pfnDraw2DLine; DrawPolygon pfnDrawPolygon; @@ -99,10 +100,10 @@ struct hwdriver_s SetTexture pfnSetTexture; UpdateTexture pfnUpdateTexture; DeleteTexture pfnDeleteTexture; - ReadScreenFinalTexture pfnReadScreenFinalTexture; + ReadScreenTexture pfnReadScreenTexture; GClipRect pfnGClipRect; ClearMipMapCache pfnClearMipMapCache; - SetSpecialState pfnSetSpecialState;//Hurdler: added for backward compatibility + SetSpecialState pfnSetSpecialState; DrawModel pfnDrawModel; CreateModelVBOs pfnCreateModelVBOs; SetTransform pfnSetTransform; @@ -112,23 +113,24 @@ struct hwdriver_s #endif PostImgRedraw pfnPostImgRedraw; FlushScreenTextures pfnFlushScreenTextures; - StartScreenWipe pfnStartScreenWipe; - EndScreenWipe pfnEndScreenWipe; DoScreenWipe pfnDoScreenWipe; - MakeIntermissionBG pfnMakeIntermissionBG; - DrawIntermissionBG pfnDrawIntermissionBG; - MakeScreenTexture pfnMakeScreenTexture; RenderVhsEffect pfnRenderVhsEffect; - MakeScreenFinalTexture pfnMakeScreenFinalTexture; + DrawScreenTexture pfnDrawScreenTexture; + MakeScreenTexture pfnMakeScreenTexture; DrawScreenFinalTexture pfnDrawScreenFinalTexture; - CompileShaders pfnCompileShaders; - CleanShaders pfnCleanShaders; + InitShaders pfnInitShaders; + LoadShader pfnLoadShader; + CompileShader pfnCompileShader; SetShader pfnSetShader; UnSetShader pfnUnSetShader; SetShaderInfo pfnSetShaderInfo; - LoadCustomShader pfnLoadCustomShader; + + SetPaletteLookup pfnSetPaletteLookup; + CreateLightTable pfnCreateLightTable; + ClearLightTables pfnClearLightTables; + SetScreenPalette pfnSetScreenPalette; }; extern struct hwdriver_s hwdriver; diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index f04ef1f0b..ca7b514b5 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -108,6 +108,8 @@ void HWR_FreeExtraSubsectors(void); // -------- // hw_cache.c // -------- +RGBA_t *HWR_GetTexturePalette(void); + void HWR_InitMapTextures(void); void HWR_LoadMapTextures(size_t pnumtextures); void HWR_FreeMapTextures(void); @@ -133,7 +135,10 @@ void HWR_FreeColormapCache(void); void HWR_UnlockCachedPatch(GLPatch_t *gpatch); void HWR_SetPalette(RGBA_t *palette); - +void HWR_SetMapPalette(void); +UINT32 HWR_CreateLightTable(UINT8 *lighttable); +UINT32 HWR_GetLightTableID(extracolormap_t *colormap); +void HWR_ClearLightTables(void); // -------- // hw_draw.c @@ -141,6 +146,20 @@ void HWR_SetPalette(RGBA_t *palette); extern INT32 patchformat; extern INT32 textureformat; +// -------- +// hw_shaders.c +// -------- +boolean HWR_InitShaders(void); +void HWR_CompileShaders(void); + +int HWR_GetShaderFromTarget(int shader_target); + +void HWR_LoadAllCustomShaders(void); +void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3); +const char *HWR_GetShaderName(INT32 shader); + +extern customshaderxlat_t shaderxlat[]; + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 9a4430c4a..03a56f94b 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -131,26 +131,6 @@ static line_t *gl_linedef; static sector_t *gl_frontsector; 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; -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 precise_t ps_hw_skyboxtime = 0; precise_t ps_hw_nodesorttime = 0; @@ -172,13 +152,38 @@ precise_t ps_hw_batchdrawtime = 0; boolean gl_init = false; boolean gl_maploaded = false; boolean gl_sessioncommandsadded = false; -boolean gl_shadersavailable = true; +// false if shaders have not been initialized yet, or if shaders are not available +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; +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 // ========================================================================== -static boolean HWR_UseShader(void) +// Returns true if shaders can be used. +boolean HWR_UseShader(void) { return (cv_glshaders.value && gl_shadersavailable); } @@ -295,6 +300,10 @@ void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *col poly_color.s.blue = (UINT8)blue; } + // Shift the lightlevel for Palette rendering mode to replicate software´s limited 32 lightlevels + if (HWR_ShouldUsePaletteRendering()) + light_level = (light_level >> LIGHTSEGSHIFT) << LIGHTSEGSHIFT; + // Clamp the light level, since it can sometimes go out of the 0-255 range from animations light_level = min(max(light_level, cv_secbright.value), 255); @@ -310,6 +319,11 @@ void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *col Surface->LightInfo.newfade = (colormap != NULL) ? !!(colormap->flags & CMF_NEWFADE) : false; Surface->LightInfo.directional = (maplighting.directional == true && directional == true); + + if (HWR_ShouldUsePaletteRendering()) + Surface->LightTableId = HWR_GetLightTableID(colormap); + else + Surface->LightTableId = 0; } UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap) // Let's see if this can work @@ -399,7 +413,7 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool static FOutVector *planeVerts = NULL; static UINT16 numAllocedPlaneVerts = 0; - INT32 shader = SHADER_DEFAULT; + INT32 shader = SHADER_NONE; // no convex poly were generated for this subsector if (!xsub->planepoly) @@ -728,7 +742,7 @@ static void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, I // static void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blendmode, INT32 lightlevel, extracolormap_t *wallcolormap) { - INT32 shader = SHADER_DEFAULT; + INT32 shader = SHADER_NONE; HWR_Lighting(pSurf, lightlevel, wallcolormap, P_SectorUsesDirectionalLighting(gl_frontsector)); @@ -939,7 +953,7 @@ static void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf) wallVerts[0].t = wallVerts[1].t = 0; wallVerts[0].s = wallVerts[3].s = 0; wallVerts[2].s = wallVerts[1].s = 0; - // this no longer sets top/bottom coords, this should be done before caling the function + // this no longer sets top/bottom coords, this should be done before calling the function HWR_ProjectWall(wallVerts, Surf, PF_Invisible|PF_NoTexture, 255, NULL); // PF_Invisible so it's not drawn into the colour buffer // PF_NoTexture for no texture @@ -2361,7 +2375,7 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, { FSurfaceInfo Surf; FOutVector *v3d; - INT32 shader = SHADER_DEFAULT; + INT32 shader = SHADER_NONE; size_t nrPlaneVerts = polysector->numVertices; INT32 i; @@ -3126,7 +3140,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) float fscale; float fx; float fy; float offset; extracolormap_t *colormap = NULL; FBITFIELD blendmode = PF_ReverseSubtract; - INT32 shader = SHADER_DEFAULT; + INT32 shader = SHADER_NONE; UINT8 i; INT32 heightsec, phs; SINT8 flip = P_MobjFlip(thing); @@ -3318,7 +3332,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) boolean lightset = true; FBITFIELD blend = 0; FBITFIELD occlusion; - INT32 shader = SHADER_DEFAULT; + INT32 shader = SHADER_NONE; boolean use_linkdraw_hack = false; UINT8 alpha; @@ -3906,7 +3920,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) } { - INT32 shader = SHADER_DEFAULT; + INT32 shader = SHADER_NONE; FBITFIELD blend = 0; FBITFIELD occlusion; boolean use_linkdraw_hack = false; @@ -3981,7 +3995,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) // Sprite drawer for precipitation static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) { - INT32 shader = SHADER_DEFAULT; + INT32 shader = SHADER_NONE; FBITFIELD blend = 0; FOutVector wallVerts[4]; patch_t *gpatch; @@ -4468,7 +4482,6 @@ static void HWR_CreateDrawNodes(void) // Okay! Let's draw it all! Woo! HWD.pfnSetTransform(&atransform); - HWD.pfnSetShader(SHADER_DEFAULT); for (i = 0; i < p; i++) { @@ -5585,7 +5598,9 @@ static void HWR_DrawSkyBackground(player_t *player) HWR_BuildSkyDome(); } - HWD.pfnSetShader(SHADER_SKY); // sky shader + if (HWR_UseShader()) + HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_SKY)); + HWD.pfnSetTransform(&dometransform); HWD.pfnRenderSkyDome(&gl_sky); } @@ -5671,8 +5686,6 @@ static void HWR_DrawSkyBackground(player_t *player) HWD.pfnUnSetShader(); HWD.pfnDrawPolygon(NULL, v, 4, 0); } - - HWD.pfnSetShader(SHADER_DEFAULT); } @@ -5788,13 +5801,7 @@ static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean // static void HWR_SetShaderState(void) { - hwdshaderoption_t state = cv_glshaders.value; - - if (!cv_glallowshaders.value) - state = (cv_glshaders.value == HWD_SHADEROPTION_ON ? HWD_SHADEROPTION_NOCUSTOM : cv_glshaders.value); - - HWD.pfnSetSpecialState(HWD_SET_SHADERS, (INT32)state); - HWD.pfnSetShader(SHADER_DEFAULT); + HWD.pfnSetSpecialState(HWD_SET_SHADERS, (INT32)HWR_UseShader()); } static void HWR_ClearClipper(void) @@ -5816,6 +5823,7 @@ void HWR_RenderSkyboxView(player_t *player) camera_t *thiscam = &camera[viewnum]; const float fpov = FIXED_TO_FLOAT(cv_fov[viewssnum].value+player->fovadd); + if (!HWR_ShouldUsePaletteRendering()) { // do we really need to save player (is it not the same)? player_t *saved_player = stplyr; @@ -6159,6 +6167,56 @@ void HWR_RenderPlayerView(void) 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, these 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. + HWR_LoadMapTextures(numtextures); + } + } + 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, these 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. + HWR_LoadMapTextures(numtextures); + } + } +} + void HWR_LoadLevel(void) { #ifdef ALAM_LIGHTING @@ -6172,6 +6230,9 @@ void HWR_LoadLevel(void) HWR_ClearSkyDome(); HWR_BuildSkyDome(); + if (HWR_ShouldUsePaletteRendering()) + HWR_SetMapPalette(); + gl_maploaded = true; } @@ -6179,7 +6240,7 @@ void HWR_LoadLevel(void) // 3D ENGINE COMMANDS // ========================================================================== -static CV_PossibleValue_t glshaders_cons_t[] = {{HWD_SHADEROPTION_OFF, "Off"}, {HWD_SHADEROPTION_ON, "On"}, {HWD_SHADEROPTION_NOCUSTOM, "Ignore custom shaders"}, {0, NULL}}; +CV_PossibleValue_t glshaders_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Ignore custom shaders"}, {0, NULL}}; #ifdef BAD_MODEL_OPTIONS static CV_PossibleValue_t glmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}}; #endif @@ -6227,16 +6288,65 @@ 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); +CV_PossibleValue_t glpalettedepth_cons_t[] = {{16, "16 bits"}, {24, "24 bits"}, {0, NULL}}; +void CV_glpaletterendering_OnChange(void); +void CV_glpalettedepth_OnChange(void); + +consvar_t cv_glpaletterendering = CVAR_INIT ("gr_paletteshader", "Off", CV_CALL|CV_SAVE, 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); + +#define ONLY_IF_GL_LOADED if (vid.glstate != VID_GL_LIBRARY_LOADED) return; + static void CV_glfiltermode_OnChange(void) { - if (rendermode == render_opengl) - HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_glfiltermode.value); + ONLY_IF_GL_LOADED + HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_glfiltermode.value); } static void CV_glanisotropic_OnChange(void) { - if (rendermode == render_opengl) - HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_glanisotropicmode.value); + ONLY_IF_GL_LOADED + HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_glanisotropicmode.value); +} + +void CV_glmodellighting_OnChange(void); +void CV_glmodellighting_OnChange(void) +{ + ONLY_IF_GL_LOADED + // if shaders have been compiled, then they now need to be recompiled. + if (gl_shadersavailable) + HWR_CompileShaders(); +} + +void CV_glpaletterendering_OnChange(void) +{ + ONLY_IF_GL_LOADED + if (gl_shadersavailable) + { + HWR_CompileShaders(); + HWR_TogglePaletteRendering(); + } +} + +void CV_glpalettedepth_OnChange(void); +void CV_glpalettedepth_OnChange(void) +{ + ONLY_IF_GL_LOADED + // refresh the screen palette + if (HWR_ShouldUsePaletteRendering()) + HWR_SetPalette(pLocalPalette); +} + +void CV_glshaders_OnChange(void); +void CV_glshaders_OnChange(void) +{ + ONLY_IF_GL_LOADED + HWR_SetShaderState(); + 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 @@ -6271,6 +6381,9 @@ void HWR_AddCommands(void) CV_RegisterVar(&cv_glbatching); CV_RegisterVar(&cv_glanisotropicmode); + + CV_RegisterVar(&cv_glpaletterendering); + CV_RegisterVar(&cv_glpalettedepth); } void HWR_AddSessionCommands(void) @@ -6289,6 +6402,8 @@ void HWR_Startup(void) { CONS_Printf("HWR_Startup()...\n"); + textureformat = patchformat = GL_TEXFMT_RGBA; + HWR_InitPolyPool(); HWR_AddSessionCommands(); HWR_InitMapTextures(); @@ -6297,14 +6412,12 @@ void HWR_Startup(void) HWR_InitLight(); #endif + gl_shadersavailable = HWR_InitShaders(); + HWR_SetShaderState(); HWR_LoadAllCustomShaders(); - if (!HWR_CompileShaders()) - gl_shadersavailable = false; + HWR_TogglePaletteRendering(); } - if (rendermode == render_opengl) - textureformat = patchformat = GL_TEXFMT_RGBA; - gl_init = true; } @@ -6399,7 +6512,7 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, FBITFIELD blendmode = blend; UINT8 alpha = pSurf->PolyColor.s.alpha; // retain the alpha - INT32 shader = SHADER_DEFAULT; + INT32 shader = SHADER_NONE; // Lighting is done here instead so that fog isn't drawn incorrectly on transparent walls after sorting HWR_Lighting(pSurf, lightlevel, wallcolormap, P_SectorUsesDirectionalLighting(gl_frontsector)); @@ -6437,7 +6550,7 @@ void HWR_DoPostProcessor(player_t *player) // Armageddon Blast Flash! // Could this even be considered postprocessor? - if (player->flashcount) + if (player->flashcount && !HWR_ShouldUsePaletteRendering()) { FOutVector v[4]; FSurfaceInfo Surf; @@ -6463,7 +6576,8 @@ void HWR_DoPostProcessor(player_t *player) } // Capture the screen for intermission and screen waving - HWD.pfnMakeScreenTexture(); + if (gamestate != GS_INTERMISSION) + HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_GENERIC1); if (r_splitscreen) // Not supported in splitscreen - someone want to add support? return; @@ -6508,6 +6622,10 @@ void HWR_DoPostProcessor(player_t *player) } } HWD.pfnPostImgRedraw(v); + + // Capture the screen again for screen waving on the intermission + if (gamestate != GS_INTERMISSION) + HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_GENERIC1); } // Flipping of the screen isn't done here anymore } @@ -6515,23 +6633,18 @@ void HWR_DoPostProcessor(player_t *player) void HWR_StartScreenWipe(void) { //CONS_Debug(DBG_RENDER, "In HWR_StartScreenWipe()\n"); - HWD.pfnStartScreenWipe(); + HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_WIPE_START); } void HWR_EndScreenWipe(void) { //CONS_Debug(DBG_RENDER, "In HWR_EndScreenWipe()\n"); - HWD.pfnEndScreenWipe(); -} - -void HWR_MakeIntermissionBG(void) -{ - HWD.pfnMakeIntermissionBG(); + HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_WIPE_END); } void HWR_DrawIntermissionBG(void) { - HWD.pfnDrawIntermissionBG(); + HWD.pfnDrawScreenTexture(HWD_SCREENTEXTURE_GENERIC1, NULL, 0); } // @@ -6576,7 +6689,7 @@ void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum) return; HWR_GetFadeMask(wipelumpnum); - HWD.pfnDoScreenWipe(); + HWD.pfnDoScreenWipe(HWD_SCREENTEXTURE_WIPE_START, HWD_SCREENTEXTURE_WIPE_END); } void HWR_DoTintedWipe(UINT8 wipenum, UINT8 scrnnum) @@ -6592,190 +6705,14 @@ void HWR_RenderVhsEffect(INT16 upbary, INT16 downbary, UINT8 updistort, UINT8 do void HWR_MakeScreenFinalTexture(void) { - HWD.pfnMakeScreenFinalTexture(); + int tex = HWR_ShouldUsePaletteRendering() ? HWD_SCREENTEXTURE_GENERIC3 : HWD_SCREENTEXTURE_GENERIC2; + HWD.pfnMakeScreenTexture(tex); } void HWR_DrawScreenFinalTexture(int width, int height) { - HWD.pfnDrawScreenFinalTexture(width, height); -} - -static inline UINT16 HWR_FindShaderDefs(UINT16 wadnum) -{ - UINT16 i; - lumpinfo_t *lump_p; - - lump_p = wadfiles[wadnum]->lumpinfo; - for (i = 0; i < wadfiles[wadnum]->numlumps; i++, lump_p++) - if (memcmp(lump_p->name, "SHADERS", 7) == 0) - return i; - - return INT16_MAX; -} - -boolean HWR_CompileShaders(void) -{ - return HWD.pfnCompileShaders(); -} - -customshaderxlat_t shaderxlat[] = -{ - {"Flat", SHADER_FLOOR}, - {"WallTexture", SHADER_WALL}, - {"Sprite", SHADER_SPRITE}, - {"Model", SHADER_MODEL}, - {"ModelLighting", SHADER_MODEL_LIGHTING}, - {"WaterRipple", SHADER_WATER}, - {"Fog", SHADER_FOG}, - {"Sky", SHADER_SKY}, - {NULL, 0}, -}; - -void HWR_LoadAllCustomShaders(void) -{ - INT32 i; - - // read every custom shader - for (i = 0; i < numwadfiles; i++) - HWR_LoadCustomShadersFromFile(i, (wadfiles[i]->type == RET_PK3)); -} - -void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3) -{ - UINT16 lump; - char *shaderdef, *line; - char *stoken; - char *value; - size_t size; - int linenum = 1; - int shadertype = 0; - int i; - - lump = HWR_FindShaderDefs(wadnum); - if (lump == INT16_MAX) - return; - - shaderdef = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE); - size = W_LumpLengthPwad(wadnum, lump); - - line = Z_Malloc(size+1, PU_STATIC, NULL); - memcpy(line, shaderdef, size); - line[size] = '\0'; - - stoken = strtok(line, "\r\n "); - while (stoken) - { - if ((stoken[0] == '/' && stoken[1] == '/') - || (stoken[0] == '#'))// skip comments - { - stoken = strtok(NULL, "\r\n"); - goto skip_field; - } - - if (!stricmp(stoken, "GLSL")) - { - value = strtok(NULL, "\r\n "); - if (!value) - { - CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); - stoken = strtok(NULL, "\r\n"); // skip end of line - goto skip_lump; - } - - if (!stricmp(value, "VERTEX")) - shadertype = 1; - else if (!stricmp(value, "FRAGMENT")) - shadertype = 2; - -skip_lump: - stoken = strtok(NULL, "\r\n "); - linenum++; - } - else - { - value = strtok(NULL, "\r\n= "); - if (!value) - { - CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: Missing shader target (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); - stoken = strtok(NULL, "\r\n"); // skip end of line - goto skip_field; - } - - if (!shadertype) - { - CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); - Z_Free(line); - return; - } - - for (i = 0; shaderxlat[i].type; i++) - { - if (!stricmp(shaderxlat[i].type, stoken)) - { - size_t shader_size; - char *shader_source; - char *shader_lumpname; - UINT16 shader_lumpnum; - - if (PK3) - { - shader_lumpname = Z_Malloc(strlen(value) + 12, PU_STATIC, NULL); - strcpy(shader_lumpname, "Shaders/sh_"); - strcat(shader_lumpname, value); - shader_lumpnum = W_CheckNumForFullNamePK3(shader_lumpname, wadnum, 0); - } - else - { - shader_lumpname = Z_Malloc(strlen(value) + 4, PU_STATIC, NULL); - strcpy(shader_lumpname, "SH_"); - strcat(shader_lumpname, value); - shader_lumpnum = W_CheckNumForNamePwad(shader_lumpname, wadnum, 0); - } - - if (shader_lumpnum == INT16_MAX) - { - CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: Missing shader source %s (file %s, line %d)\n", shader_lumpname, wadfiles[wadnum]->filename, linenum); - Z_Free(shader_lumpname); - continue; - } - - shader_size = W_LumpLengthPwad(wadnum, shader_lumpnum); - shader_source = Z_Malloc(shader_size, PU_STATIC, NULL); - W_ReadLumpPwad(wadnum, shader_lumpnum, shader_source); - - HWD.pfnLoadCustomShader(shaderxlat[i].id, shader_source, shader_size, (shadertype == 2)); - - Z_Free(shader_source); - Z_Free(shader_lumpname); - } - } - -skip_field: - stoken = strtok(NULL, "\r\n= "); - linenum++; - } - } - - Z_Free(line); - return; -} - -const char *HWR_GetShaderName(INT32 shader) -{ - INT32 i; - - if (shader) - { - for (i = 0; shaderxlat[i].type; i++) - { - if (shaderxlat[i].id == shader) - return shaderxlat[i].type; - } - - return "Unknown"; - } - - return "Default"; + int tex = HWR_ShouldUsePaletteRendering() ? HWD_SCREENTEXTURE_GENERIC3 : HWD_SCREENTEXTURE_GENERIC2; + HWD.pfnDrawScreenFinalTexture(tex, width, height); } #endif // HWRENDER diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index d73e161c9..f60ec4a33 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -70,6 +70,7 @@ void HWR_MakeScreenFinalTexture(void); void HWR_DrawScreenFinalTexture(int width, int height); // This stuff is put here so models can use them +boolean HWR_UseShader(void); boolean HWR_OverrideObjectLightLevel(mobj_t *thing, INT32 *lightlevel); void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *colormap, const boolean directional); UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap); // Let's see if this can work @@ -79,13 +80,7 @@ FBITFIELD HWR_GetBlendModeFlag(INT32 ast); FBITFIELD HWR_SurfaceBlend(INT32 style, INT32 transtablenum, FSurfaceInfo *pSurf); FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf); -boolean HWR_CompileShaders(void); - -void HWR_LoadAllCustomShaders(void); -void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3); -const char *HWR_GetShaderName(INT32 shader); - -extern customshaderxlat_t shaderxlat[]; +boolean HWR_ShouldUsePaletteRendering(void); extern CV_PossibleValue_t glanisotropicmode_cons_t[]; @@ -120,6 +115,8 @@ extern consvar_t cv_glspritebillboarding; extern consvar_t cv_glskydome; extern consvar_t cv_glbatching; +extern consvar_t cv_glpaletterendering; +extern consvar_t cv_glpalettedepth; extern float gl_viewwidth, gl_viewheight, gl_baseviewwindowy; diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index f80f6bf86..8ba786970 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -391,8 +391,6 @@ static void md2_loadTexture(md2_t *model) if (!grPatch->mipmap->downloaded && !grPatch->mipmap->data) { int w = 0, h = 0; - UINT32 size; - RGBA_t *image; #ifdef HAVE_PNG grPatch->mipmap->format = PNG_Load(filename, &w, &h, grPatch); @@ -413,13 +411,19 @@ static void md2_loadTexture(md2_t *model) grPatch->mipmap->width = (UINT16)w; grPatch->mipmap->height = (UINT16)h; - // Lactozilla: Apply colour cube - image = grPatch->mipmap->data; - size = w*h; - while (size--) + // for palette rendering, color cube is applied in post-processing instead of here + if (!HWR_ShouldUsePaletteRendering()) { - V_CubeApply(&image->s.red, &image->s.green, &image->s.blue); - image++; + UINT32 size; + RGBA_t *image; + // Lactozilla: Apply colour cube + image = grPatch->mipmap->data; + size = w*h; + while (size--) + { + V_CubeApply(&image->s.red, &image->s.green, &image->s.blue); + image++; + } } } @@ -1714,7 +1718,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) p.flip = atransform.flip; p.mirror = atransform.mirror; - HWD.pfnSetShader(SHADER_MODEL); // model shader + if (HWR_UseShader()) + HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_MODEL)); { float this_scale = FIXED_TO_FLOAT(interp.scale); fixed_t floorClip = spr->mobj->terrain ? spr->mobj->terrain->floorClip : 0; diff --git a/src/hardware/hw_shaders.c b/src/hardware/hw_shaders.c index d9168e9dc..2d74ae765 100644 --- a/src/hardware/hw_shaders.c +++ b/src/hardware/hw_shaders.c @@ -434,6 +434,7 @@ customshaderxlat_t shaderxlat[] = {"WallTexture", SHADER_WALL}, {"Sprite", SHADER_SPRITE}, {"Model", SHADER_MODEL}, + {"ModelLight", SHADER_MODEL_LIGHTING}, {"WaterRipple", SHADER_WATER}, {"Fog", SHADER_FOG}, {"Sky", SHADER_SKY}, @@ -444,11 +445,13 @@ customshaderxlat_t shaderxlat[] = void HWR_LoadAllCustomShaders(void) { + /* INT32 i; // read every custom shader - //for (i = 0; i < numwadfiles; i++) - // HWR_LoadCustomShadersFromFile(i, (type == RET_PK3))); + for (i = 0; i < numwadfiles; i++) + HWR_LoadCustomShadersFromFile(i, (type == RET_PK3))); + */ } void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3) diff --git a/src/hardware/hw_shaders.h b/src/hardware/hw_shaders.h new file mode 100644 index 000000000..9e99bdd1f --- /dev/null +++ b/src/hardware/hw_shaders.h @@ -0,0 +1,432 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2021 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_shaders.h +/// \brief Handles the shaders used by the game. + +#ifndef _HW_SHADERS_H_ +#define _HW_SHADERS_H_ + +#include "../doomtype.h" + +// ================ +// Vertex shaders +// ================ + +// +// Generic vertex shader +// + +#define GLSL_DEFAULT_VERTEX_SHADER \ + "void main()\n" \ + "{\n" \ + "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \ + "gl_FrontColor = gl_Color;\n" \ + "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \ + "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ + "}\0" + +// reinterpretation of sprite lighting for models +// it's a combination of how it works for normal sprites & papersprites +#define GLSL_MODEL_LIGHTING_VERTEX_SHADER \ + "uniform float lighting;\n" \ + "uniform vec3 light_dir;\n" \ + "uniform float light_contrast;\n" \ + "uniform float light_backlight;\n" \ + "void main()\n" \ + "{\n" \ + "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \ + "float light = lighting;\n" \ + "if (length(light_dir) > 0.000001) {\n" \ + "mat4 m4 = gl_ProjectionMatrix * gl_ModelViewMatrix;\n" \ + "mat3 m3 = mat3( m4[0].xyz, m4[1].xyz, m4[2].xyz );\n" \ + "float extralight = -dot(normalize(gl_Normal * m3), normalize(light_dir));\n" \ + "extralight *= light_contrast - light_backlight;\n" \ + "extralight *= lighting / 255.0;\n" \ + "light += extralight * 2.5;\n" \ + "}\n" \ + "light = clamp(light / 255.0, 0.0, 1.0);\n" \ + "gl_FrontColor = vec4(light, light, light, 1.0);\n" \ + "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \ + "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ + "}\0" + +// ================== +// Fragment shaders +// ================== + +// +// Generic fragment shader +// + +#define GLSL_DEFAULT_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "void main(void) {\n" \ + "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \ + "}\0" + +// +// 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 \ + "float R_DoomColormap(float light, float z)\n" \ + "{\n" \ + "float lightnum = clamp(light / 17.0, 0.0, 15.0);\n" \ + "float lightz = clamp(z / 16.0, 0.0, 127.0);\n" \ + "float startmap = (15.0 - lightnum) * 4.0;\n" \ + "float scale = 160.0 / (lightz + 1.0);\n" \ + "return startmap - scale * 0.5;\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 \ + "float R_DoomLightingEquation(float light)\n" \ + "{\n" \ + "float z = gl_FragCoord.z / gl_FragCoord.w;\n" \ + "float colormap = floor(R_DoomColormap(light, z)) + 0.5;\n" \ + "return clamp(colormap, 0.0, 31.0) / 32.0;\n" \ + "}\n" + +#define GLSL_SOFTWARE_TINT_EQUATION \ + "if (mix(tint_color.a, 0.0, brightmap_mix) > 0.0) {\n" \ + "float color_bright = sqrt((base_color.r * base_color.r) + (base_color.g * base_color.g) + (base_color.b * base_color.b));\n" \ + "float strength = sqrt(9.0 * mix(tint_color.a, 0.0, brightmap_mix));\n" \ + "final_color.r = clamp((color_bright * (tint_color.r * strength)) + (base_color.r * (1.0 - strength)), 0.0, 1.0);\n" \ + "final_color.g = clamp((color_bright * (tint_color.g * strength)) + (base_color.g * (1.0 - strength)), 0.0, 1.0);\n" \ + "final_color.b = clamp((color_bright * (tint_color.b * strength)) + (base_color.b * (1.0 - strength)), 0.0, 1.0);\n" \ + "}\n" + +#define GLSL_SOFTWARE_FADE_EQUATION \ + "float darkness = R_DoomLightingEquation(final_lighting);\n" \ + "if (fade_start > 0.0 || fade_end < 31.0) {\n" \ + "float fs = fade_start / 31.0;\n" \ + "float fe = fade_end / 31.0;\n" \ + "float fd = fe - fs;\n" \ + "darkness = clamp((darkness - fs) * (1.0 / fd), 0.0, 1.0);\n" \ + "}\n" \ + "float colorBrightness = sqrt((final_color.r * final_color.r) + (final_color.g * final_color.g) + (final_color.b * final_color.b));\n" \ + "float fogBrightness = sqrt((fade_color.r * fade_color.r) + (fade_color.g * fade_color.g) + (fade_color.b * fade_color.b));\n" \ + "float colorIntensity = 0.0;\n" \ + "if (colorBrightness < fogBrightness) {\n" \ + "colorIntensity = 1.0 - min(final_color.r, min(final_color.g, final_color.b));\n" \ + "colorIntensity = abs(colorIntensity - (1.0 - max(fade_color.r, max(fade_color.g, fade_color.b))));\n" \ + "} else {\n" \ + "colorIntensity = max(final_color.r, max(final_color.g, final_color.b));\n" \ + "colorIntensity = abs(colorIntensity - min(fade_color.r, min(fade_color.g, fade_color.b)));\n" \ + "}\n" \ + "colorIntensity *= darkness;\n" \ + "colorIntensity *= fade_color.a * 10.0;\n" \ + "if (abs(final_color.r - fade_color.r) <= colorIntensity) {\n" \ + " final_color.r = fade_color.r;\n" \ + "} else if (final_color.r < fade_color.r) {\n" \ + "final_color.r += colorIntensity;\n" \ + "} else {\n" \ + "final_color.r -= colorIntensity;\n" \ + "}\n" \ + "if (abs(final_color.g - fade_color.g) <= colorIntensity) {\n" \ + "final_color.g = fade_color.g;\n" \ + "} else if (final_color.g < fade_color.g) {\n" \ + "final_color.g += colorIntensity;\n" \ + "} else {\n" \ + "final_color.g -= colorIntensity;\n" \ + "}\n" \ + "if (abs(final_color.b - fade_color.b) <= colorIntensity) {\n" \ + "final_color.b = fade_color.b;\n" \ + "} else if (final_color.b < fade_color.b) {\n" \ + "final_color.b += colorIntensity;\n" \ + "} else {\n" \ + "final_color.b -= colorIntensity;\n" \ + "}\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(final_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 \ + "#ifdef SRB2_PALETTE_RENDERING\n" \ + "uniform sampler2D tex;\n" \ + "uniform sampler2D brightmap;\n" \ + "uniform vec4 poly_color;\n" \ + "uniform float lighting;\n" \ + "uniform sampler3D palette_lookup_tex;\n" \ + "uniform sampler2D lighttable_tex;\n" \ + GLSL_DOOM_COLORMAP \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + "float brightmap_mix = floor(texture2D(brightmap, gl_TexCoord[0].st).r);\n" \ + "float light_gain = (255.0 - lighting) * brightmap_mix;\n" \ + "float final_lighting = lighting + light_gain;\n" \ + GLSL_PALETTE_RENDERING \ + "}\n" \ + "#else\n" \ + "uniform sampler2D tex;\n" \ + "uniform sampler2D brightmap;\n" \ + "uniform vec4 poly_color;\n" \ + "uniform vec4 tint_color;\n" \ + "uniform vec4 fade_color;\n" \ + "uniform float lighting;\n" \ + "uniform float fade_start;\n" \ + "uniform float fade_end;\n" \ + GLSL_DOOM_COLORMAP \ + GLSL_DOOM_LIGHT_EQUATION \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + "vec4 base_color = texel * poly_color;\n" \ + "vec4 final_color = base_color;\n" \ + "float brightmap_mix = floor(texture2D(brightmap, gl_TexCoord[0].st).r);\n" \ + "float light_gain = (255.0 - lighting) * brightmap_mix;\n" \ + "float final_lighting = lighting + light_gain;\n" \ + GLSL_SOFTWARE_TINT_EQUATION \ + GLSL_SOFTWARE_FADE_EQUATION \ + "final_color.a = texel.a * poly_color.a;\n" \ + "gl_FragColor = final_color;\n" \ + "}\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_FLOOR_FRAGMENT_SHADER \ + "#version 120\n" \ + GLSL_FLOOR_FUDGES \ + GLSL_SOFTWARE_FRAGMENT_SHADER + +#define GLSL_WALL_FRAGMENT_SHADER \ + "#version 120\n" \ + GLSL_WALL_FUDGES \ + GLSL_SOFTWARE_FRAGMENT_SHADER + +// same as above but multiplies results with the lighting value from the +// accompanying vertex shader (stored in gl_Color) +#define GLSL_SOFTWARE_MODEL_LIGHTING_FRAGMENT_SHADER \ + GLSL_WALL_FUDGES \ + "#ifdef SRB2_PALETTE_RENDERING\n" \ + "uniform sampler2D tex;\n" \ + "uniform sampler2D brightmap;\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" \ + "float final_lighting = gl_Color.r * 255.0;\n" \ + "float brightmap_mix = floor(texture2D(brightmap, gl_TexCoord[0].st).r);\n" \ + "float light_gain = (255.0 - final_lighting) * brightmap_mix;\n" \ + "final_lighting += light_gain;\n" \ +GLSL_PALETTE_RENDERING \ + "}\n" \ + "#else\n" \ + "uniform sampler2D tex;\n" \ + "uniform sampler2D brightmap;\n" \ + "uniform vec4 poly_color;\n" \ + "uniform vec4 tint_color;\n" \ + "uniform vec4 fade_color;\n" \ + "uniform float fade_start;\n" \ + "uniform float fade_end;\n" \ + GLSL_DOOM_COLORMAP \ + GLSL_DOOM_LIGHT_EQUATION \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + "vec4 base_color = texel * poly_color;\n" \ + "vec4 final_color = base_color;\n" \ + "float final_lighting = gl_Color.r * 255.0;\n" \ + "float brightmap_mix = floor(texture2D(brightmap, gl_TexCoord[0].st).r);\n" \ + "float light_gain = (255.0 - final_lighting) * brightmap_mix;\n" \ + "final_lighting += light_gain;\n" \ + GLSL_SOFTWARE_TINT_EQUATION \ + GLSL_SOFTWARE_FADE_EQUATION \ + "final_color.a = texel.a * poly_color.a;\n" \ + "gl_FragColor = final_color;\n" \ + "}\n" \ + "#endif\0" + +// +// Water surface shader +// +// Mostly guesstimated, rather than the rest being built off Software science. +// 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 \ + "#version 120\n" \ + 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 sampler2D brightmap;\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 \ + "float brightmap_mix = floor(texture2D(brightmap, gl_TexCoord[0].st).r);\n" \ + "float light_gain = (255.0 - lighting) * brightmap_mix;\n" \ + "float final_lighting = lighting + light_gain;\n" \ + GLSL_PALETTE_RENDERING \ + "}\n" \ + "#else\n" \ + "uniform sampler2D tex;\n" \ + "uniform sampler2D brightmap;\n" \ + "uniform vec4 poly_color;\n" \ + "uniform vec4 tint_color;\n" \ + "uniform vec4 fade_color;\n" \ + "uniform float lighting;\n" \ + "uniform float fade_start;\n" \ + "uniform float fade_end;\n" \ + "uniform float leveltime;\n" \ + GLSL_DOOM_COLORMAP \ + GLSL_DOOM_LIGHT_EQUATION \ + "void main(void) {\n" \ + GLSL_WATER_TEXEL \ + "vec4 base_color = texel * poly_color;\n" \ + "vec4 final_color = base_color;\n" \ + "float brightmap_mix = floor(texture2D(brightmap, gl_TexCoord[0].st).r);\n" \ + "float light_gain = (255.0 - lighting) * brightmap_mix;\n" \ + "float final_lighting = lighting + light_gain;\n" \ + GLSL_SOFTWARE_TINT_EQUATION \ + GLSL_SOFTWARE_FADE_EQUATION \ + "final_color.a = texel.a * poly_color.a;\n" \ + "gl_FragColor = final_color;\n" \ + "}\n" \ + "#endif\0" + +// +// Fog block shader +// +// 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 \ + "#version 120\n" \ + GLSL_FLOOR_FUDGES \ + "uniform vec4 tint_color;\n" \ + "uniform vec4 fade_color;\n" \ + "uniform float lighting;\n" \ + "uniform float fade_start;\n" \ + "uniform float fade_end;\n" \ + GLSL_DOOM_COLORMAP \ + GLSL_DOOM_LIGHT_EQUATION \ + "void main(void) {\n" \ + "vec4 base_color = gl_Color;\n" \ + "vec4 final_color = base_color;\n" \ + "float brightmap_mix = 0.0;\n" \ + "float light_gain = 0.0;\n" \ + "float final_lighting = lighting + light_gain;\n" \ + GLSL_SOFTWARE_TINT_EQUATION \ + GLSL_SOFTWARE_FADE_EQUATION \ + "gl_FragColor = final_color;\n" \ + "}\0" + +// +// Sky fragment shader +// Modulates poly_color with gl_Color +// +#define GLSL_SKY_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "void main(void) {\n" \ + "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * gl_Color * poly_color;\n" \ + "}\0" + +// Shader for the palette rendering postprocess step +#define GLSL_PALETTE_POSTPROCESS_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform sampler3D palette_lookup_tex;\n" \ + "uniform sampler1D 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(palette_tex, palette_coord);\n" \ + "gl_FragColor = final_color;\n" \ + "}\0" + +// Applies a palettized colormap fade to tex +#define GLSL_UI_COLORMAP_FADE_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform float lighting;\n" \ + "uniform sampler3D palette_lookup_tex;\n" \ + "uniform sampler2D lighttable_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" \ + "vec2 lighttable_coord = vec2((tex_pal_idx + 0.5) / 256.0, (lighting + 0.5) / 32.0);\n" \ + "gl_FragColor = texture2D(lighttable_tex, lighttable_coord);\n" \ + "}\0" + +// +// Generic vertex shader +// + +#define GLSL_FALLBACK_VERTEX_SHADER \ + "void main()\n" \ + "{\n" \ + "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \ + "gl_FrontColor = gl_Color;\n" \ + "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \ + "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ + "}\0" + +// +// Generic fragment shader +// + +#define GLSL_FALLBACK_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "void main(void) {\n" \ + "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \ + "}\0" + +// +// Sky fragment shader +// Modulates poly_color with gl_Color +// +#define GLSL_SKY_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "void main(void) {\n" \ + "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * gl_Color * poly_color;\n" \ + "}\0" + +#endif diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 31aa0e120..3700083e2 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -24,12 +24,14 @@ #include "../../r_fps.h" // For R_GetTimeFrac, used for the leveltime shader uniform #include "r_opengl.h" #include "r_vbo.h" +#include "../hw_clip.h" +#include "../hw_shaders.h" + +#if defined (HWRENDER) && !defined (NOROPENGL) // requires GL 4.3 //#define GLDEBUGMESSAGE -#if defined (HWRENDER) && !defined (NOROPENGL) - struct GLRGBAFloat { GLfloat red; @@ -38,12 +40,21 @@ struct GLRGBAFloat GLfloat alpha; }; 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 // ========================================================================== +static const GLubyte white[4] = { 255, 255, 255, 255 }; + // With OpenGL 1.1+, the first texture should be 1 static GLuint NOTEXTURE_NUM = 0; @@ -59,6 +70,7 @@ static float NEAR_CLIPPING_PLANE = NZCLIP_PLANE; static GLuint tex_downloaded = 0; +static GLuint lt_downloaded = 0; // currently bound lighttable texture static GLfloat fov = 90.0f; static FBITFIELD CurrentPolyFlags; @@ -69,8 +81,15 @@ static FTextureInfo *TexCacheHead = NULL; static RGBA_t *textureBuffer = NULL; static size_t textureBufferSize = 0; -RGBA_t myPaletteData[256]; -GLint screen_width = 0; // used by Draw2DLine() +// 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_height = 0; GLint texsize = 512; // Power-of-two screen texture render resolution GLbyte screen_depth = 0; @@ -96,11 +115,7 @@ static GLint viewport[4]; // flush all of the stored textures, leaving them unavailable at times such as between levels // These need to start at 0 and be set to their number, and be reset to 0 when deleted so that intel GPUs // can know when the textures aren't there, as textures are always considered resident in their virtual memory -static GLuint screentexture = 0; -static GLuint intermissionbg = 0; -static GLuint startScreenWipe = 0; -static GLuint endScreenWipe = 0; -static GLuint finalScreenTexture = 0; +static GLuint screenTextures[NUMSCREENTEXTURES] = {0}; // shortcut for ((float)1/i) static const GLfloat byte2float[256] = { @@ -386,10 +401,14 @@ typedef void (APIENTRY * PFNglTexEnvi) (GLenum target, GLenum pname, GLint param static PFNglTexEnvi pglTexEnvi; typedef void (APIENTRY * PFNglTexParameteri) (GLenum target, GLenum pname, GLint param); 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); 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); static PFNglTexSubImage2D pglTexSubImage2D; +typedef void (APIENTRY * PFNglGetTexImage) (GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +static PFNglGetTexImage pglGetTexImage; /* 1.1 functions */ /* texture objects */ //GL_EXT_texture_object @@ -406,6 +425,10 @@ typedef void (APIENTRY * PFNglCopyTexSubImage2D) (GLenum target, GLint level, GL static PFNglCopyTexSubImage2D pglCopyTexSubImage2D; #endif +/* 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 */ typedef void (APIENTRY *PFNglActiveTexture) (GLenum); static PFNglActiveTexture pglActiveTexture; @@ -455,6 +478,9 @@ static PFNglDebugMessageCallback pglDebugMessageCallback; #ifndef GL_TEXTURE1 #define GL_TEXTURE1 0x84C1 #endif +#ifndef GL_TEXTURE2 +#define GL_TEXTURE2 0x84C2 +#endif /* 1.5 Parms */ #ifndef GL_ARRAY_BUFFER @@ -526,8 +552,10 @@ boolean SetupGLfunc(void) GETOPENGLFUNC(pglTexEnvi, glTexEnvi) GETOPENGLFUNC(pglTexParameteri, glTexParameteri) + GETOPENGLFUNC(pglTexImage1D, glTexImage1D) GETOPENGLFUNC(pglTexImage2D, glTexImage2D) GETOPENGLFUNC(pglTexSubImage2D, glTexSubImage2D) + GETOPENGLFUNC(pglGetTexImage, glGetTexImage) GETOPENGLFUNC(pglGenTextures, glGenTextures) GETOPENGLFUNC(pglDeleteTextures, glDeleteTextures) @@ -543,7 +571,7 @@ boolean SetupGLfunc(void) } static boolean gl_shadersenabled = false; -static hwdshaderoption_t gl_allowshaders = HWD_SHADEROPTION_OFF; +static INT32 gl_allowshaders = 0; #ifdef GL_SHADERS typedef GLuint (APIENTRY *PFNglCreateShader) (GLenum); @@ -609,7 +637,12 @@ typedef enum gluniform_light_contrast, gluniform_light_backlight, - // misc. (custom shaders) + // palette rendering + gluniform_palette_tex, // 1d texture containing a palette + gluniform_palette_lookup_tex, // 3d texture containing the rgb->index lookup table + gluniform_lighttable_tex, // 2d texture containing a light table + + // misc. gluniform_leveltime, gluniform_max, @@ -617,14 +650,15 @@ typedef enum typedef struct gl_shader_s { + char *vertex_shader; + char *fragment_shader; GLuint program; GLint uniforms[gluniform_max+1]; - boolean custom; } gl_shader_t; static gl_shader_t gl_shaders[HWR_MAXSHADERS]; -static gl_shader_t gl_usershaders[HWR_MAXSHADERS]; -static shadersource_t gl_customshaders[HWR_MAXSHADERS]; + +static gl_shader_t gl_fallback_shader; // 09102020 typedef struct gl_shaderstate_s @@ -645,319 +679,18 @@ static INT32 shader_light_contrast = 0; static INT32 shader_light_backlight = 0; // Lactozilla: Shader functions -static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar *vert_shader, const GLchar *frag_shader); +static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i); static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum); static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f}; - -#define GLSL_DOOM_COLORMAP \ - "float R_DoomColormap(float light, float z)\n" \ - "{\n" \ - "float lightnum = clamp(light / 17.0, 0.0, 15.0);\n" \ - "float lightz = clamp(z / 16.0, 0.0, 127.0);\n" \ - "float startmap = (15.0 - lightnum) * 4.0;\n" \ - "float scale = 160.0 / (lightz + 1.0);\n" \ - "return startmap - scale * 0.5;\n" \ - "}\n" - -#define GLSL_DOOM_LIGHT_EQUATION \ - "float R_DoomLightingEquation(float light)\n" \ - "{\n" \ - "float z = gl_FragCoord.z / gl_FragCoord.w;\n" \ - "float colormap = floor(R_DoomColormap(light, z)) + 0.5;\n" \ - "return clamp(colormap, 0.0, 31.0) / 32.0;\n" \ - "}\n" - -#define GLSL_SOFTWARE_TINT_EQUATION \ - "if (mix(tint_color.a, 0.0, brightmap_mix) > 0.0) {\n" \ - "float color_bright = sqrt((base_color.r * base_color.r) + (base_color.g * base_color.g) + (base_color.b * base_color.b));\n" \ - "float strength = sqrt(9.0 * mix(tint_color.a, 0.0, brightmap_mix));\n" \ - "final_color.r = clamp((color_bright * (tint_color.r * strength)) + (base_color.r * (1.0 - strength)), 0.0, 1.0);\n" \ - "final_color.g = clamp((color_bright * (tint_color.g * strength)) + (base_color.g * (1.0 - strength)), 0.0, 1.0);\n" \ - "final_color.b = clamp((color_bright * (tint_color.b * strength)) + (base_color.b * (1.0 - strength)), 0.0, 1.0);\n" \ - "}\n" - -#define GLSL_SOFTWARE_FADE_EQUATION \ - "float darkness = R_DoomLightingEquation(final_lighting);\n" \ - "if (fade_start > 0.0 || fade_end < 31.0) {\n" \ - "float fs = fade_start / 31.0;\n" \ - "float fe = fade_end / 31.0;\n" \ - "float fd = fe - fs;\n" \ - "darkness = clamp((darkness - fs) * (1.0 / fd), 0.0, 1.0);\n" \ - "}\n" \ - "if (newfade)\n" \ - "{\n" \ - "float colorBrightness = sqrt((final_color.r * final_color.r) + (final_color.g * final_color.g) + (final_color.b * final_color.b));\n" \ - "float fogBrightness = sqrt((fade_color.r * fade_color.r) + (fade_color.g * fade_color.g) + (fade_color.b * fade_color.b));\n" \ - "float colorIntensity = 0.0;\n" \ - "if (colorBrightness < fogBrightness) {\n" \ - "colorIntensity = 1.0 - min(final_color.r, min(final_color.g, final_color.b));\n" \ - "colorIntensity = abs(colorIntensity - (1.0 - max(fade_color.r, max(fade_color.g, fade_color.b))));\n" \ - "} else {\n" \ - "colorIntensity = max(final_color.r, max(final_color.g, final_color.b));\n" \ - "colorIntensity = abs(colorIntensity - min(fade_color.r, min(fade_color.g, fade_color.b)));\n" \ - "}\n" \ - "colorIntensity *= darkness;\n" \ - "colorIntensity *= fade_color.a * 10.0;\n" \ - "if (abs(final_color.r - fade_color.r) <= colorIntensity) {\n" \ - "final_color.r = fade_color.r;\n" \ - "} else if (final_color.r < fade_color.r) {\n" \ - "final_color.r += colorIntensity;\n" \ - "} else {\n" \ - "final_color.r -= colorIntensity;\n" \ - "}\n" \ - "if (abs(final_color.g - fade_color.g) <= colorIntensity) {\n" \ - "final_color.g = fade_color.g;\n" \ - "} else if (final_color.g < fade_color.g) {\n" \ - "final_color.g += colorIntensity;\n" \ - "} else {\n" \ - "final_color.g -= colorIntensity;\n" \ - "}\n" \ - "if (abs(final_color.b - fade_color.b) <= colorIntensity) {\n" \ - "final_color.b = fade_color.b;\n" \ - "} else if (final_color.b < fade_color.b) {\n" \ - "final_color.b += colorIntensity;\n" \ - "} else {\n" \ - "final_color.b -= colorIntensity;\n" \ - "}\n" \ - "} else {\n" \ - "final_color = mix(final_color, fade_color, darkness);\n" \ - "}\n" - -// ================ -// Vertex shaders -// ================ - -// -// Generic vertex shader -// - -#define GLSL_DEFAULT_VERTEX_SHADER \ - "void main()\n" \ - "{\n" \ - "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \ - "gl_FrontColor = gl_Color;\n" \ - "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \ - "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ - "}\0" - -// reinterpretation of sprite lighting for models -// it's a combination of how it works for normal sprites & papersprites -#define GLSL_MODEL_LIGHTING_VERTEX_SHADER \ - "uniform float lighting;\n" \ - "uniform vec3 light_dir;\n" \ - "uniform float light_contrast;\n" \ - "uniform float light_backlight;\n" \ - "void main()\n" \ - "{\n" \ - "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \ - "float light = lighting;\n" \ - "if (length(light_dir) > 0.000001) {\n" \ - "mat4 m4 = gl_ProjectionMatrix * gl_ModelViewMatrix;\n" \ - "mat3 m3 = mat3( m4[0].xyz, m4[1].xyz, m4[2].xyz );\n" \ - "float extralight = -dot(normalize(gl_Normal * m3), normalize(light_dir));\n" \ - "extralight *= light_contrast - light_backlight;\n" \ - "extralight *= lighting / 255.0;\n" \ - "light += extralight * 2.5;\n" \ - "}\n" \ - "light = clamp(light / 255.0, 0.0, 1.0);\n" \ - "gl_FrontColor = vec4(light, light, light, 1.0);\n" \ - "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \ - "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ - "}\0" - -// ================== -// Fragment shaders -// ================== - -// -// Generic fragment shader -// - -#define GLSL_DEFAULT_FRAGMENT_SHADER \ - "uniform sampler2D tex;\n" \ - "uniform vec4 poly_color;\n" \ - "void main(void) {\n" \ - "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \ - "}\0" - -// -// Software fragment shader -// - -#define GLSL_SOFTWARE_FRAGMENT_SHADER \ - "uniform sampler2D tex;\n" \ - "uniform sampler2D brightmap;\n" \ - "uniform vec4 poly_color;\n" \ - "uniform vec4 tint_color;\n" \ - "uniform vec4 fade_color;\n" \ - "uniform float lighting;\n" \ - "uniform float fade_start;\n" \ - "uniform float fade_end;\n" \ - "uniform bool newfade;\n" \ - GLSL_DOOM_COLORMAP \ - GLSL_DOOM_LIGHT_EQUATION \ - "void main(void) {\n" \ - "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ - "vec4 base_color = texel * poly_color;\n" \ - "vec4 final_color = base_color;\n" \ - "float brightmap_mix = floor(texture2D(brightmap, gl_TexCoord[0].st).r);\n" \ - "float light_gain = (255.0 - lighting) * brightmap_mix;\n" \ - "float final_lighting = lighting + light_gain;\n" \ - GLSL_SOFTWARE_TINT_EQUATION \ - GLSL_SOFTWARE_FADE_EQUATION \ - "final_color.a = texel.a * poly_color.a;\n" \ - "gl_FragColor = final_color;\n" \ - "}\0" - -// same as above but multiplies results with the lighting value from the -// accompanying vertex shader (stored in gl_Color) -#define GLSL_SOFTWARE_MODEL_LIGHTING_FRAGMENT_SHADER \ - "uniform sampler2D tex;\n" \ - "uniform sampler2D brightmap;\n" \ - "uniform vec4 poly_color;\n" \ - "uniform vec4 tint_color;\n" \ - "uniform vec4 fade_color;\n" \ - "uniform float fade_start;\n" \ - "uniform float fade_end;\n" \ - "uniform bool newfade;\n" \ - GLSL_DOOM_COLORMAP \ - GLSL_DOOM_LIGHT_EQUATION \ - "void main(void) {\n" \ - "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ - "vec4 base_color = texel * poly_color;\n" \ - "vec4 final_color = base_color;\n" \ - "float final_lighting = gl_Color.r * 255.0;\n" \ - "float brightmap_mix = floor(texture2D(brightmap, gl_TexCoord[0].st).r);\n" \ - "float light_gain = (255.0 - final_lighting) * brightmap_mix;\n" \ - "final_lighting += light_gain;\n" \ - GLSL_SOFTWARE_TINT_EQUATION \ - GLSL_SOFTWARE_FADE_EQUATION \ - "final_color.a = texel.a * poly_color.a;\n" \ - "gl_FragColor = final_color;\n" \ - "}\0" - -// -// Water surface shader -// -// Mostly guesstimated, rather than the rest being built off Software science. -// Still needs to distort things underneath/around the water... -// - -#define GLSL_WATER_FRAGMENT_SHADER \ - "uniform sampler2D tex;\n" \ - "uniform sampler2D brightmap;\n" \ - "uniform vec4 poly_color;\n" \ - "uniform vec4 tint_color;\n" \ - "uniform vec4 fade_color;\n" \ - "uniform float lighting;\n" \ - "uniform float fade_start;\n" \ - "uniform float fade_end;\n" \ - "uniform bool newfade;\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_LIGHT_EQUATION \ - "void main(void) {\n" \ - "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" \ - "vec4 base_color = texel * poly_color;\n" \ - "vec4 final_color = base_color;\n" \ - "float brightmap_mix = floor(texture2D(brightmap, gl_TexCoord[0].st).r);\n" \ - "float light_gain = (255.0 - lighting) * brightmap_mix;\n" \ - "float final_lighting = lighting + light_gain;\n" \ - GLSL_SOFTWARE_TINT_EQUATION \ - GLSL_SOFTWARE_FADE_EQUATION \ - "final_color.a = texel.a * poly_color.a;\n" \ - "gl_FragColor = final_color;\n" \ - "}\0" - -// -// Fog block shader -// -// Alpha of the planes themselves are still slightly off -- see HWR_FogBlockAlpha -// - -#define GLSL_FOG_FRAGMENT_SHADER \ - "uniform vec4 tint_color;\n" \ - "uniform vec4 fade_color;\n" \ - "uniform float lighting;\n" \ - "uniform float fade_start;\n" \ - "uniform float fade_end;\n" \ - "uniform bool newfade;\n" \ - GLSL_DOOM_COLORMAP \ - GLSL_DOOM_LIGHT_EQUATION \ - "void main(void) {\n" \ - "vec4 base_color = gl_Color;\n" \ - "vec4 final_color = base_color;\n" \ - "float brightmap_mix = 0.0;\n" \ - "float light_gain = 0.0;\n" \ - "float final_lighting = lighting + light_gain;\n" \ - GLSL_SOFTWARE_TINT_EQUATION \ - GLSL_SOFTWARE_FADE_EQUATION \ - "gl_FragColor = final_color;\n" \ - "}\0" - -// -// Sky fragment shader -// Modulates poly_color with gl_Color -// -#define GLSL_SKY_FRAGMENT_SHADER \ - "uniform sampler2D tex;\n" \ - "uniform vec4 poly_color;\n" \ - "void main(void) {\n" \ - "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * gl_Color * poly_color;\n" \ - "}\0" - -// ================ -// Shader sources -// ================ - -static struct { - const char *vertex; - const char *fragment; -} const gl_shadersources[] = { - // Default shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_DEFAULT_FRAGMENT_SHADER}, - - // Floor shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, - - // Wall shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, - - // Sprite shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, - - // Model shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, - - // Model shader + diffuse lighting from above - {GLSL_MODEL_LIGHTING_VERTEX_SHADER, GLSL_SOFTWARE_MODEL_LIGHTING_FRAGMENT_SHADER}, - - // Water shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_WATER_FRAGMENT_SHADER}, - - // Fog shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_FOG_FRAGMENT_SHADER}, - - // Sky shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SKY_FRAGMENT_SHADER}, - - {NULL, NULL}, -}; - #endif // GL_SHADERS void SetupGLFunc4(void) { + /* 1.2 funcs */ + *(void**)&pglTexImage3D = GetGLFunc("glTexImage3D"); + /* 1.3 funcs */ *(void**)&pglActiveTexture = GetGLFunc("glActiveTexture"); *(void**)&pglMultiTexCoord2f = GetGLFunc("glMultiTexCoord2f"); *(void**)&pglClientActiveTexture = GetGLFunc("glClientActiveTexture"); @@ -1001,55 +734,20 @@ void SetupGLFunc4(void) #endif } -EXPORT boolean HWRAPI(CompileShaders) (void) +EXPORT boolean HWRAPI(InitShaders) (void) { #ifdef GL_SHADERS - GLint i; if (!pglUseProgram) return false; - gl_customshaders[SHADER_DEFAULT].vertex = NULL; - gl_customshaders[SHADER_DEFAULT].fragment = NULL; + gl_fallback_shader.vertex_shader = Z_StrDup(GLSL_FALLBACK_VERTEX_SHADER); + gl_fallback_shader.fragment_shader = Z_StrDup(GLSL_FALLBACK_FRAGMENT_SHADER); - for (i = 0; gl_shadersources[i].vertex && gl_shadersources[i].fragment; i++) + if (!Shader_CompileProgram(&gl_fallback_shader, -1)) { - gl_shader_t *shader, *usershader; - const GLchar *vert_shader = gl_shadersources[i].vertex; - const GLchar *frag_shader = gl_shadersources[i].fragment; - - if (i >= HWR_MAXSHADERS) - break; - - shader = &gl_shaders[i]; - usershader = &gl_usershaders[i]; - - if (shader->program) - pglDeleteProgram(shader->program); - if (usershader->program) - pglDeleteProgram(usershader->program); - - shader->program = 0; - usershader->program = 0; - - if (!Shader_CompileProgram(shader, i, vert_shader, frag_shader)) - shader->program = 0; - - // Compile custom shader - if ((i == SHADER_DEFAULT) || !(gl_customshaders[i].vertex || gl_customshaders[i].fragment)) - continue; - - // 18032019 - if (gl_customshaders[i].vertex) - vert_shader = gl_customshaders[i].vertex; - if (gl_customshaders[i].fragment) - frag_shader = gl_customshaders[i].fragment; - - if (!Shader_CompileProgram(usershader, i, vert_shader, frag_shader)) - { - GL_MSG_Warning("CompileShaders: Could not compile custom shader program for %s\n", HWR_GetShaderName(i)); - usershader->program = 0; - } + GL_MSG_Error("Failed to compile the fallback shader program!\n"); + return false; } return true; @@ -1058,6 +756,59 @@ EXPORT boolean HWRAPI(CompileShaders) (void) #endif } +EXPORT void HWRAPI(LoadShader) (int slot, char *code, hwdshaderstage_t stage) +{ +#ifdef GL_SHADERS + gl_shader_t *shader; + + if (slot < 0 || slot >= HWR_MAXSHADERS) + I_Error("LoadShader: Invalid slot %d", slot); + + shader = &gl_shaders[slot]; + +#define LOADSHADER(source) { \ + if (shader->source) \ + Z_Free(shader->source); \ + shader->source = code; \ + } + + if (stage == HWD_SHADERSTAGE_VERTEX) + LOADSHADER(vertex_shader) + else if (stage == HWD_SHADERSTAGE_FRAGMENT) + LOADSHADER(fragment_shader) + else + I_Error("LoadShader: invalid shader stage"); + +#undef LOADSHADER +#else + (void)slot; + (void)code; + (void)stage; +#endif +} + + +EXPORT boolean HWRAPI(CompileShader) (int slot) +{ +#ifdef GL_SHADERS + if (slot < 0 || slot >= HWR_MAXSHADERS) + I_Error("CompileShader: Invalid slot %d", slot); + + if (Shader_CompileProgram(&gl_shaders[slot], slot)) + { + return true; + } + else + { + gl_shaders[slot].program = 0; + return false; + } +#else + (void)slot; + return false; +#endif +} + // // Shader info // Those are given to the uniforms. @@ -1095,90 +846,36 @@ EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value) #endif } -// -// Custom shader loading -// -EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boolean isfragment) +EXPORT void HWRAPI(SetShader) (int slot) { #ifdef GL_SHADERS - shadersource_t *shader; - - if (!pglUseProgram) - return; - - if (number < 1 || number > HWR_MAXSHADERS) - I_Error("LoadCustomShader: cannot load shader %d (min 1, max %d)", number, HWR_MAXSHADERS); - else if (code == NULL) - I_Error("LoadCustomShader: empty shader"); - - shader = &gl_customshaders[number]; - -#define COPYSHADER(source) { \ - if (shader->source) \ - free(shader->source); \ - shader->source = malloc(size+1); \ - strncpy(shader->source, code, size); \ - shader->source[size] = 0; \ - } - - if (isfragment) - COPYSHADER(fragment) - else - COPYSHADER(vertex) - -#else - (void)number; - (void)shader; - (void)size; - (void)fragment; -#endif -} - -EXPORT void HWRAPI(SetShader) (int type) -{ -#ifdef GL_SHADERS - if (type == SHADER_NONE) + if (slot == SHADER_NONE) { UnSetShader(); return; } - if (gl_allowshaders != HWD_SHADEROPTION_OFF) + if (gl_allowshaders) { - gl_shader_t *shader = gl_shaderstate.current; + gl_shader_t *next_shader = &gl_shaders[slot]; // the gl_shader_t we are going to switch to - // If using model lighting, set the appropriate shader. - // However don't override a custom shader. - if (type == SHADER_MODEL && model_lighting - && !(gl_shaders[SHADER_MODEL].custom && !gl_shaders[SHADER_MODEL_LIGHTING].custom)) - type = SHADER_MODEL_LIGHTING; + if (!next_shader->program) + next_shader = &gl_fallback_shader; // unusable shader, use fallback instead - if ((shader == NULL) || (GLuint)type != gl_shaderstate.type) + // update gl_shaderstate if an actual shader switch is needed + if (gl_shaderstate.current != next_shader) { - gl_shader_t *baseshader = &gl_shaders[type]; - gl_shader_t *usershader = &gl_usershaders[type]; - - if (usershader->program) - shader = (gl_allowshaders == HWD_SHADEROPTION_NOCUSTOM) ? baseshader : usershader; - else - shader = baseshader; - - gl_shaderstate.current = shader; - gl_shaderstate.type = type; + gl_shaderstate.current = next_shader; + gl_shaderstate.program = next_shader->program; + gl_shaderstate.type = slot; gl_shaderstate.changed = true; } + gl_shadersenabled = true; - if (gl_shaderstate.program != shader->program) - { - gl_shaderstate.program = shader->program; - gl_shaderstate.changed = true; - } - - gl_shadersenabled = (shader->program != 0); return; } #else - (void)type; + (void)slot; #endif gl_shadersenabled = false; } @@ -1186,36 +883,20 @@ EXPORT void HWRAPI(SetShader) (int type) EXPORT void HWRAPI(UnSetShader) (void) { #ifdef GL_SHADERS - gl_shaderstate.current = NULL; - gl_shaderstate.type = 0; - gl_shaderstate.program = 0; + if (gl_shadersenabled) // don't repeatedly call glUseProgram if not needed + { + gl_shaderstate.current = NULL; + gl_shaderstate.type = 0; + gl_shaderstate.program = 0; - if (pglUseProgram) - pglUseProgram(0); + if (pglUseProgram) + pglUseProgram(0); + } #endif gl_shadersenabled = false; } -EXPORT void HWRAPI(CleanShaders) (void) -{ - INT32 i; - - for (i = 1; i < HWR_MAXSHADERS; i++) - { - shadersource_t *shader = &gl_customshaders[i]; - - if (shader->vertex) - free(shader->vertex); - - if (shader->fragment) - free(shader->fragment); - - shader->vertex = NULL; - shader->fragment = NULL; - } -} - // -----------------+ // SetNoTexture : Disable texture // -----------------+ @@ -1580,20 +1261,29 @@ EXPORT void HWRAPI(ClearMipMapCache) (void) Flush(); } -// -----------------------+ -// ReadScreenFinalTexture : Reads out the final screen texture -// Returns : 24bit RGB pixel array stored in dest -// -----------------------+ -EXPORT void HWRAPI(ReadScreenFinalTexture) (UINT8 * restrict dest, INT32 scale) +// Writes screen texture tex into dst_data. +// Pixel format is 24-bit RGB. Row order is top to bottom. +// Dimensions are screen_width * screen_height. +EXPORT void HWRAPI(ReadScreenTexture) (int tex, UINT8 *restrict dest, INT32 scale) { const INT32 stride = (screen_width/scale)*3; INT32 scanlines = screen_height; GLubyte * restrict image; + // at the time this function is called, generic2 can be found drawn on the framebuffer + // if some other screen texture is needed, draw it to the framebuffer + // and draw generic2 back after reading the framebuffer. + // this hack is for some reason **much** faster than the simple solution of using glGetTexImage. + if (tex != HWD_SCREENTEXTURE_GENERIC2) + DrawScreenTexture(tex, NULL, 0); + image = malloc(screen_width*screen_height*3); pglPixelStorei(GL_PACK_ALIGNMENT, 1); pglReadPixels(0, 0, screen_width, screen_height, GL_RGB, GL_UNSIGNED_BYTE, image); + if (tex != HWD_SCREENTEXTURE_GENERIC2) + DrawScreenTexture(HWD_SCREENTEXTURE_GENERIC2, NULL, 0); + // TODO the downscaling happens in the screen capture code now, // yet we're still doing this on the CPU? sheesh... // this is where actual knowledge of OpenGL would've come in handy @@ -1612,6 +1302,7 @@ EXPORT void HWRAPI(ReadScreenFinalTexture) (UINT8 * restrict dest, INT32 scale) free(image - ((screen_height % scale) * screen_width*3)); } + // -----------------+ // GClipRect : Defines the 2D hardware clipping window // -----------------+ @@ -2229,69 +1920,91 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF #endif } -static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar *vert_shader, const GLchar *frag_shader) +static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i) { - GLuint gl_vertShader, gl_fragShader; + GLuint gl_vertShader = 0; + GLuint gl_fragShader = 0; GLint result; + const GLchar *vert_shader = shader->vertex_shader; + const GLchar *frag_shader = shader->fragment_shader; - // - // Load and compile vertex shader - // - gl_vertShader = pglCreateShader(GL_VERTEX_SHADER); - if (!gl_vertShader) + if (shader->program) + pglDeleteProgram(shader->program); + + if (!vert_shader && !frag_shader) { - GL_MSG_Error("Shader_CompileProgram: Error creating vertex shader %s\n", HWR_GetShaderName(i)); + GL_MSG_Error("Shader_CompileProgram: Missing shaders for shader program %s\n", HWR_GetShaderName(i)); return false; } - pglShaderSource(gl_vertShader, 1, &vert_shader, NULL); - pglCompileShader(gl_vertShader); - - // check for compile errors - pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result); - if (result == GL_FALSE) + if (vert_shader) { - Shader_CompileError("Error compiling vertex shader", gl_vertShader, i); - pglDeleteShader(gl_vertShader); - return false; + // + // Load and compile vertex shader + // + gl_vertShader = pglCreateShader(GL_VERTEX_SHADER); + if (!gl_vertShader) + { + GL_MSG_Error("Shader_CompileProgram: Error creating vertex shader %s\n", HWR_GetShaderName(i)); + return false; + } + + pglShaderSource(gl_vertShader, 1, &vert_shader, NULL); + pglCompileShader(gl_vertShader); + + // check for compile errors + pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result); + if (result == GL_FALSE) + { + Shader_CompileError("Error compiling vertex shader", gl_vertShader, i); + pglDeleteShader(gl_vertShader); + return false; + } } - // - // Load and compile fragment shader - // - gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER); - if (!gl_fragShader) + if (frag_shader) { - GL_MSG_Error("Shader_CompileProgram: Error creating fragment shader %s\n", HWR_GetShaderName(i)); - pglDeleteShader(gl_vertShader); - pglDeleteShader(gl_fragShader); - return false; - } + // + // Load and compile fragment shader + // + gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER); + if (!gl_fragShader) + { + GL_MSG_Error("Shader_CompileProgram: Error creating fragment shader %s\n", HWR_GetShaderName(i)); + pglDeleteShader(gl_vertShader); + pglDeleteShader(gl_fragShader); + return false; + } - pglShaderSource(gl_fragShader, 1, &frag_shader, NULL); - pglCompileShader(gl_fragShader); + pglShaderSource(gl_fragShader, 1, &frag_shader, NULL); + pglCompileShader(gl_fragShader); - // check for compile errors - pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result); - if (result == GL_FALSE) - { - Shader_CompileError("Error compiling fragment shader", gl_fragShader, i); - pglDeleteShader(gl_vertShader); - pglDeleteShader(gl_fragShader); - return false; + // check for compile errors + pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result); + if (result == GL_FALSE) + { + Shader_CompileError("Error compiling fragment shader", gl_fragShader, i); + pglDeleteShader(gl_vertShader); + pglDeleteShader(gl_fragShader); + return false; + } } shader->program = pglCreateProgram(); - pglAttachShader(shader->program, gl_vertShader); - pglAttachShader(shader->program, gl_fragShader); + if (vert_shader) + pglAttachShader(shader->program, gl_vertShader); + if (frag_shader) + pglAttachShader(shader->program, gl_fragShader); pglLinkProgram(shader->program); // check link status pglGetProgramiv(shader->program, GL_LINK_STATUS, &result); // delete the shader objects - pglDeleteShader(gl_vertShader); - pglDeleteShader(gl_fragShader); + if (vert_shader) + pglDeleteShader(gl_vertShader); + if (frag_shader) + pglDeleteShader(gl_fragShader); // couldn't link? if (result != GL_TRUE) @@ -2320,11 +2033,33 @@ static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar shader->uniforms[gluniform_light_contrast] = GETUNI("light_contrast"); shader->uniforms[gluniform_light_backlight] = GETUNI("light_backlight"); + // palette rendering + shader->uniforms[gluniform_palette_tex] = GETUNI("palette_tex"); + shader->uniforms[gluniform_palette_lookup_tex] = GETUNI("palette_lookup_tex"); + shader->uniforms[gluniform_lighttable_tex] = GETUNI("lighttable_tex"); + // misc. (custom shaders) shader->uniforms[gluniform_leveltime] = GETUNI("leveltime"); #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_palette_tex], 3, pglUniform1i); + UNIFORM_1(shader->uniforms[gluniform_palette_lookup_tex], 2, pglUniform1i); + UNIFORM_1(shader->uniforms[gluniform_lighttable_tex], 3, pglUniform1i); + // changed to tex units 2 and 3 due to brightmap handling, binding two things to the same unit will just overwrite each other! + + // restore gl shader state + pglUseProgram(gl_shaderstate.program); + #undef UNIFORM_1 + return true; } @@ -2387,6 +2122,14 @@ static void PreparePolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FBITFIELD fade.green = byte2float[pSurf->FadeColor.s.green]; fade.blue = byte2float[pSurf->FadeColor.s.blue]; fade.alpha = byte2float[pSurf->FadeColor.s.alpha]; + + if (pSurf->LightTableId && pSurf->LightTableId != lt_downloaded) + { + pglActiveTexture(GL_TEXTURE3); + pglBindTexture(GL_TEXTURE_2D, pSurf->LightTableId); + pglActiveTexture(GL_TEXTURE0); + lt_downloaded = pSurf->LightTableId; + } } } @@ -2569,9 +2312,6 @@ EXPORT void HWRAPI(RenderSkyDome) (gl_sky_t *sky) pglDisableClientState(GL_COLOR_ARRAY); } -// ========================================================================== -// -// ========================================================================== EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value) { switch (IdState) @@ -2581,7 +2321,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value) break; case HWD_SET_SHADERS: - gl_allowshaders = (hwdshaderoption_t)Value; + gl_allowshaders = Value; break; case HWD_SET_TEXTUREFILTERMODE: @@ -2929,6 +2669,14 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float else if (Surface->PolyColor.s.alpha == 0xFF) 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); Shader_SetUniforms(Surface, &poly, &tint, &fade); @@ -3296,64 +3044,18 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]) pglEnable(GL_BLEND); } + // Sryder: This needs to be called whenever the screen changes resolution in order to reset the screen textures to use // a new size EXPORT void HWRAPI(FlushScreenTextures) (void) { - pglDeleteTextures(1, &screentexture); - pglDeleteTextures(1, &intermissionbg); - pglDeleteTextures(1, &startScreenWipe); - pglDeleteTextures(1, &endScreenWipe); - pglDeleteTextures(1, &finalScreenTexture); - screentexture = 0; - intermissionbg = 0; - startScreenWipe = 0; - endScreenWipe = 0; - finalScreenTexture = 0; + int i; + pglDeleteTextures(NUMSCREENTEXTURES, screenTextures); + for (i = 0; i < NUMSCREENTEXTURES; i++) + screenTextures[i] = 0; } -static void GetScreenTexture(GLuint *texnum) -{ - boolean firstTime = (*texnum == 0); - - // Create screen texture - if (firstTime) - pglGenTextures(1, texnum); - pglBindTexture(GL_TEXTURE_2D, *texnum); - - if (firstTime) - { - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - Clamp2D(GL_TEXTURE_WRAP_S); - Clamp2D(GL_TEXTURE_WRAP_T); - pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0); - } - else - pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize); - - tex_downloaded = *texnum; -} - -// Create Screen to fade from -EXPORT void HWRAPI(StartScreenWipe) (void) -{ - GetScreenTexture(&startScreenWipe); -} - -// Create Screen to fade to -EXPORT void HWRAPI(EndScreenWipe)(void) -{ - GetScreenTexture(&endScreenWipe); -} - -EXPORT void HWRAPI(MakeIntermissionBG) (void) -{ - GetScreenTexture(&intermissionbg); -} - -// Draw the last scene under the intermission -EXPORT void HWRAPI(DrawIntermissionBG)(void) +EXPORT void HWRAPI(DrawScreenTexture)(int tex, FSurfaceInfo *surf, FBITFIELD polyflags) { float xfix, yfix; @@ -3384,18 +3086,22 @@ EXPORT void HWRAPI(DrawIntermissionBG)(void) pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - pglBindTexture(GL_TEXTURE_2D, intermissionbg); + pglBindTexture(GL_TEXTURE_2D, screenTextures[tex]); + if (surf) + PreparePolygon(surf, NULL, polyflags); + else + Shader_SetUniforms(NULL, NULL, NULL, NULL); // prepare shader, if it is enabled pglColor4ubv(white); pglTexCoordPointer(2, GL_FLOAT, 0, fix); pglVertexPointer(3, GL_FLOAT, 0, screenVerts); pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); - tex_downloaded = intermissionbg; + tex_downloaded = screenTextures[tex]; } // Do screen fades! -EXPORT void HWRAPI(DoScreenWipe)(void) +EXPORT void HWRAPI(DoScreenWipe)(int wipeStart, int wipeEnd) { float xfix, yfix; @@ -3422,9 +3128,6 @@ EXPORT void HWRAPI(DoScreenWipe)(void) xfix = 1/((float)(texsize)/((float)((screen_width)))); yfix = 1/((float)(texsize)/((float)((screen_height)))); - // const float screenVerts[12] - - // float fix[8]; fix[0] = 0.0f; fix[1] = 0.0f; fix[2] = 0.0f; @@ -3440,7 +3143,7 @@ EXPORT void HWRAPI(DoScreenWipe)(void) pglEnable(GL_TEXTURE_2D); // Draw the original screen - pglBindTexture(GL_TEXTURE_2D, startScreenWipe); + pglBindTexture(GL_TEXTURE_2D, screenTextures[wipeStart]); pglColor4ubv(white); pglTexCoordPointer(2, GL_FLOAT, 0, fix); pglVertexPointer(3, GL_FLOAT, 0, screenVerts); @@ -3451,7 +3154,7 @@ EXPORT void HWRAPI(DoScreenWipe)(void) // Draw the end screen that fades in pglActiveTexture(GL_TEXTURE0); pglEnable(GL_TEXTURE_2D); - pglBindTexture(GL_TEXTURE_2D, endScreenWipe); + pglBindTexture(GL_TEXTURE_2D, screenTextures[wipeEnd]); pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); pglActiveTexture(GL_TEXTURE1); @@ -3473,88 +3176,129 @@ EXPORT void HWRAPI(DoScreenWipe)(void) pglActiveTexture(GL_TEXTURE0); pglClientActiveTexture(GL_TEXTURE0); - tex_downloaded = endScreenWipe; + tex_downloaded = screenTextures[wipeEnd]; } // Create a texture from the screen. -EXPORT void HWRAPI(MakeScreenTexture) (void) +EXPORT void HWRAPI(MakeScreenTexture) (int tex) { - GetScreenTexture(&screentexture); + boolean firstTime = (screenTextures[tex] == 0); + + // Create screen texture + if (firstTime) + pglGenTextures(1, &screenTextures[tex]); + pglBindTexture(GL_TEXTURE_2D, screenTextures[tex]); + + if (firstTime) + { + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + Clamp2D(GL_TEXTURE_WRAP_S); + Clamp2D(GL_TEXTURE_WRAP_T); + pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0); + } + else + pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize); + + tex_downloaded = screenTextures[tex]; } EXPORT void HWRAPI(RenderVhsEffect) (INT16 upbary, INT16 downbary, UINT8 updistort, UINT8 downdistort, UINT8 barsize) { float xfix, yfix; float fix[8]; - GLubyte color[4] = {255, 255, 255, 255}; float i; + + GLubyte color[4] = {255, 255, 255, 255}; + float screenVerts[12] = { -1.0f, -1.0f, 1.0f, - -1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f }; - // look for power of two that is large enough for the screen - while (texsize < screen_width || texsize < screen_height) - texsize <<= 1; + xfix = 1/((float)(texsize)/((float)((screen_width)))); yfix = 1/((float)(texsize)/((float)((screen_height)))); + + const GLfloat scrwf = (float)screen_width; + const GLfloat scrwh = (float)screen_height; + // Slight fuzziness - MakeScreenTexture(); + MakeScreenTexture(HWD_SCREENTEXTURE_VHS); SetBlend(PF_Modulated|PF_Translucent|PF_NoDepthTest); - pglBindTexture(GL_TEXTURE_2D, screentexture); - for (i = 0; i < 1; i += 2.f/vid.height) + pglBindTexture(GL_TEXTURE_2D, screenTextures[HWD_SCREENTEXTURE_VHS]); + + const float stride = 2.f/scrwh; + + for (i = 0; i < 1; i += stride) { - fix[2] = (float)(rand() % 128) / -22000 * xfix; + fix[2] = (float)(rand() % 128) / -22000.f * xfix; fix[0] = fix[2]; fix[6] = fix[0] + xfix; fix[4] = fix[2] + xfix; fix[1] = fix[7] = i*yfix; - fix[3] = fix[5] = (i+0.015)*yfix; + fix[3] = fix[5] = (i+0.015f)*yfix; + screenVerts[1] = screenVerts[10] = 2*i - 1.0f; - screenVerts[4] = screenVerts[7] = screenVerts[1] + 0.03; + screenVerts[4] = screenVerts[7] = screenVerts[1] + 0.03f; + pglColor4ubv(color); + pglTexCoordPointer(2, GL_FLOAT, 0, fix); pglVertexPointer(3, GL_FLOAT, 0, screenVerts); pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); } + // Upward bar - MakeScreenTexture(); - pglBindTexture(GL_TEXTURE_2D, screentexture); + //GL_MakeScreenTexture(HWD_SCREENTEXTURE_VHS); + //pglBindTexture(GL_TEXTURE_2D, screenTextures[HWD_SCREENTEXTURE_VHS]); + color[0] = color[1] = color[2] = 190; color[3] = 250; pglColor4ubv(color); + fix[0] = 0.0f; fix[6] = xfix; - fix[2] = (float)updistort / screen_width * xfix; + fix[2] = (float)updistort / scrwf * xfix; fix[4] = fix[2] + fix[6]; - screenVerts[1] = screenVerts[10] = 2.0f*upbary/screen_height - 1.0f; - screenVerts[4] = screenVerts[7] = screenVerts[1] + (float)barsize/screen_height; - fix[1] = fix[7] = (float)upbary/screen_height * yfix; - fix[3] = fix[5] = fix[1] + (float)barsize/2/screen_height * yfix; + + screenVerts[1] = screenVerts[10] = 2.0f*upbary/scrwh - 1.0f; + screenVerts[4] = screenVerts[7] = screenVerts[1] + (float)barsize/scrwh; + + fix[1] = fix[7] = (float)upbary/scrwh * yfix; + fix[3] = fix[5] = fix[1] + (float)barsize/2/scrwh * yfix; + pglTexCoordPointer(2, GL_FLOAT, 0, fix); pglVertexPointer(3, GL_FLOAT, 0, screenVerts); pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); + fix[1] = fix[7] += (fix[3] - fix[7])*2; screenVerts[1] = screenVerts[10] += (screenVerts[4] - screenVerts[1])*2; pglTexCoordPointer(2, GL_FLOAT, 0, fix); pglVertexPointer(3, GL_FLOAT, 0, screenVerts); pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); + // Downward bar - MakeScreenTexture(); - pglBindTexture(GL_TEXTURE_2D, screentexture); + //GL_MakeScreenTexture(HWD_SCREENTEXTURE_VHS); + //pglBindTexture(GL_TEXTURE_2D, screenTextures[HWD_SCREENTEXTURE_VHS]); + fix[0] = 0.0f; fix[6] = xfix; - fix[2] = (float)downdistort / screen_width * -xfix; + fix[2] = (float)downdistort / scrwf * -xfix; fix[4] = fix[2] + fix[6]; - screenVerts[1] = screenVerts[10] = 2.0f*downbary/screen_height - 1.0f; - screenVerts[4] = screenVerts[7] = screenVerts[1] + (float)barsize/screen_height; - fix[1] = fix[7] = (float)downbary/screen_height * yfix; - fix[3] = fix[5] = fix[1] + (float)barsize/2/screen_height * yfix; + + screenVerts[1] = screenVerts[10] = 2.0f*downbary/scrwh - 1.0f; + screenVerts[4] = screenVerts[7] = screenVerts[1] + (float)barsize/scrwh; + + fix[1] = fix[7] = (float)downbary/scrwh * yfix; + fix[3] = fix[5] = fix[1] + (float)barsize/2/scrwh * yfix; + pglTexCoordPointer(2, GL_FLOAT, 0, fix); pglVertexPointer(3, GL_FLOAT, 0, screenVerts); pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); + fix[1] = fix[7] += (fix[3] - fix[7])*2; screenVerts[1] = screenVerts[10] += (screenVerts[4] - screenVerts[1])*2; pglTexCoordPointer(2, GL_FLOAT, 0, fix); @@ -3562,12 +3306,7 @@ EXPORT void HWRAPI(RenderVhsEffect) (INT16 upbary, INT16 downbary, UINT8 updisto pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); } -EXPORT void HWRAPI(MakeScreenFinalTexture) (void) -{ - GetScreenTexture(&finalScreenTexture); -} - -EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) +EXPORT void HWRAPI(DrawScreenFinalTexture)(int tex, int width, int height) { float xfix, yfix; float origaspect, newaspect; @@ -3622,7 +3361,7 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) clearColour.red = clearColour.green = clearColour.blue = 0; clearColour.alpha = 1; ClearBuffer(true, false, &clearColour); - pglBindTexture(GL_TEXTURE_2D, finalScreenTexture); + pglBindTexture(GL_TEXTURE_2D, screenTextures[tex]); pglColor4ubv(white); @@ -3630,7 +3369,92 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) pglVertexPointer(3, GL_FLOAT, 0, off); pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); - tex_downloaded = finalScreenTexture; + tex_downloaded = screenTextures[tex]; +} + +EXPORT void HWRAPI(SetPaletteLookup)(UINT8 *lut) +{ + GLenum internalFormat; + if (gl_version[0] == '1' || gl_version[0] == '2') + { + // if the OpenGL version is below 3.0, then the GL_R8 format may not be available. + // so use GL_LUMINANCE8 instead to get a single component 8-bit format + // (it is possible to have access to shaders even in some OpenGL 1.x systems, + // so palette rendering can still possibly be achieved there) + internalFormat = GL_LUMINANCE8; + } + else + { + internalFormat = GL_R8; + } + if (!paletteLookupTex) + pglGenTextures(1, &paletteLookupTex); + pglActiveTexture(GL_TEXTURE2); + 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, internalFormat, 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_TEXTURE3); + 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 diff --git a/src/hardware/r_opengl/r_opengl.h b/src/hardware/r_opengl/r_opengl.h index f09d0bbeb..0281122ee 100644 --- a/src/hardware/r_opengl/r_opengl.h +++ b/src/hardware/r_opengl/r_opengl.h @@ -37,6 +37,7 @@ #define _CREATE_DLL_ // necessary for Unix AND Windows #include "../../doomdef.h" #include "../hw_drv.h" +#include "../../z_zone.h" #ifdef __cplusplus extern "C" { @@ -53,10 +54,10 @@ extern "C" { #define DEBUG_TO_FILE // output debugging msgs to ogllog.txt // todo: find some way of getting SDL to log to ogllog.txt, without -// interfering with r_opengl.dll -#ifdef HAVE_SDL -#undef DEBUG_TO_FILE -#endif +// interfering with r_opengl.dll r_opengl.dll is gone since over a decade lol +//#ifdef HAVE_SDL +//#undef DEBUG_TO_FILE +//#endif //#if defined(HAVE_SDL) && !defined(_DEBUG) //#undef DEBUG_TO_FILE //#endif diff --git a/src/r_data.c b/src/r_data.c index 59ecb0717..247cea619 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -32,7 +32,7 @@ #include "dehacked.h" #ifdef HWRENDER -#include "hardware/hw_glob.h" +#include "hardware/hw_glob.h" // HWR_ClearLightTables #endif // DRRR @@ -374,6 +374,9 @@ void R_ClearColormaps(void) { // Purged by PU_LEVEL, just overwrite the pointer extra_colormaps = R_CreateDefaultColormap(true); +#ifdef HWRENDER + HWR_ClearLightTables(); +#endif } // diff --git a/src/r_defs.h b/src/r_defs.h index 44c3bf56d..da3f547c8 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -76,6 +76,11 @@ struct extracolormap_t 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 lumpnum_t lump; // for colormap lump matching, init to LUMPERROR char lumpname[9]; // for netsyncing diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index c854e7174..e5a8d504d 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -66,7 +66,7 @@ void *hwSym(const char *funcName,void *handle) { void *funcPointer = NULL; #ifdef HWRENDER - if (fastcmp("SetPalette", funcName)) + if (fastcmp("SetTexturePalette", funcName)) funcPointer = FUNCPTRCAST(&OglSdlSetPalette); GETFUNC(Init); @@ -79,7 +79,7 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(SetTexture); GETFUNC(UpdateTexture); GETFUNC(DeleteTexture); - GETFUNC(ReadScreenFinalTexture); + GETFUNC(ReadScreenTexture); GETFUNC(GClipRect); GETFUNC(ClearMipMapCache); GETFUNC(SetSpecialState); @@ -89,23 +89,24 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(SetTransform); GETFUNC(PostImgRedraw); GETFUNC(FlushScreenTextures); - GETFUNC(StartScreenWipe); - GETFUNC(EndScreenWipe); GETFUNC(DoScreenWipe); - GETFUNC(MakeIntermissionBG); - GETFUNC(DrawIntermissionBG); - GETFUNC(MakeScreenTexture); GETFUNC(RenderVhsEffect); - GETFUNC(MakeScreenFinalTexture); + GETFUNC(DrawScreenTexture); + GETFUNC(MakeScreenTexture); GETFUNC(DrawScreenFinalTexture); - GETFUNC(CompileShaders); - GETFUNC(CleanShaders); + GETFUNC(InitShaders); + GETFUNC(LoadShader); + GETFUNC(CompileShader); GETFUNC(SetShader); GETFUNC(UnSetShader); GETFUNC(SetShaderInfo); - GETFUNC(LoadCustomShader); + + GETFUNC(SetPaletteLookup); + GETFUNC(CreateLightTable); + GETFUNC(ClearLightTables); + GETFUNC(SetScreenPalette); #else //HWRENDER if (fastcmp("FinishUpdate", funcName)) diff --git a/src/sdl/i_video.cpp b/src/sdl/i_video.cpp index aebdf8435..3b7caafa4 100644 --- a/src/sdl/i_video.cpp +++ b/src/sdl/i_video.cpp @@ -1318,7 +1318,17 @@ void I_FinishUpdate(void) } #ifdef HWRENDER else if (rendermode == render_opengl) + { + // Final postprocess step of palette rendering, after everything else has been drawn. + if (HWR_ShouldUsePaletteRendering()) + { + HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_GENERIC2); + HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_PALETTE_POSTPROCESS)); + HWD.pfnDrawScreenTexture(HWD_SCREENTEXTURE_GENERIC2, NULL, 0); + HWD.pfnUnSetShader(); + } OglSdlFinishUpdate(cv_vidwait.value); + } #endif } @@ -1757,34 +1767,34 @@ static void Impl_InitOpenGL(void) *(void**)&HWD.pfnSetTexture = hwSym("SetTexture",NULL); *(void**)&HWD.pfnUpdateTexture = hwSym("UpdateTexture",NULL); *(void**)&HWD.pfnDeleteTexture = hwSym("DeleteTexture",NULL); - *(void**)&HWD.pfnReadScreenFinalTexture=hwSym("ReadScreenFinalTexture",NULL); + *(void**)&HWD.pfnReadScreenTexture= hwSym("ReadScreenTexture",NULL); *(void**)&HWD.pfnGClipRect = hwSym("GClipRect",NULL); *(void**)&HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL); *(void**)&HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL); - *(void**)&HWD.pfnSetPalette = hwSym("SetPalette",NULL); + *(void**)&HWD.pfnSetTexturePalette= hwSym("SetTexturePalette",NULL); *(void**)&HWD.pfnGetTextureUsed = hwSym("GetTextureUsed",NULL); *(void**)&HWD.pfnDrawModel = hwSym("DrawModel",NULL); *(void**)&HWD.pfnCreateModelVBOs = hwSym("CreateModelVBOs",NULL); *(void**)&HWD.pfnSetTransform = hwSym("SetTransform",NULL); *(void**)&HWD.pfnPostImgRedraw = hwSym("PostImgRedraw",NULL); *(void**)&HWD.pfnFlushScreenTextures=hwSym("FlushScreenTextures",NULL); - *(void**)&HWD.pfnStartScreenWipe = hwSym("StartScreenWipe",NULL); - *(void**)&HWD.pfnEndScreenWipe = hwSym("EndScreenWipe",NULL); *(void**)&HWD.pfnDoScreenWipe = hwSym("DoScreenWipe",NULL); - *(void**)&HWD.pfnDrawIntermissionBG=hwSym("DrawIntermissionBG",NULL); - *(void**)&HWD.pfnMakeIntermissionBG=hwSym("MakeIntermissionBG",NULL); + *(void**)&HWD.pfnDrawScreenTexture= hwSym("DrawScreenTexture",NULL); *(void**)&HWD.pfnMakeScreenTexture= hwSym("MakeScreenTexture",NULL); *(void**)&HWD.pfnRenderVhsEffect = hwSym("RenderVhsEffect",NULL); - *(void**)&HWD.pfnMakeScreenFinalTexture=hwSym("MakeScreenFinalTexture",NULL); *(void**)&HWD.pfnDrawScreenFinalTexture=hwSym("DrawScreenFinalTexture",NULL); - *(void**)&HWD.pfnCompileShaders = hwSym("CompileShaders",NULL); - *(void**)&HWD.pfnCleanShaders = hwSym("CleanShaders",NULL); + *(void**)&HWD.pfnInitShaders = hwSym("InitShaders",NULL); + *(void**)&HWD.pfnLoadShader = hwSym("LoadShader",NULL); + *(void**)&HWD.pfnCompileShader = hwSym("CompileShader",NULL); *(void**)&HWD.pfnSetShader = hwSym("SetShader",NULL); *(void**)&HWD.pfnUnSetShader = hwSym("UnSetShader",NULL); *(void**)&HWD.pfnSetShaderInfo = hwSym("SetShaderInfo",NULL); - *(void**)&HWD.pfnLoadCustomShader = hwSym("LoadCustomShader",NULL); + *(void**)&HWD.pfnSetPaletteLookup = hwSym("SetPaletteLookup",NULL); + *(void**)&HWD.pfnCreateLightTable = hwSym("CreateLightTable",NULL); + *(void**)&HWD.pfnClearLightTables = hwSym("ClearLightTables",NULL); + *(void**)&HWD.pfnSetScreenPalette = hwSym("SetScreenPalette",NULL); if (HWD.pfnInit()) vid.glstate = VID_GL_LIBRARY_LOADED; @@ -1793,6 +1803,7 @@ static void Impl_InitOpenGL(void) vid.glstate = VID_GL_LIBRARY_ERROR; CV_StealthSet(&cv_renderer, "Software"); + rendermode = render_soft; if (setrenderneeded) diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c index b2c6b4363..27ffd06c2 100644 --- a/src/sdl/ogl_sdl.c +++ b/src/sdl/ogl_sdl.c @@ -192,7 +192,9 @@ void OglSdlFinishUpdate(boolean waitvbl) // Sryder: We need to draw the final screen texture again into the other buffer in the original position so that // effects that want to take the old screen can do so after this - HWR_DrawScreenFinalTexture(realwidth, realheight); + // Generic2 has the screen image without palette rendering brightness adjustments. + // Using that here will prevent brightness adjustments being applied twice. + DrawScreenTexture(HWD_SCREENTEXTURE_GENERIC2, NULL, 0); } EXPORT void HWRAPI(OglSdlSetPalette) (RGBA_t *palette) diff --git a/src/st_stuff.c b/src/st_stuff.c index 976a93e7e..383d978e1 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -145,8 +145,8 @@ void ST_doPaletteStuff(void) palette = 0; #ifdef HWRENDER - if (rendermode == render_opengl) - palette = 0; // No flashpals here in OpenGL + if (rendermode == render_opengl && !HWR_ShouldUsePaletteRendering()) + palette = 0; // Don't set the palette to a flashpal in OpenGL's truecolor mode #endif if (palette != st_palette) @@ -970,7 +970,7 @@ void ST_Drawer(void) //25/08/99: Hurdler: palette changes is done for all players, // not only player1! That's why this part // of code is moved somewhere else. - if (rendermode == render_soft) + if (rendermode == render_soft || HWR_ShouldUsePaletteRendering()) #endif if (rendermode != render_none) ST_doPaletteStuff(); diff --git a/src/w_wad.cpp b/src/w_wad.cpp index 6ea718573..fb5955974 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -1075,10 +1075,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup, boole #ifdef HWRENDER // Read shaders from file if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED)) - { HWR_LoadCustomShadersFromFile(numwadfiles - 1, (type == RET_PK3)); - HWR_CompileShaders(); - } #endif // HWRENDER // check if compatmode is needed diff --git a/src/y_inter.c b/src/y_inter.c index 4b107d4b9..c193686b9 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -381,7 +381,7 @@ void Y_ConsiderScreenBuffer(void) else if (rendermode == render_opengl) { y_screenbuffer = Z_Malloc(0, PU_STATIC, NULL); - HWR_MakeIntermissionBG(); + HWR_DrawIntermissionBG(); } #endif }