From de37df1be04e9d1dfb11083a9585eb6ac1761633 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Tue, 11 May 2021 01:13:28 +0300 Subject: [PATCH 01/25] OpenGL shader code rearrangement and shader pre-preprocessor --- src/CMakeLists.txt | 1 + src/Makefile | 3 +- src/hardware/hw_batching.c | 8 +- src/hardware/hw_defs.h | 30 +- src/hardware/hw_drv.h | 14 +- src/hardware/hw_glob.h | 14 + src/hardware/hw_main.c | 229 +------- src/hardware/hw_main.h | 9 +- src/hardware/hw_md2.c | 3 +- src/hardware/hw_shaders.c | 756 +++++++++++++++++++++++++++ src/hardware/r_opengl/r_opengl.c | 526 +++++-------------- src/hardware/r_opengl/r_opengl.h | 1 + src/sdl/Srb2SDL-vc10.vcxproj | 1 + src/sdl/Srb2SDL-vc10.vcxproj.filters | 3 + src/sdl/hwsym_sdl.c | 6 +- src/sdl/i_video.c | 6 +- src/w_wad.c | 3 - 17 files changed, 980 insertions(+), 633 deletions(-) create mode 100644 src/hardware/hw_shaders.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 87a0499b6..c243ac5ea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -508,6 +508,7 @@ if(${SRB2_CONFIG_HWRENDER}) ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2load.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md3load.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_model.c + ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_shaders.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/u_list.c ) diff --git a/src/Makefile b/src/Makefile index a4c3c4fdb..a5772a526 100644 --- a/src/Makefile +++ b/src/Makefile @@ -288,7 +288,8 @@ else OPTS+=-DHWRENDER OBJS+=$(OBJDIR)/hw_bsp.o $(OBJDIR)/hw_draw.o $(OBJDIR)/hw_light.o \ $(OBJDIR)/hw_main.o $(OBJDIR)/hw_clip.o $(OBJDIR)/hw_md2.o $(OBJDIR)/hw_cache.o \ - $(OBJDIR)/hw_md2load.o $(OBJDIR)/hw_md3load.o $(OBJDIR)/hw_model.o $(OBJDIR)/u_list.o $(OBJDIR)/hw_batching.o + $(OBJDIR)/hw_md2load.o $(OBJDIR)/hw_md3load.o $(OBJDIR)/hw_model.o \ + $(OBJDIR)/hw_shaders.o $(OBJDIR)/u_list.o $(OBJDIR)/hw_batching.o endif OPTS += -DCOMPVERSION diff --git a/src/hardware/hw_batching.c b/src/hardware/hw_batching.c index b13ad03ea..7eb1a61f2 100644 --- a/src/hardware/hw_batching.c +++ b/src/hardware/hw_batching.c @@ -76,7 +76,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) { @@ -114,7 +114,7 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt polygonArray[polygonArraySize].numVerts = iNumPts; polygonArray[polygonArraySize].polyFlags = PolyFlags; polygonArray[polygonArraySize].texture = current_texture; - polygonArray[polygonArraySize].shader = shader; + polygonArray[polygonArraySize].shader = (shader_target != -1) ? HWR_GetShaderFromTarget(shader_target) : shader_target; polygonArray[polygonArraySize].horizonSpecial = horizonSpecial; polygonArraySize++; @@ -123,8 +123,8 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt } else { - if (shader) - HWD.pfnSetShader(shader); + if (shader_target != -1) + HWD.pfnSetShader(HWR_GetShaderFromTarget(shader_target)); HWD.pfnDrawPolygon(pSurf, pOutVerts, iNumPts, PolyFlags); } } diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 8df9b8916..2d9751477 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -133,32 +133,26 @@ 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_DEFAULT = 0, - SHADER_FLOOR, SHADER_WALL, SHADER_SPRITE, - SHADER_MODEL, SHADER_MODEL_LIGHTING, + SHADER_MODEL, SHADER_WATER, SHADER_FOG, SHADER_SKY, - 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 @@ -300,6 +294,14 @@ enum hwdsetspecialstate typedef enum hwdsetspecialstate hwdspecialstate_t; +enum hwdshaderstage +{ + HWD_SHADERSTAGE_VERTEX, + HWD_SHADERSTAGE_FRAGMENT, +}; + +typedef enum hwdshaderstage hwdshaderstage_t; + // Lactozilla: Shader options enum hwdshaderoption { diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 8cae144ff..8eddeebea 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -68,13 +68,13 @@ EXPORT void HWRAPI(DrawScreenFinalTexture) (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); // ========================================================================== // HWR DRIVER OBJECT, FOR CLIENT PROGRAM @@ -120,13 +120,13 @@ struct hwdriver_s MakeScreenFinalTexture pfnMakeScreenFinalTexture; DrawScreenFinalTexture pfnDrawScreenFinalTexture; - CompileShaders pfnCompileShaders; - CleanShaders pfnCleanShaders; + InitShaders pfnInitShaders; + LoadShader pfnLoadShader; + CompileShader pfnCompileShader; SetShader pfnSetShader; UnSetShader pfnUnSetShader; SetShaderInfo pfnSetShaderInfo; - LoadCustomShader pfnLoadCustomShader; }; extern struct hwdriver_s hwdriver; diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index 2aba62248..f0f1fad46 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -136,4 +136,18 @@ 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[]; + #endif //_HW_GLOB_ diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index e94c637e4..79f4eec0c 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -167,13 +167,15 @@ 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; // ========================================================================== // Lighting // ========================================================================== -static boolean HWR_UseShader(void) +// Returns true if shaders can be used. +boolean HWR_UseShader(void) { return (cv_glshaders.value && gl_shadersavailable); } @@ -376,7 +378,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 = -1; // no convex poly were generated for this subsector if (!xsub->planepoly) @@ -798,7 +800,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 = -1; HWR_Lighting(pSurf, lightlevel, wallcolormap); @@ -2687,7 +2689,7 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, { FSurfaceInfo Surf; FOutVector *v3d; - INT32 shader = SHADER_DEFAULT; + INT32 shader = -1; size_t nrPlaneVerts = polysector->numVertices; INT32 i; @@ -3598,7 +3600,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_Translucent|PF_Modulated; - INT32 shader = SHADER_DEFAULT; + INT32 shader = -1; UINT8 i; SINT8 flip = P_MobjFlip(thing); @@ -3745,7 +3747,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) boolean lightset = true; FBITFIELD blend = 0; FBITFIELD occlusion; - INT32 shader = SHADER_DEFAULT; + INT32 shader = -1; boolean use_linkdraw_hack = false; UINT8 alpha; @@ -4259,7 +4261,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) } { - INT32 shader = SHADER_DEFAULT; + INT32 shader = -1; FBITFIELD blend = 0; FBITFIELD occlusion; boolean use_linkdraw_hack = false; @@ -4327,7 +4329,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 = -1; FBITFIELD blend = 0; FOutVector wallVerts[4]; patch_t *gpatch; @@ -4765,7 +4767,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++) { @@ -5674,7 +5675,8 @@ 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); } @@ -5760,8 +5762,6 @@ static void HWR_DrawSkyBackground(player_t *player) HWD.pfnUnSetShader(); HWD.pfnDrawPolygon(NULL, v, 4, 0); } - - HWD.pfnSetShader(SHADER_DEFAULT); } @@ -5851,13 +5851,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()); } // ========================================================================== @@ -6303,13 +6297,14 @@ 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}}; +static CV_PossibleValue_t glshaders_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Ignore custom shaders"}, {0, NULL}}; static CV_PossibleValue_t glmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}}; static CV_PossibleValue_t glfakecontrast_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Smooth"}, {0, NULL}}; static CV_PossibleValue_t glshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Third-person"}, {0, NULL}}; static void CV_glfiltermode_OnChange(void); static void CV_glanisotropic_OnChange(void); +static void CV_glmodellighting_OnChange(void); static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"}, {HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"}, {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"}, @@ -6332,7 +6327,7 @@ consvar_t cv_glcoronasize = CVAR_INIT ("gr_coronasize", "1", CV_SAVE|CV_FLOAT, 0 consvar_t cv_glmodels = CVAR_INIT ("gr_models", "Off", CV_SAVE, CV_OnOff, NULL); consvar_t cv_glmodelinterpolation = CVAR_INIT ("gr_modelinterpolation", "Sometimes", CV_SAVE, glmodelinterpolation_cons_t, NULL); -consvar_t cv_glmodellighting = CVAR_INIT ("gr_modellighting", "Off", CV_SAVE, CV_OnOff, NULL); +consvar_t cv_glmodellighting = CVAR_INIT ("gr_modellighting", "Off", CV_SAVE|CV_CALL, CV_OnOff, CV_glmodellighting_OnChange); consvar_t cv_glshearing = CVAR_INIT ("gr_shearing", "Off", CV_SAVE, glshearing_cons_t, NULL); consvar_t cv_glspritebillboarding = CVAR_INIT ("gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL); @@ -6359,6 +6354,13 @@ static void CV_glanisotropic_OnChange(void) HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_glanisotropicmode.value); } +static void CV_glmodellighting_OnChange(void) +{ + // if shaders have been compiled, then they now need to be recompiled. + if (gl_shadersavailable) + HWR_CompileShaders(); +} + //added by Hurdler: console varibale that are saved void HWR_AddCommands(void) { @@ -6417,9 +6419,8 @@ void HWR_Startup(void) HWR_InitLight(); #endif + gl_shadersavailable = HWR_InitShaders(); HWR_LoadAllCustomShaders(); - if (!HWR_CompileShaders()) - gl_shadersavailable = false; } if (rendermode == render_opengl) @@ -6518,7 +6519,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 = -1; // Lighting is done here instead so that fog isn't drawn incorrectly on transparent walls after sorting HWR_Lighting(pSurf, lightlevel, wallcolormap); @@ -6716,182 +6717,4 @@ 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); - M_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"; -} - #endif // HWRENDER diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 4ad09aa3d..9a3477b03 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -65,6 +65,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); void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *colormap); UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap); // Let's see if this can work @@ -73,14 +74,6 @@ 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[]; - extern CV_PossibleValue_t glanisotropicmode_cons_t[]; #ifdef ALAM_LIGHTING diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 5caf344f7..3dc3a0839 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1644,7 +1644,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) p.mirror = atransform.mirror; // from Kart #endif - HWD.pfnSetShader(SHADER_MODEL); // model shader + if (HWR_UseShader()) + HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_MODEL)); HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, finalscale, flip, hflip, &Surf); } diff --git a/src/hardware/hw_shaders.c b/src/hardware/hw_shaders.c new file mode 100644 index 000000000..c5e04fb8f --- /dev/null +++ b/src/hardware/hw_shaders.c @@ -0,0 +1,756 @@ +// 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. + +#ifdef HWRENDER + +#include "hw_glob.h" +#include "hw_drv.h" +#include "../z_zone.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" + +// replicates the way fixed function lighting is used by the model lighting option, +// stores the lighting result to gl_Color +// (ambient lighting of 0.75 and diffuse lighting from above) +#define GLSL_MODEL_VERTEX_SHADER \ + "void main()\n" \ + "{\n" \ + "#ifdef MODEL_LIGHTING\n" \ + "float nDotVP = dot(gl_Normal, vec3(0, 1, 0));\n" \ + "float light = 0.75 + max(nDotVP, 0.0);\n" \ + "gl_FrontColor = vec4(light, light, light, 1.0);\n" \ + "#else\n" \ + "gl_FrontColor = gl_Color;\n" \ + "#endif\n" \ + "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\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_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 (tint_color.a > 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 * tint_color.a);\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(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" \ + "final_color = mix(final_color, fade_color, darkness);\n" + +#define GLSL_SOFTWARE_FRAGMENT_SHADER \ + "uniform sampler2D tex;\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" \ + 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_FRAGMENT_SHADER \ + "uniform sampler2D tex;\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" \ + GLSL_SOFTWARE_TINT_EQUATION \ + GLSL_SOFTWARE_FADE_EQUATION \ + "#ifdef MODEL_LIGHTING\n" \ + "final_color *= gl_Color;\n" \ + "#endif\n" \ + "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 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" \ + "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 z = (gl_FragCoord.z / gl_FragCoord.w) / 2.0;\n" \ + "float a = -pi * (z * freq) + (leveltime * speed);\n" \ + "float sdistort = sin(a) * amp;\n" \ + "float cdistort = cos(a) * amp;\n" \ + "vec4 texel = texture2D(tex, vec2(gl_TexCoord[0].s - sdistort, gl_TexCoord[0].t - cdistort));\n" \ + "vec4 base_color = texel * poly_color;\n" \ + "vec4 final_color = base_color;\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" \ + GLSL_DOOM_COLORMAP \ + GLSL_DOOM_LIGHT_EQUATION \ + "void main(void) {\n" \ + "vec4 base_color = gl_Color;\n" \ + "vec4 final_color = base_color;\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[] = { + // 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_MODEL_VERTEX_SHADER, GLSL_SOFTWARE_MODEL_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}, +}; + +typedef struct +{ + int base_shader; // index of base shader_t + int custom_shader; // index of custom shader_t +} shadertarget_t; + +typedef struct +{ + char *vertex; + char *fragment; + boolean compiled; +} shader_t; // these are in an array and accessed by indices + +// the array has NUMSHADERTARGETS entries for base shaders and for custom shaders +// the array could be expanded in the future to fit "dynamic" custom shaders that +// aren't fixed to shader targets +static shader_t gl_shaders[NUMSHADERTARGETS*2]; + +static shadertarget_t gl_shadertargets[NUMSHADERTARGETS]; + +#define MODEL_LIGHTING_DEFINE "#define MODEL_LIGHTING" + +// Initialize shader variables and the backend's shader system. Load the base shaders. +// Returns false if shaders cannot be used. +boolean HWR_InitShaders(void) +{ + int i; + + if (!HWD.pfnInitShaders()) + return false; + + for (i = 0; i < NUMSHADERTARGETS; i++) + { + // set up string pointers for base shaders + gl_shaders[i].vertex = Z_StrDup(gl_shadersources[i].vertex); + gl_shaders[i].fragment = Z_StrDup(gl_shadersources[i].fragment); + // set shader target indices to correct values + gl_shadertargets[i].base_shader = i; + gl_shadertargets[i].custom_shader = -1; + } + + HWR_CompileShaders(); + + return true; +} + +// helper function: strstr but returns an int with the substring position +// returns INT32_MAX if not found +static INT32 strstr_int(const char *str1, const char *str2) +{ + char *location = strstr(str1, str2); + if (location) + return location - str1; + else + return INT32_MAX; +} + +// Creates a preprocessed copy of the shader according to the current graphics settings +// Returns a pointer to the results on success and NULL on failure. +// Remember memory management of the returned string. +static char *HWR_PreprocessShader(char *original) +{ + const char *line_ending = "\n"; + int line_ending_len; + char *read_pos = original; + int insertion_pos = 0; + int original_len = strlen(original); + int distance_to_end = original_len; + int new_len; + char *new_shader; + char *write_pos; + + if (strstr(original, "\r\n")) + { + line_ending = "\r\n"; + // check that all line endings are same, + // otherwise the parsing code won't function correctly + while ((read_pos = strchr(read_pos, '\n'))) + { + read_pos--; + if (*read_pos != '\r') + { + CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Shader contains mixed line ending types. Please use either only LF (Unix) or only CRLF (Windows) line endings.\n"); + return NULL; + } + read_pos += 2; + } + read_pos = original; + } + + line_ending_len = strlen(line_ending); + + // We need to find a place to put the #define commands. + // To stay within GLSL specs, they must be *after* the #version define, + // if there is any. So we need to look for that. And also let's not + // get fooled if there is a #version inside a comment! + // Time for some string parsing :D + +#define STARTSWITH(str, with_what) !strncmp(str, with_what, sizeof(with_what)-1) +#define ADVANCE(amount) read_pos += amount; distance_to_end -= amount; + while (true) + { + // we're at the start of a line or at the end of a block comment. + // first get any possible whitespace out of the way + int whitespace_len = strspn(read_pos, " \t"); + if (whitespace_len == distance_to_end) + break; // we got to the end + ADVANCE(whitespace_len) + + if (STARTSWITH(read_pos, "#version")) + { + // getting closer + INT32 newline_pos = strstr_int(read_pos, line_ending); + INT32 line_comment_pos = strstr_int(read_pos, "//"); + INT32 block_comment_pos = strstr_int(read_pos, "/*"); + if (newline_pos == INT32_MAX && line_comment_pos == INT32_MAX && + block_comment_pos == INT32_MAX) + { + // #version is at the end of the file. Probably not a valid shader. + CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Shader unexpectedly ends after #version.\n"); + return NULL; + } + else + { + // insert at the earliest occurence of newline or comment after #version + insertion_pos = min(line_comment_pos, block_comment_pos); + insertion_pos = min(newline_pos, insertion_pos); + insertion_pos += read_pos - original; + break; + } + } + else + { + // go to next newline or end of next block comment if it starts before the newline + // and is not inside a line comment + INT32 newline_pos = strstr_int(read_pos, line_ending); + INT32 line_comment_pos; + INT32 block_comment_pos; + // optimization: temporarily put a null at the line ending, so strstr does not needlessly + // look past it since we're only interested in the current line + if (newline_pos != INT32_MAX) + read_pos[newline_pos] = '\0'; + line_comment_pos = strstr_int(read_pos, "//"); + block_comment_pos = strstr_int(read_pos, "/*"); + // restore the line ending, remove the null we just put there + if (newline_pos != INT32_MAX) + read_pos[newline_pos] = line_ending[0]; + if (line_comment_pos < block_comment_pos) + { + // line comment found, skip rest of the line + if (newline_pos != INT32_MAX) + { + ADVANCE(newline_pos + line_ending_len) + } + else + { + // we got to the end + break; + } + } + else if (block_comment_pos < line_comment_pos) + { + // block comment found, skip past it + INT32 block_comment_end; + ADVANCE(block_comment_pos + 2) + block_comment_end = strstr_int(read_pos, "*/"); + if (block_comment_end == INT32_MAX) + { + // could also leave insertion_pos at 0 and let the GLSL compiler + // output an error message for this broken comment + CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Encountered unclosed block comment in shader.\n"); + return NULL; + } + ADVANCE(block_comment_end + 2) + } + else if (newline_pos == INT32_MAX) + { + // we got to the end + break; + } + else + { + // nothing special on this line, move to the next one + ADVANCE(newline_pos + line_ending_len) + } + } + } +#undef STARTSWITH +#undef ADVANCE + + // Calculate length of modified shader. + new_len = original_len; + if (cv_glmodellighting.value) + new_len += sizeof(MODEL_LIGHTING_DEFINE) - 1 + 2 * line_ending_len; + + // Allocate memory for modified shader. + new_shader = Z_Malloc(new_len + 1, PU_STATIC, NULL); + + read_pos = original; + write_pos = new_shader; + + // Copy the part before our additions. + M_Memcpy(write_pos, original, insertion_pos); + read_pos += insertion_pos; + write_pos += insertion_pos; + + // Write the additions. + if (cv_glmodellighting.value) + { + strcpy(write_pos, line_ending); + write_pos += line_ending_len; + strcpy(write_pos, MODEL_LIGHTING_DEFINE); + write_pos += sizeof(MODEL_LIGHTING_DEFINE) - 1; + strcpy(write_pos, line_ending); + write_pos += line_ending_len; + } + + // Copy the part after our additions. + M_Memcpy(write_pos, read_pos, original_len - insertion_pos); + + // Terminate the new string. + new_shader[new_len] = '\0'; + + return new_shader; +} + +// preprocess and compile shader at gl_shaders[index] +static void HWR_CompileShader(int index) +{ + char *vertex_source = gl_shaders[index].vertex; + char *fragment_source = gl_shaders[index].fragment; + + if (vertex_source) + { + char *preprocessed = HWR_PreprocessShader(vertex_source); + if (!preprocessed) return; + HWD.pfnLoadShader(index, preprocessed, HWD_SHADERSTAGE_VERTEX); + } + if (fragment_source) + { + char *preprocessed = HWR_PreprocessShader(fragment_source); + if (!preprocessed) return; + HWD.pfnLoadShader(index, preprocessed, HWD_SHADERSTAGE_FRAGMENT); + } + + gl_shaders[index].compiled = HWD.pfnCompileShader(index); +} + +// compile or recompile shaders +void HWR_CompileShaders(void) +{ + int i; + + for (i = 0; i < NUMSHADERTARGETS; i++) + { + int custom_index = gl_shadertargets[i].custom_shader; + HWR_CompileShader(i); + if (!gl_shaders[i].compiled) + CONS_Alert(CONS_ERROR, "HWR_CompileShaders: Compilation failed for base %s shader!\n", shaderxlat[i].type); + if (custom_index != -1) + { + HWR_CompileShader(custom_index); + if (!gl_shaders[custom_index].compiled) + CONS_Alert(CONS_ERROR, "HWR_CompileShaders: Recompilation failed for the custom %s shader! See the console messages above for more information.\n", shaderxlat[i].type); + } + } +} + +int HWR_GetShaderFromTarget(int shader_target) +{ + int custom_shader = gl_shadertargets[shader_target].custom_shader; + // use custom shader if following are true + // - custom shader exists + // - custom shader has been compiled successfully + // - custom shaders are enabled + // - custom shaders are allowed by the server + if (custom_shader != -1 && gl_shaders[custom_shader].compiled && + cv_glshaders.value == 1 && cv_glallowshaders.value) + return custom_shader; + else + return gl_shadertargets[shader_target].base_shader; +} + +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; +} + +customshaderxlat_t shaderxlat[] = +{ + {"Flat", SHADER_FLOOR}, + {"WallTexture", SHADER_WALL}, + {"Sprite", SHADER_SPRITE}, + {"Model", SHADER_MODEL}, + {"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; + boolean modified_shaders[NUMSHADERTARGETS] = {0}; + + if (!gl_shadersavailable) + return; + + 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); + M_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_string_length; + char *shader_source; + char *shader_lumpname; + UINT16 shader_lumpnum; + int shader_index; // index in gl_shaders + + 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_string_length = W_LumpLengthPwad(wadnum, shader_lumpnum) + 1; + shader_source = Z_Malloc(shader_string_length, PU_STATIC, NULL); + W_ReadLumpPwad(wadnum, shader_lumpnum, shader_source); + shader_source[shader_string_length-1] = '\0'; + + shader_index = shaderxlat[i].id + NUMSHADERTARGETS; + if (!modified_shaders[shaderxlat[i].id]) + { + // this will clear any old custom shaders from previously loaded files + // Z_Free checks if the pointer is NULL! + Z_Free(gl_shaders[shader_index].vertex); + gl_shaders[shader_index].vertex = NULL; + Z_Free(gl_shaders[shader_index].fragment); + gl_shaders[shader_index].fragment = NULL; + } + modified_shaders[shaderxlat[i].id] = true; + + if (shadertype == 1) + { + if (gl_shaders[shader_index].vertex) + { + CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: %s is overwriting another %s vertex shader from the same addon! (file %s, line %d)\n", shader_lumpname, shaderxlat[i].type, wadfiles[wadnum]->filename, linenum); + Z_Free(gl_shaders[shader_index].vertex); + } + gl_shaders[shader_index].vertex = shader_source; + } + else + { + if (gl_shaders[shader_index].fragment) + { + CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: %s is overwriting another %s fragment shader from the same addon! (file %s, line %d)\n", shader_lumpname, shaderxlat[i].type, wadfiles[wadnum]->filename, linenum); + Z_Free(gl_shaders[shader_index].fragment); + } + gl_shaders[shader_index].fragment = shader_source; + } + + Z_Free(shader_lumpname); + } + } + +skip_field: + stoken = strtok(NULL, "\r\n= "); + linenum++; + } + } + + for (i = 0; i < NUMSHADERTARGETS; i++) + { + if (modified_shaders[i]) + { + int shader_index = i + NUMSHADERTARGETS; // index to gl_shaders + gl_shadertargets[i].custom_shader = shader_index; + HWR_CompileShader(shader_index); + if (!gl_shaders[shader_index].compiled) + CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: A compilation error occured for the %s shader in file %s. See the console messages above for more information.\n", shaderxlat[i].type, wadfiles[wadnum]->filename); + } + } + + 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"; +} + +#endif // HWRENDER diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index af06a198f..eb7f9e1e4 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -598,14 +598,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 @@ -621,21 +622,17 @@ static gl_shaderstate_t gl_shaderstate; static INT32 shader_leveltime = 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}; -// ================ -// Vertex shaders -// ================ - // // Generic vertex shader // -#define GLSL_DEFAULT_VERTEX_SHADER \ +#define GLSL_FALLBACK_VERTEX_SHADER \ "void main()\n" \ "{\n" \ "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \ @@ -644,226 +641,17 @@ static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f}; "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ "}\0" -// replicates the way fixed function lighting is used by the model lighting option, -// stores the lighting result to gl_Color -// (ambient lighting of 0.75 and diffuse lighting from above) -#define GLSL_MODEL_LIGHTING_VERTEX_SHADER \ - "void main()\n" \ - "{\n" \ - "float nDotVP = dot(gl_Normal, vec3(0, 1, 0));\n" \ - "float light = 0.75 + max(nDotVP, 0.0);\n" \ - "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\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 \ +#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" -// -// Software fragment shader -// - -#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 (tint_color.a > 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 * tint_color.a);\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(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" \ - "final_color = mix(final_color, fade_color, darkness);\n" - -#define GLSL_SOFTWARE_FRAGMENT_SHADER \ - "uniform sampler2D tex;\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" \ - 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 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" \ - GLSL_SOFTWARE_TINT_EQUATION \ - GLSL_SOFTWARE_FADE_EQUATION \ - "final_color *= gl_Color;\n" \ - "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 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" \ - "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 z = (gl_FragCoord.z / gl_FragCoord.w) / 2.0;\n" \ - "float a = -pi * (z * freq) + (leveltime * speed);\n" \ - "float sdistort = sin(a) * amp;\n" \ - "float cdistort = cos(a) * amp;\n" \ - "vec4 texel = texture2D(tex, vec2(gl_TexCoord[0].s - sdistort, gl_TexCoord[0].t - cdistort));\n" \ - "vec4 base_color = texel * poly_color;\n" \ - "vec4 final_color = base_color;\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" \ - GLSL_DOOM_COLORMAP \ - GLSL_DOOM_LIGHT_EQUATION \ - "void main(void) {\n" \ - "vec4 base_color = gl_Color;\n" \ - "vec4 final_color = base_color;\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) @@ -910,55 +698,19 @@ void SetupGLFunc4(void) pgluBuild2DMipmaps = GetGLFunc("gluBuild2DMipmaps"); } -EXPORT boolean HWRAPI(CompileShaders) (void) +EXPORT boolean HWRAPI(InitShaders) (void) { #ifdef GL_SHADERS - GLint i; - if (!pglUseProgram) return false; + + gl_fallback_shader.vertex_shader = Z_StrDup(GLSL_FALLBACK_VERTEX_SHADER); + gl_fallback_shader.fragment_shader = Z_StrDup(GLSL_FALLBACK_FRAGMENT_SHADER); - gl_customshaders[SHADER_DEFAULT].vertex = NULL; - gl_customshaders[SHADER_DEFAULT].fragment = NULL; - - 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; @@ -967,6 +719,58 @@ 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. @@ -989,84 +793,31 @@ 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) -{ -#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) +EXPORT void HWRAPI(SetShader) (int slot) { #ifdef GL_SHADERS if (gl_allowshaders != HWD_SHADEROPTION_OFF) { - 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; } - if (gl_shaderstate.program != shader->program) - { - gl_shaderstate.program = shader->program; - gl_shaderstate.changed = true; - } + gl_shadersenabled = true; - gl_shadersenabled = (shader->program != 0); return; } #else - (void)type; + (void)slot; #endif gl_shadersenabled = false; } @@ -1085,25 +836,6 @@ EXPORT void HWRAPI(UnSetShader) (void) 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 // -----------------+ @@ -2052,69 +1784,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) diff --git a/src/hardware/r_opengl/r_opengl.h b/src/hardware/r_opengl/r_opengl.h index f44e0818b..f7e33c46a 100644 --- a/src/hardware/r_opengl/r_opengl.h +++ b/src/hardware/r_opengl/r_opengl.h @@ -46,6 +46,7 @@ #define _CREATE_DLL_ // necessary for Unix AND Windows #include "../../doomdef.h" #include "../hw_drv.h" +#include "../../z_zone.h" // ========================================================================== // DEFINITIONS diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj index d46a4af2b..503b47a05 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj +++ b/src/sdl/Srb2SDL-vc10.vcxproj @@ -392,6 +392,7 @@ + diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters index adae2f446..65b5661ff 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj.filters +++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters @@ -684,6 +684,9 @@ Hw_Hardware + + Hw_Hardware + Hw_Hardware diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index 96e3d7d69..e0c90cef4 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -105,13 +105,13 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(MakeScreenFinalTexture); GETFUNC(DrawScreenFinalTexture); - GETFUNC(CompileShaders); - GETFUNC(CleanShaders); + GETFUNC(InitShaders); + GETFUNC(LoadShader); + GETFUNC(CompileShader); GETFUNC(SetShader); GETFUNC(UnSetShader); GETFUNC(SetShaderInfo); - GETFUNC(LoadCustomShader); #else //HWRENDER if (0 == strcmp("FinishUpdate", funcName)) diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 0ed10463f..5aaf97b10 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1878,13 +1878,13 @@ void VID_StartupOpenGL(void) HWD.pfnMakeScreenFinalTexture=hwSym("MakeScreenFinalTexture",NULL); HWD.pfnDrawScreenFinalTexture=hwSym("DrawScreenFinalTexture",NULL); - HWD.pfnCompileShaders = hwSym("CompileShaders",NULL); - HWD.pfnCleanShaders = hwSym("CleanShaders",NULL); + HWD.pfnInitShaders = hwSym("InitShaders",NULL); + HWD.pfnLoadShader = hwSym("LoadShader",NULL); + HWD.pfnCompileShader = hwSym("CompileShader",NULL); HWD.pfnSetShader = hwSym("SetShader",NULL); HWD.pfnUnSetShader = hwSym("UnSetShader",NULL); HWD.pfnSetShaderInfo = hwSym("SetShaderInfo",NULL); - HWD.pfnLoadCustomShader = hwSym("LoadCustomShader",NULL); vid.glstate = HWD.pfnInit() ? VID_GL_LIBRARY_LOADED : VID_GL_LIBRARY_ERROR; // let load the OpenGL library diff --git a/src/w_wad.c b/src/w_wad.c index 6149aec6e..7f6908ab4 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -859,10 +859,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) #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 // TODO: HACK ALERT - Load Lua & SOC stuff right here. I feel like this should be out of this place, but... Let's stick with this for now. From 118fc581927eddeae1befd5c43951df1bf1af75b Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Tue, 11 May 2021 01:30:53 +0300 Subject: [PATCH 02/25] Some stuff I forgot from ogl-shader-preprocessor --- src/hardware/hw_defs.h | 10 ---------- src/hardware/r_opengl/r_opengl.c | 6 +++--- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 2d9751477..bbf9d8424 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -302,16 +302,6 @@ enum hwdshaderstage typedef enum hwdshaderstage hwdshaderstage_t; -// Lactozilla: Shader options -enum hwdshaderoption -{ - HWD_SHADEROPTION_OFF, - HWD_SHADEROPTION_ON, - HWD_SHADEROPTION_NOCUSTOM, -}; - -typedef enum hwdshaderoption hwdshaderoption_t; - // Lactozilla: Shader info // Generally set at the start of the frame. enum hwdshaderinfo diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index eb7f9e1e4..9321934b7 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -532,7 +532,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); @@ -796,7 +796,7 @@ EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value) EXPORT void HWRAPI(SetShader) (int slot) { #ifdef GL_SHADERS - if (gl_allowshaders != HWD_SHADEROPTION_OFF) + if (gl_allowshaders) { gl_shader_t *next_shader = &gl_shaders[slot]; // the gl_shader_t we are going to switch to @@ -2160,7 +2160,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: From ac1b5ae546e713434298e8046c5cde666ff29e26 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Sun, 16 May 2021 01:38:23 +0300 Subject: [PATCH 03/25] OpenGL palette rendering and related things --- src/hardware/hw_cache.c | 218 +++++++++++++++++++++++++++---- src/hardware/hw_defs.h | 10 +- src/hardware/hw_drv.h | 18 ++- src/hardware/hw_glob.h | 3 + src/hardware/hw_main.c | 186 +++++++++++++++++++++----- src/hardware/hw_main.h | 5 +- src/hardware/hw_shaders.c | 178 +++++++++++++++++++------ src/hardware/r_opengl/r_opengl.c | 162 +++++++++++++++++++++-- src/m_menu.c | 18 +-- src/r_data.c | 7 + src/r_defs.h | 5 + src/sdl/hwsym_sdl.c | 7 +- src/sdl/i_video.c | 18 ++- src/st_stuff.c | 6 +- 14 files changed, 719 insertions(+), 122 deletions(-) diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 83a4e2e03..99dba2c61 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -32,6 +32,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. +static RGBA_t *HWR_GetTexturePalette(void) +{ + return HWR_ShouldUsePaletteRendering() ? mapPalette : pLocalPalette; +} + static INT32 format2bpp(GLTextureFormat_t format) { if (format == GL_TEXFMT_RGBA) @@ -49,7 +57,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; @@ -121,7 +129,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; @@ -130,7 +138,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)) { @@ -160,7 +168,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; @@ -231,7 +239,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; @@ -240,7 +248,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)) { @@ -284,10 +292,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 @@ -313,7 +324,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); } } @@ -332,16 +343,19 @@ 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; + palette = HWR_GetTexturePalette(); + ColumnDrawerPointer = (patch->flip & 2) ? HWR_DrawFlippedColumnInCache : HWR_DrawColumnInCache; x1 = patch->originx; @@ -409,7 +423,7 @@ static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap, pblockheight, blockmodulo, yfracstep, scale_y, patch, height, - bpp); + bpp, palette); } } @@ -454,6 +468,9 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex) INT32 i; boolean skyspecial = false; //poor hack for Legacy large skies.. + RGBA_t *palette; + palette = HWR_GetTexturePalette(); + texture = textures[texnum]; // hack the Legacy skies.. @@ -472,7 +489,10 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex) grtex->mipmap.width = (UINT16)texture->width; grtex->mipmap.height = (UINT16)texture->height; - grtex->mipmap.format = textureformat; + if (skyspecial) + grtex->mipmap.format = GL_TEXFMT_RGBA; // that skyspecial code below assumes this format ... + else + grtex->mipmap.format = textureformat; blockwidth = texture->width; blockheight = texture->height; @@ -484,7 +504,7 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex) INT32 j; RGBA_t col; - col = V_GetColor(HWR_PATCHES_CHROMAKEY_COLORINDEX); + col = palette[HWR_PATCHES_CHROMAKEY_COLORINDEX]; for (j = 0; j < blockheight; j++) { for (i = 0; i < blockwidth; i++) @@ -759,19 +779,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 // -------------------------------------------------------------------------- @@ -1111,6 +1118,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++; @@ -1341,4 +1350,159 @@ 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; + } + palette = RGBA_converted; + } + + // check if the palette has changed from the previous one + if (memcmp(mapPalette, palette, sizeof(mapPalette))) + { + memcpy(mapPalette, palette, sizeof(mapPalette)); + // in palette rendering mode, this means that all rgba textures now have wrong colors + // and the lookup table is outdated + HWR_SetPaletteLookup(mapPalette); + HWD.pfnSetTexturePalette(mapPalette); + if (patchformat == GL_TEXFMT_RGBA || textureformat == GL_TEXFMT_RGBA) + { + Z_FreeTag(PU_HWRCACHE); + Z_FreeTag(PU_HWRCACHE_UNLOCKED); + } + } +} + +// Creates a hardware lighttable from the supplied lighttable. +// Returns the id of the hw lighttable, usable in FSurfaceInfo. +UINT32 HWR_CreateLightTable(UINT8 *lighttable) +{ + UINT32 i, id; + RGBA_t *palette = HWR_GetTexturePalette(); + RGBA_t *hw_lighttable = Z_Malloc(256 * 32 * sizeof(RGBA_t), PU_STATIC, NULL); + + // To make the palette index -> RGBA mapping easier for the shader, + // the hardware lighttable is composed of RGBA colors instead of palette indices. + for (i = 0; i < 256 * 32; i++) + hw_lighttable[i] = palette[lighttable[i]]; + + id = HWD.pfnCreateLightTable(hw_lighttable); + Z_Free(hw_lighttable); + return id; +} + +// Note: all hardware lighttable ids assigned before this +// call become invalid and must not be used. +void HWR_ClearLightTables(void) +{ + if (vid.glstate == VID_GL_LIBRARY_LOADED) + HWD.pfnClearLightTables(); +} + #endif //HWRENDER diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index bbf9d8424..287c3a2be 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -18,6 +18,12 @@ #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 // ========================================================================== @@ -146,6 +152,7 @@ enum SHADER_WATER, SHADER_FOG, SHADER_SKY, + SHADER_PALETTE_POSTPROCESS, NUMSHADERTARGETS, }; @@ -275,6 +282,7 @@ struct FSurfaceInfo RGBA_t PolyColor; RGBA_t TintColor; RGBA_t FadeColor; + UINT32 LightTableId; FLightInfo LightInfo; }; typedef struct FSurfaceInfo FSurfaceInfo; @@ -282,7 +290,7 @@ typedef struct FSurfaceInfo FSurfaceInfo; #define GL_DEFAULTMIX 0x00000000 #define GL_DEFAULTFOG 0xFF000000 -//Hurdler: added for backward compatibility +// Various settings and states for the rendering backend. enum hwdsetspecialstate { HWD_SET_MODEL_LIGHTING = 1, diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 8eddeebea..629f616da 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -32,7 +32,7 @@ EXPORT void HWRAPI(Shutdown) (void); #ifdef _WINDOWS EXPORT void HWRAPI(GetModeList) (vmode_t **pvidmodes, INT32 *numvidmodes); #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); @@ -47,10 +47,8 @@ EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip); EXPORT void HWRAPI(ClearMipMapCache) (void); -//Hurdler: added for backward compatibility EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value); -//Hurdler: added for new development EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface); EXPORT void HWRAPI(CreateModelVBOs) (model_t *model); EXPORT void HWRAPI(SetTransform) (FTransform *ptransform); @@ -76,6 +74,11 @@ EXPORT void HWRAPI(UnSetShader) (void); EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value); +EXPORT void HWRAPI(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 // ========================================================================== @@ -85,7 +88,7 @@ EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value); struct hwdriver_s { Init pfnInit; - SetPalette pfnSetPalette; + SetTexturePalette pfnSetTexturePalette; FinishUpdate pfnFinishUpdate; Draw2DLine pfnDraw2DLine; DrawPolygon pfnDrawPolygon; @@ -99,7 +102,7 @@ struct hwdriver_s ReadRect pfnReadRect; GClipRect pfnGClipRect; ClearMipMapCache pfnClearMipMapCache; - SetSpecialState pfnSetSpecialState;//Hurdler: added for backward compatibility + SetSpecialState pfnSetSpecialState; DrawModel pfnDrawModel; CreateModelVBOs pfnCreateModelVBOs; SetTransform pfnSetTransform; @@ -127,6 +130,11 @@ struct hwdriver_s UnSetShader pfnUnSetShader; SetShaderInfo pfnSetShaderInfo; + + 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 f0f1fad46..316f32ef8 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -128,6 +128,9 @@ 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); +void HWR_ClearLightTables(void); // -------- diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 79f4eec0c..cb976a8f8 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -126,26 +126,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; -static float gl_viewsin, gl_viewcos; - -// Maybe not necessary with the new T&L code (needs to be checked!) -static float gl_viewludsin, gl_viewludcos; // look up down kik test -static float gl_fovlud; - -static angle_t gl_aimingangle; -static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox); - // Render stats precise_t ps_hw_skyboxtime = 0; precise_t ps_hw_nodesorttime = 0; @@ -170,6 +150,29 @@ boolean gl_sessioncommandsadded = false; // false if shaders have not been initialized yet, or if shaders are not available boolean gl_shadersavailable = false; +// Whether the internal state is set to palette rendering or not. +static boolean gl_palette_rendering_state = false; + +// -------------------------------------------------------------------------- +// STUFF FOR THE PROJECTION CODE +// -------------------------------------------------------------------------- + +FTransform atransform; +// duplicates of the main code, set after R_SetupFrame() passed them into sharedstruct, +// copied here for local use +static fixed_t dup_viewx, dup_viewy, dup_viewz; +static angle_t dup_viewangle; + +static float gl_viewx, gl_viewy, gl_viewz; +static float gl_viewsin, gl_viewcos; + +// Maybe not necessary with the new T&L code (needs to be checked!) +static float gl_viewludsin, gl_viewludcos; // look up down kik test +static float gl_fovlud; + +static angle_t gl_aimingangle; +static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox); + // ========================================================================== // Lighting // ========================================================================== @@ -234,6 +237,33 @@ void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *col Surface->LightInfo.light_level = light_level; Surface->LightInfo.fade_start = (colormap != NULL) ? colormap->fadestart : 0; Surface->LightInfo.fade_end = (colormap != NULL) ? colormap->fadeend : 31; + + if (HWR_ShouldUsePaletteRendering()) + { + boolean default_colormap = false; + if (!colormap) + { + colormap = R_GetDefaultColormap(); // a place to store the hw lighttable id + // alternatively could just store the id in a global variable if there are issues + default_colormap = true; + } + // create hw lighttable if there isn't one + if (!colormap->gl_lighttable_id) + { + UINT8 *colormap_pointer; + + if (default_colormap) + colormap_pointer = colormaps; // don't actually use the data from the "default colormap" + else + colormap_pointer = colormap->colormap; + colormap->gl_lighttable_id = HWR_CreateLightTable(colormap_pointer); + } + Surface->LightTableId = colormap->gl_lighttable_id; + } + else + { + Surface->LightTableId = 0; + } } UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap) // Let's see if this can work @@ -905,13 +935,15 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, { if (pfloor && (pfloor->flags & FF_FOG)) { - lightnum = HWR_CalcWallLight(pfloor->master->frontsector->lightlevel, v1x, v1y, v2x, v2y); + lightnum = pfloor->master->frontsector->lightlevel; colormap = pfloor->master->frontsector->extra_colormap; + lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, v1x, v1y, v2x, v2y); } else { - lightnum = HWR_CalcWallLight(*list[i].lightlevel, v1x, v1y, v2x, v2y); + lightnum = *list[i].lightlevel; colormap = *list[i].extra_colormap; + lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, v1x, v1y, v2x, v2y); } } @@ -1113,8 +1145,9 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom cliphigh = (float)(texturehpeg + (gl_curline->flength*FRACUNIT)); } - lightnum = HWR_CalcWallLight(gl_frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); + lightnum = gl_frontsector->lightlevel; colormap = gl_frontsector->extra_colormap; + lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y); if (gl_frontsector) Surf.PolyColor.s.alpha = 255; @@ -1739,8 +1772,9 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom blendmode = PF_Fog|PF_NoTexture; - lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); + lightnum = rover->master->frontsector->lightlevel; colormap = rover->master->frontsector->extra_colormap; + lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y); Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap); @@ -1851,8 +1885,9 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom blendmode = PF_Fog|PF_NoTexture; - lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); + lightnum = rover->master->frontsector->lightlevel; colormap = rover->master->frontsector->extra_colormap; + lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y); Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap); @@ -5867,6 +5902,7 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) else type = &postimgtype; + if (!HWR_ShouldUsePaletteRendering()) { // do we really need to save player (is it not the same)? player_t *saved_player = stplyr; @@ -6080,6 +6116,7 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) HWR_RenderSkyboxView(viewnumber, player); // This is drawn before everything else so it is placed behind ps_hw_skyboxtime = I_GetPreciseTime() - ps_hw_skyboxtime; + if (!HWR_ShouldUsePaletteRendering()) { // do we really need to save player (is it not the same)? player_t *saved_player = stplyr; @@ -6277,6 +6314,56 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) HWD.pfnGClipRect(0, 0, vid.width, vid.height, NZCLIP_PLANE); } +// Returns whether palette rendering is "actually enabled." +// Can't have palette rendering if shaders are disabled. +boolean HWR_ShouldUsePaletteRendering(void) +{ + return (cv_glpaletterendering.value && HWR_UseShader()); +} + +// enable or disable palette rendering state depending on settings and availability +// called when relevant settings change +// shader recompilation is done in the cvar callback +static void HWR_TogglePaletteRendering(void) +{ + // which state should we go to? + if (HWR_ShouldUsePaletteRendering()) + { + // are we not in that state already? + if (!gl_palette_rendering_state) + { + gl_palette_rendering_state = true; + + // The textures will still be converted to RGBA by r_opengl. + // This however makes hw_cache use paletted blending for composite textures! + // (patchformat is not touched) + textureformat = GL_TEXFMT_P_8; + + HWR_SetMapPalette(); + HWR_SetPalette(pLocalPalette); + + // If the r_opengl "texture palette" stays the same during this switch, the textures + // will not be cleared out. However they are still out of date since the + // composite texture blending method has changed. Therefore they need to be cleared. + HWD.pfnClearMipMapCache(); + } + } + else + { + // are we not in that state already? + if (gl_palette_rendering_state) + { + gl_palette_rendering_state = false; + textureformat = GL_TEXFMT_RGBA; + HWR_SetPalette(pLocalPalette); + // If the r_opengl "texture palette" stays the same during this switch, the textures + // will not be cleared out. However they are still out of date since the + // composite texture blending method has changed. Therefore they need to be cleared. + HWD.pfnClearMipMapCache(); + } + } +} + void HWR_LoadLevel(void) { #ifdef ALAM_LIGHTING @@ -6290,6 +6377,9 @@ void HWR_LoadLevel(void) HWR_ClearSkyDome(); HWR_BuildSkyDome(); + if (HWR_ShouldUsePaletteRendering()) + HWR_SetMapPalette(); + gl_maploaded = true; } @@ -6305,6 +6395,9 @@ static CV_PossibleValue_t glshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Thi static void CV_glfiltermode_OnChange(void); static void CV_glanisotropic_OnChange(void); static void CV_glmodellighting_OnChange(void); +static void CV_glpaletterendering_OnChange(void); +static void CV_glpalettedepth_OnChange(void); +static void CV_glshaders_OnChange(void); static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"}, {HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"}, {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"}, @@ -6314,7 +6407,7 @@ static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSA {0, NULL}}; CV_PossibleValue_t glanisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}}; -consvar_t cv_glshaders = CVAR_INIT ("gr_shaders", "On", CV_SAVE, glshaders_cons_t, NULL); +consvar_t cv_glshaders = CVAR_INIT ("gr_shaders", "On", CV_SAVE|CV_CALL, glshaders_cons_t, CV_glshaders_OnChange); consvar_t cv_glallowshaders = CVAR_INIT ("gr_allowclientshaders", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_fovchange = CVAR_INIT ("gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL); @@ -6342,6 +6435,11 @@ consvar_t cv_glsolvetjoin = CVAR_INIT ("gr_solvetjoin", "On", 0, CV_OnOff, NULL) consvar_t cv_glbatching = CVAR_INIT ("gr_batching", "On", 0, CV_OnOff, NULL); +static CV_PossibleValue_t glpalettedepth_cons_t[] = {{16, "16 bits"}, {24, "24 bits"}, {0, NULL}}; + +consvar_t cv_glpaletterendering = CVAR_INIT ("gr_paletterendering", "Off", CV_SAVE|CV_CALL, CV_OnOff, CV_glpaletterendering_OnChange); +consvar_t cv_glpalettedepth = CVAR_INIT ("gr_palettedepth", "16 bits", CV_SAVE|CV_CALL, glpalettedepth_cons_t, CV_glpalettedepth_OnChange); + static void CV_glfiltermode_OnChange(void) { if (rendermode == render_opengl) @@ -6361,6 +6459,31 @@ static void CV_glmodellighting_OnChange(void) HWR_CompileShaders(); } +static void CV_glpaletterendering_OnChange(void) +{ + if (gl_shadersavailable) + { + HWR_CompileShaders(); + HWR_TogglePaletteRendering(); + } +} + +static void CV_glpalettedepth_OnChange(void) +{ + // refresh the screen palette + if (HWR_ShouldUsePaletteRendering()) + HWR_SetPalette(pLocalPalette); +} + +static void CV_glshaders_OnChange(void) +{ + if (cv_glpaletterendering.value) + { + // can't do palette rendering without shaders, so update the state if needed + HWR_TogglePaletteRendering(); + } +} + //added by Hurdler: console varibale that are saved void HWR_AddCommands(void) { @@ -6389,6 +6512,9 @@ void HWR_AddCommands(void) CV_RegisterVar(&cv_glbatching); + CV_RegisterVar(&cv_glpaletterendering); + CV_RegisterVar(&cv_glpalettedepth); + #ifndef NEWCLIP CV_RegisterVar(&cv_glclipwalls); #endif @@ -6411,6 +6537,8 @@ void HWR_Startup(void) { CONS_Printf("HWR_Startup()...\n"); + textureformat = patchformat = GL_TEXFMT_RGBA; + HWR_InitPolyPool(); HWR_AddSessionCommands(); HWR_InitMapTextures(); @@ -6421,11 +6549,9 @@ void HWR_Startup(void) gl_shadersavailable = HWR_InitShaders(); HWR_LoadAllCustomShaders(); + HWR_TogglePaletteRendering(); } - if (rendermode == render_opengl) - textureformat = patchformat = GL_TEXFMT_RGBA; - gl_init = true; } @@ -6564,7 +6690,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; diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 9a3477b03..71a1a6984 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -74,6 +74,8 @@ FBITFIELD HWR_GetBlendModeFlag(INT32 ast); FBITFIELD HWR_SurfaceBlend(INT32 style, INT32 transtablenum, FSurfaceInfo *pSurf); FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf); +boolean HWR_ShouldUsePaletteRendering(void); + extern CV_PossibleValue_t glanisotropicmode_cons_t[]; #ifdef ALAM_LIGHTING @@ -96,8 +98,9 @@ extern consvar_t cv_glspritebillboarding; extern consvar_t cv_glskydome; extern consvar_t cv_glfakecontrast; extern consvar_t cv_glslopecontrast; - 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_shaders.c b/src/hardware/hw_shaders.c index c5e04fb8f..e28624226 100644 --- a/src/hardware/hw_shaders.c +++ b/src/hardware/hw_shaders.c @@ -38,7 +38,7 @@ #define GLSL_MODEL_VERTEX_SHADER \ "void main()\n" \ "{\n" \ - "#ifdef MODEL_LIGHTING\n" \ + "#ifdef SRB2_MODEL_LIGHTING\n" \ "float nDotVP = dot(gl_Normal, vec3(0, 1, 0));\n" \ "float light = 0.75 + max(nDotVP, 0.0);\n" \ "gl_FrontColor = vec4(light, light, light, 1.0);\n" \ @@ -69,6 +69,7 @@ // 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" \ @@ -76,8 +77,12 @@ "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" \ + "float cap = (155.0 - light) * 0.26;\n" \ + "return max(startmap * STARTMAP_FUDGE - scale * 0.5 * SCALE_FUDGE, cap);\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" \ @@ -106,7 +111,28 @@ "}\n" \ "final_color = mix(final_color, fade_color, darkness);\n" +#define GLSL_PALETTE_RENDERING \ + "float tex_pal_idx = texture3D(palette_lookup_tex, vec3((texel * 63.0 + 0.5) / 64.0))[0] * 255.0;\n" \ + "float z = gl_FragCoord.z / gl_FragCoord.w;\n" \ + "float light_y = clamp(floor(R_DoomColormap(lighting, z)), 0.0, 31.0);\n" \ + "vec2 lighttable_coord = vec2((tex_pal_idx + 0.5) / 256.0, (light_y + 0.5) / 32.0);\n" \ + "vec4 final_color = texture2D(lighttable_tex, lighttable_coord);\n" \ + "final_color.a = texel.a * poly_color.a;\n" \ + "gl_FragColor = final_color;\n" \ + #define GLSL_SOFTWARE_FRAGMENT_SHADER \ + "#ifdef SRB2_PALETTE_RENDERING\n" \ + "uniform sampler2D tex;\n" \ + "uniform sampler3D palette_lookup_tex;\n" \ + "uniform sampler2D lighttable_tex;\n" \ + "uniform vec4 poly_color;\n" \ + "uniform float lighting;\n" \ + GLSL_DOOM_COLORMAP \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + GLSL_PALETTE_RENDERING \ + "}\n" \ + "#else\n" \ "uniform sampler2D tex;\n" \ "uniform vec4 poly_color;\n" \ "uniform vec4 tint_color;\n" \ @@ -124,11 +150,45 @@ GLSL_SOFTWARE_FADE_EQUATION \ "final_color.a = texel.a * poly_color.a;\n" \ "gl_FragColor = final_color;\n" \ - "}\0" + "}\n" \ + "#endif\0" + +// hand tuned adjustments for light level calculation +#define GLSL_FLOOR_FUDGES \ + "#define STARTMAP_FUDGE 1.06\n" \ + "#define SCALE_FUDGE 1.15\n" + +#define GLSL_WALL_FUDGES \ + "#define STARTMAP_FUDGE 1.05\n" \ + "#define SCALE_FUDGE 2.2\n" + +#define GLSL_SOFTWARE_FRAGMENT_SHADER_FLOORS \ + GLSL_FLOOR_FUDGES \ + GLSL_SOFTWARE_FRAGMENT_SHADER + +#define GLSL_SOFTWARE_FRAGMENT_SHADER_WALLS \ + GLSL_WALL_FUDGES \ + GLSL_SOFTWARE_FRAGMENT_SHADER // same as above but multiplies results with the lighting value from the -// accompanying vertex shader (stored in gl_Color) +// accompanying vertex shader (stored in gl_Color) if model lighting is enabled #define GLSL_SOFTWARE_MODEL_FRAGMENT_SHADER \ + GLSL_WALL_FUDGES \ + "#ifdef SRB2_PALETTE_RENDERING\n" \ + "uniform sampler2D tex;\n" \ + "uniform sampler3D palette_lookup_tex;\n" \ + "uniform sampler2D lighttable_tex;\n" \ + "uniform vec4 poly_color;\n" \ + "uniform float lighting;\n" \ + GLSL_DOOM_COLORMAP \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + "#ifdef SRB2_MODEL_LIGHTING\n" \ + "texel *= gl_Color;\n" \ + "#endif\n" \ + GLSL_PALETTE_RENDERING \ + "}\n" \ + "#else\n" \ "uniform sampler2D tex;\n" \ "uniform vec4 poly_color;\n" \ "uniform vec4 tint_color;\n" \ @@ -144,12 +204,13 @@ "vec4 final_color = base_color;\n" \ GLSL_SOFTWARE_TINT_EQUATION \ GLSL_SOFTWARE_FADE_EQUATION \ - "#ifdef MODEL_LIGHTING\n" \ + "#ifdef SRB2_MODEL_LIGHTING\n" \ "final_color *= gl_Color;\n" \ "#endif\n" \ "final_color.a = texel.a * poly_color.a;\n" \ "gl_FragColor = final_color;\n" \ - "}\0" + "}\n" \ + "#endif\0" // // Water surface shader @@ -158,7 +219,32 @@ // 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 \ + GLSL_FLOOR_FUDGES \ + "const float freq = 0.025;\n" \ + "const float amp = 0.025;\n" \ + "const float speed = 2.0;\n" \ + "const float pi = 3.14159;\n" \ + "#ifdef SRB2_PALETTE_RENDERING\n" \ + "uniform sampler2D tex;\n" \ + "uniform sampler3D palette_lookup_tex;\n" \ + "uniform sampler2D lighttable_tex;\n" \ + "uniform vec4 poly_color;\n" \ + "uniform float lighting;\n" \ + "uniform float leveltime;\n" \ + GLSL_DOOM_COLORMAP \ + "void main(void) {\n" \ + GLSL_WATER_TEXEL \ + GLSL_PALETTE_RENDERING \ + "}\n" \ + "#else\n" \ "uniform sampler2D tex;\n" \ "uniform vec4 poly_color;\n" \ "uniform vec4 tint_color;\n" \ @@ -167,25 +253,18 @@ "uniform float fade_start;\n" \ "uniform float fade_end;\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 z = (gl_FragCoord.z / gl_FragCoord.w) / 2.0;\n" \ - "float a = -pi * (z * freq) + (leveltime * speed);\n" \ - "float sdistort = sin(a) * amp;\n" \ - "float cdistort = cos(a) * amp;\n" \ - "vec4 texel = texture2D(tex, vec2(gl_TexCoord[0].s - sdistort, gl_TexCoord[0].t - cdistort));\n" \ + GLSL_WATER_TEXEL \ "vec4 base_color = texel * poly_color;\n" \ "vec4 final_color = base_color;\n" \ GLSL_SOFTWARE_TINT_EQUATION \ GLSL_SOFTWARE_FADE_EQUATION \ "final_color.a = texel.a * poly_color.a;\n" \ "gl_FragColor = final_color;\n" \ - "}\0" + "}\n" \ + "#endif\0" // // Fog block shader @@ -193,7 +272,10 @@ // 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 \ + GLSL_FLOOR_FUDGES \ "uniform vec4 tint_color;\n" \ "uniform vec4 fade_color;\n" \ "uniform float lighting;\n" \ @@ -220,6 +302,19 @@ "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_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform sampler3D palette_lookup_tex;\n" \ + "uniform sampler1D screen_palette_tex;\n" \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + "float tex_pal_idx = texture3D(palette_lookup_tex, vec3((texel * 63.0 + 0.5) / 64.0))[0] * 255.0;\n" \ + "float palette_coord = (tex_pal_idx + 0.5) / 256.0;\n" \ + "vec4 final_color = texture1D(screen_palette_tex, palette_coord);\n" \ + "gl_FragColor = final_color;\n" \ + "}\0" + // ================ // Shader sources // ================ @@ -229,13 +324,13 @@ static struct { const char *fragment; } const gl_shadersources[] = { // Floor shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER_FLOORS}, // Wall shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER_WALLS}, // Sprite shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER_WALLS}, // Model shader {GLSL_MODEL_VERTEX_SHADER, GLSL_SOFTWARE_MODEL_FRAGMENT_SHADER}, @@ -249,6 +344,9 @@ static struct { // Sky shader {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SKY_FRAGMENT_SHADER}, + // Palette postprocess shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_PALETTE_POSTPROCESS_SHADER}, + {NULL, NULL}, }; @@ -272,7 +370,8 @@ static shader_t gl_shaders[NUMSHADERTARGETS*2]; static shadertarget_t gl_shadertargets[NUMSHADERTARGETS]; -#define MODEL_LIGHTING_DEFINE "#define MODEL_LIGHTING" +#define MODEL_LIGHTING_DEFINE "#define SRB2_MODEL_LIGHTING" +#define PALETTE_RENDERING_DEFINE "#define SRB2_PALETTE_RENDERING" // Initialize shader variables and the backend's shader system. Load the base shaders. // Returns false if shaders cannot be used. @@ -446,6 +545,8 @@ static char *HWR_PreprocessShader(char *original) new_len = original_len; if (cv_glmodellighting.value) new_len += sizeof(MODEL_LIGHTING_DEFINE) - 1 + 2 * line_ending_len; + if (cv_glpaletterendering.value) + new_len += sizeof(PALETTE_RENDERING_DEFINE) - 1 + 2 * line_ending_len; // Allocate memory for modified shader. new_shader = Z_Malloc(new_len + 1, PU_STATIC, NULL); @@ -458,16 +559,23 @@ static char *HWR_PreprocessShader(char *original) read_pos += insertion_pos; write_pos += insertion_pos; +#define WRITE_DEFINE(define) \ + { \ + strcpy(write_pos, line_ending); \ + write_pos += line_ending_len; \ + strcpy(write_pos, define); \ + write_pos += sizeof(define) - 1; \ + strcpy(write_pos, line_ending); \ + write_pos += line_ending_len; \ + } + // Write the additions. if (cv_glmodellighting.value) - { - strcpy(write_pos, line_ending); - write_pos += line_ending_len; - strcpy(write_pos, MODEL_LIGHTING_DEFINE); - write_pos += sizeof(MODEL_LIGHTING_DEFINE) - 1; - strcpy(write_pos, line_ending); - write_pos += line_ending_len; - } + WRITE_DEFINE(MODEL_LIGHTING_DEFINE) + if (cv_glpaletterendering.value) + WRITE_DEFINE(PALETTE_RENDERING_DEFINE) + +#undef WRITE_DEFINE // Copy the part after our additions. M_Memcpy(write_pos, read_pos, original_len - insertion_pos); @@ -557,6 +665,7 @@ customshaderxlat_t shaderxlat[] = {"WaterRipple", SHADER_WATER}, {"Fog", SHADER_FOG}, {"Sky", SHADER_SKY}, + {"PalettePostprocess", SHADER_PALETTE_POSTPROCESS}, {NULL, 0}, }; @@ -739,18 +848,13 @@ const char *HWR_GetShaderName(INT32 shader) { INT32 i; - if (shader) + for (i = 0; shaderxlat[i].type; i++) { - for (i = 0; shaderxlat[i].type; i++) - { - if (shaderxlat[i].id == shader) - return shaderxlat[i].type; - } - - return "Unknown"; + if (shaderxlat[i].id == shader) + return shaderxlat[i].type; } - return "Default"; + return "Unknown"; } #endif // HWRENDER diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 9321934b7..3e9959757 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -34,12 +34,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; @@ -55,6 +64,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; @@ -62,7 +72,14 @@ static FBITFIELD CurrentPolyFlags; static FTextureInfo *TexCacheTail = NULL; static FTextureInfo *TexCacheHead = NULL; -RGBA_t myPaletteData[256]; +// Linked list of all lighttables. +static LTListItem *LightTablesTail = NULL; +static LTListItem *LightTablesHead = NULL; + +static RGBA_t screenPalette[256] = {0}; // the palette for the postprocessing step in palette rendering +static GLuint screenPaletteTex = 0; // 1D texture containing the screen palette +static GLuint paletteLookupTex = 0; // 3D texture containing RGB -> palette index lookup table +RGBA_t myPaletteData[256]; // the palette for converting textures to RGBA GLint screen_width = 0; // used by Draw2DLine() GLint screen_height = 0; GLbyte screen_depth = 0; @@ -377,6 +394,8 @@ 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); @@ -400,6 +419,10 @@ static PFNglCopyTexSubImage2D pglCopyTexSubImage2D; typedef GLint (APIENTRY * PFNgluBuild2DMipmaps) (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data); static PFNgluBuild2DMipmaps pgluBuild2DMipmaps; +/* 1.2 functions for 3D textures */ +typedef void (APIENTRY * PFNglTexImage3D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +static PFNglTexImage3D pglTexImage3D; + /* 1.3 functions for multitexturing */ typedef void (APIENTRY *PFNglActiveTexture) (GLenum); static PFNglActiveTexture pglActiveTexture; @@ -444,6 +467,9 @@ static PFNglBlendEquation pglBlendEquation; #ifndef GL_TEXTURE1 #define GL_TEXTURE1 0x84C1 #endif +#ifndef GL_TEXTURE2 +#define GL_TEXTURE2 0x84C2 +#endif /* 1.5 Parms */ #ifndef GL_ARRAY_BUFFER @@ -515,6 +541,7 @@ boolean SetupGLfunc(void) GETOPENGLFUNC(pglTexEnvi, glTexEnvi) GETOPENGLFUNC(pglTexParameteri, glTexParameteri) + GETOPENGLFUNC(pglTexImage1D, glTexImage1D) GETOPENGLFUNC(pglTexImage2D, glTexImage2D) GETOPENGLFUNC(pglTexSubImage2D, glTexSubImage2D) @@ -590,7 +617,12 @@ typedef enum gluniform_fade_start, gluniform_fade_end, - // misc. (custom shaders) + // palette rendering + gluniform_screen_palette_tex, + gluniform_palette_lookup_tex, + gluniform_lighttable_tex, + + // misc. gluniform_leveltime, gluniform_max, @@ -656,6 +688,9 @@ static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f}; void SetupGLFunc4(void) { + /* 1.2 funcs */ + pglTexImage3D = GetGLFunc("glTexImage3D"); + /* 1.3 funcs */ pglActiveTexture = GetGLFunc("glActiveTexture"); pglMultiTexCoord2f = GetGLFunc("glMultiTexCoord2f"); pglClientActiveTexture = GetGLFunc("glClientActiveTexture"); @@ -1496,6 +1531,9 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo) w = pTexInfo->width; h = pTexInfo->height; + if (w*h > 2048*2048 && pTexInfo->format != GL_TEXFMT_RGBA) + I_Error("Tried to convert too big texture: %dx%d", w, h); + if ((pTexInfo->format == GL_TEXFMT_P_8) || (pTexInfo->format == GL_TEXFMT_AP_88)) { @@ -1889,11 +1927,31 @@ static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i) shader->uniforms[gluniform_fade_start] = GETUNI("fade_start"); shader->uniforms[gluniform_fade_end] = GETUNI("fade_end"); - // misc. (custom shaders) - shader->uniforms[gluniform_leveltime] = GETUNI("leveltime"); + // palette rendering + shader->uniforms[gluniform_screen_palette_tex] = GETUNI("screen_palette_tex"); + shader->uniforms[gluniform_palette_lookup_tex] = GETUNI("palette_lookup_tex"); + shader->uniforms[gluniform_lighttable_tex] = GETUNI("lighttable_tex"); + // misc. + shader->uniforms[gluniform_leveltime] = GETUNI("leveltime"); #undef GETUNI + // set permanent uniform values +#define UNIFORM_1(uniform, a, function) \ + if (uniform != -1) \ + function (uniform, a); + + pglUseProgram(shader->program); + + // texture unit numbers for the samplers used for palette rendering + UNIFORM_1(shader->uniforms[gluniform_screen_palette_tex], 2, pglUniform1i); + UNIFORM_1(shader->uniforms[gluniform_palette_lookup_tex], 1, pglUniform1i); + UNIFORM_1(shader->uniforms[gluniform_lighttable_tex], 2, pglUniform1i); + + // restore gl shader state + pglUseProgram(gl_shaderstate.program); +#undef UNIFORM_1 + return true; } @@ -1956,6 +2014,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_TEXTURE2); + pglBindTexture(GL_TEXTURE_2D, pSurf->LightTableId); + pglActiveTexture(GL_TEXTURE0); + lt_downloaded = pSurf->LightTableId; + } } } @@ -2148,9 +2214,6 @@ EXPORT void HWRAPI(RenderSkyDome) (gl_sky_t *sky) pglDisableClientState(GL_COLOR_ARRAY); } -// ========================================================================== -// -// ========================================================================== EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value) { switch (IdState) @@ -2514,6 +2577,14 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 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); @@ -3249,6 +3320,9 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) ClearBuffer(true, false, &clearColour); pglBindTexture(GL_TEXTURE_2D, finalScreenTexture); + // prepare shader, if it is enabled + Shader_SetUniforms(NULL, NULL, NULL, NULL); + pglColor4ubv(white); pglTexCoordPointer(2, GL_FLOAT, 0, fix); @@ -3258,4 +3332,76 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) tex_downloaded = finalScreenTexture; } +EXPORT void HWRAPI(SetPaletteLookup)(UINT8 *lut) +{ + if (!paletteLookupTex) + pglGenTextures(1, &paletteLookupTex); + pglActiveTexture(GL_TEXTURE1); + pglBindTexture(GL_TEXTURE_3D, paletteLookupTex); + pglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + pglTexImage3D(GL_TEXTURE_3D, 0, GL_R8, HWR_PALETTE_LUT_SIZE, HWR_PALETTE_LUT_SIZE, HWR_PALETTE_LUT_SIZE, + 0, GL_RED, GL_UNSIGNED_BYTE, lut); + pglActiveTexture(GL_TEXTURE0); +} + +EXPORT UINT32 HWRAPI(CreateLightTable)(RGBA_t *hw_lighttable) +{ + LTListItem *item = malloc(sizeof(LTListItem)); + if (!LightTablesTail) + { + LightTablesHead = LightTablesTail = item; + } + else + { + LightTablesTail->next = item; + LightTablesTail = item; + } + item->next = NULL; + pglGenTextures(1, &item->id); + pglBindTexture(GL_TEXTURE_2D, item->id); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + pglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, hw_lighttable); + + // restore previously bound texture + pglBindTexture(GL_TEXTURE_2D, tex_downloaded); + + return item->id; +} + +// Delete light table textures, ids given before become invalid and must not be used. +EXPORT void HWRAPI(ClearLightTables)(void) +{ + while (LightTablesHead) + { + LTListItem *item = LightTablesHead; + pglDeleteTextures(1, (GLuint *)&item->id); + LightTablesHead = item->next; + free(item); + } + + LightTablesTail = NULL; + + // we no longer have a bound light table (if we had one), we just deleted it! + lt_downloaded = 0; +} + +// This palette is used for the palette rendering postprocessing step. +EXPORT void HWRAPI(SetScreenPalette)(RGBA_t *palette) +{ + if (memcmp(screenPalette, palette, sizeof(screenPalette))) + { + memcpy(screenPalette, palette, sizeof(screenPalette)); + if (!screenPaletteTex) + pglGenTextures(1, &screenPaletteTex); + pglActiveTexture(GL_TEXTURE2); + pglBindTexture(GL_TEXTURE_1D, screenPaletteTex); + pglTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + pglTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + pglTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, palette); + pglActiveTexture(GL_TEXTURE0); + } +} + #endif //HWRENDER diff --git a/src/m_menu.c b/src/m_menu.c index 13531f1b8..300cbcbc3 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1443,18 +1443,20 @@ static menuitem_t OP_OpenGLOptionsMenu[] = {IT_HEADER, NULL, "General", NULL, 51}, {IT_STRING|IT_CVAR, NULL, "Shaders", &cv_glshaders, 63}, - {IT_STRING|IT_CVAR, NULL, "Lack of perspective", &cv_glshearing, 73}, - {IT_STRING|IT_CVAR, NULL, "Field of view", &cv_fov, 83}, + {IT_STRING|IT_CVAR, NULL, "Palette rendering", &cv_glpaletterendering, 73}, + {IT_STRING|IT_CVAR, NULL, "Palette bit depth", &cv_glpalettedepth, 83}, + {IT_STRING|IT_CVAR, NULL, "Lack of perspective", &cv_glshearing, 93}, + {IT_STRING|IT_CVAR, NULL, "Field of view", &cv_fov, 103}, - {IT_HEADER, NULL, "Miscellaneous", NULL, 102}, - {IT_STRING|IT_CVAR, NULL, "Bit depth", &cv_scr_depth, 114}, - {IT_STRING|IT_CVAR, NULL, "Texture filter", &cv_glfiltermode, 124}, - {IT_STRING|IT_CVAR, NULL, "Anisotropic", &cv_glanisotropicmode, 134}, + {IT_HEADER, NULL, "Miscellaneous", NULL, 122}, + {IT_STRING|IT_CVAR, NULL, "Bit depth", &cv_scr_depth, 134}, + {IT_STRING|IT_CVAR, NULL, "Texture filter", &cv_glfiltermode, 144}, + {IT_STRING|IT_CVAR, NULL, "Anisotropic", &cv_glanisotropicmode, 154}, #ifdef ALAM_LIGHTING - {IT_SUBMENU|IT_STRING, NULL, "Lighting...", &OP_OpenGLLightingDef, 144}, + {IT_SUBMENU|IT_STRING, NULL, "Lighting...", &OP_OpenGLLightingDef, 164}, #endif #if defined (_WINDOWS) && (!((defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL))) - {IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 154}, + {IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 174}, #endif }; diff --git a/src/r_data.c b/src/r_data.c index 2cfe9cb7a..340c1721e 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -30,6 +30,10 @@ #include "byteptr.h" #include "dehacked.h" +#ifdef HWRENDER +#include "hardware/hw_glob.h" // HWR_ClearLightTables +#endif + // // Graphics. // SRB2 graphics for walls and sprites @@ -425,6 +429,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 9c649fbc4..0f83c7545 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -69,6 +69,11 @@ typedef struct extracolormap_s 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 e0c90cef4..e1441744c 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -74,7 +74,7 @@ void *hwSym(const char *funcName,void *handle) { void *funcPointer = NULL; #ifdef HWRENDER - if (0 == strcmp("SetPalette", funcName)) + if (0 == strcmp("SetTexturePalette", funcName)) funcPointer = &OglSdlSetPalette; GETFUNC(Init); @@ -113,6 +113,11 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(SetShaderInfo); + GETFUNC(SetPaletteLookup); + GETFUNC(CreateLightTable); + GETFUNC(ClearLightTables); + GETFUNC(SetScreenPalette); + #else //HWRENDER if (0 == strcmp("FinishUpdate", funcName)) return funcPointer; //&FinishUpdate; diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 5aaf97b10..c0168d2e5 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1241,6 +1241,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()) + { + // not using the function for its original named purpose but can be used like this too + HWR_MakeScreenFinalTexture(); + HWD.pfnSetSpecialState(HWD_SET_SHADERS, 1); + HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_PALETTE_POSTPROCESS)); + HWR_DrawScreenFinalTexture(vid.width, vid.height); + HWD.pfnUnSetShader(); + HWD.pfnSetSpecialState(HWD_SET_SHADERS, 0); + } OglSdlFinishUpdate(cv_vidwait.value); } #endif @@ -1863,7 +1874,7 @@ void VID_StartupOpenGL(void) HWD.pfnGClipRect = hwSym("GClipRect",NULL); HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL); HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL); - HWD.pfnSetPalette = hwSym("SetPalette",NULL); + HWD.pfnSetTexturePalette= hwSym("SetTexturePalette",NULL); HWD.pfnGetTextureUsed = hwSym("GetTextureUsed",NULL); HWD.pfnDrawModel = hwSym("DrawModel",NULL); HWD.pfnCreateModelVBOs = hwSym("CreateModelVBOs",NULL); @@ -1886,6 +1897,11 @@ void VID_StartupOpenGL(void) HWD.pfnSetShaderInfo = hwSym("SetShaderInfo",NULL); + HWD.pfnSetPaletteLookup = hwSym("SetPaletteLookup",NULL); + HWD.pfnCreateLightTable = hwSym("CreateLightTable",NULL); + HWD.pfnClearLightTables = hwSym("ClearLightTables",NULL); + HWD.pfnSetScreenPalette = hwSym("SetScreenPalette",NULL); + vid.glstate = HWD.pfnInit() ? VID_GL_LIBRARY_LOADED : VID_GL_LIBRARY_ERROR; // let load the OpenGL library if (vid.glstate == VID_GL_LIBRARY_ERROR) diff --git a/src/st_stuff.c b/src/st_stuff.c index a1fbbec03..cd5fdaaa5 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -209,8 +209,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) @@ -2786,7 +2786,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(); From 99204a7aa88101517c35b75295107b0637ca75e8 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Sun, 13 Jun 2021 16:57:06 +0300 Subject: [PATCH 04/25] Remove palette depth from menu --- src/m_menu.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 300cbcbc3..922883661 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1444,19 +1444,18 @@ static menuitem_t OP_OpenGLOptionsMenu[] = {IT_HEADER, NULL, "General", NULL, 51}, {IT_STRING|IT_CVAR, NULL, "Shaders", &cv_glshaders, 63}, {IT_STRING|IT_CVAR, NULL, "Palette rendering", &cv_glpaletterendering, 73}, - {IT_STRING|IT_CVAR, NULL, "Palette bit depth", &cv_glpalettedepth, 83}, - {IT_STRING|IT_CVAR, NULL, "Lack of perspective", &cv_glshearing, 93}, - {IT_STRING|IT_CVAR, NULL, "Field of view", &cv_fov, 103}, + {IT_STRING|IT_CVAR, NULL, "Lack of perspective", &cv_glshearing, 83}, + {IT_STRING|IT_CVAR, NULL, "Field of view", &cv_fov, 93}, - {IT_HEADER, NULL, "Miscellaneous", NULL, 122}, - {IT_STRING|IT_CVAR, NULL, "Bit depth", &cv_scr_depth, 134}, - {IT_STRING|IT_CVAR, NULL, "Texture filter", &cv_glfiltermode, 144}, - {IT_STRING|IT_CVAR, NULL, "Anisotropic", &cv_glanisotropicmode, 154}, + {IT_HEADER, NULL, "Miscellaneous", NULL, 112}, + {IT_STRING|IT_CVAR, NULL, "Bit depth", &cv_scr_depth, 124}, + {IT_STRING|IT_CVAR, NULL, "Texture filter", &cv_glfiltermode, 134}, + {IT_STRING|IT_CVAR, NULL, "Anisotropic", &cv_glanisotropicmode, 144}, #ifdef ALAM_LIGHTING - {IT_SUBMENU|IT_STRING, NULL, "Lighting...", &OP_OpenGLLightingDef, 164}, + {IT_SUBMENU|IT_STRING, NULL, "Lighting...", &OP_OpenGLLightingDef, 154}, #endif #if defined (_WINDOWS) && (!((defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL))) - {IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 174}, + {IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 164}, #endif }; From cf16fd29381cf67542f741f8de4ff017b167819e Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Sun, 13 Jun 2021 17:56:11 +0300 Subject: [PATCH 05/25] Fix custom shaders that define only one stage, like footfix --- src/hardware/hw_shaders.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/hardware/hw_shaders.c b/src/hardware/hw_shaders.c index e28624226..c341577eb 100644 --- a/src/hardware/hw_shaders.c +++ b/src/hardware/hw_shaders.c @@ -834,6 +834,12 @@ skip_field: { int shader_index = i + NUMSHADERTARGETS; // index to gl_shaders gl_shadertargets[i].custom_shader = shader_index; + // if only one stage (vertex/fragment) is defined, the other one + // is copied from the base shaders. + if (!gl_shaders[shader_index].fragment) + gl_shaders[shader_index].fragment = Z_StrDup(gl_shadersources[i].fragment); + if (!gl_shaders[shader_index].vertex) + gl_shaders[shader_index].vertex = Z_StrDup(gl_shadersources[i].vertex); HWR_CompileShader(shader_index); if (!gl_shaders[shader_index].compiled) CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: A compilation error occured for the %s shader in file %s. See the console messages above for more information.\n", shaderxlat[i].type, wadfiles[wadnum]->filename); From 725a8195ab28282f2ac1f5fc9924df8c7bc280f8 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Mon, 14 Jun 2021 00:57:20 +0300 Subject: [PATCH 06/25] Decrease the amount of texture clearing when switching palette rendering state --- src/hardware/hw_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index cb976a8f8..2f525d736 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -6342,10 +6342,10 @@ static void HWR_TogglePaletteRendering(void) HWR_SetMapPalette(); HWR_SetPalette(pLocalPalette); - // If the r_opengl "texture palette" stays the same during this switch, the textures + // 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. - HWD.pfnClearMipMapCache(); + HWR_LoadMapTextures(numtextures); } } else @@ -6356,10 +6356,10 @@ static void HWR_TogglePaletteRendering(void) gl_palette_rendering_state = false; textureformat = GL_TEXFMT_RGBA; HWR_SetPalette(pLocalPalette); - // If the r_opengl "texture palette" stays the same during this switch, the textures + // 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. - HWD.pfnClearMipMapCache(); + HWR_LoadMapTextures(numtextures); } } } From 913bbb3fc0b5fe3e9d09d6e858fa1af47029b13f Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Wed, 8 Sep 2021 03:18:13 +0300 Subject: [PATCH 07/25] Fix brightness issues with 2d drawing functions and palette rendering --- src/hardware/hw_cache.c | 2 +- src/hardware/hw_draw.c | 14 +++++++++----- src/hardware/hw_glob.h | 2 ++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 99dba2c61..acc38d1eb 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -35,7 +35,7 @@ INT32 textureformat = GL_TEXFMT_P_8; // use chromakey for hole RGBA_t mapPalette[256] = {0}; // the palette for the currently loaded level or menu etc. // Returns a pointer to the palette which should be used for caching textures. -static RGBA_t *HWR_GetTexturePalette(void) +RGBA_t *HWR_GetTexturePalette(void) { return HWR_ShouldUsePaletteRendering() ? mapPalette : pLocalPalette; } diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index ba4923d10..b2185c5af 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -672,7 +672,8 @@ void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength) } 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); @@ -845,7 +846,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); @@ -1050,8 +1052,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); @@ -1236,6 +1239,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) FOutVector v[4]; FSurfaceInfo Surf; float fx, fy, fw, fh; + RGBA_t *palette = HWR_GetTexturePalette(); UINT8 perplayershuffle = 0; @@ -1323,7 +1327,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT) { - 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; @@ -1400,7 +1404,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]; HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated|PF_NoTexture|PF_NoDepthTest); diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index 316f32ef8..0d3055c1a 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -104,6 +104,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); From f7a8bedec1f80b646ae044efea9e0ff8da93f5f9 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Tue, 14 Sep 2021 00:17:34 +0300 Subject: [PATCH 08/25] Fix palette rendering brightness issues on wipes, add timedemo support to gif recording --- src/hardware/hw_defs.h | 13 ++ src/hardware/hw_draw.c | 6 +- src/hardware/hw_drv.h | 20 +- src/hardware/hw_main.c | 20 +- src/hardware/r_opengl/r_opengl.c | 316 ++++++++++++------------------- src/m_anigif.c | 5 +- src/m_misc.c | 2 +- src/sdl/hwsym_sdl.c | 6 +- src/sdl/i_video.c | 11 +- src/sdl/ogl_sdl.c | 4 +- 10 files changed, 171 insertions(+), 232 deletions(-) diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 287c3a2be..ff5e86838 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -329,5 +329,18 @@ 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, // screen before palette rendering's postprocessing + HWD_SCREENTEXTURE_GENERIC3, // screen after palette rendering's postprocessing + NUMSCREENTEXTURES, // (generic3 is unused if palette rendering is disabled) +}; + +typedef enum hwdscreentexture hwdscreentexture_t; + #endif //_HWR_DEFS_ diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index b2185c5af..9e80e8954 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -1484,11 +1484,12 @@ static inline boolean saveTGA(const char *file_name, void *buffer, UINT8 *HWR_GetScreenshot(void) { UINT8 *buf = malloc(vid.width * vid.height * 3 * sizeof (*buf)); + int tex = HWR_ShouldUsePaletteRendering() ? HWD_SCREENTEXTURE_GENERIC3 : HWD_SCREENTEXTURE_GENERIC2; if (!buf) return NULL; // returns 24bit 888 RGB - HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf); + HWD.pfnReadRect(tex, (void *)buf); return buf; } @@ -1496,6 +1497,7 @@ boolean HWR_Screenshot(const char *pathname) { boolean ret; UINT8 *buf = malloc(vid.width * vid.height * 3 * sizeof (*buf)); + int tex = HWR_ShouldUsePaletteRendering() ? HWD_SCREENTEXTURE_GENERIC3 : HWD_SCREENTEXTURE_GENERIC2; if (!buf) { @@ -1504,7 +1506,7 @@ boolean HWR_Screenshot(const char *pathname) } // returns 24bit 888 RGB - HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf); + HWD.pfnReadRect(tex, (void *)buf); #ifdef USE_PNG ret = M_SavePNG(pathname, buf, vid.width, vid.height, NULL); diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 629f616da..82e2c285c 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -43,7 +43,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(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 *dst_data); +EXPORT void HWRAPI(ReadRect) (int tex, UINT8 *dst_data); EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip); EXPORT void HWRAPI(ClearMipMapCache) (void); @@ -55,13 +55,11 @@ EXPORT void HWRAPI(SetTransform) (FTransform *ptransform); 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(DrawIntermissionBG) (void); -EXPORT void HWRAPI(MakeScreenTexture) (void); -EXPORT void HWRAPI(MakeScreenFinalTexture) (void); -EXPORT void HWRAPI(DrawScreenFinalTexture) (int width, int height); +EXPORT void HWRAPI(SwapScreenTextures) (int tex1, int tex2); +EXPORT void HWRAPI(DoScreenWipe) (int wipeStart, int wipeEnd); +EXPORT void HWRAPI(DrawScreenTexture) (int tex); +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]); @@ -115,12 +113,10 @@ struct hwdriver_s #endif PostImgRedraw pfnPostImgRedraw; FlushScreenTextures pfnFlushScreenTextures; - StartScreenWipe pfnStartScreenWipe; - EndScreenWipe pfnEndScreenWipe; + SwapScreenTextures pfnSwapScreenTextures; DoScreenWipe pfnDoScreenWipe; - DrawIntermissionBG pfnDrawIntermissionBG; + DrawScreenTexture pfnDrawScreenTexture; MakeScreenTexture pfnMakeScreenTexture; - MakeScreenFinalTexture pfnMakeScreenFinalTexture; DrawScreenFinalTexture pfnDrawScreenFinalTexture; InitShaders pfnInitShaders; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 2f525d736..1c83b211b 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -6715,7 +6715,7 @@ void HWR_DoPostProcessor(player_t *player) // Capture the screen for intermission and screen waving if(gamestate != GS_INTERMISSION) - HWD.pfnMakeScreenTexture(); + HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_GENERIC1); if (splitscreen) // Not supported in splitscreen - someone want to add support? return; @@ -6760,26 +6760,26 @@ void HWR_DoPostProcessor(player_t *player) // Capture the screen again for screen waving on the intermission if(gamestate != GS_INTERMISSION) - HWD.pfnMakeScreenTexture(); + HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_GENERIC1); } // Flipping of the screen isn't done here anymore } -void HWR_StartScreenWipe(void) +void HWR_StartScreenWipe() { //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(); + HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_WIPE_END); } void HWR_DrawIntermissionBG(void) { - HWD.pfnDrawIntermissionBG(); + HWD.pfnDrawScreenTexture(HWD_SCREENTEXTURE_GENERIC1); } // @@ -6824,7 +6824,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) @@ -6835,12 +6835,14 @@ void HWR_DoTintedWipe(UINT8 wipenum, UINT8 scrnnum) 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); + int tex = HWR_ShouldUsePaletteRendering() ? HWD_SCREENTEXTURE_GENERIC3 : HWD_SCREENTEXTURE_GENERIC2; + HWD.pfnDrawScreenFinalTexture(tex, width, height); } #endif // HWRENDER diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 3e9959757..3f77be1ec 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -104,10 +104,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 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] = { @@ -400,6 +397,8 @@ typedef void (APIENTRY * PFNglTexImage2D) (GLenum target, GLint level, GLint int 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 @@ -544,6 +543,7 @@ boolean SetupGLfunc(void) GETOPENGLFUNC(pglTexImage1D, glTexImage1D) GETOPENGLFUNC(pglTexImage2D, glTexImage2D) GETOPENGLFUNC(pglTexSubImage2D, glTexSubImage2D) + GETOPENGLFUNC(pglGetTexImage, glGetTexImage) GETOPENGLFUNC(pglGenTextures, glGenTextures) GETOPENGLFUNC(pglDeleteTextures, glDeleteTextures) @@ -1163,55 +1163,83 @@ EXPORT void HWRAPI(ClearMipMapCache) (void) } -// -----------------+ -// ReadRect : Read a rectangle region of the truecolor framebuffer -// : store pixels as 16bit 565 RGB -// Returns : 16bit 565 RGB pixel array stored in dst_data -// -----------------+ -EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, - INT32 dst_stride, UINT16 * dst_data) +// 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. +// TODO should rename to ReadScreenTexture +EXPORT void HWRAPI(ReadRect) (int tex, UINT8 *dst_data) { INT32 i; + int dst_stride = screen_width * 3; // stride between rows of image data + GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (screen_height - 1); + //precise_t ts1, ts2, ts3, ts4, ts5, total_time, get_time, loop_time; + GLubyte *row; + //ts1 = I_GetPreciseTime(); + row = malloc(dst_stride); + if (!row) return; + //ts2 = I_GetPreciseTime(); + // 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); + pglPixelStorei(GL_PACK_ALIGNMENT, 1); + pglReadPixels(0, 0, screen_width, screen_height, GL_RGB, GL_UNSIGNED_BYTE, dst_data); + if (tex != HWD_SCREENTEXTURE_GENERIC2) + DrawScreenTexture(HWD_SCREENTEXTURE_GENERIC2); + //ts3 = I_GetPreciseTime(); + // Flip image upside down. + // In other words, convert OpenGL's "bottom->top" row order into "top->bottom". + for(i = 0; i < screen_height/2; i++) + { + memcpy(row, top, dst_stride); + memcpy(top, bottom, dst_stride); + memcpy(bottom, row, dst_stride); + top += dst_stride; + bottom -= dst_stride; + } + //ts4 = I_GetPreciseTime(); + free(row); + //ts5 = I_GetPreciseTime(); + //total_time = I_PreciseToMicros(ts5 - ts1); + //get_time = I_PreciseToMicros(ts3 - ts2); + //loop_time = I_PreciseToMicros(ts4 - ts3); + //CONS_Printf("ReadRect: total time: %" PRIu64 ", read pixels thing: %" PRIu64 " memcpy loop: %" PRIu64 "\n", total_time, get_time, loop_time); + + // the slow glGetTexImage based implementation. left in here in case i wanna test it more + // TODO remove this at some point + + /*int texsize = 512; + GLsizei buffer_size; + GLubyte *buffer; // GL_DBG_Printf ("ReadRect()\n"); - if (dst_stride == width*3) - { - GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (height - 1); - GLubyte *row = malloc(dst_stride); - if (!row) return; - pglPixelStorei(GL_PACK_ALIGNMENT, 1); - pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, dst_data); - pglPixelStorei(GL_UNPACK_ALIGNMENT, 1); - for(i = 0; i < height/2; i++) - { - memcpy(row, top, dst_stride); - memcpy(top, bottom, dst_stride); - memcpy(bottom, row, dst_stride); - top += dst_stride; - bottom -= dst_stride; - } - free(row); - } - else - { - INT32 j; - GLubyte *image = malloc(width*height*3*sizeof (*image)); - if (!image) return; - pglPixelStorei(GL_PACK_ALIGNMENT, 1); - pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image); - pglPixelStorei(GL_UNPACK_ALIGNMENT, 1); - for (i = height-1; i >= 0; i--) - { - for (j = 0; j < width; j++) - { - dst_data[(height-1-i)*width+j] = - (UINT16)( - ((image[(i*width+j)*3]>>3)<<11) | - ((image[(i*width+j)*3+1]>>2)<<5) | - ((image[(i*width+j)*3+2]>>3))); - } - } - free(image); - } + precise_t ts1, ts2, ts3, ts4, ts5, total_time, get_time, loop_time; + ts1 = I_GetPreciseTime(); + // look for power of two that is large enough for the screen + while (texsize < screen_width || texsize < screen_height) + texsize <<= 1; + buffer_size = texsize * texsize * 4; + buffer = malloc(buffer_size); + tex_downloaded = screenTextures[tex]; + pglBindTexture(GL_TEXTURE_2D, tex_downloaded); + ts2 = I_GetPreciseTime(); + pglGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, buffer); // GL better not overwrite my buffer :v + ts3 = I_GetPreciseTime(); + //for (i = 0; i < screen_height; i++) // i: pixel row index that we are writing + //{ + // // read the frame from the lower left corner of the GL screen texture + // // flip it upside down so it's in correct format + // memcpy(dst_data + (screen_height - i - 1) * screen_width * 3, + // buffer + i * texsize * 3, screen_width * 3); + //} + ts4 = I_GetPreciseTime(); + free(buffer); + ts5 = I_GetPreciseTime(); + total_time = I_PreciseToMicros(ts5 - ts1); + get_time = I_PreciseToMicros(ts3 - ts2); + loop_time = I_PreciseToMicros(ts4 - ts3); + CONS_Printf("ReadRect: total time: %" PRIu64 ", glGetTexImage: %" PRIu64 " memcpy loop: %" PRIu64 "\n", total_time, get_time, loop_time);*/ } @@ -2896,7 +2924,7 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]) INT32 x, y; float float_x, float_y, float_nextx, float_nexty; float xfix, yfix; - INT32 texsize = 2048; + INT32 texsize = 512; const float blackBack[16] = { @@ -2906,11 +2934,9 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]) 16.0f, -16.0f, 6.0f }; - // Use a power of two texture, dammit - if(screen_width <= 1024) - texsize = 1024; - if(screen_width <= 512) - texsize = 512; + // look for power of two that is large enough for the screen + while (texsize < screen_width || texsize < screen_height) + texsize <<= 1; // X/Y stretch fix for all resolutions(!) xfix = (float)(texsize)/((float)((screen_width)/(float)(SCREENVERTS-1))); @@ -2984,84 +3010,24 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]) // a new size EXPORT void HWRAPI(FlushScreenTextures) (void) { - pglDeleteTextures(1, &screentexture); - pglDeleteTextures(1, &startScreenWipe); - pglDeleteTextures(1, &endScreenWipe); - pglDeleteTextures(1, &finalScreenTexture); - screentexture = 0; - startScreenWipe = 0; - endScreenWipe = 0; - finalScreenTexture = 0; + int i; + pglDeleteTextures(NUMSCREENTEXTURES, screenTextures); + for (i = 0; i < NUMSCREENTEXTURES; i++) + screenTextures[i] = 0; } -// Create Screen to fade from -EXPORT void HWRAPI(StartScreenWipe) (void) +EXPORT void HWRAPI(SwapScreenTextures) (int tex1, int tex2) { - INT32 texsize = 2048; - boolean firstTime = (startScreenWipe == 0); - - // Use a power of two texture, dammit - if(screen_width <= 512) - texsize = 512; - else if(screen_width <= 1024) - texsize = 1024; - - // Create screen texture - if (firstTime) - pglGenTextures(1, &startScreenWipe); - pglBindTexture(GL_TEXTURE_2D, startScreenWipe); - - 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 = startScreenWipe; -} - -// Create Screen to fade to -EXPORT void HWRAPI(EndScreenWipe)(void) -{ - INT32 texsize = 2048; - boolean firstTime = (endScreenWipe == 0); - - // Use a power of two texture, dammit - if(screen_width <= 512) - texsize = 512; - else if(screen_width <= 1024) - texsize = 1024; - - // Create screen texture - if (firstTime) - pglGenTextures(1, &endScreenWipe); - pglBindTexture(GL_TEXTURE_2D, endScreenWipe); - - 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 = endScreenWipe; + GLuint temp = screenTextures[tex1]; + screenTextures[tex1] = screenTextures[tex2]; + screenTextures[tex2] = temp; } -// Draw the last scene under the intermission -EXPORT void HWRAPI(DrawIntermissionBG)(void) +EXPORT void HWRAPI(DrawScreenTexture)(int tex) { float xfix, yfix; - INT32 texsize = 2048; + INT32 texsize = 512; const float screenVerts[12] = { @@ -3073,10 +3039,9 @@ EXPORT void HWRAPI(DrawIntermissionBG)(void) float fix[8]; - if(screen_width <= 1024) - texsize = 1024; - if(screen_width <= 512) - texsize = 512; + // 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)))); @@ -3095,20 +3060,21 @@ EXPORT void HWRAPI(DrawIntermissionBG)(void) pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - pglBindTexture(GL_TEXTURE_2D, screentexture); + pglBindTexture(GL_TEXTURE_2D, screenTextures[tex]); + 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 = screentexture; + tex_downloaded = screenTextures[tex]; } // Do screen fades! -EXPORT void HWRAPI(DoScreenWipe)(void) +EXPORT void HWRAPI(DoScreenWipe)(int wipeStart, int wipeEnd) { - INT32 texsize = 2048; + INT32 texsize = 512; float xfix, yfix; INT32 fademaskdownloaded = tex_downloaded; // the fade mask that has been set @@ -3131,11 +3097,9 @@ EXPORT void HWRAPI(DoScreenWipe)(void) 1.0f, 1.0f }; - // Use a power of two texture, dammit - if(screen_width <= 1024) - texsize = 1024; - if(screen_width <= 512) - texsize = 512; + // 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)))); @@ -3158,7 +3122,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); @@ -3169,7 +3133,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); @@ -3193,25 +3157,23 @@ 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) { - INT32 texsize = 2048; - boolean firstTime = (screentexture == 0); + INT32 texsize = 512; + boolean firstTime = (screenTextures[tex] == 0); - // Use a power of two texture, dammit - if(screen_width <= 512) - texsize = 512; - else if(screen_width <= 1024) - texsize = 1024; + // look for power of two that is large enough for the screen + while (texsize < screen_width || texsize < screen_height) + texsize <<= 1; // Create screen texture if (firstTime) - pglGenTextures(1, &screentexture); - pglBindTexture(GL_TEXTURE_2D, screentexture); + pglGenTextures(1, &screenTextures[tex]); + pglBindTexture(GL_TEXTURE_2D, screenTextures[tex]); if (firstTime) { @@ -3224,54 +3186,23 @@ EXPORT void HWRAPI(MakeScreenTexture) (void) else pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize); - tex_downloaded = screentexture; + tex_downloaded = screenTextures[tex]; } -EXPORT void HWRAPI(MakeScreenFinalTexture) (void) -{ - INT32 texsize = 2048; - boolean firstTime = (finalScreenTexture == 0); - - // Use a power of two texture, dammit - if(screen_width <= 512) - texsize = 512; - else if(screen_width <= 1024) - texsize = 1024; - - // Create screen texture - if (firstTime) - pglGenTextures(1, &finalScreenTexture); - pglBindTexture(GL_TEXTURE_2D, finalScreenTexture); - - 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 = 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; float xoff = 1, yoff = 1; // xoffset and yoffset for the polygon to have black bars around the screen FRGBAFloat clearColour; - INT32 texsize = 2048; + INT32 texsize = 512; float off[12]; float fix[8]; - if(screen_width <= 1024) - texsize = 1024; - if(screen_width <= 512) - texsize = 512; + // 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)))); @@ -3318,10 +3249,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); - - // prepare shader, if it is enabled - Shader_SetUniforms(NULL, NULL, NULL, NULL); + pglBindTexture(GL_TEXTURE_2D, screenTextures[tex]); pglColor4ubv(white); @@ -3329,7 +3257,7 @@ 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) diff --git a/src/m_anigif.c b/src/m_anigif.c index 41f99254e..0590e7a54 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -21,6 +21,7 @@ #include "i_system.h" // I_GetPreciseTime #include "m_misc.h" #include "st_stuff.h" // st_palette +#include "doomstat.h" // singletics #ifdef HWRENDER #include "hardware/hw_main.h" @@ -604,7 +605,7 @@ static void GIF_framewrite(void) UINT16 delay = 0; INT32 startline; - if (gif_dynamicdelay ==(UINT8) 2) + if (gif_dynamicdelay ==(UINT8) 2 && !singletics) { // golden's attempt at creating a "dynamic delay" UINT16 mingifdelay = 10; // minimum gif delay in milliseconds (keep at 10 because gifs can't get more precise). @@ -617,7 +618,7 @@ static void GIF_framewrite(void) gif_delayus -= frames*(mingifdelay*1000); // remove frames by the amount of milliseconds they take. don't reset to 0, the microseconds help consistency. } } - else if (gif_dynamicdelay ==(UINT8) 1) + else if (gif_dynamicdelay ==(UINT8) 1 && !singletics) { float delayf = ceil(100.0f/NEWTICRATE); diff --git a/src/m_misc.c b/src/m_misc.c index 17a398b83..2c69aa134 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -1250,7 +1250,7 @@ void M_SaveFrame(void) // paranoia: should be unnecessary without singletics static tic_t oldtic = 0; - if (oldtic == I_GetTime()) + if (oldtic == I_GetTime() && !singletics) return; else oldtic = I_GetTime(); diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index e1441744c..8e48350fc 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -97,12 +97,10 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(SetTransform); GETFUNC(PostImgRedraw); GETFUNC(FlushScreenTextures); - GETFUNC(StartScreenWipe); - GETFUNC(EndScreenWipe); + GETFUNC(SwapScreenTextures); GETFUNC(DoScreenWipe); - GETFUNC(DrawIntermissionBG); + GETFUNC(DrawScreenTexture); GETFUNC(MakeScreenTexture); - GETFUNC(MakeScreenFinalTexture); GETFUNC(DrawScreenFinalTexture); GETFUNC(InitShaders); diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index c0168d2e5..763506b41 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1244,11 +1244,10 @@ void I_FinishUpdate(void) // Final postprocess step of palette rendering, after everything else has been drawn. if (HWR_ShouldUsePaletteRendering()) { - // not using the function for its original named purpose but can be used like this too - HWR_MakeScreenFinalTexture(); + HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_GENERIC2); HWD.pfnSetSpecialState(HWD_SET_SHADERS, 1); HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_PALETTE_POSTPROCESS)); - HWR_DrawScreenFinalTexture(vid.width, vid.height); + HWD.pfnDrawScreenTexture(HWD_SCREENTEXTURE_GENERIC2); HWD.pfnUnSetShader(); HWD.pfnSetSpecialState(HWD_SET_SHADERS, 0); } @@ -1881,12 +1880,10 @@ void VID_StartupOpenGL(void) HWD.pfnSetTransform = hwSym("SetTransform",NULL); HWD.pfnPostImgRedraw = hwSym("PostImgRedraw",NULL); HWD.pfnFlushScreenTextures=hwSym("FlushScreenTextures",NULL); - HWD.pfnStartScreenWipe = hwSym("StartScreenWipe",NULL); - HWD.pfnEndScreenWipe = hwSym("EndScreenWipe",NULL); + HWD.pfnSwapScreenTextures=hwSym("SwapScreenTextures",NULL); HWD.pfnDoScreenWipe = hwSym("DoScreenWipe",NULL); - HWD.pfnDrawIntermissionBG=hwSym("DrawIntermissionBG",NULL); + HWD.pfnDrawScreenTexture= hwSym("DrawScreenTexture",NULL); HWD.pfnMakeScreenTexture= hwSym("MakeScreenTexture",NULL); - HWD.pfnMakeScreenFinalTexture=hwSym("MakeScreenFinalTexture",NULL); HWD.pfnDrawScreenFinalTexture=hwSym("DrawScreenFinalTexture",NULL); HWD.pfnInitShaders = hwSym("InitShaders",NULL); diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c index 52727c056..69300cf9f 100644 --- a/src/sdl/ogl_sdl.c +++ b/src/sdl/ogl_sdl.c @@ -230,7 +230,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); } EXPORT void HWRAPI(OglSdlSetPalette) (RGBA_t *palette) From 0894547d1a54e1107a5a32034d96693a9e29cabc Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Fri, 17 Sep 2021 22:19:51 +0300 Subject: [PATCH 09/25] Use GL_LUMINANCE8 for 3d palette lookup texture on OpenGL versions older than 3.0 Fixes white screen when the GL_R8 format is not available --- src/hardware/r_opengl/r_opengl.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 3f77be1ec..7c9a37131 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -3262,13 +3262,26 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int tex, int width, int height) 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_TEXTURE1); pglBindTexture(GL_TEXTURE_3D, paletteLookupTex); pglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); pglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - pglTexImage3D(GL_TEXTURE_3D, 0, GL_R8, HWR_PALETTE_LUT_SIZE, HWR_PALETTE_LUT_SIZE, HWR_PALETTE_LUT_SIZE, + 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); } From 0c70ca90685000687376a2a219e8284a6bc35fb2 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Fri, 17 Sep 2021 23:16:53 +0300 Subject: [PATCH 10/25] Add support for mixed line endings to the shader preprocessor Fixes CurveV3.pk3 --- src/hardware/hw_shaders.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/hardware/hw_shaders.c b/src/hardware/hw_shaders.c index c341577eb..8bc4cde9c 100644 --- a/src/hardware/hw_shaders.c +++ b/src/hardware/hw_shaders.c @@ -426,15 +426,18 @@ static char *HWR_PreprocessShader(char *original) if (strstr(original, "\r\n")) { line_ending = "\r\n"; - // check that all line endings are same, - // otherwise the parsing code won't function correctly + // check if all line endings are same while ((read_pos = strchr(read_pos, '\n'))) { read_pos--; if (*read_pos != '\r') { - CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Shader contains mixed line ending types. Please use either only LF (Unix) or only CRLF (Windows) line endings.\n"); - return NULL; + // this file contains mixed CRLF and LF line endings. + // treating it as a LF file during parsing should keep + // the results sane enough as long as the gpu driver is fine + // with these kinds of weirdly formatted shader sources. + line_ending = "\n"; + break; } read_pos += 2; } From bbf23a5143382d578dbe233761f453926d86d996 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Sat, 18 Sep 2021 22:45:54 +0300 Subject: [PATCH 11/25] Add #line offsets in the shader preprocessor so error reports point to correct lines from the original shader file, move #version and preamble to top instead of inserting defines after the original #version --- src/hardware/hw_shaders.c | 122 ++++++++++++++++++++++++++++---------- 1 file changed, 90 insertions(+), 32 deletions(-) diff --git a/src/hardware/hw_shaders.c b/src/hardware/hw_shaders.c index 8bc4cde9c..cb929ae6e 100644 --- a/src/hardware/hw_shaders.c +++ b/src/hardware/hw_shaders.c @@ -370,6 +370,8 @@ static shader_t gl_shaders[NUMSHADERTARGETS*2]; static shadertarget_t gl_shadertargets[NUMSHADERTARGETS]; +#define WHITESPACE_CHARS " \t" + #define MODEL_LIGHTING_DEFINE "#define SRB2_MODEL_LIGHTING" #define PALETTE_RENDERING_DEFINE "#define SRB2_PALETTE_RENDERING" @@ -416,12 +418,14 @@ static char *HWR_PreprocessShader(char *original) const char *line_ending = "\n"; int line_ending_len; char *read_pos = original; - int insertion_pos = 0; int original_len = strlen(original); int distance_to_end = original_len; int new_len; char *new_shader; char *write_pos; + char shader_glsl_version[3]; + int version_pos = -1; + int version_len = 0; if (strstr(original, "\r\n")) { @@ -446,44 +450,62 @@ static char *HWR_PreprocessShader(char *original) line_ending_len = strlen(line_ending); - // We need to find a place to put the #define commands. - // To stay within GLSL specs, they must be *after* the #version define, - // if there is any. So we need to look for that. And also let's not - // get fooled if there is a #version inside a comment! + // Find the #version directive, if it exists. Also don't get fooled if it's + // inside a comment. Copy the version digits so they can be used in the preamble. // Time for some string parsing :D #define STARTSWITH(str, with_what) !strncmp(str, with_what, sizeof(with_what)-1) -#define ADVANCE(amount) read_pos += amount; distance_to_end -= amount; +#define ADVANCE(amount) read_pos += (amount); distance_to_end -= (amount); while (true) { // we're at the start of a line or at the end of a block comment. // first get any possible whitespace out of the way - int whitespace_len = strspn(read_pos, " \t"); + int whitespace_len = strspn(read_pos, WHITESPACE_CHARS); if (whitespace_len == distance_to_end) break; // we got to the end ADVANCE(whitespace_len) if (STARTSWITH(read_pos, "#version")) { - // getting closer - INT32 newline_pos = strstr_int(read_pos, line_ending); - INT32 line_comment_pos = strstr_int(read_pos, "//"); - INT32 block_comment_pos = strstr_int(read_pos, "/*"); - if (newline_pos == INT32_MAX && line_comment_pos == INT32_MAX && - block_comment_pos == INT32_MAX) + // found a version directive (and it's not inside a comment) + // now locate, verify and read the version number + int version_number_len; + version_pos = read_pos - original; + ADVANCE(sizeof("#version") - 1) + whitespace_len = strspn(read_pos, WHITESPACE_CHARS); + if (!whitespace_len) { - // #version is at the end of the file. Probably not a valid shader. - CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Shader unexpectedly ends after #version.\n"); + CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Syntax error in #version. Expected space after #version, but got other text.\n"); return NULL; } - else + else if (whitespace_len == distance_to_end) { - // insert at the earliest occurence of newline or comment after #version - insertion_pos = min(line_comment_pos, block_comment_pos); - insertion_pos = min(newline_pos, insertion_pos); - insertion_pos += read_pos - original; - break; + CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Syntax error in #version. Expected version number, but got end of file.\n"); + return NULL; } + ADVANCE(whitespace_len) + version_number_len = strspn(read_pos, "0123456789"); + if (!version_number_len) + { + CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Syntax error in #version. Expected version number, but got other text.\n"); + return NULL; + } + else if (version_number_len != 3) + { + CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Syntax error in #version. Expected version with 3 digits, but got %d digits.\n", version_number_len); + return NULL; + } + M_Memcpy(shader_glsl_version, read_pos, 3); + ADVANCE(version_number_len) + version_len = (read_pos - original) - version_pos; + whitespace_len = strspn(read_pos, WHITESPACE_CHARS); + ADVANCE(whitespace_len) + if (STARTSWITH(read_pos, "es")) + { + CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Support for ES shaders is not implemented.\n"); + return NULL; + } + break; } else { @@ -544,12 +566,25 @@ static char *HWR_PreprocessShader(char *original) #undef STARTSWITH #undef ADVANCE +#define ADD_TO_LEN(def) new_len += sizeof(def) - 1 + line_ending_len; + // Calculate length of modified shader. new_len = original_len; if (cv_glmodellighting.value) - new_len += sizeof(MODEL_LIGHTING_DEFINE) - 1 + 2 * line_ending_len; + ADD_TO_LEN(MODEL_LIGHTING_DEFINE) if (cv_glpaletterendering.value) - new_len += sizeof(PALETTE_RENDERING_DEFINE) - 1 + 2 * line_ending_len; + ADD_TO_LEN(PALETTE_RENDERING_DEFINE) + +#undef ADD_TO_LEN + +#define VERSION_PART "#version " + + if (new_len != original_len) + { + if (version_pos != -1) + new_len += sizeof(VERSION_PART) - 1 + 3 + line_ending_len; + new_len += sizeof("#line 0") - 1 + line_ending_len; + } // Allocate memory for modified shader. new_shader = Z_Malloc(new_len + 1, PU_STATIC, NULL); @@ -557,22 +592,27 @@ static char *HWR_PreprocessShader(char *original) read_pos = original; write_pos = new_shader; - // Copy the part before our additions. - M_Memcpy(write_pos, original, insertion_pos); - read_pos += insertion_pos; - write_pos += insertion_pos; + if (new_len != original_len && version_pos != -1) + { + strcpy(write_pos, VERSION_PART); + write_pos += sizeof(VERSION_PART) - 1; + M_Memcpy(write_pos, shader_glsl_version, 3); + write_pos += 3; + strcpy(write_pos, line_ending); + write_pos += line_ending_len; + } + +#undef VERSION_PART #define WRITE_DEFINE(define) \ { \ - strcpy(write_pos, line_ending); \ - write_pos += line_ending_len; \ strcpy(write_pos, define); \ write_pos += sizeof(define) - 1; \ strcpy(write_pos, line_ending); \ write_pos += line_ending_len; \ } - // Write the additions. + // Write the defines. if (cv_glmodellighting.value) WRITE_DEFINE(MODEL_LIGHTING_DEFINE) if (cv_glpaletterendering.value) @@ -580,8 +620,26 @@ static char *HWR_PreprocessShader(char *original) #undef WRITE_DEFINE - // Copy the part after our additions. - M_Memcpy(write_pos, read_pos, original_len - insertion_pos); + // Write a #line directive, so compiler errors will report line numbers from the + // original shader without our preamble lines. + if (new_len != original_len) + { + // line numbering in the #line directive is different for versions 110-150 + if (version_pos == -1 || shader_glsl_version[0] == '1') + strcpy(write_pos, "#line 0"); + else + strcpy(write_pos, "#line 1"); + write_pos += sizeof("#line 0") - 1; + strcpy(write_pos, line_ending); + write_pos += line_ending_len; + } + + // Copy the original shader. + M_Memcpy(write_pos, read_pos, original_len); + + // Erase the original #version directive, if it exists and was copied. + if (new_len != original_len && version_pos != -1) + memset(write_pos + version_pos, ' ', version_len); // Terminate the new string. new_shader[new_len] = '\0'; From 6c4cb3a025713253f3d230530c0dd6545d674cee Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Sun, 19 Sep 2021 00:17:56 +0300 Subject: [PATCH 12/25] Don't apply color cube in md2_loadTexture when in palette rendering mode Fixes brightness getting applied twice on models in palette rendering mode --- src/hardware/hw_md2.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 3dc3a0839..d4ce5f410 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -387,8 +387,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); @@ -409,13 +407,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++; + } } } HWD.pfnSetTexture(grPatch->mipmap); From 386c4a95f3aac8857be2f85d47ce830f1a63b9c0 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Sun, 19 Sep 2021 00:27:02 +0300 Subject: [PATCH 13/25] Fix void that was accidentally removed earlier in hw_main.c --- src/hardware/hw_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 1c83b211b..4a4b50d22 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -6765,7 +6765,7 @@ void HWR_DoPostProcessor(player_t *player) // Flipping of the screen isn't done here anymore } -void HWR_StartScreenWipe() +void HWR_StartScreenWipe(void) { //CONS_Debug(DBG_RENDER, "In HWR_StartScreenWipe()\n"); HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_WIPE_START); From 89af6b10adb956379a9851edcff0896034f5b704 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Sat, 25 Sep 2021 18:10:14 +0300 Subject: [PATCH 14/25] Prevent gl_FrontColor overflow in model lighting shader manually Some drivers don't clamp it for some reason. Fixes overbright model lighting and broken colors when combined with palette rendering on affected drivers. --- src/hardware/hw_shaders.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_shaders.c b/src/hardware/hw_shaders.c index cb929ae6e..7f3b5433f 100644 --- a/src/hardware/hw_shaders.c +++ b/src/hardware/hw_shaders.c @@ -40,7 +40,7 @@ "{\n" \ "#ifdef SRB2_MODEL_LIGHTING\n" \ "float nDotVP = dot(gl_Normal, vec3(0, 1, 0));\n" \ - "float light = 0.75 + max(nDotVP, 0.0);\n" \ + "float light = min(0.75 + max(nDotVP, 0.0), 1.0);\n" \ "gl_FrontColor = vec4(light, light, light, 1.0);\n" \ "#else\n" \ "gl_FrontColor = gl_Color;\n" \ From 1ebc8096a0353451ddd2aa663c57f4fa8c0f14e4 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Fri, 8 Oct 2021 22:07:58 +0300 Subject: [PATCH 15/25] Some cleanup I forgot to do --- src/hardware/hw_draw.c | 4 +-- src/hardware/hw_drv.h | 6 ++-- src/hardware/r_opengl/r_opengl.c | 55 +------------------------------- src/sdl/hwsym_sdl.c | 3 +- src/sdl/i_video.c | 3 +- 5 files changed, 7 insertions(+), 64 deletions(-) diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 9e80e8954..b39c8bdac 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -1489,7 +1489,7 @@ UINT8 *HWR_GetScreenshot(void) if (!buf) return NULL; // returns 24bit 888 RGB - HWD.pfnReadRect(tex, (void *)buf); + HWD.pfnReadScreenTexture(tex, (void *)buf); return buf; } @@ -1506,7 +1506,7 @@ boolean HWR_Screenshot(const char *pathname) } // returns 24bit 888 RGB - HWD.pfnReadRect(tex, (void *)buf); + HWD.pfnReadScreenTexture(tex, (void *)buf); #ifdef USE_PNG ret = M_SavePNG(pathname, buf, vid.width, vid.height, NULL); diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 82e2c285c..aa3a9a613 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -43,7 +43,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(ReadRect) (int tex, UINT8 *dst_data); +EXPORT void HWRAPI(ReadScreenTexture) (int tex, UINT8 *dst_data); EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip); EXPORT void HWRAPI(ClearMipMapCache) (void); @@ -55,7 +55,6 @@ EXPORT void HWRAPI(SetTransform) (FTransform *ptransform); EXPORT INT32 HWRAPI(GetTextureUsed) (void); EXPORT void HWRAPI(FlushScreenTextures) (void); -EXPORT void HWRAPI(SwapScreenTextures) (int tex1, int tex2); EXPORT void HWRAPI(DoScreenWipe) (int wipeStart, int wipeEnd); EXPORT void HWRAPI(DrawScreenTexture) (int tex); EXPORT void HWRAPI(MakeScreenTexture) (int tex); @@ -97,7 +96,7 @@ struct hwdriver_s SetTexture pfnSetTexture; UpdateTexture pfnUpdateTexture; DeleteTexture pfnDeleteTexture; - ReadRect pfnReadRect; + ReadScreenTexture pfnReadScreenTexture; GClipRect pfnGClipRect; ClearMipMapCache pfnClearMipMapCache; SetSpecialState pfnSetSpecialState; @@ -113,7 +112,6 @@ struct hwdriver_s #endif PostImgRedraw pfnPostImgRedraw; FlushScreenTextures pfnFlushScreenTextures; - SwapScreenTextures pfnSwapScreenTextures; DoScreenWipe pfnDoScreenWipe; DrawScreenTexture pfnDrawScreenTexture; MakeScreenTexture pfnMakeScreenTexture; diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 7c9a37131..bacfea1d9 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -1166,18 +1166,14 @@ EXPORT void HWRAPI(ClearMipMapCache) (void) // 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. -// TODO should rename to ReadScreenTexture -EXPORT void HWRAPI(ReadRect) (int tex, UINT8 *dst_data) +EXPORT void HWRAPI(ReadScreenTexture) (int tex, UINT8 *dst_data) { INT32 i; int dst_stride = screen_width * 3; // stride between rows of image data GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (screen_height - 1); - //precise_t ts1, ts2, ts3, ts4, ts5, total_time, get_time, loop_time; GLubyte *row; - //ts1 = I_GetPreciseTime(); row = malloc(dst_stride); if (!row) return; - //ts2 = I_GetPreciseTime(); // 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. @@ -1188,7 +1184,6 @@ EXPORT void HWRAPI(ReadRect) (int tex, UINT8 *dst_data) pglReadPixels(0, 0, screen_width, screen_height, GL_RGB, GL_UNSIGNED_BYTE, dst_data); if (tex != HWD_SCREENTEXTURE_GENERIC2) DrawScreenTexture(HWD_SCREENTEXTURE_GENERIC2); - //ts3 = I_GetPreciseTime(); // Flip image upside down. // In other words, convert OpenGL's "bottom->top" row order into "top->bottom". for(i = 0; i < screen_height/2; i++) @@ -1199,47 +1194,7 @@ EXPORT void HWRAPI(ReadRect) (int tex, UINT8 *dst_data) top += dst_stride; bottom -= dst_stride; } - //ts4 = I_GetPreciseTime(); free(row); - //ts5 = I_GetPreciseTime(); - //total_time = I_PreciseToMicros(ts5 - ts1); - //get_time = I_PreciseToMicros(ts3 - ts2); - //loop_time = I_PreciseToMicros(ts4 - ts3); - //CONS_Printf("ReadRect: total time: %" PRIu64 ", read pixels thing: %" PRIu64 " memcpy loop: %" PRIu64 "\n", total_time, get_time, loop_time); - - // the slow glGetTexImage based implementation. left in here in case i wanna test it more - // TODO remove this at some point - - /*int texsize = 512; - GLsizei buffer_size; - GLubyte *buffer; - // GL_DBG_Printf ("ReadRect()\n"); - precise_t ts1, ts2, ts3, ts4, ts5, total_time, get_time, loop_time; - ts1 = I_GetPreciseTime(); - // look for power of two that is large enough for the screen - while (texsize < screen_width || texsize < screen_height) - texsize <<= 1; - buffer_size = texsize * texsize * 4; - buffer = malloc(buffer_size); - tex_downloaded = screenTextures[tex]; - pglBindTexture(GL_TEXTURE_2D, tex_downloaded); - ts2 = I_GetPreciseTime(); - pglGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, buffer); // GL better not overwrite my buffer :v - ts3 = I_GetPreciseTime(); - //for (i = 0; i < screen_height; i++) // i: pixel row index that we are writing - //{ - // // read the frame from the lower left corner of the GL screen texture - // // flip it upside down so it's in correct format - // memcpy(dst_data + (screen_height - i - 1) * screen_width * 3, - // buffer + i * texsize * 3, screen_width * 3); - //} - ts4 = I_GetPreciseTime(); - free(buffer); - ts5 = I_GetPreciseTime(); - total_time = I_PreciseToMicros(ts5 - ts1); - get_time = I_PreciseToMicros(ts3 - ts2); - loop_time = I_PreciseToMicros(ts4 - ts3); - CONS_Printf("ReadRect: total time: %" PRIu64 ", glGetTexImage: %" PRIu64 " memcpy loop: %" PRIu64 "\n", total_time, get_time, loop_time);*/ } @@ -3016,14 +2971,6 @@ EXPORT void HWRAPI(FlushScreenTextures) (void) screenTextures[i] = 0; } -EXPORT void HWRAPI(SwapScreenTextures) (int tex1, int tex2) -{ - GLuint temp = screenTextures[tex1]; - screenTextures[tex1] = screenTextures[tex2]; - screenTextures[tex2] = temp; -} - - EXPORT void HWRAPI(DrawScreenTexture)(int tex) { float xfix, yfix; diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index 8e48350fc..ca87fcc79 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -87,7 +87,7 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(SetTexture); GETFUNC(UpdateTexture); GETFUNC(DeleteTexture); - GETFUNC(ReadRect); + GETFUNC(ReadScreenTexture); GETFUNC(GClipRect); GETFUNC(ClearMipMapCache); GETFUNC(SetSpecialState); @@ -97,7 +97,6 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(SetTransform); GETFUNC(PostImgRedraw); GETFUNC(FlushScreenTextures); - GETFUNC(SwapScreenTextures); GETFUNC(DoScreenWipe); GETFUNC(DrawScreenTexture); GETFUNC(MakeScreenTexture); diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 763506b41..4b1840797 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1869,7 +1869,7 @@ void VID_StartupOpenGL(void) HWD.pfnSetTexture = hwSym("SetTexture",NULL); HWD.pfnUpdateTexture = hwSym("UpdateTexture",NULL); HWD.pfnDeleteTexture = hwSym("DeleteTexture",NULL); - HWD.pfnReadRect = hwSym("ReadRect",NULL); + HWD.pfnReadScreenTexture= hwSym("ReadScreenTexture",NULL); HWD.pfnGClipRect = hwSym("GClipRect",NULL); HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL); HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL); @@ -1880,7 +1880,6 @@ void VID_StartupOpenGL(void) HWD.pfnSetTransform = hwSym("SetTransform",NULL); HWD.pfnPostImgRedraw = hwSym("PostImgRedraw",NULL); HWD.pfnFlushScreenTextures=hwSym("FlushScreenTextures",NULL); - HWD.pfnSwapScreenTextures=hwSym("SwapScreenTextures",NULL); HWD.pfnDoScreenWipe = hwSym("DoScreenWipe",NULL); HWD.pfnDrawScreenTexture= hwSym("DrawScreenTexture",NULL); HWD.pfnMakeScreenTexture= hwSym("MakeScreenTexture",NULL); From b3c970d6b483e83a0f924fe752015902badec424 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Wed, 9 Mar 2022 02:43:51 +0200 Subject: [PATCH 16/25] Light table support for HWR_FadeScreenMenuBack --- src/hardware/hw_cache.c | 26 ++++++++++++++++++++++++++ src/hardware/hw_defs.h | 5 +++-- src/hardware/hw_draw.c | 13 +++++++++++++ src/hardware/hw_drv.h | 2 +- src/hardware/hw_glob.h | 1 + src/hardware/hw_main.c | 26 ++------------------------ src/hardware/hw_shaders.c | 15 +++++++++++++++ src/hardware/r_opengl/r_opengl.c | 12 ++++++++---- src/sdl/i_video.c | 2 +- src/sdl/ogl_sdl.c | 2 +- 10 files changed, 71 insertions(+), 33 deletions(-) diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 9170d79d7..75a77e9f0 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -1497,6 +1497,32 @@ UINT32 HWR_CreateLightTable(UINT8 *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) diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index b175c21e0..bf1bed9ee 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -153,8 +153,9 @@ enum SHADER_FOG, SHADER_SKY, SHADER_PALETTE_POSTPROCESS, + SHADER_UI_COLORMAP_FADE, - NUMSHADERTARGETS, + NUMSHADERTARGETS }; // Maximum amount of shader programs @@ -335,7 +336,7 @@ 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, // screen before palette rendering's postprocessing + HWD_SCREENTEXTURE_GENERIC2, // palette-based colormap fade, screen before palette rendering's postprocessing HWD_SCREENTEXTURE_GENERIC3, // screen after palette rendering's postprocessing NUMSCREENTEXTURES, // (generic3 is unused if palette rendering is disabled) }; diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 90b9d0372..e8365ee2f 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -797,6 +797,19 @@ 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); } diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 503547865..d4fe88d47 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -56,7 +56,7 @@ EXPORT INT32 HWRAPI(GetTextureUsed) (void); EXPORT void HWRAPI(FlushScreenTextures) (void); EXPORT void HWRAPI(DoScreenWipe) (int wipeStart, int wipeEnd); -EXPORT void HWRAPI(DrawScreenTexture) (int tex); +EXPORT void HWRAPI(DrawScreenTexture) (int tex, FSurfaceInfo *surf, FBITFIELD polyflags); EXPORT void HWRAPI(MakeScreenTexture) (int tex); EXPORT void HWRAPI(DrawScreenFinalTexture) (int tex, int width, int height); diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index 2c582d6d8..70218de0d 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -132,6 +132,7 @@ 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); diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index f7752dfa9..7dfe1bff9 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -239,31 +239,9 @@ void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *col Surface->LightInfo.fade_end = (colormap != NULL) ? colormap->fadeend : 31; if (HWR_ShouldUsePaletteRendering()) - { - boolean default_colormap = false; - if (!colormap) - { - colormap = R_GetDefaultColormap(); // a place to store the hw lighttable id - // alternatively could just store the id in a global variable if there are issues - default_colormap = true; - } - // create hw lighttable if there isn't one - if (!colormap->gl_lighttable_id) - { - UINT8 *colormap_pointer; - - if (default_colormap) - colormap_pointer = colormaps; // don't actually use the data from the "default colormap" - else - colormap_pointer = colormap->colormap; - colormap->gl_lighttable_id = HWR_CreateLightTable(colormap_pointer); - } - Surface->LightTableId = colormap->gl_lighttable_id; - } + Surface->LightTableId = HWR_GetLightTableID(colormap); else - { Surface->LightTableId = 0; - } } UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap) // Let's see if this can work @@ -6835,7 +6813,7 @@ void HWR_EndScreenWipe(void) void HWR_DrawIntermissionBG(void) { - HWD.pfnDrawScreenTexture(HWD_SCREENTEXTURE_GENERIC1); + HWD.pfnDrawScreenTexture(HWD_SCREENTEXTURE_GENERIC1, NULL, 0); } // diff --git a/src/hardware/hw_shaders.c b/src/hardware/hw_shaders.c index d4d7f21bc..6f81a55ef 100644 --- a/src/hardware/hw_shaders.c +++ b/src/hardware/hw_shaders.c @@ -315,6 +315,18 @@ "gl_FragColor = final_color;\n" \ "}\0" +#define GLSL_UI_COLORMAP_FADE_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" \ + // ================ // Shader sources // ================ @@ -347,6 +359,9 @@ static struct { // Palette postprocess shader {GLSL_DEFAULT_VERTEX_SHADER, GLSL_PALETTE_POSTPROCESS_SHADER}, + // UI colormap fade shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_UI_COLORMAP_FADE_SHADER}, + {NULL, NULL}, }; diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index efeb8289d..6152b2c43 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -1181,11 +1181,11 @@ EXPORT void HWRAPI(ReadScreenTexture) (int tex, UINT8 *dst_data) // 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); + DrawScreenTexture(tex, NULL, 0); pglPixelStorei(GL_PACK_ALIGNMENT, 1); pglReadPixels(0, 0, screen_width, screen_height, GL_RGB, GL_UNSIGNED_BYTE, dst_data); if (tex != HWD_SCREENTEXTURE_GENERIC2) - DrawScreenTexture(HWD_SCREENTEXTURE_GENERIC2); + DrawScreenTexture(HWD_SCREENTEXTURE_GENERIC2, NULL, 0); // Flip image upside down. // In other words, convert OpenGL's "bottom->top" row order into "top->bottom". for(i = 0; i < screen_height/2; i++) @@ -1965,6 +1965,7 @@ static void Shader_CompileError(const char *message, GLuint program, INT32 shade } // code that is common between DrawPolygon and DrawIndexedTriangles +// DrawScreenTexture also can use this function for fancier screen texture drawing // the corona thing is there too, i have no idea if that stuff works with DrawIndexedTriangles and batching static void PreparePolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FBITFIELD PolyFlags) { @@ -2978,7 +2979,7 @@ EXPORT void HWRAPI(FlushScreenTextures) (void) screenTextures[i] = 0; } -EXPORT void HWRAPI(DrawScreenTexture)(int tex) +EXPORT void HWRAPI(DrawScreenTexture)(int tex, FSurfaceInfo *surf, FBITFIELD polyflags) { float xfix, yfix; INT32 texsize = 512; @@ -3015,7 +3016,10 @@ EXPORT void HWRAPI(DrawScreenTexture)(int tex) pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); pglBindTexture(GL_TEXTURE_2D, screenTextures[tex]); - Shader_SetUniforms(NULL, NULL, NULL, NULL); // prepare shader, if it is enabled + 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); diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index ad539e76b..da357354c 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1260,7 +1260,7 @@ void I_FinishUpdate(void) HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_GENERIC2); HWD.pfnSetSpecialState(HWD_SET_SHADERS, 1); HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_PALETTE_POSTPROCESS)); - HWD.pfnDrawScreenTexture(HWD_SCREENTEXTURE_GENERIC2); + HWD.pfnDrawScreenTexture(HWD_SCREENTEXTURE_GENERIC2, NULL, 0); HWD.pfnUnSetShader(); HWD.pfnSetSpecialState(HWD_SET_SHADERS, 0); } diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c index 91df683ec..cd09dc071 100644 --- a/src/sdl/ogl_sdl.c +++ b/src/sdl/ogl_sdl.c @@ -234,7 +234,7 @@ void OglSdlFinishUpdate(boolean waitvbl) // effects that want to take the old screen can do so after this // Generic2 has the screen image without palette rendering brightness adjustments. // Using that here will prevent brightness adjustments being applied twice. - DrawScreenTexture(HWD_SCREENTEXTURE_GENERIC2); + DrawScreenTexture(HWD_SCREENTEXTURE_GENERIC2, NULL, 0); } EXPORT void HWRAPI(OglSdlSetPalette) (RGBA_t *palette) From f74433cc64cd6639e4f15145cf9e3bb7d383cb75 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Sat, 12 Mar 2022 02:04:57 +0200 Subject: [PATCH 17/25] Tinted wipe support for OpenGL --- src/f_wipe.c | 2 +- src/hardware/hw_defs.h | 1 + src/hardware/hw_drv.h | 2 +- src/hardware/hw_main.c | 30 +++++++++++--- src/hardware/hw_main.h | 1 - src/hardware/hw_shaders.c | 28 ++++++++++++- src/hardware/r_opengl/r_opengl.c | 71 ++++++++++++++++++++------------ 7 files changed, 99 insertions(+), 36 deletions(-) diff --git a/src/f_wipe.c b/src/f_wipe.c index 43b7180b7..b9a09e89f 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -565,7 +565,7 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu) if (rendermode == render_opengl) { // send in the wipe type and wipe frame because we need to cache the graphic - HWR_DoTintedWipe(wipetype, wipeframe-1); + HWR_DoWipe(wipetype, wipeframe-1); } else #endif diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index bf1bed9ee..c325e9d3f 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -154,6 +154,7 @@ enum SHADER_SKY, SHADER_PALETTE_POSTPROCESS, SHADER_UI_COLORMAP_FADE, + SHADER_UI_TINTED_WIPE, NUMSHADERTARGETS }; diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index d4fe88d47..f4d9a09f8 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -55,7 +55,7 @@ EXPORT void HWRAPI(SetTransform) (FTransform *ptransform); EXPORT INT32 HWRAPI(GetTextureUsed) (void); EXPORT void HWRAPI(FlushScreenTextures) (void); -EXPORT void HWRAPI(DoScreenWipe) (int wipeStart, int wipeEnd); +EXPORT void HWRAPI(DoScreenWipe) (int wipeStart, int wipeEnd, FSurfaceInfo *surf, FBITFIELD polyFlags); EXPORT void HWRAPI(DrawScreenTexture) (int tex, FSurfaceInfo *surf, FBITFIELD polyflags); EXPORT void HWRAPI(MakeScreenTexture) (int tex); EXPORT void HWRAPI(DrawScreenFinalTexture) (int tex, int width, int height); diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 7dfe1bff9..4c14a4cfe 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -6858,13 +6858,31 @@ void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum) return; HWR_GetFadeMask(wipelumpnum); - HWD.pfnDoScreenWipe(HWD_SCREENTEXTURE_WIPE_START, HWD_SCREENTEXTURE_WIPE_END); -} + if (wipestyle == WIPESTYLE_COLORMAP && HWR_UseShader()) + { + FSurfaceInfo surf = {0}; + FBITFIELD polyflags = PF_Modulated|PF_NoDepthTest; -void HWR_DoTintedWipe(UINT8 wipenum, UINT8 scrnnum) -{ - // It does the same thing - HWR_DoWipe(wipenum, scrnnum); + polyflags |= (wipestyleflags & WSF_TOWHITE) ? PF_Additive : PF_ReverseSubtract; + surf.PolyColor.s.red = FADEREDFACTOR; + surf.PolyColor.s.green = FADEGREENFACTOR; + surf.PolyColor.s.blue = FADEBLUEFACTOR; + // polycolor alpha communicates fadein / fadeout to the shader and the backend + surf.PolyColor.s.alpha = (wipestyleflags & WSF_FADEIN) ? 255 : 0; + + // backend shader may not have been enabled yet so do it here + HWR_SetShaderState(); + + HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_UI_TINTED_WIPE)); + HWD.pfnDoScreenWipe(HWD_SCREENTEXTURE_WIPE_START, HWD_SCREENTEXTURE_WIPE_END, + &surf, polyflags); + HWD.pfnUnSetShader(); + } + else + { + HWD.pfnDoScreenWipe(HWD_SCREENTEXTURE_WIPE_START, HWD_SCREENTEXTURE_WIPE_END, + NULL, 0); + } } void HWR_MakeScreenFinalTexture(void) diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 8af1fc041..36d1e94f9 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -62,7 +62,6 @@ void HWR_StartScreenWipe(void); void HWR_EndScreenWipe(void); void HWR_DrawIntermissionBG(void); void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum); -void HWR_DoTintedWipe(UINT8 wipenum, UINT8 scrnnum); void HWR_MakeScreenFinalTexture(void); void HWR_DrawScreenFinalTexture(int width, int height); diff --git a/src/hardware/hw_shaders.c b/src/hardware/hw_shaders.c index 6f81a55ef..4e2ec14a1 100644 --- a/src/hardware/hw_shaders.c +++ b/src/hardware/hw_shaders.c @@ -315,6 +315,7 @@ "gl_FragColor = final_color;\n" \ "}\0" +// Applies a palettized colormap fade to tex #define GLSL_UI_COLORMAP_FADE_SHADER \ "uniform sampler2D tex;\n" \ "uniform float lighting;\n" \ @@ -325,7 +326,29 @@ "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" \ + "}\0" + +// For wipes that use additive and subtractive blending. +// alpha_factor = 31 * 8 / 10 = 24.8 +// Calculated based on the use of the "fade" variable from the GETCOLOR macro +// in r_data.c:R_CreateFadeColormaps. +// However this value created some ugliness in fades to white (special stage entry) +// while palette rendering is enabled, so I raised the value just a bit. +#define GLSL_UI_TINTED_WIPE_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "const float alpha_factor = 24.875;\n" \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + "vec4 final_color = poly_color;\n" \ + "float alpha = texel.a;\n" \ + "if (final_color.a >= 0.5)\n" \ + "alpha = 1.0 - alpha;\n" \ + "alpha *= alpha_factor;\n" \ + "final_color *= alpha;\n" \ + "final_color.a = 1.0;\n" \ + "gl_FragColor = final_color;\n" \ + "}\0" // ================ // Shader sources @@ -362,6 +385,9 @@ static struct { // UI colormap fade shader {GLSL_DEFAULT_VERTEX_SHADER, GLSL_UI_COLORMAP_FADE_SHADER}, + // UI tinted wipe shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_UI_TINTED_WIPE_SHADER}, + {NULL, NULL}, }; diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 6152b2c43..e9027eba5 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -3030,7 +3030,8 @@ EXPORT void HWRAPI(DrawScreenTexture)(int tex, FSurfaceInfo *surf, FBITFIELD pol } // Do screen fades! -EXPORT void HWRAPI(DoScreenWipe)(int wipeStart, int wipeEnd) +EXPORT void HWRAPI(DoScreenWipe)(int wipeStart, int wipeEnd, FSurfaceInfo *surf, + FBITFIELD polyFlags) { INT32 texsize = 512; float xfix, yfix; @@ -3055,6 +3056,12 @@ EXPORT void HWRAPI(DoScreenWipe)(int wipeStart, int wipeEnd) 1.0f, 1.0f }; + int firstScreen; + if (surf && surf->PolyColor.s.alpha == 255) + firstScreen = wipeEnd; // it's a tinted fade-in, we need wipeEnd + else + firstScreen = wipeStart; + // look for power of two that is large enough for the screen while (texsize < screen_width || texsize < screen_height) texsize <<= 1; @@ -3079,43 +3086,55 @@ EXPORT void HWRAPI(DoScreenWipe)(int wipeStart, int wipeEnd) SetBlend(PF_Modulated|PF_NoDepthTest); pglEnable(GL_TEXTURE_2D); - // Draw the original screen - pglBindTexture(GL_TEXTURE_2D, screenTextures[wipeStart]); + pglBindTexture(GL_TEXTURE_2D, screenTextures[firstScreen]); pglColor4ubv(white); pglTexCoordPointer(2, GL_FLOAT, 0, fix); pglVertexPointer(3, GL_FLOAT, 0, screenVerts); pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); - SetBlend(PF_Modulated|PF_Translucent|PF_NoDepthTest); + if (surf) + { + // Draw fade mask to screen using surf and polyFlags + // Used for colormap/tinted wipes. + pglBindTexture(GL_TEXTURE_2D, fademaskdownloaded); + pglTexCoordPointer(2, GL_FLOAT, 0, defaultST); + pglVertexPointer(3, GL_FLOAT, 0, screenVerts); + PreparePolygon(surf, NULL, polyFlags); + pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + else // Blend wipeEnd into screen with the fade mask + { + SetBlend(PF_Modulated|PF_Translucent|PF_NoDepthTest); - // Draw the end screen that fades in - pglActiveTexture(GL_TEXTURE0); - pglEnable(GL_TEXTURE_2D); - pglBindTexture(GL_TEXTURE_2D, screenTextures[wipeEnd]); - pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + // Draw the end screen that fades in + pglActiveTexture(GL_TEXTURE0); + pglEnable(GL_TEXTURE_2D); + pglBindTexture(GL_TEXTURE_2D, screenTextures[wipeEnd]); + pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - pglActiveTexture(GL_TEXTURE1); - pglEnable(GL_TEXTURE_2D); - pglBindTexture(GL_TEXTURE_2D, fademaskdownloaded); + pglActiveTexture(GL_TEXTURE1); + pglEnable(GL_TEXTURE_2D); + pglBindTexture(GL_TEXTURE_2D, fademaskdownloaded); - pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - // const float defaultST[8] + // const float defaultST[8] - pglClientActiveTexture(GL_TEXTURE0); - pglTexCoordPointer(2, GL_FLOAT, 0, fix); - pglVertexPointer(3, GL_FLOAT, 0, screenVerts); - pglClientActiveTexture(GL_TEXTURE1); - pglEnableClientState(GL_TEXTURE_COORD_ARRAY); - pglTexCoordPointer(2, GL_FLOAT, 0, defaultST); - pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); + pglClientActiveTexture(GL_TEXTURE0); + pglTexCoordPointer(2, GL_FLOAT, 0, fix); + pglVertexPointer(3, GL_FLOAT, 0, screenVerts); + pglClientActiveTexture(GL_TEXTURE1); + pglEnableClientState(GL_TEXTURE_COORD_ARRAY); + pglTexCoordPointer(2, GL_FLOAT, 0, defaultST); + pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); - pglDisable(GL_TEXTURE_2D); // disable the texture in the 2nd texture unit - pglDisableClientState(GL_TEXTURE_COORD_ARRAY); + pglDisable(GL_TEXTURE_2D); // disable the texture in the 2nd texture unit + pglDisableClientState(GL_TEXTURE_COORD_ARRAY); - pglActiveTexture(GL_TEXTURE0); - pglClientActiveTexture(GL_TEXTURE0); - tex_downloaded = screenTextures[wipeEnd]; + pglActiveTexture(GL_TEXTURE0); + pglClientActiveTexture(GL_TEXTURE0); + tex_downloaded = screenTextures[wipeEnd]; + } } // Create a texture from the screen. From 1fd9d38994577307b9a878dc35507cd9eecf78ff Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Tue, 15 Mar 2022 03:50:47 +0200 Subject: [PATCH 18/25] Several changes: Move HWR_SetShaderState calls from level rendering to HWR_Startup and shader cvar changes Don't run hwr cvar onchange code when opengl is not loaded Rename screen_palette_tex shader uniform to more generic palette_tex Fix palette version of HWR_FadeScreenMenuBack not working outside levels --- src/hardware/hw_main.c | 25 ++++++++++++------------- src/hardware/hw_shaders.c | 4 ++-- src/hardware/r_opengl/r_opengl.c | 10 +++++----- src/sdl/i_video.c | 2 -- 4 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 4c14a4cfe..18f3be561 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -6041,9 +6041,6 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) // Actually it only works on Walls and Planes HWD.pfnSetTransform(&atransform); - // Reset the shader state. - HWR_SetShaderState(); - validcount++; if (cv_glbatching.value) @@ -6256,9 +6253,6 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) // Actually it only works on Walls and Planes HWD.pfnSetTransform(&atransform); - // Reset the shader state. - HWR_SetShaderState(); - ps_numbspcalls.value.i = 0; ps_numpolyobjects.value.i = 0; PS_START_TIMING(ps_bsptime); @@ -6474,20 +6468,23 @@ static CV_PossibleValue_t glpalettedepth_cons_t[] = {{16, "16 bits"}, {24, "24 b consvar_t cv_glpaletterendering = CVAR_INIT ("gr_paletterendering", "Off", CV_SAVE|CV_CALL, CV_OnOff, CV_glpaletterendering_OnChange); consvar_t cv_glpalettedepth = CVAR_INIT ("gr_palettedepth", "16 bits", CV_SAVE|CV_CALL, glpalettedepth_cons_t, CV_glpalettedepth_OnChange); +#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); } static 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(); @@ -6495,6 +6492,7 @@ static void CV_glmodellighting_OnChange(void) static void CV_glpaletterendering_OnChange(void) { + ONLY_IF_GL_LOADED if (gl_shadersavailable) { HWR_CompileShaders(); @@ -6504,6 +6502,7 @@ static void CV_glpaletterendering_OnChange(void) static void CV_glpalettedepth_OnChange(void) { + ONLY_IF_GL_LOADED // refresh the screen palette if (HWR_ShouldUsePaletteRendering()) HWR_SetPalette(pLocalPalette); @@ -6511,6 +6510,8 @@ static void CV_glpalettedepth_OnChange(void) static 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 @@ -6582,6 +6583,7 @@ void HWR_Startup(void) #endif gl_shadersavailable = HWR_InitShaders(); + HWR_SetShaderState(); HWR_LoadAllCustomShaders(); HWR_TogglePaletteRendering(); } @@ -6870,9 +6872,6 @@ void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum) // polycolor alpha communicates fadein / fadeout to the shader and the backend surf.PolyColor.s.alpha = (wipestyleflags & WSF_FADEIN) ? 255 : 0; - // backend shader may not have been enabled yet so do it here - HWR_SetShaderState(); - HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_UI_TINTED_WIPE)); HWD.pfnDoScreenWipe(HWD_SCREENTEXTURE_WIPE_START, HWD_SCREENTEXTURE_WIPE_END, &surf, polyflags); diff --git a/src/hardware/hw_shaders.c b/src/hardware/hw_shaders.c index 4e2ec14a1..dcf6a7154 100644 --- a/src/hardware/hw_shaders.c +++ b/src/hardware/hw_shaders.c @@ -306,12 +306,12 @@ #define GLSL_PALETTE_POSTPROCESS_SHADER \ "uniform sampler2D tex;\n" \ "uniform sampler3D palette_lookup_tex;\n" \ - "uniform sampler1D screen_palette_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(screen_palette_tex, palette_coord);\n" \ + "vec4 final_color = texture1D(palette_tex, palette_coord);\n" \ "gl_FragColor = final_color;\n" \ "}\0" diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index e9027eba5..7354f2b76 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -617,9 +617,9 @@ typedef enum gluniform_fade_end, // palette rendering - gluniform_screen_palette_tex, - gluniform_palette_lookup_tex, - gluniform_lighttable_tex, + 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, @@ -1918,7 +1918,7 @@ static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i) shader->uniforms[gluniform_fade_end] = GETUNI("fade_end"); // palette rendering - shader->uniforms[gluniform_screen_palette_tex] = GETUNI("screen_palette_tex"); + 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"); @@ -1934,7 +1934,7 @@ static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i) pglUseProgram(shader->program); // texture unit numbers for the samplers used for palette rendering - UNIFORM_1(shader->uniforms[gluniform_screen_palette_tex], 2, pglUniform1i); + UNIFORM_1(shader->uniforms[gluniform_palette_tex], 2, pglUniform1i); UNIFORM_1(shader->uniforms[gluniform_palette_lookup_tex], 1, pglUniform1i); UNIFORM_1(shader->uniforms[gluniform_lighttable_tex], 2, pglUniform1i); diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index da357354c..e626aac05 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1258,11 +1258,9 @@ void I_FinishUpdate(void) if (HWR_ShouldUsePaletteRendering()) { HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_GENERIC2); - HWD.pfnSetSpecialState(HWD_SET_SHADERS, 1); HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_PALETTE_POSTPROCESS)); HWD.pfnDrawScreenTexture(HWD_SCREENTEXTURE_GENERIC2, NULL, 0); HWD.pfnUnSetShader(); - HWD.pfnSetSpecialState(HWD_SET_SHADERS, 0); } OglSdlFinishUpdate(cv_vidwait.value); } From 978006bc97c894e61996bc9815e56debea5a2957 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Thu, 17 Mar 2022 03:40:01 +0200 Subject: [PATCH 19/25] Ensure consistent GL state when drawing screen textures Fixes palettized wipes being broken under some common conditions --- src/hardware/r_opengl/r_opengl.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 7354f2b76..b4bd14d7e 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -3016,11 +3016,9 @@ EXPORT void HWRAPI(DrawScreenTexture)(int tex, FSurfaceInfo *surf, FBITFIELD pol pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 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); + PreparePolygon(surf, NULL, surf ? polyflags : (PF_NoDepthTest)); + if (!surf) + pglColor4ubv(white); pglTexCoordPointer(2, GL_FLOAT, 0, fix); pglVertexPointer(3, GL_FLOAT, 0, screenVerts); @@ -3226,6 +3224,7 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int tex, int width, int height) clearColour.red = clearColour.green = clearColour.blue = 0; clearColour.alpha = 1; ClearBuffer(true, false, &clearColour); + SetBlend(PF_NoDepthTest); pglBindTexture(GL_TEXTURE_2D, screenTextures[tex]); pglColor4ubv(white); From d310729b542a0f288316d4a5d4e62fd794ef08f5 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Wed, 23 Mar 2022 01:19:15 +0200 Subject: [PATCH 20/25] Add tinted fade support to HWR_FadeScreenMenuBack --- src/hardware/hw_draw.c | 56 ++++++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index e8365ee2f..fa933b66b 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -30,6 +30,7 @@ #include "../st_stuff.h" #include "../p_local.h" // stplyr #include "../g_game.h" // players +#include "../f_finale.h" // fade color factors #include #include "../i_video.h" // for rendermode != render_glide @@ -783,6 +784,7 @@ void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength) { FOutVector v[4]; FSurfaceInfo Surf; + FBITFIELD poly_flags = PF_NoTexture|PF_Modulated|PF_NoDepthTest; v[0].x = v[3].x = -1.0f; v[2].x = v[1].x = 1.0f; @@ -795,31 +797,59 @@ void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength) v[0].t = v[1].t = 1.0f; v[2].t = v[3].t = 0.0f; - if (color & 0xFF00) // Do COLORMAP fade. + if (color & 0xFF00) // Special fade options { - if (HWR_ShouldUsePaletteRendering()) + UINT16 option = color & 0x0F00; + if (option == 0x0A00 || option == 0x0B00) // Tinted fades { - const hwdscreentexture_t scr_tex = HWD_SCREENTEXTURE_GENERIC2; + INT32 r, g, b; + int fade = strength * 8; - 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(); + r = FADEREDFACTOR*fade/10; + g = FADEGREENFACTOR*fade/10; + b = FADEBLUEFACTOR*fade/10; - return; + Surf.PolyColor.s.red = min(r, 255); + Surf.PolyColor.s.green = min(g, 255); + Surf.PolyColor.s.blue = min(b, 255); + Surf.PolyColor.s.alpha = 255; + + if (option == 0x0A00) // Tinted subtractive fade + poly_flags |= PF_ReverseSubtract; + else if (option == 0x0B00) // Tinted additive fade + poly_flags |= PF_Additive; + } + else // 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; + } + else + { + Surf.PolyColor.rgba = UINT2RGBA(0x01010160); + Surf.PolyColor.s.alpha = (strength*8); + poly_flags |= PF_Translucent; + } } - Surf.PolyColor.rgba = UINT2RGBA(0x01010160); - Surf.PolyColor.s.alpha = (strength*8); } else // Do TRANSMAP** fade. { RGBA_t *palette = HWR_GetTexturePalette(); Surf.PolyColor.rgba = palette[color&0xFF].rgba; Surf.PolyColor.s.alpha = softwaretranstogl[strength]; + poly_flags |= PF_Translucent; } - HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); + HWD.pfnDrawPolygon(&Surf, v, 4, poly_flags); } // -----------------+ From a1265728e25dc60b18af450da5a32a203b2c5f42 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Thu, 24 Mar 2022 00:46:52 +0200 Subject: [PATCH 21/25] Rename some shader source defines, add the two new shaders to shaderxlat --- src/hardware/hw_shaders.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/hardware/hw_shaders.c b/src/hardware/hw_shaders.c index dcf6a7154..5b586a006 100644 --- a/src/hardware/hw_shaders.c +++ b/src/hardware/hw_shaders.c @@ -162,17 +162,17 @@ "#define STARTMAP_FUDGE 1.05\n" \ "#define SCALE_FUDGE 2.2\n" -#define GLSL_SOFTWARE_FRAGMENT_SHADER_FLOORS \ +#define GLSL_FLOOR_FRAGMENT_SHADER \ GLSL_FLOOR_FUDGES \ GLSL_SOFTWARE_FRAGMENT_SHADER -#define GLSL_SOFTWARE_FRAGMENT_SHADER_WALLS \ +#define GLSL_WALL_FRAGMENT_SHADER \ 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) if model lighting is enabled -#define GLSL_SOFTWARE_MODEL_FRAGMENT_SHADER \ +#define GLSL_MODEL_FRAGMENT_SHADER \ GLSL_WALL_FUDGES \ "#ifdef SRB2_PALETTE_RENDERING\n" \ "uniform sampler2D tex;\n" \ @@ -303,7 +303,7 @@ "}\0" // Shader for the palette rendering postprocess step -#define GLSL_PALETTE_POSTPROCESS_SHADER \ +#define GLSL_PALETTE_POSTPROCESS_FRAGMENT_SHADER \ "uniform sampler2D tex;\n" \ "uniform sampler3D palette_lookup_tex;\n" \ "uniform sampler1D palette_tex;\n" \ @@ -316,7 +316,7 @@ "}\0" // Applies a palettized colormap fade to tex -#define GLSL_UI_COLORMAP_FADE_SHADER \ +#define GLSL_UI_COLORMAP_FADE_FRAGMENT_SHADER \ "uniform sampler2D tex;\n" \ "uniform float lighting;\n" \ "uniform sampler3D palette_lookup_tex;\n" \ @@ -334,7 +334,7 @@ // in r_data.c:R_CreateFadeColormaps. // However this value created some ugliness in fades to white (special stage entry) // while palette rendering is enabled, so I raised the value just a bit. -#define GLSL_UI_TINTED_WIPE_SHADER \ +#define GLSL_UI_TINTED_WIPE_FRAGMENT_SHADER \ "uniform sampler2D tex;\n" \ "uniform vec4 poly_color;\n" \ "const float alpha_factor = 24.875;\n" \ @@ -359,16 +359,16 @@ static struct { const char *fragment; } const gl_shadersources[] = { // Floor shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER_FLOORS}, + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_FLOOR_FRAGMENT_SHADER}, // Wall shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER_WALLS}, + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_WALL_FRAGMENT_SHADER}, // Sprite shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER_WALLS}, + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_WALL_FRAGMENT_SHADER}, // Model shader - {GLSL_MODEL_VERTEX_SHADER, GLSL_SOFTWARE_MODEL_FRAGMENT_SHADER}, + {GLSL_MODEL_VERTEX_SHADER, GLSL_MODEL_FRAGMENT_SHADER}, // Water shader {GLSL_DEFAULT_VERTEX_SHADER, GLSL_WATER_FRAGMENT_SHADER}, @@ -380,13 +380,13 @@ static struct { {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SKY_FRAGMENT_SHADER}, // Palette postprocess shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_PALETTE_POSTPROCESS_SHADER}, + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_PALETTE_POSTPROCESS_FRAGMENT_SHADER}, // UI colormap fade shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_UI_COLORMAP_FADE_SHADER}, + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_UI_COLORMAP_FADE_FRAGMENT_SHADER}, // UI tinted wipe shader - {GLSL_DEFAULT_VERTEX_SHADER, GLSL_UI_TINTED_WIPE_SHADER}, + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_UI_TINTED_WIPE_FRAGMENT_SHADER}, {NULL, NULL}, }; @@ -768,6 +768,8 @@ customshaderxlat_t shaderxlat[] = {"Fog", SHADER_FOG}, {"Sky", SHADER_SKY}, {"PalettePostprocess", SHADER_PALETTE_POSTPROCESS}, + {"UIColormapFade", SHADER_UI_COLORMAP_FADE}, + {"UITintedWipe", SHADER_UI_TINTED_WIPE}, {NULL, 0}, }; From 80089816475f659ca71eb13205d1040c37fb7486 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Tue, 3 Oct 2023 19:35:18 +0300 Subject: [PATCH 22/25] Add hw_shaders.c to hardware/CMakeLists.txt --- src/hardware/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hardware/CMakeLists.txt b/src/hardware/CMakeLists.txt index e7819aba9..3b6135c1d 100644 --- a/src/hardware/CMakeLists.txt +++ b/src/hardware/CMakeLists.txt @@ -10,5 +10,6 @@ target_sources(SRB2SDL2 PRIVATE hw_md3load.c hw_model.c hw_batching.c + hw_shaders.c r_opengl/r_opengl.c ) From 2d17c751653b765f0df59e0d52e883baba0db3a2 Mon Sep 17 00:00:00 2001 From: Logan Aerl Arias Date: Sat, 17 Feb 2024 19:50:52 -0500 Subject: [PATCH 23/25] Update r_defs.h add back pic_t --- src/r_defs.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/r_defs.h b/src/r_defs.h index 1b979a0df..65fd883c9 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -25,6 +25,10 @@ #include "screen.h" // MAXVIDWIDTH, MAXVIDHEIGHT +#ifdef HWRENDER +#include "m_aatree.h" +#endif + #include "taglist.h" // @@ -902,6 +906,26 @@ typedef struct // the [0] is &columnofs[width] } ATTRPACK softwarepatch_t; +#ifdef _MSC_VER +#pragma warning(disable : 4200) +#endif + +// a pic is an unmasked block of pixels, stored in horizontal way +typedef struct +{ + INT16 width; + UINT8 zero; // set to 0 allow autodetection of pic_t + // mode instead of patch or raw + UINT8 mode; // see pic_mode_t above + INT16 height; + INT16 reserved1; // set to 0 + UINT8 data[0]; +} ATTRPACK pic_t; + +#ifdef _MSC_VER +#pragma warning(default : 4200) +#endif + #if defined(_MSC_VER) #pragma pack() #endif From 9c85ccc8204f51106e2c930d37e3502a90b1c3da Mon Sep 17 00:00:00 2001 From: Logan Aerl Arias Date: Sat, 17 Feb 2024 19:52:22 -0500 Subject: [PATCH 24/25] Update hw_main.c cv_fovchange was moved from hw_main.c to r_main.c cv_glallowshaders was moved from hw_main.c to d_netcmd.c --- src/hardware/hw_main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 3e441577a..1cfffca54 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -6555,8 +6555,6 @@ static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSA CV_PossibleValue_t glanisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}}; consvar_t cv_glshaders = CVAR_INIT ("gr_shaders", "On", CV_SAVE|CV_CALL, glshaders_cons_t, CV_glshaders_OnChange); -consvar_t cv_glallowshaders = CVAR_INIT ("gr_allowclientshaders", "On", CV_NETVAR, CV_OnOff, NULL); -consvar_t cv_fovchange = CVAR_INIT ("gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL); #ifdef ALAM_LIGHTING consvar_t cv_gldynamiclighting = CVAR_INIT ("gr_dynamiclighting", "On", CV_SAVE, CV_OnOff, NULL); From d895ff88f9438a03e9305f1e6f529711f5b167f6 Mon Sep 17 00:00:00 2001 From: Logan Aerl Arias Date: Sat, 17 Feb 2024 19:53:25 -0500 Subject: [PATCH 25/25] Update hw_batching.c HWR_ProcessPolygon()'s shader parameter was renamed to shader_target --- src/hardware/hw_batching.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_batching.c b/src/hardware/hw_batching.c index 8242973ee..b9ab2592d 100644 --- a/src/hardware/hw_batching.c +++ b/src/hardware/hw_batching.c @@ -134,7 +134,7 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt DIGEST(hash, pSurf->PolyColor.rgba); if (cv_glshaders.value && gl_shadersavailable) { - DIGEST(hash, shader); + DIGEST(hash, shader_target); DIGEST(hash, pSurf->TintColor.rgba); DIGEST(hash, pSurf->FadeColor.rgba); DIGEST(hash, pSurf->LightInfo.light_level);