diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8f6a56235..d4d684313 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -452,6 +452,8 @@ endif() if(${SRB2_CONFIG_HWRENDER}) add_definitions(-DHWRENDER) set(SRB2_HWRENDER_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_batching.c + ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_shaders.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_bsp.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_cache.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_clip.c @@ -467,6 +469,8 @@ if(${SRB2_CONFIG_HWRENDER}) ) set (SRB2_HWRENDER_HEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_batching.h + ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_shaders.h ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_clip.h ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_data.h ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_defs.h diff --git a/src/Makefile b/src/Makefile index 06567753a..cf1cfb006 100644 --- a/src/Makefile +++ b/src/Makefile @@ -275,7 +275,7 @@ 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_trick.o \ - $(OBJDIR)/hw_md2load.o $(OBJDIR)/hw_md3load.o $(OBJDIR)/hw_model.o $(OBJDIR)/u_list.o + $(OBJDIR)/hw_md2load.o $(OBJDIR)/hw_md3load.o $(OBJDIR)/hw_model.o $(OBJDIR)/u_list.o $(OBJDIR)/hw_batching.o $(OBJDIR)/hw_shaders.o endif OPTS += -DCOMPVERSION diff --git a/src/d_main.c b/src/d_main.c index 3850243b8..9f3ad8ac9 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1523,14 +1523,6 @@ void D_SRB2Main(void) HWR_AddCommands(); #endif -#ifdef HWRENDER - if (rendermode == render_opengl) - { - for (i = 0; i < numwadfiles; i++) - HWR_LoadShaders(i, (wadfiles[i]->type == RET_PK3)); - } -#endif - //--------------------------------------------------------- CONSOLE // setup loading screen SCR_Startup(); diff --git a/src/hardware/hw_batching.c b/src/hardware/hw_batching.c new file mode 100644 index 000000000..388bb2023 --- /dev/null +++ b/src/hardware/hw_batching.c @@ -0,0 +1,462 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2020-2023 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_batching.c +/// \brief Draw call batching and related things. + +#ifdef HWRENDER +#include "hw_glob.h" +#include "hw_batching.h" +#include "hw_main.h" +#include "../i_system.h" + +typedef struct +{ + FSurfaceInfo surf; // surf also has its own polyflags for some reason, but it seems unused + unsigned int vertsIndex; // location of verts in unsortedVertices + FUINT numVerts; + FBITFIELD polyFlags; + GLMipmap_t *texture; + int shader; + // this tells batching that the plane belongs to a horizon line and must be drawn in correct order with the skywalls + boolean horizonSpecial; +} DrawCallInfo; + +// The texture for the next polygon given to HWR_ProcessPolygon. +// Set with HWR_SetCurrentTexture. +GLMipmap_t *current_texture = NULL; + +boolean currently_batching = false; + +// Dynamic arrays for: +// - unsorted draw calls +// - sorted order of draw calls +// - unsorted vertices +// - final (sorted) vertices +// - vertex indices for sorted vertices + +// contains the draw calls from DrawPolygon, waiting to be processed +DrawCallInfo* drawCalls = NULL; +int drawCallsSize = 0; +int drawCallsCapacity = 65536; + +// contains sorted order (array indices) for drawCalls +// (therefore size and capacity shared with it) +UINT32* drawCallOrder = NULL; + +// contains unsorted vertices and texture coordinates from DrawPolygon +FOutVector* unsortedVertices = NULL; +int unsortedVerticesSize = 0; +int unsortedVerticesCapacity = 65536; + +// contains subset of sorted vertices and texture coordinates to be sent to gpu +FOutVector* finalVertices = NULL; +int finalVerticesSize = 0; +int finalVerticesCapacity = 65536; + +// contains vertex indices into finalVertices for glDrawElements, +// taking into account fan->triangles conversion +UINT32* finalIndices = NULL; // this is alloced with 3x finalVertices size +int finalIndicesSize = 0; + +// Enables batching mode. HWR_ProcessPolygon will collect polygons instead of passing them directly to the rendering backend. +// Call HWR_RenderBatches to render all the collected geometry. +void HWR_StartBatching(void) +{ + if (currently_batching) + I_Error("Repeat call to HWR_StartBatching without HWR_RenderBatches"); + + // init arrays if that has not been done yet + if (!finalVertices) + { + finalVertices = malloc(finalVerticesCapacity * sizeof(FOutVector)); + finalIndices = malloc(finalVerticesCapacity * 3 * sizeof(UINT32)); + drawCalls = malloc(drawCallsCapacity * sizeof(DrawCallInfo)); + drawCallOrder = malloc(drawCallsCapacity * sizeof(UINT32)); + unsortedVertices = malloc(unsortedVerticesCapacity * sizeof(FOutVector)); + } + + currently_batching = true; +} + +// This replaces the direct calls to pfnSetTexture in cases where batching is available. +// The texture selection is saved for the next HWR_ProcessPolygon call. +// Doing this was easier than getting a texture pointer to HWR_ProcessPolygon. +void HWR_SetCurrentTexture(GLMipmap_t *texture) +{ + if (currently_batching) + current_texture = texture; + else + HWD.pfnSetTexture(texture); +} + +static void HWR_CollectDrawCallInfo(FSurfaceInfo *pSurf, FUINT iNumPts, FBITFIELD PolyFlags, int shader_target, boolean horizonSpecial) +{ + // make sure dynamic array has capacity + if (drawCallsSize == drawCallsCapacity) + { + DrawCallInfo* new_array; + // ran out of space, make new array double the size + drawCallsCapacity *= 2; + new_array = malloc(drawCallsCapacity * sizeof(DrawCallInfo)); + memcpy(new_array, drawCalls, drawCallsSize * sizeof(DrawCallInfo)); + free(drawCalls); + drawCalls = new_array; + // also need to redo the index array, dont need to copy it though + free(drawCallOrder); + drawCallOrder = malloc(drawCallsCapacity * sizeof(UINT32)); + } + // add entry to array + drawCalls[drawCallsSize].surf = *pSurf; + drawCalls[drawCallsSize].vertsIndex = unsortedVerticesSize; + drawCalls[drawCallsSize].numVerts = iNumPts; + drawCalls[drawCallsSize].polyFlags = PolyFlags; + drawCalls[drawCallsSize].texture = current_texture; + drawCalls[drawCallsSize].shader = (shader_target != -1) ? HWR_GetShaderFromTarget(shader_target) : shader_target; + drawCalls[drawCallsSize].horizonSpecial = horizonSpecial; + drawCallsSize++; +} + +static void HWR_CollectDrawCallVertices(FOutVector *pOutVerts, FUINT iNumPts) +{ + // make sure dynamic array has capacity + while (unsortedVerticesSize + (int)iNumPts > unsortedVerticesCapacity) + { + FOutVector* new_array; + // need more space for vertices in unsortedVertices + unsortedVerticesCapacity *= 2; + new_array = malloc(unsortedVerticesCapacity * sizeof(FOutVector)); + memcpy(new_array, unsortedVertices, unsortedVerticesSize * sizeof(FOutVector)); + free(unsortedVertices); + unsortedVertices = new_array; + } + // add vertices to array + memcpy(&unsortedVertices[unsortedVerticesSize], pOutVerts, iNumPts * sizeof(FOutVector)); + unsortedVerticesSize += iNumPts; +} + +// 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_target, boolean horizonSpecial) +{ + if (currently_batching) + { + if (!pSurf) + { + // handling null FSurfaceInfo is not implemented + I_Error("Got a null FSurfaceInfo in batching"); + } + + HWR_CollectDrawCallInfo(pSurf, iNumPts, PolyFlags, shader_target, horizonSpecial); + HWR_CollectDrawCallVertices(pOutVerts, iNumPts); + } + else + { + HWD.pfnSetShader((shader_target != SHADER_NONE) ? HWR_GetShaderFromTarget(shader_target) : shader_target); + HWD.pfnDrawPolygon(pSurf, pOutVerts, iNumPts, PolyFlags); + } +} + +static int compareDrawCalls(const void *p1, const void *p2) +{ + UINT32 index1 = *(const UINT32*)p1; + UINT32 index2 = *(const UINT32*)p2; + DrawCallInfo* poly1 = &drawCalls[index1]; + DrawCallInfo* poly2 = &drawCalls[index2]; + int diff; + INT64 diff64; + UINT32 downloaded1 = 0; + UINT32 downloaded2 = 0; + + int shader1 = poly1->shader; + int shader2 = poly2->shader; + // make skywalls and horizon lines first in order + if (poly1->polyFlags & PF_NoTexture || poly1->horizonSpecial) + shader1 = -1; + if (poly2->polyFlags & PF_NoTexture || poly2->horizonSpecial) + shader2 = -1; + diff = shader1 - shader2; + if (diff != 0) return diff; + + // skywalls and horizon lines must retain their order for horizon lines to work + if (shader1 == -1 && shader2 == -1) + return index1 - index2; + + if (poly1->texture) + downloaded1 = poly1->texture->downloaded; // there should be a opengl texture name here, usable for comparisons + if (poly2->texture) + downloaded2 = poly2->texture->downloaded; + diff64 = downloaded1 - downloaded2; + if (diff64 != 0) return diff64; + + diff = poly1->polyFlags - poly2->polyFlags; + if (diff != 0) return diff; + + diff64 = poly1->surf.PolyColor.rgba - poly2->surf.PolyColor.rgba; + if (diff64 < 0) return -1; else if (diff64 > 0) return 1; + diff64 = poly1->surf.TintColor.rgba - poly2->surf.TintColor.rgba; + if (diff64 < 0) return -1; else if (diff64 > 0) return 1; + diff64 = poly1->surf.FadeColor.rgba - poly2->surf.FadeColor.rgba; + if (diff64 < 0) return -1; else if (diff64 > 0) return 1; + + diff = poly1->surf.LightInfo.light_level - poly2->surf.LightInfo.light_level; + if (diff != 0) return diff; + diff = poly1->surf.LightInfo.fade_start - poly2->surf.LightInfo.fade_start; + if (diff != 0) return diff; + diff = poly1->surf.LightInfo.fade_end - poly2->surf.LightInfo.fade_end; + return diff; +} + +static int compareDrawCallsNoShaders(const void *p1, const void *p2) +{ + UINT32 index1 = *(const UINT32*)p1; + UINT32 index2 = *(const UINT32*)p2; + DrawCallInfo* poly1 = &drawCalls[index1]; + DrawCallInfo* poly2 = &drawCalls[index2]; + int diff; + INT64 diff64; + + GLMipmap_t *texture1 = poly1->texture; + GLMipmap_t *texture2 = poly2->texture; + UINT32 downloaded1 = 0; + UINT32 downloaded2 = 0; + if (poly1->polyFlags & PF_NoTexture || poly1->horizonSpecial) + texture1 = NULL; + if (poly2->polyFlags & PF_NoTexture || poly2->horizonSpecial) + texture2 = NULL; + if (texture1) + downloaded1 = texture1->downloaded; // there should be a opengl texture name here, usable for comparisons + if (texture2) + downloaded2 = texture2->downloaded; + // skywalls and horizon lines must retain their order for horizon lines to work + if (!texture1 && !texture2) + return index1 - index2; + diff64 = downloaded1 - downloaded2; + if (diff64 != 0) return diff64; + + diff = poly1->polyFlags - poly2->polyFlags; + if (diff != 0) return diff; + + diff64 = poly1->surf.PolyColor.rgba - poly2->surf.PolyColor.rgba; + if (diff64 < 0) return -1; else if (diff64 > 0) return 1; + + return 0; +} + +static void HWR_CollectVerticesIntoBatch(DrawCallInfo *drawCall) +{ + int firstVIndex; + int lastVIndex; + int numVerts = drawCall->numVerts; + // before writing, check if there is enough room + // using 'while' instead of 'if' here makes sure that there will *always* be enough room. + // probably never will this loop run more than once though + while (finalVerticesSize + numVerts > finalVerticesCapacity) + { + FOutVector* new_array; + UINT32* new_index_array; + finalVerticesCapacity *= 2; + new_array = malloc(finalVerticesCapacity * sizeof(FOutVector)); + memcpy(new_array, finalVertices, finalVerticesSize * sizeof(FOutVector)); + free(finalVertices); + finalVertices = new_array; + // also increase size of index array, 3x of vertex array since + // going from fans to triangles increases vertex count to 3x + new_index_array = malloc(finalVerticesCapacity * 3 * sizeof(UINT32)); + memcpy(new_index_array, finalIndices, finalIndicesSize * sizeof(UINT32)); + free(finalIndices); + finalIndices = new_index_array; + } + // write the vertices of the polygon + memcpy(&finalVertices[finalVerticesSize], &unsortedVertices[drawCall->vertsIndex], + numVerts * sizeof(FOutVector)); + // write the indexes, pointing to the fan vertexes but in triangles format + firstVIndex = finalVerticesSize; + lastVIndex = finalVerticesSize + numVerts; + finalVerticesSize += 2; + while (finalVerticesSize < lastVIndex) + { + finalIndices[finalIndicesSize++] = firstVIndex; + finalIndices[finalIndicesSize++] = finalVerticesSize - 1; + finalIndices[finalIndicesSize++] = finalVerticesSize++; + } +} + +static GLMipmap_t *HWR_GetDrawCallTexture(DrawCallInfo *dc) +{ + return (dc->polyFlags & PF_NoTexture) ? NULL : dc->texture; +} + +// flags returned by HWR_MarkStateChanges +#define SHADER_CHANGED 1 +#define TEXTURE_CHANGED 2 +#define POLYFLAGS_CHANGED 4 +#define SURFACEINFO_CHANGED 8 + +static unsigned int HWR_MarkStateChanges(DrawCallInfo *current, DrawCallInfo *next) +{ + unsigned int stateChanges = 0; + FSurfaceInfo *currentSI = ¤t->surf; + FSurfaceInfo *nextSI = &next->surf; + + // check if a state change is required and flag it to stateChanges + + if (current->shader != next->shader && cv_grshaders.value && gr_shadersavailable) + stateChanges |= SHADER_CHANGED; + if (HWR_GetDrawCallTexture(current) != HWR_GetDrawCallTexture(next)) + stateChanges |= TEXTURE_CHANGED; + if (current->polyFlags != next->polyFlags) + stateChanges |= POLYFLAGS_CHANGED; + if (cv_grshaders.value && gr_shadersavailable) + { + if (currentSI->PolyColor.rgba != nextSI->PolyColor.rgba || + currentSI->TintColor.rgba != nextSI->TintColor.rgba || + currentSI->FadeColor.rgba != nextSI->FadeColor.rgba || + currentSI->LightInfo.light_level != nextSI->LightInfo.light_level || + currentSI->LightInfo.fade_start != nextSI->LightInfo.fade_start || + currentSI->LightInfo.fade_end != nextSI->LightInfo.fade_end) + { + stateChanges |= SURFACEINFO_CHANGED; + } + } + else + { + if (currentSI->PolyColor.rgba != nextSI->PolyColor.rgba) + stateChanges |= SURFACEINFO_CHANGED; + } + + return stateChanges; +} + +static void HWR_ExecuteStateChanges(unsigned int stateChanges, DrawCallInfo *dc) +{ + if ((stateChanges & SHADER_CHANGED) && cv_grshaders.value && gr_shadersavailable) + { + HWD.pfnSetShader(dc->shader); + ps_hw_numshaders.value.i++; + } + if (stateChanges & TEXTURE_CHANGED) + { + // for PF_NoTexture the texture is set in DrawIndexedTriangles + if (!(dc->polyFlags & PF_NoTexture)) + { + // texture should be already ready for use from calls to + // SetTexture during batch collection + HWD.pfnSetTexture(dc->texture); + } + ps_hw_numtextures.value.i++; + } + // these two are just parameters to DrawIndexedTriangles + // (changes to polyflags states are tracked in r_opengl.c though) + if (stateChanges & POLYFLAGS_CHANGED) + ps_hw_numpolyflags.value.i++; + if (stateChanges & SURFACEINFO_CHANGED) + ps_hw_numcolors.value.i++; +} + + +static void HWR_InitBatchingStats(void) +{ + ps_hw_numpolys.value.i = drawCallsSize; + ps_hw_numcalls.value.i = ps_hw_numverts.value.i + = ps_hw_numshaders.value.i = ps_hw_numtextures.value.i + = ps_hw_numpolyflags.value.i = ps_hw_numcolors.value.i = 0; +} + +// This function organizes the geometry and draw calls collected by HWR_ProcessPolygon +// calls into batches and uses the rendering backend to draw them. +void HWR_RenderBatches(void) +{ + int drawCallReadPos = 0; // position in drawCallOrder + int i; + + if (!currently_batching) + I_Error("HWR_RenderBatches called without starting batching"); + + currently_batching = false; // no longer collecting batches + + HWR_InitBatchingStats(); + + if (!drawCallsSize) + return; // nothing to draw + + // init drawCallOrder + for (i = 0; i < drawCallsSize; i++) + drawCallOrder[i] = i; + + // sort the draw calls + PS_START_TIMING(ps_hw_batchsorttime); + if (cv_grshaders.value && gr_shadersavailable) + qsort(drawCallOrder, drawCallsSize, sizeof(UINT32), compareDrawCalls); + else + qsort(drawCallOrder, drawCallsSize, sizeof(UINT32), compareDrawCallsNoShaders); + PS_STOP_TIMING(ps_hw_batchsorttime); + // sort grouping order + // 1. shader + // 2. texture + // 3. polyflags + // 4. colors + light level + // not sure about what order of the last 2 should be, or if it even matters + + PS_START_TIMING(ps_hw_batchdrawtime); + + // set state for first batch + HWR_ExecuteStateChanges(0xFFFF, &drawCalls[drawCallOrder[0]]); + + // - iterate through draw calls + // - accumulate converted vertices and indices into finalVertices and finalIndices + // and send them as a combined draw call when a state change occurs + while (1) + { + boolean stopFlag = false; + unsigned int stateChanges = 0; // flags defined above HWR_MarkStateChanges + DrawCallInfo *currentDrawCall = &drawCalls[drawCallOrder[drawCallReadPos++]]; + DrawCallInfo *nextDrawCall = NULL; + + HWR_CollectVerticesIntoBatch(currentDrawCall); + + if (drawCallReadPos >= drawCallsSize) // was that the last draw call? + { + stopFlag = true; + } + else + { + nextDrawCall = &drawCalls[drawCallOrder[drawCallReadPos]]; + stateChanges = HWR_MarkStateChanges(currentDrawCall, nextDrawCall); + } + + if (stateChanges || stopFlag) + { + // execute combined draw call + HWD.pfnDrawIndexedTriangles(¤tDrawCall->surf, finalVertices, + finalIndicesSize, currentDrawCall->polyFlags, finalIndices); + // update stats + ps_hw_numcalls.value.i++; + ps_hw_numverts.value.i += finalIndicesSize; + // reset final geometry collection arrays + finalVerticesSize = 0; + finalIndicesSize = 0; + } + else + continue; + + // if we're here then either its time to stop or time to change state + if (stopFlag) + break; + else + HWR_ExecuteStateChanges(stateChanges, nextDrawCall); + } + // reset the arrays (set sizes to 0) + drawCallsSize = 0; + unsortedVerticesSize = 0; + + PS_STOP_TIMING(ps_hw_batchdrawtime); +} + +#endif // HWRENDER diff --git a/src/hardware/hw_batching.h b/src/hardware/hw_batching.h new file mode 100644 index 000000000..b4e4bd9e3 --- /dev/null +++ b/src/hardware/hw_batching.h @@ -0,0 +1,27 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file hw_batching.h +/// \brief Draw call batching and related things. + +#ifndef __HWR_BATCHING_H__ +#define __HWR_BATCHING_H__ + +#include "hw_defs.h" +#include "hw_data.h" +#include "hw_drv.h" + +void HWR_StartBatching(void); +void HWR_SetCurrentTexture(GLMipmap_t *texture); +void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, int shader, boolean horizonSpecial); +void HWR_RenderBatches(void); + +extern boolean currently_batching; + +#endif diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 642e28354..593da1058 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -17,6 +17,7 @@ #include "hw_main.h" #include "hw_glob.h" #include "hw_drv.h" +#include "hw_batching.h" #include "../doomstat.h" //gamemode #include "../i_video.h" //rendermode @@ -592,7 +593,11 @@ GLTexture_t *HWR_GetTexture(INT32 tex) if (!grtex->mipmap.grInfo.data && !grtex->mipmap.downloaded) HWR_GenerateTexture(tex, grtex); - HWD.pfnSetTexture(&grtex->mipmap); + // If hardware does not have the texture, then call pfnSetTexture to upload it + if (!grtex->mipmap.downloaded) + HWD.pfnSetTexture(&grtex->mipmap); + + HWR_SetCurrentTexture(&grtex->mipmap); // The system-memory data can be purged now. Z_ChangeTag(grtex->mipmap.grInfo.data, PU_HWRCACHE_UNLOCKED); @@ -676,7 +681,11 @@ void HWR_GetFlat(lumpnum_t flatlumpnum, boolean noencoremap) if (!grmip->downloaded && !grmip->grInfo.data) HWR_CacheFlat(grmip, flatlumpnum); - HWD.pfnSetTexture(grmip); + // If hardware does not have the texture, then call pfnSetTexture to upload it + if (!grmip->downloaded) + HWD.pfnSetTexture(grmip); + + HWR_SetCurrentTexture(grmip); // The system-memory data can be purged now. Z_ChangeTag(grmip->grInfo.data, PU_HWRCACHE_UNLOCKED); @@ -702,8 +711,11 @@ static void HWR_LoadMappedPatch(GLMipmap_t *grmip, GLPatch_t *gpatch) Z_Free(patch); } - - HWD.pfnSetTexture(grmip); + // If hardware does not have the texture, then call pfnSetTexture to upload it + if (!grmip->downloaded) + HWD.pfnSetTexture(grmip); + + HWR_SetCurrentTexture(grmip); // The system-memory data can be purged now. Z_ChangeTag(grmip->grInfo.data, PU_HWRCACHE_UNLOCKED); @@ -733,7 +745,11 @@ void HWR_GetPatch(GLPatch_t *gpatch) Z_Free(ptr); } - HWD.pfnSetTexture(gpatch->mipmap); + // If hardware does not have the texture, then call pfnSetTexture to upload it + if (!gpatch->mipmap->downloaded) + HWD.pfnSetTexture(gpatch->mipmap); + + HWR_SetCurrentTexture(gpatch->mipmap); // The system-memory patch data can be purged now. Z_ChangeTag(gpatch->mipmap->grInfo.data, PU_HWRCACHE_UNLOCKED); diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 1313d80aa..cbcbef5ac 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -165,6 +165,46 @@ typedef struct FLOAT s,t; } FOutVector; +#ifdef GL_SHADERS +// Shader targets used to render specific types of geometry. +// A shader target is resolved to an actual shader with HWR_GetShaderFromTarget. +// The shader returned may be a base shader or a custom shader. +enum +{ + SHADER_NONE = -1, + SHADER_FLOOR = 0, + SHADER_WALL, + SHADER_MODEL, + SHADER_SPRITE, + SHADER_WATER, + SHADER_FOG, + SHADER_SKY, + SHADER_PALETTE_POSTPROCESS, + SHADER_UI_COLORMAP_FADE, + + NUMSHADERTARGETS +}; + +// 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 +{ + const char *type; + INT32 id; +} customshaderxlat_t; + +enum hwdshaderstage +{ + HWD_SHADERSTAGE_VERTEX, + HWD_SHADERSTAGE_FRAGMENT, +}; + +typedef enum hwdshaderstage hwdshaderstage_t; + +#endif + // ========================================================================== // RENDER MODES // ========================================================================== @@ -288,4 +328,15 @@ enum hwdfiltermode HWD_SET_TEXTUREFILTER_MIXED3, }; +// Screen texture slots +enum hwdscreentexture +{ + HWD_SCREENTEXTURE_WIPE_START, // source image for the wipe/fade effect + HWD_SCREENTEXTURE_WIPE_END, // destination image for the wipe/fade effect + HWD_SCREENTEXTURE_GENERIC1, // underwater/heat effect, intermission background + HWD_SCREENTEXTURE_GENERIC2, // palette-based colormap fade, final screen texture + 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 653157990..bd09b69d2 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -122,7 +122,7 @@ void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option) flags |= PF_ForceWrapY; // clip it since it is used for bunny scroll in doom I - HWD.pfnDrawPolygon(NULL, v, 4, flags, false); + HWD.pfnDrawPolygon(NULL, v, 4, flags); } void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap) @@ -300,10 +300,10 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t else if (alphalevel == 15) Surf.PolyColor.s.alpha = softwaretranstogl_hi[hudtrans]; else Surf.PolyColor.s.alpha = softwaretranstogl[10-alphalevel]; flags |= PF_Modulated; - HWD.pfnDrawPolygon(&Surf, v, 4, flags, false); + HWD.pfnDrawPolygon(&Surf, v, 4, flags); } else - HWD.pfnDrawPolygon(NULL, v, 4, flags, false); + HWD.pfnDrawPolygon(NULL, v, 4, flags); } void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h) @@ -454,10 +454,10 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal else if (alphalevel == 15) Surf.PolyColor.s.alpha = softwaretranstogl_hi[cv_translucenthud.value]; else Surf.PolyColor.s.alpha = softwaretranstogl[10-alphalevel]; flags |= PF_Modulated; - HWD.pfnDrawPolygon(&Surf, v, 4, flags, false); + HWD.pfnDrawPolygon(&Surf, v, 4, flags); } else - HWD.pfnDrawPolygon(NULL, v, 4, flags, false); + HWD.pfnDrawPolygon(NULL, v, 4, flags); } // ========================================================================== @@ -533,7 +533,7 @@ void HWR_DrawFlatFill (INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum // BTW, I see we put 0 for PFs, and If I'm right, that // means we take the previous PFs as default // how can we be sure they are ok? - HWD.pfnDrawPolygon(NULL, v, 4, PF_NoDepthTest, false); //PF_Translucent); + HWD.pfnDrawPolygon(NULL, v, 4, PF_NoDepthTest); //PF_Translucent); } @@ -548,6 +548,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; @@ -562,8 +563,25 @@ void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength) if (color & 0xFF00) // Do COLORMAP fade. { - Surf.PolyColor.rgba = UINT2RGBA(0x01010160); - Surf.PolyColor.s.alpha = (strength*8); + if (HWR_ShouldUsePaletteRendering() && cv_grscreentextures.value) + { + 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; + } } else // Do TRANSMAP** fade. { @@ -574,9 +592,11 @@ void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength) Surf.PolyColor.s.alpha = softwaretranstogl[strength]; else Surf.PolyColor.s.alpha = (UINT8)(strength*25.5f); + + poly_flags |= PF_Translucent; } - HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest, false); + HWD.pfnDrawPolygon(&Surf, v, 4, poly_flags); } // Draw the console background with translucency support @@ -603,7 +623,7 @@ void HWR_DrawConsoleBack(UINT32 color, INT32 height) Surf.PolyColor.rgba = UINT2RGBA(color); Surf.PolyColor.s.alpha = 0x80; - HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest, false); + HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); } @@ -854,7 +874,7 @@ void HWR_DrawDiag(INT32 x, INT32 y, INT32 wh, INT32 color) Surf.PolyColor = palette[color&0xFF]; HWD.pfnDrawPolygon(&Surf, v, 4, - PF_Modulated|PF_NoTexture|PF_NoDepthTest, false); + PF_Modulated|PF_NoTexture|PF_NoDepthTest); } // -------------------+ @@ -963,7 +983,7 @@ void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, UINT32 color, INT32 Surf.PolyColor.rgba = UINT2RGBA(color); Surf.PolyColor.s.alpha = 0x80; - HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest, false); + HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); } // -----------------+ @@ -1081,7 +1101,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) else Surf.PolyColor.s.alpha = softwaretranstogl[10-alphalevel]; } - HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest, false); + HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); } #ifdef HAVE_PNG @@ -1165,7 +1185,7 @@ UINT8 *HWR_GetScreenshot(void) return NULL; // returns 24bit 888 RGB - HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf); + HWD.pfnReadScreenTexture(HWD_SCREENTEXTURE_GENERIC2, (void *)buf); return buf; } @@ -1181,7 +1201,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.pfnReadScreenTexture(HWD_SCREENTEXTURE_GENERIC2, (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 60ea552b2..df4d431f9 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -32,12 +32,13 @@ EXPORT void HWRAPI(SetupGLInfo) (void); 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, boolean horizonSpecial); +EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags); +EXPORT void HWRAPI(DrawIndexedTriangles) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, unsigned int *IndexArray); EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags); EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FBOOLEAN StencilMask, FRGBAFloat *ClearColor); EXPORT void HWRAPI(SetTexture) (FTextureInfo *TexInfo); EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *TexInfo); -EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 *dst_data); +EXPORT void HWRAPI(ReadScreenTexture) (int tex, UINT16 *dst_data); EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip, float farclip); EXPORT void HWRAPI(ClearMipMapCache) (void); @@ -55,30 +56,24 @@ EXPORT INT32 HWRAPI(GetTextureUsed) (void); EXPORT void HWRAPI(RenderSkyDome) (INT32 tex, INT32 texture_width, INT32 texture_height, FTransform transform); 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(DoScreenWipe) (int wipeStart, int wipeEnd); +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); + EXPORT void HWRAPI(RenderVhsEffect) (fixed_t upbary, fixed_t downbary, UINT8 updistort, UINT8 downdistort, UINT8 barsize); -EXPORT void HWRAPI(MakeScreenFinalTexture) (void); -EXPORT void HWRAPI(DrawScreenFinalTexture) (int width, int height); #define SCREENVERTS 10 EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]); // jimita -EXPORT boolean HWRAPI(LoadShaders) (void); -EXPORT void HWRAPI(KillShaders) (void); -EXPORT void HWRAPI(SetShader) (int shader); +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 *shader, size_t size, boolean fragment); -EXPORT boolean HWRAPI(InitCustomShaders) (void); - -EXPORT void HWRAPI(StartBatching) (void); -EXPORT void HWRAPI(RenderBatches) (precise_t *sSortTime, precise_t *sDrawTime, int *sNumPolys, int *sNumVerts, int *sNumCalls, int *sNumShaders, int *sNumTextures, int *sNumPolyFlags, int *sNumColors); EXPORT void HWRAPI(SetPaletteLookup)(UINT8 *lut); EXPORT UINT32 HWRAPI(CreateLightTable)(RGBA_t *hw_lighttable); @@ -99,11 +94,12 @@ struct hwdriver_s FinishUpdate pfnFinishUpdate; Draw2DLine pfnDraw2DLine; DrawPolygon pfnDrawPolygon; + DrawIndexedTriangles pfnDrawIndexedTriangles; SetBlend pfnSetBlend; ClearBuffer pfnClearBuffer; SetTexture pfnSetTexture; UpdateTexture pfnUpdateTexture; - ReadRect pfnReadRect; + ReadScreenTexture pfnReadScreenTexture; GClipRect pfnGClipRect; ClearMipMapCache pfnClearMipMapCache; SetSpecialState pfnSetSpecialState; @@ -113,29 +109,22 @@ struct hwdriver_s GetTextureUsed pfnGetTextureUsed; PostImgRedraw pfnPostImgRedraw; FlushScreenTextures pfnFlushScreenTextures; - StartScreenWipe pfnStartScreenWipe; - EndScreenWipe pfnEndScreenWipe; DoScreenWipe pfnDoScreenWipe; - DrawIntermissionBG pfnDrawIntermissionBG; + DrawScreenTexture pfnDrawScreenTexture; MakeScreenTexture pfnMakeScreenTexture; - RenderVhsEffect pfnRenderVhsEffect; - MakeScreenFinalTexture pfnMakeScreenFinalTexture; + RenderVhsEffect pfnRenderVhsEffect; DrawScreenFinalTexture pfnDrawScreenFinalTexture; RenderSkyDome pfnRenderSkyDome; - LoadShaders pfnLoadShaders; - KillShaders pfnKillShaders; + InitShaders pfnInitShaders; + LoadShader pfnLoadShader; + CompileShader pfnCompileShader; SetShader pfnSetShader; UnSetShader pfnUnSetShader; SetShaderInfo pfnSetShaderInfo; - LoadCustomShader pfnLoadCustomShader; - InitCustomShaders pfnInitCustomShaders; - StartBatching pfnStartBatching; - RenderBatches pfnRenderBatches; - SetPaletteLookup pfnSetPaletteLookup; CreateLightTable pfnCreateLightTable; ClearLightTables pfnClearLightTables; diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index 082a6a78c..9e565a8aa 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -95,4 +95,18 @@ void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector, void HWR_RenderDrawNodes(void); +// -------- +// 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_ \ No newline at end of file diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index b4a77cc24..b0ed574ab 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -19,6 +19,7 @@ #include "hw_main.h" #include "hw_glob.h" #include "hw_drv.h" +#include "hw_batching.h" #include "hw_md2.h" #include "hw_clip.h" #include "hw_light.h" @@ -57,8 +58,8 @@ // ========================================================================== struct hwdriver_s hwdriver; - -boolean gr_shadersavailable = true; +// false if shaders have not been initialized yet, or if shaders are not available +boolean gr_shadersavailable = false; // Whether the internal state is set to palette rendering or not. static boolean gr_palette_rendering_state = false; @@ -70,7 +71,6 @@ static boolean gr_palette_rendering_state = false; static void CV_filtermode_ONChange(void); static void CV_anisotropic_ONChange(void); static void CV_screentextures_ONChange(void); -static void CV_useCustomShaders_ONChange(void); static void CV_grshaders_OnChange(void); static void CV_grpaletterendering_OnChange(void); static void CV_grpalettedepth_OnChange(void); @@ -89,10 +89,10 @@ consvar_t cv_grrounddown = {"gr_rounddown", "Off", 0, CV_OnOff, NULL, 0, NULL, N consvar_t cv_grfiltermode = {"gr_filtermode", "Nearest", CV_CALL|CV_SAVE, grfiltermode_cons_t, CV_filtermode_ONChange, 0, NULL, NULL, 0, 0, NULL}; - + consvar_t cv_granisotropicmode = {"gr_anisotropicmode", "1", CV_CALL|CV_SAVE, granisotropicmode_cons_t, CV_anisotropic_ONChange, 0, NULL, NULL, 0, 0, NULL}; - + consvar_t cv_grcorrecttricks = {"gr_correcttricks", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grsolvetjoin = {"gr_solvetjoin", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -111,7 +111,7 @@ static CV_PossibleValue_t grrenderdistance_cons_t[] = { {6, "12288"}, {7, "16384"}, {0, NULL}}; consvar_t cv_grrenderdistance = {"gr_renderdistance", "Max", CV_SAVE, grrenderdistance_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; - + consvar_t cv_grportals = {"gr_portals", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_nostencil = {"nostencil", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_portalline = {"portalline", "0", 0, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -120,10 +120,10 @@ CV_PossibleValue_t secbright_cons_t[] = {{0, "MIN"}, {255, "MAX"}, {0, NULL}}; consvar_t cv_secbright = {"secbright", "0", CV_SAVE, secbright_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; - + consvar_t cv_grfovchange = {"gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; - + // values for the far clipping plane static float clipping_distances[] = {1024.0f, 2048.0f, 4096.0f, 6144.0f, 8192.0f, 12288.0f, 16384.0f}; // values for bsp culling @@ -142,8 +142,8 @@ static INT32 current_bsp_culling_distance = 0; consvar_t cv_grscreentextures = {"gr_screentextures", "On", CV_CALL|CV_SAVE, CV_OnOff, CV_screentextures_ONChange, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_grshaders = {"gr_shaders", "On", CV_CALL|CV_SAVE, CV_OnOff, CV_grshaders_OnChange, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_grusecustomshaders = {"gr_usecustomshaders", "Yes", CV_CALL|CV_SAVE, CV_OnOff, CV_useCustomShaders_ONChange, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t grshaders_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Ignore custom shaders"}, {0, NULL}}; +consvar_t cv_grshaders = {"gr_shaders", "On", CV_CALL|CV_SAVE, grshaders_cons_t, CV_grshaders_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grpaletterendering = {"gr_paletteshader", "Off", CV_CALL|CV_SAVE, CV_OnOff, CV_grpaletterendering_OnChange, 0, NULL, NULL, 0, 0, NULL}; @@ -162,57 +162,63 @@ consvar_t cv_grslopecontrast = {"gr_slopecontrast", "Off", CV_SAVE, CV_OnOff, NU consvar_t cv_grhorizonlines = {"gr_horizonlines", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; + +#define ONLY_IF_GL_LOADED if (vid.glstate != VID_GL_LIBRARY_LOADED) return; static void CV_filtermode_ONChange(void) { - if (rendermode == render_opengl) + ONLY_IF_GL_LOADED HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_grfiltermode.value); } static void CV_anisotropic_ONChange(void) { - if (rendermode == render_opengl) + ONLY_IF_GL_LOADED HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_granisotropicmode.value); } static void CV_screentextures_ONChange(void) { - if (rendermode == render_opengl) + ONLY_IF_GL_LOADED HWD.pfnSetSpecialState(HWD_SET_SCREEN_TEXTURES, cv_grscreentextures.value); } static void CV_grshaders_OnChange(void) { - if ((rendermode == render_opengl) && (cv_grpaletterendering.value)) + ONLY_IF_GL_LOADED + HWR_SetShaderState(); + if ((cv_grpaletterendering.value)) { // can't do palette rendering without shaders, so update the state if needed HWR_TogglePaletteRendering(); } } -static void CV_useCustomShaders_ONChange(void) // should we do a call to HWR_TogglePaletteRendering here aswell in pal rendering mode? -{ - if (rendermode == render_opengl) - { - if (HWR_UseShader()) - HWD.pfnInitCustomShaders(); - } -} - static void CV_grpaletterendering_OnChange(void) { - if ((rendermode == render_opengl) && (gr_shadersavailable)) + ONLY_IF_GL_LOADED + if (gr_shadersavailable) { + HWR_CompileShaders(); HWR_TogglePaletteRendering(); } } static void CV_grpalettedepth_OnChange(void) { - if ((rendermode == render_opengl) && (HWR_ShouldUsePaletteRendering())) + ONLY_IF_GL_LOADED + if (HWR_ShouldUsePaletteRendering()) HWR_SetPalette(pLocalPalette); } +// +// Sets the shader state. +// +void HWR_SetShaderState(void) +{ + HWD.pfnSetSpecialState(HWD_SET_SHADERS, (INT32)HWR_UseShader()); +} + // ========================================================================== // Globals // ========================================================================== @@ -650,6 +656,8 @@ void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, boolean isc static FOutVector *planeVerts = NULL; static UINT16 numAllocedPlaneVerts = 0; + + INT32 shader = SHADER_NONE; // no convex poly were generated for this subsector if (!xsub->planepoly) @@ -827,16 +835,16 @@ void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, boolean isc if (HWR_UseShader()) { if (PolyFlags & PF_Fog) - HWD.pfnSetShader(6); // fog shader + shader = SHADER_FOG; // fog shader else if (PolyFlags & PF_Ripple) - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 11 : 5); // water shader + shader = SHADER_WATER; // water shader else - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 9 : 1); // floor shader + shader = SHADER_FLOOR; // floor shader PolyFlags |= PF_ColorMapped; } - HWD.pfnDrawPolygon(&Surf, planeVerts, nrPlaneVerts, PolyFlags, false); + HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, PolyFlags, shader, false); if (subsector && cv_grhorizonlines.value) { @@ -921,7 +929,7 @@ void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, boolean isc horizonpts[4].y = gr_viewz; // Draw - HWD.pfnDrawPolygon(&Surf, horizonpts, 6, PolyFlags, true); + HWR_ProcessPolygon(&Surf, horizonpts, 6, PolyFlags, shader, true); } } } @@ -937,6 +945,8 @@ static void HWR_DrawSegsSplats(FSurfaceInfo * pSurf) fixed_t i; // seg bbox fixed_t segbbox[4]; + + INT32 shader = SHADER_NONE; M_ClearBox(segbbox); M_AddToBox(segbbox, @@ -989,11 +999,9 @@ static void HWR_DrawSegsSplats(FSurfaceInfo * pSurf) } if (HWR_UseShader()) - { - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 10 : 2); // wall shader - } + shader = SHADER_WALL; // wall shader - HWD.pfnDrawPolygon(&pSurf, wallVerts, 4, i|PF_Modulated|PF_Decal, false); + HWR_ProcessPolygon(&pSurf, wallVerts, 4, i|PF_Modulated|PF_Decal, shader, false); } } #endif @@ -1024,11 +1032,13 @@ FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf) // void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blendmode, INT32 lightlevel, extracolormap_t *wallcolormap) { + INT32 shader = SHADER_NONE; + HWR_Lighting(pSurf, lightlevel, wallcolormap); if (HWR_UseShader()) { - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 10 : 2); // wall shader + shader = SHADER_WALL; // wall shader blendmode |= PF_ColorMapped; } @@ -1039,7 +1049,7 @@ void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend blendmode &= ~PF_Masked; } - HWD.pfnDrawPolygon(pSurf, wallVerts, 4, blendmode|PF_Modulated|PF_Occlude, false); + HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode|PF_Modulated|PF_Occlude, shader, false); // wall shader #ifdef WALLSPLATS if (gr_curline->linedef->splats && cv_splats.value) @@ -1395,11 +1405,11 @@ static void HWR_DrawSkyWallList(void) surf.PolyColor.rgba = 0xFFFFFFFF; - HWD.pfnSetTexture(NULL); + HWR_SetCurrentTexture(NULL); HWD.pfnUnSetShader(); for (i = 0; i < skyWallVertexArraySize; i++) { - HWD.pfnDrawPolygon(&surf, skyWallVertexArray + i * 4, 4, PF_Occlude|PF_Invisible|PF_NoTexture, false); + HWD.pfnDrawPolygon(&surf, skyWallVertexArray + i * 4, 4, PF_Occlude|PF_Invisible|PF_NoTexture); } } @@ -1420,7 +1430,7 @@ void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf) } else { - HWD.pfnSetTexture(NULL); + HWR_SetCurrentTexture(NULL); HWR_ProjectWall(wallVerts, Surf, PF_Invisible|PF_NoTexture, 255, NULL); } // PF_Invisible so it's not drawn into the colour buffer @@ -3115,6 +3125,8 @@ void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fixed_t static FOutVector *planeVerts = NULL; static UINT16 numAllocedPlaneVerts = 0; + + INT32 shader = SHADER_NONE; nrPlaneVerts = polysector->numVertices; @@ -3260,11 +3272,11 @@ void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fixed_t if (HWR_UseShader()) { - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 9 : 1); // floor shader + shader = SHADER_FLOOR; // floor shader blendmode |= PF_ColorMapped; } - HWD.pfnDrawPolygon(&Surf, planeVerts, nrPlaneVerts, blendmode, false); + HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, blendmode, shader, false); // floor shader } void HWR_AddPolyObjectPlanes(void) @@ -3920,6 +3932,8 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t fixed_t slopez; float offset = 0; + INT32 shader = SHADER_NONE; + R_GetShadowZ(spr->mobj, &floorslope); mobjfloor = HWR_OpaqueFloorAtPos( @@ -4069,10 +4083,10 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t if (HWR_UseShader()) { - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 9 : 1); // floor shader + shader = SHADER_FLOOR; // floor shader } - - HWD.pfnDrawPolygon(&sSurf, swallVerts, 4, PF_Translucent|PF_Modulated, false); + + HWR_ProcessPolygon(&sSurf, swallVerts, 4, PF_Translucent|PF_Modulated, shader, false); } } @@ -4168,6 +4182,8 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) fixed_t v1x, v1y, v2x, v2y; #endif + INT32 shader = SHADER_NONE; + this_scale = FIXED_TO_FLOAT(spr->mobj->scale); if (hires) @@ -4441,11 +4457,11 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) if (HWR_UseShader()) { - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 10 : 3); // sprite shader + shader = SHADER_SPRITE; // sprite shader blend |= PF_ColorMapped; } - HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, false); + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, shader, false); // sprite shader top = bot; #ifdef ESLOPE @@ -4486,11 +4502,11 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) if (HWR_UseShader()) { - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 10 : 3); // sprite shader + shader = SHADER_SPRITE; // sprite shader blend |= PF_ColorMapped; } - HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, false); + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, shader, false); // sprite shader } // -----------------+ @@ -4504,6 +4520,9 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) FOutVector wallVerts[4]; GLPatch_t *gpatch; // sprite patch converted to hardware FSurfaceInfo Surf; + + INT32 shader = SHADER_NONE; + const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)( (spr->mobj->localskin) ? spr->mobj->localskin : spr->mobj->skin ))->flags & SF_HIRES); if (spr->mobj) this_scale = FIXED_TO_FLOAT(spr->mobj->scale); @@ -4644,11 +4663,11 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) if (HWR_UseShader()) { - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 10 : 3); // sprite shader + shader = SHADER_SPRITE; // sprite shader blend |= PF_ColorMapped; } - HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, false); + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, shader, false); } } @@ -4659,6 +4678,8 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) FOutVector wallVerts[4]; GLPatch_t *gpatch; // sprite patch converted to hardware FSurfaceInfo Surf; + + INT32 shader = SHADER_NONE; if (!spr->mobj) return; @@ -4743,11 +4764,11 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) if (HWR_UseShader()) { - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 10 : 3); // sprite shader + shader = SHADER_SPRITE; // sprite shader blend |= PF_ColorMapped; } - HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, false); + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, shader, false); } // -------------------------------------------------------------------------- @@ -5774,9 +5795,9 @@ void HWR_DrawSkyBackground(float fpov) dometransform.splitscreen = splitscreen; HWR_GetTexture(texturetranslation[skytexture]); - HWD.pfnSetShader(7); // sky shader + if (HWR_UseShader()) + HWD.pfnSetShader(HWR_GetShaderFromTarget(SHADER_SKY));// sky shader HWD.pfnRenderSkyDome(skytexture, textures[skytexture]->width, textures[skytexture]->height, dometransform); - HWD.pfnSetShader(0); } @@ -6044,8 +6065,9 @@ static void HWR_RenderViewpoint(gl_portal_t *rootportal, const float fpov, playe } //drawcount = 0; validcount++; + if (cv_grbatching.value) - HWD.pfnStartBatching(); + HWR_StartBatching(); ps_numbspcalls.value.i = 0; ps_numpolyobjects.value.i = 0; @@ -6066,14 +6088,10 @@ static void HWR_RenderViewpoint(gl_portal_t *rootportal, const float fpov, playe gr_portal = oldgl_portal_state; PS_STOP_TIMING(ps_bsptime); - + if (cv_grbatching.value) - { - HWD.pfnRenderBatches(&ps_hw_batchsorttime.value.p, &ps_hw_batchdrawtime.value.p, - &ps_hw_numpolys.value.i, &ps_hw_numverts.value.i, &ps_hw_numcalls.value.i, - &ps_hw_numshaders.value.i, &ps_hw_numtextures.value.i, &ps_hw_numpolyflags.value.i, - &ps_hw_numcolors.value.i); - } + HWR_RenderBatches(); + if (skyWallVertexArraySize)// if there are skywalls to draw using the alternate method { HWR_SetStencilState(HWR_STENCIL_SKY, -1); @@ -6245,8 +6263,7 @@ void HWR_RenderFrame(INT32 viewnumber, player_t *player, boolean skybox) HWR_ClearClipper(); // Reset the shader state. - HWD.pfnSetSpecialState(HWD_SET_SHADERS, cv_grshaders.value); - HWD.pfnSetShader(0); + //HWR_SetShaderState(); validcount++; @@ -6363,7 +6380,7 @@ void HWR_AddCommands(void) CV_RegisterVar(&cv_granisotropicmode); CV_RegisterVar(&cv_grcorrecttricks); CV_RegisterVar(&cv_grsolvetjoin); - + CV_RegisterVar(&cv_grbatching); CV_RegisterVar(&cv_grfofcut); CV_RegisterVar(&cv_fofzfightfix); @@ -6388,7 +6405,6 @@ void HWR_AddCommands(void) CV_RegisterVar(&cv_grshearing); CV_RegisterVar(&cv_grshaders); - CV_RegisterVar(&cv_grusecustomshaders); CV_RegisterVar(&cv_grportals); CV_RegisterVar(&cv_nostencil); @@ -6399,7 +6415,7 @@ void HWR_AddCommands(void) CV_RegisterVar(&cv_grpaletterendering); CV_RegisterVar(&cv_grpalettedepth); - CV_RegisterVar(&cv_grflashpal); + CV_RegisterVar(&cv_grflashpal); } // -------------------------------------------------------------------------- @@ -6419,24 +6435,22 @@ void HWR_Startup(void) HWR_InitMD2(); HWD.pfnSetupGLInfo(); - } + gr_shadersavailable = HWR_InitShaders(); + HWR_SetShaderState(); + HWR_LoadAllCustomShaders(); + + HWR_TogglePaletteRendering(); + + if (msaa) + { + if (a2c) + HWD.pfnSetSpecialState(HWD_SET_MSAA, 2); + else + HWD.pfnSetSpecialState(HWD_SET_MSAA, 1); + } + } startupdone = true; - - // jimita - HWD.pfnKillShaders(); - if (!HWD.pfnLoadShaders()) - gr_shadersavailable = false; - - HWR_TogglePaletteRendering(); - - if (msaa) - { - if (a2c) - HWD.pfnSetSpecialState(HWD_SET_MSAA, 2); - else - HWD.pfnSetSpecialState(HWD_SET_MSAA, 1); - } } // -------------------------------------------------------------------------- @@ -6454,6 +6468,8 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, { FBITFIELD blendmode = blend; UINT8 alpha = pSurf->PolyColor.s.alpha; // retain the alpha + + INT32 shader = SHADER_NONE; // Lighting is done here instead so that fog isn't drawn incorrectly on transparent walls after sorting HWR_Lighting(pSurf, lightlevel, wallcolormap); @@ -6466,7 +6482,7 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, if (fogwall) { blendmode |= PF_Fog; - HWD.pfnSetShader(6); // fog shader + shader = SHADER_FOG; // fog shader } blendmode |= PF_Modulated; // No PF_Occlude means overlapping (incorrect) transparency @@ -6475,12 +6491,12 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, { if (HWR_UseShader()) { - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 10 : 2); // wall shader + shader = SHADER_WALL; // wall shader blendmode |= PF_ColorMapped; } } - HWD.pfnDrawPolygon(pSurf, wallVerts, 4, blendmode, false); + HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode, shader, false); #ifdef WALLSPLATS if (gr_curline->linedef->splats && cv_splats.value) @@ -6531,7 +6547,7 @@ void HWR_DoPostProcessor(player_t *player) Surf.PolyColor.s.alpha = 0xc0; // match software mode - HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated|PF_Translucent|PF_NoTexture|PF_NoDepthTest, false); + HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated|PF_Translucent|PF_NoTexture|PF_NoDepthTest); } if (!cv_grscreentextures.value) // screen textures are needed for the rest of the effects @@ -6539,7 +6555,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; @@ -6583,24 +6599,24 @@ 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) { - HWD.pfnStartScreenWipe(); + HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_WIPE_START); } void HWR_EndScreenWipe(void) { - HWD.pfnEndScreenWipe(); + HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_WIPE_END); } void HWR_DrawIntermissionBG(void) { - HWD.pfnDrawIntermissionBG(); + HWD.pfnDrawScreenTexture(HWD_SCREENTEXTURE_GENERIC1, NULL, 0); } void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum) @@ -6628,7 +6644,7 @@ void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum) } HWR_GetFadeMask(lumpnum); - HWD.pfnDoScreenWipe(); + HWD.pfnDoScreenWipe(HWD_SCREENTEXTURE_WIPE_START, HWD_SCREENTEXTURE_WIPE_END); } void HWR_RenderVhsEffect(fixed_t upbary, fixed_t downbary, UINT8 updistort, UINT8 downdistort, UINT8 barsize) @@ -6638,169 +6654,11 @@ void HWR_RenderVhsEffect(fixed_t upbary, fixed_t downbary, UINT8 updistort, UINT void HWR_MakeScreenFinalTexture(void) { - HWD.pfnMakeScreenFinalTexture(); + HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_GENERIC2); } void HWR_DrawScreenFinalTexture(int width, int height) { - HWD.pfnDrawScreenFinalTexture(width, height); + HWD.pfnDrawScreenFinalTexture(HWD_SCREENTEXTURE_GENERIC2, width, height); } - -// jimita 18032019 -typedef struct -{ - char type[16]; - INT32 id; -} shaderxlat_t; - -static inline UINT16 HWR_CheckShader(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; -} - -void HWR_LoadShaders(UINT16 wadnum, boolean PK3) -{ - UINT16 lump; - char *shaderdef, *line; - char *stoken; - char *value; - size_t size; - int linenum = 1; - int shadertype = 0; - int i; - - #define SHADER_TYPES 7 - shaderxlat_t shaderxlat[SHADER_TYPES] = - { - {"Flat", 1}, - {"WallTexture", 2}, - {"Sprite", 3}, - {"Model", 4}, - {"WaterRipple", 5}, - {"Fog", 6}, - {"Sky", 7}, - }; - - lump = HWR_CheckShader(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); - if (!line) - I_Error("HWR_LoadShaders: No more free memory\n"); - - 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_LoadShaders: 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_LoadShaders: 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_LoadShaders: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); - Z_Free(line); - return; - } - - for (i = 0; i < SHADER_TYPES; 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_LoadShaders: 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++; - } - } - - HWD.pfnInitCustomShaders(); - - Z_Free(line); - return; -} - #endif // HWRENDER diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index f879bdf04..0d63732e3 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -64,6 +64,8 @@ extern ps_metric_t ps_hw_numcolors; extern ps_metric_t ps_hw_batchsorttime; extern ps_metric_t ps_hw_batchdrawtime; +extern boolean gr_shadersavailable; + // hw_draw.c void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option); void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap); @@ -83,7 +85,6 @@ boolean HWR_Screenshot(const char *lbmname); // hw_main.c void HWR_RenderFrame(INT32 viewnumber, player_t *player, boolean skybox); void HWR_RenderPlayerView(INT32 viewnumber, player_t *player); -void HWR_LoadShaders(UINT16 wadnum, boolean PK3); void HWR_SetViewSize(void); void HWR_AddCommands(void); void HWR_SetTransform(float fpov, player_t *player); @@ -165,6 +166,8 @@ RGBA_t *HWR_GetTexturePalette(void); // hw_trick.c void HWR_CorrectSWTricks(void); +void HWR_SetShaderState(void); + // Console variables extern consvar_t cv_grshaders; extern consvar_t cv_grfofcut; @@ -188,7 +191,6 @@ extern consvar_t cv_grhorizonlines; extern consvar_t cv_grfallbackplayermodel; extern consvar_t cv_grbatching; extern consvar_t cv_grrenderdistance; -extern consvar_t cv_grusecustomshaders; extern consvar_t cv_grpaletterendering; extern consvar_t cv_grpalettedepth; extern consvar_t cv_grflashpal; diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 2a581b489..c64d77639 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1458,7 +1458,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) p.mirror = atransform.mirror; // from Kart #endif - HWD.pfnSetShader(4); // model shader + HWD.pfnSetShader(SHADER_MODEL); // model shader { SINT8 flipfactor = flip ? -1 : 1; diff --git a/src/hardware/hw_shaders.c b/src/hardware/hw_shaders.c new file mode 100644 index 000000000..f9c755b0d --- /dev/null +++ b/src/hardware/hw_shaders.c @@ -0,0 +1,630 @@ +// 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.c +/// \brief Handles the shaders used by the game. + +#ifdef HWRENDER + +#include "hw_main.h" +#include "hw_glob.h" +#include "hw_drv.h" +#include "hw_shaders.h" +#include "../z_zone.h" + +// ================ +// Shader sources +// ================ + +static struct { + const char *vertex; + const char *fragment; +} const gl_shadersources[] = { + + // Floor shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_FLOOR_FRAGMENT_SHADER}, + + // Wall shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_WALL_FRAGMENT_SHADER}, + + // Sprite shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_WALL_FRAGMENT_SHADER}, + + // Model shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_WALL_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}, + + // Palette postprocess shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_PALETTE_POSTPROCESS_FRAGMENT_SHADER}, + + // UI colormap fade shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_UI_COLORMAP_FADE_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 WHITESPACE_CHARS " \t" + +#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. +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 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")) + { + line_ending = "\r\n"; + // check if all line endings are same + while ((read_pos = strchr(read_pos, '\n'))) + { + read_pos--; + if (*read_pos != '\r') + { + // 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; + } + read_pos = original; + } + + line_ending_len = strlen(line_ending); + + // 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); + 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, WHITESPACE_CHARS); + if (whitespace_len == distance_to_end) + break; // we got to the end + ADVANCE(whitespace_len) + + if (STARTSWITH(read_pos, "#version")) + { + // 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) + { + CONS_Alert(CONS_ERROR, "HWR_PreprocessShader: Syntax error in #version. Expected space after #version, but got other text.\n"); + return NULL; + } + else if (whitespace_len == distance_to_end) + { + 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 + { + // 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 + +#define ADD_TO_LEN(def) new_len += sizeof(def) - 1 + line_ending_len; + + // Calculate length of modified shader. + new_len = original_len; + + if (cv_grpaletterendering.value) + 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); + + read_pos = original; + write_pos = new_shader; + + 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, define); \ + write_pos += sizeof(define) - 1; \ + strcpy(write_pos, line_ending); \ + write_pos += line_ending_len; \ + } + + // Write the defines. + if (cv_grpaletterendering.value) + WRITE_DEFINE(PALETTE_RENDERING_DEFINE) + +#undef WRITE_DEFINE + + // 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'; + + 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_grshaders.value == 1) + 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}, + {"PalettePostprocess", SHADER_PALETTE_POSTPROCESS}, + {"UIColormapFade", SHADER_UI_COLORMAP_FADE}, + {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 (!HWR_UseShader()) + 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; + // 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); + } + } + + Z_Free(line); + return; +} + +const char *HWR_GetShaderName(INT32 shader) +{ + INT32 i; + + for (i = 0; shaderxlat[i].type; i++) + { + if (shaderxlat[i].id == shader) + return shaderxlat[i].type; + } + + return "Unknown"; +} + +#endif // HWRENDER diff --git a/src/hardware/hw_shaders.h b/src/hardware/hw_shaders.h new file mode 100644 index 000000000..eb705c34c --- /dev/null +++ b/src/hardware/hw_shaders.h @@ -0,0 +1,298 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2021 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file hw_shaders.h +/// \brief Handles the shaders used by the game. + +#ifndef _HW_SHADERS_H_ +#define _HW_SHADERS_H_ + +#include "../doomtype.h" + +// ================ +// Vertex shaders +// ================ + +// +// Generic vertex shader +// + +#define GLSL_DEFAULT_VERTEX_SHADER \ + "void main()\n" \ + "{\n" \ + "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \ + "gl_FrontColor = gl_Color;\n" \ + "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \ + "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ + "}\0" + +// ================== +// Fragment shaders +// ================== + +// +// Generic fragment shader +// + +#define GLSL_DEFAULT_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "void main(void) {\n" \ + "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \ + "}\0" + +// +// Software fragment shader +// + +// Include GLSL_FLOOR_FUDGES or GLSL_WALL_FUDGES or define the fudges in shaders that use this macro. +#define GLSL_DOOM_COLORMAP \ + "float R_DoomColormap(float light, float z)\n" \ + "{\n" \ + "float lightnum = clamp(light / 17.0, 0.0, 15.0);\n" \ + "float lightz = clamp(z / 16.0, 0.0, 127.0);\n" \ + "float startmap = (15.0 - lightnum) * 4.0;\n" \ + "float scale = 160.0 / (lightz + 1.0);\n" \ + "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" \ + "{\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_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" \ + "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" \ + "}\n" \ + "#endif\0" + +// hand tuned adjustments for light level calculation +#define GLSL_FLOOR_FUDGES \ + "#define STARTMAP_FUDGE 1.06\n" \ + "#define SCALE_FUDGE 1.15\n" + +#define GLSL_WALL_FUDGES \ + "#define STARTMAP_FUDGE 1.05\n" \ + "#define SCALE_FUDGE 2.2\n" + +#define GLSL_FLOOR_FRAGMENT_SHADER \ + GLSL_FLOOR_FUDGES \ + GLSL_SOFTWARE_FRAGMENT_SHADER + +#define GLSL_WALL_FRAGMENT_SHADER \ + GLSL_WALL_FUDGES \ + GLSL_SOFTWARE_FRAGMENT_SHADER + +// +// Water surface shader +// +// Mostly guesstimated, rather than the rest being built off Software science. +// Still needs to distort things underneath/around the water... +// + +#define GLSL_WATER_TEXEL \ + "float water_z = (gl_FragCoord.z / gl_FragCoord.w) / 2.0;\n" \ + "float a = -pi * (water_z * freq) + (leveltime * speed);\n" \ + "float sdistort = sin(a) * amp;\n" \ + "float cdistort = cos(a) * amp;\n" \ + "vec4 texel = texture2D(tex, vec2(gl_TexCoord[0].s - sdistort, gl_TexCoord[0].t - cdistort));\n" + +#define GLSL_WATER_FRAGMENT_SHADER \ + 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" \ + "uniform vec4 fade_color;\n" \ + "uniform float lighting;\n" \ + "uniform float fade_start;\n" \ + "uniform float fade_end;\n" \ + "uniform float leveltime;\n" \ + GLSL_DOOM_COLORMAP \ + GLSL_DOOM_LIGHT_EQUATION \ + "void main(void) {\n" \ + GLSL_WATER_TEXEL \ + "vec4 base_color = texel * poly_color;\n" \ + "vec4 final_color = base_color;\n" \ + GLSL_SOFTWARE_TINT_EQUATION \ + GLSL_SOFTWARE_FADE_EQUATION \ + "final_color.a = texel.a * poly_color.a;\n" \ + "gl_FragColor = final_color;\n" \ + "}\n" \ + "#endif\0" + +// +// Fog block shader +// +// Alpha of the planes themselves are still slightly off -- see HWR_FogBlockAlpha +// + +// The floor fudges are used, but should the wall fudges be used instead? or something inbetween? +// or separate values for floors and walls? (need to change more than this shader for that) +#define GLSL_FOG_FRAGMENT_SHADER \ + GLSL_FLOOR_FUDGES \ + "uniform vec4 tint_color;\n" \ + "uniform vec4 fade_color;\n" \ + "uniform float lighting;\n" \ + "uniform float fade_start;\n" \ + "uniform float fade_end;\n" \ + GLSL_DOOM_COLORMAP \ + GLSL_DOOM_LIGHT_EQUATION \ + "void main(void) {\n" \ + "vec4 base_color = gl_Color;\n" \ + "vec4 final_color = base_color;\n" \ + GLSL_SOFTWARE_TINT_EQUATION \ + GLSL_SOFTWARE_FADE_EQUATION \ + "gl_FragColor = final_color;\n" \ + "}\0" + +// +// Sky fragment shader +// Modulates poly_color with gl_Color +// +#define GLSL_SKY_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "void main(void) {\n" \ + "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * gl_Color * poly_color;\n" \ + "}\0" + +// Shader for the palette rendering postprocess step +#define GLSL_PALETTE_POSTPROCESS_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform sampler3D palette_lookup_tex;\n" \ + "uniform sampler1D palette_tex;\n" \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + "float tex_pal_idx = texture3D(palette_lookup_tex, vec3((texel * 63.0 + 0.5) / 64.0))[0] * 255.0;\n" \ + "float palette_coord = (tex_pal_idx + 0.5) / 256.0;\n" \ + "vec4 final_color = texture1D(palette_tex, palette_coord);\n" \ + "gl_FragColor = final_color;\n" \ + "}\0" + +// Applies a palettized colormap fade to tex +#define GLSL_UI_COLORMAP_FADE_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform float lighting;\n" \ + "uniform sampler3D palette_lookup_tex;\n" \ + "uniform sampler2D lighttable_tex;\n" \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + "float tex_pal_idx = texture3D(palette_lookup_tex, vec3((texel * 63.0 + 0.5) / 64.0))[0] * 255.0;\n" \ + "vec2 lighttable_coord = vec2((tex_pal_idx + 0.5) / 256.0, (lighting + 0.5) / 32.0);\n" \ + "gl_FragColor = texture2D(lighttable_tex, lighttable_coord);\n" \ + "}\0" \ + +// ================ +// Fallback shaders +// ================ + +// +// Generic vertex shader +// + +#define GLSL_FALLBACK_VERTEX_SHADER \ + "void main()\n" \ + "{\n" \ + "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \ + "gl_FrontColor = gl_Color;\n" \ + "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \ + "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ + "}\0" + +// +// Generic fragment shader +// + +#define GLSL_FALLBACK_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "void main(void) {\n" \ + "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \ + "}\0" + +#endif diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 6a17f6524..ae3ba5c49 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -31,9 +31,9 @@ #include "../../i_system.h" // for I_GetPreciseTime (batching time measurements) #include "../hw_main.h" +#include "../hw_batching.h" -// Eeeeh not sure is this right way, but it works < sry :c -extern consvar_t cv_grusecustomshaders; +// Eeeeh not sure is this right way, but it works < sry :c < sry again it had to go :c extern fixed_t fovtan; // also extremely bad, I'm just too lazy!!! @@ -78,10 +78,7 @@ static float NEAR_CLIPPING_PLANE = NZCLIP_PLANE; // ************************************************************************** static GLuint tex_downloaded = 0; -// these didnt work with karts batching system, hope this is not an issue -//static GLuint lt_downloaded = 0; // currently bound lighttable texture - currentSurfaceInfo -//static GLuint lt_downloaded2 = 0; // currently bound lighttable texture - nextSurfaceInfo -//static GLuint lt_downloaded3 = 0; // currently bound lighttable texture - pSurf +static GLuint lt_downloaded = 0; // currently bound lighttable texture static GLfloat fov = 90.0f; static FBITFIELD CurrentPolyFlags; @@ -126,14 +123,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; - -// Lactozilla: Set shader programs and uniforms -static void *Shader_Load(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); -static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); +static GLuint screenTextures[NUMSCREENTEXTURES] = {0}; // shortcut for ((float)1/i) static const GLfloat byte2float[256] = { @@ -569,7 +559,7 @@ boolean SetupGLfunc(void) GETOPENGLFUNC(pglTexParameteri, glTexParameteri) GETOPENGLFUNC(pglTexImage1D, glTexImage1D) GETOPENGLFUNC(pglTexImage2D, glTexImage2D) - GETOPENGLFUNC(pglTexSubImage2D , glTexSubImage2D) + GETOPENGLFUNC(pglTexSubImage2D, glTexSubImage2D) GETOPENGLFUNC(pglGenTextures, glGenTextures) GETOPENGLFUNC(pglDeleteTextures, glDeleteTextures) @@ -597,6 +587,7 @@ typedef void (APIENTRY *PFNglGetShaderiv) (GLuint, GLenum, GLint*); typedef void (APIENTRY *PFNglGetShaderInfoLog) (GLuint, GLsizei, GLsizei*, GLchar*); typedef void (APIENTRY *PFNglDeleteShader) (GLuint); typedef GLuint (APIENTRY *PFNglCreateProgram) (void); +typedef void (APIENTRY *PFNglDeleteProgram) (GLuint); typedef void (APIENTRY *PFNglAttachShader) (GLuint, GLuint); typedef void (APIENTRY *PFNglLinkProgram) (GLuint); typedef void (APIENTRY *PFNglGetProgramiv) (GLuint, GLenum, GLint*); @@ -618,6 +609,7 @@ static PFNglGetShaderiv pglGetShaderiv; static PFNglGetShaderInfoLog pglGetShaderInfoLog; static PFNglDeleteShader pglDeleteShader; static PFNglCreateProgram pglCreateProgram; +static PFNglDeleteProgram pglDeleteProgram; static PFNglAttachShader pglAttachShader; static PFNglLinkProgram pglLinkProgram; static PFNglGetProgramiv pglGetProgramiv; @@ -632,19 +624,9 @@ static PFNglUniform2fv pglUniform2fv; static PFNglUniform3fv pglUniform3fv; static PFNglGetUniformLocation pglGetUniformLocation; -#define MAXSHADERS 16 -#define MAXSHADERPROGRAMS 16 - // 18032019 -static char *gl_customvertexshaders[MAXSHADERS]; -static char *gl_customfragmentshaders[MAXSHADERS]; - -static boolean gl_allowshaders = false; static boolean gl_shadersenabled = false; -static GLuint gl_currentshaderprogram = 0; -static boolean gl_shaderprogramchanged = true; - -static boolean gl_batching = false;// are we currently collecting batches? +static INT32 gl_allowshaders = 0; static INT32 gl_enable_screen_textures = 1; @@ -674,318 +656,41 @@ typedef enum gluniform_max, } gluniform_t; -typedef struct gl_shaderprogram_s +typedef struct gl_shader_s { + char *vertex_shader; + char *fragment_shader; GLuint program; - boolean custom; GLint uniforms[gluniform_max+1]; -} gl_shaderprogram_t; -static gl_shaderprogram_t gl_shaderprograms[MAXSHADERPROGRAMS]; +} gl_shader_t; + +static gl_shader_t gl_shaders[HWR_MAXSHADERS]; +static gl_shader_t gl_fallback_shader; + +// 09102020 +typedef struct gl_shaderstate_s +{ + gl_shader_t *current; + GLuint type; + GLuint program; + boolean changed; +} gl_shaderstate_t; +static gl_shaderstate_t gl_shaderstate; // Shader info static float shader_leveltime = 0; -// ======================== -// Fragment shader macros -// ======================== +// Lactozilla: Shader functions +static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i); +static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); + +static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f}; // -// GLSL generic fragment shader +// Generic vertex 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" - -// -// GLSL 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" \ - "float cap = (155.0 - light) * 0.26;\n" \ - "return max(startmap * STARTMAP_FUDGE - scale * 0.5 * SCALE_FUDGE, cap);\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_UNIFORMS \ - "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" - -#define GLSL_SOFTWARE_MAIN \ - "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" \ - "}\n" - -// hand tuned adjustments for light level calculation -// do those even work correctly without the preprocessor? -#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_SOFTWARE_UNIFORMS \ - GLSL_FLOOR_FUDGES \ - GLSL_DOOM_COLORMAP \ - GLSL_DOOM_LIGHT_EQUATION \ - GLSL_SOFTWARE_MAIN \ - "\0" - -#define GLSL_SOFTWARE_FRAGMENT_SHADER_WALLS \ - GLSL_SOFTWARE_UNIFORMS \ - GLSL_WALL_FUDGES \ - GLSL_DOOM_COLORMAP \ - GLSL_DOOM_LIGHT_EQUATION \ - GLSL_SOFTWARE_MAIN \ - "\0" - -#define GLSL_SOFTWARE_PAL_UNIFORMS \ - "uniform sampler2D tex;\n" \ - "uniform sampler3D palette_lookup_tex;\n" \ - "uniform sampler2D lighttable_tex;\n" \ - "uniform vec4 poly_color;\n" \ - "uniform float lighting;\n" \ - -#define GLSL_SOFTWARE_PAL_MAIN \ - "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 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" \ - "}\n" - -#define GLSL_SOFTWARE_PAL_FRAGMENT_SHADER_FLOORS \ - GLSL_SOFTWARE_PAL_UNIFORMS \ - GLSL_FLOOR_FUDGES \ - GLSL_DOOM_COLORMAP \ - GLSL_SOFTWARE_PAL_MAIN \ - "\0" - -#define GLSL_SOFTWARE_PAL_FRAGMENT_SHADER_WALLS \ - GLSL_SOFTWARE_PAL_UNIFORMS \ - GLSL_WALL_FUDGES \ - GLSL_DOOM_COLORMAP \ - GLSL_SOFTWARE_PAL_MAIN \ - "\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 \ - GLSL_FLOOR_FUDGES \ - "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" - -//TODO: make this not a hacky copy of two shaders mixed together -#define GLSL_PALETTE_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" \ - "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" \ - "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" \ - "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" \ - "}\0" - -// -// Fog block shader -// -// Alpha of the planes themselves are still slightly off -- see HWR_FogBlockAlpha -// - -#define GLSL_FOG_FRAGMENT_SHADER \ - GLSL_FLOOR_FUDGES \ - "uniform vec4 tint_color;\n" \ - "uniform vec4 fade_color;\n" \ - "uniform float lighting;\n" \ - "uniform float fade_start;\n" \ - "uniform float fade_end;\n" \ - GLSL_DOOM_COLORMAP \ - GLSL_DOOM_LIGHT_EQUATION \ - "void main(void) {\n" \ - "vec4 base_color = gl_Color;\n" \ - "vec4 final_color = base_color;\n" \ - GLSL_SOFTWARE_TINT_EQUATION \ - GLSL_SOFTWARE_FADE_EQUATION \ - "gl_FragColor = final_color;\n" \ - "}\0" - -// -// Palette color quantization shader -// - -#define GLSL_PALETTE_FRAGMENT_SHADER \ - "uniform sampler2D tex;\n" \ - "uniform sampler3D palette_lookup_tex;\n" \ - "uniform sampler1D palette_tex;\n" \ - "void main(void) {\n" \ - "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ - "float tex_pal_idx = texture3D(palette_lookup_tex, vec3((texel * 63.0 + 0.5) / 64.0))[0] * 255.0;\n" \ - "float palette_coord = (tex_pal_idx + 0.5) / 256.0;\n" \ - "vec4 final_color = texture1D(palette_tex, palette_coord);\n" \ - "gl_FragColor = final_color;\n" \ - "}\0" - -// -// 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" - -static const char *fragment_shaders[] = { - // Default fragment shader - GLSL_DEFAULT_FRAGMENT_SHADER, - - // Floor fragment shader - GLSL_SOFTWARE_FRAGMENT_SHADER_FLOORS, - - // Wall fragment shader - GLSL_SOFTWARE_FRAGMENT_SHADER_WALLS, - - // Sprite fragment shader - GLSL_SOFTWARE_FRAGMENT_SHADER_WALLS, - - // Model fragment shader - GLSL_SOFTWARE_FRAGMENT_SHADER_WALLS, - - // Water fragment shader - GLSL_WATER_FRAGMENT_SHADER, - - // Fog fragment shader - GLSL_FOG_FRAGMENT_SHADER, - - // Sky fragment shader - GLSL_SKY_FRAGMENT_SHADER, - - // Palette fragment shader - GLSL_PALETTE_FRAGMENT_SHADER, - - // Palette floor fudge shader - GLSL_SOFTWARE_PAL_FRAGMENT_SHADER_FLOORS, - - // Palette wall fudge shader - GLSL_SOFTWARE_PAL_FRAGMENT_SHADER_WALLS, - - // Palette water shader - GLSL_PALETTE_WATER_FRAGMENT_SHADER, - - NULL, -}; - -// ====================== -// Vertex shader macros -// ====================== - -// -// GLSL 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" \ @@ -994,45 +699,16 @@ static const char *fragment_shaders[] = { "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ "}\0" -static const char *vertex_shaders[] = { - // Default vertex shader - GLSL_DEFAULT_VERTEX_SHADER, +// +// Generic fragment shader +// - // Floor vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - // Wall vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - // Sprite vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - // Model vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - // Water vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - // Fog vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - // Sky vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - // Palette vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - // Palette floor vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - // Palette wall vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - // Palette water vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - NULL, -}; +#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" #endif // GL_SHADERS @@ -1062,6 +738,7 @@ void SetupGLFunc4(void) pglGetShaderInfoLog = GetGLFunc("glGetShaderInfoLog"); pglDeleteShader = GetGLFunc("glDeleteShader"); pglCreateProgram = GetGLFunc("glCreateProgram"); + pglDeleteProgram = GetGLFunc("glDeleteProgram"); pglAttachShader = GetGLFunc("glAttachShader"); pglLinkProgram = GetGLFunc("glLinkProgram"); pglGetProgramiv = GetGLFunc("glGetProgramiv"); @@ -1085,160 +762,78 @@ void SetupGLFunc4(void) #endif } -// jimita -EXPORT boolean HWRAPI(LoadShaders) (void) +EXPORT boolean HWRAPI(InitShaders) (void) { #ifdef GL_SHADERS - GLuint gl_vertShader, gl_fragShader; - GLint i, result; + if (!pglUseProgram) + return false; - 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_customvertexshaders[0] = NULL; - gl_customfragmentshaders[0] = NULL; - - for (i = 0; vertex_shaders[i] && fragment_shaders[i]; i++) + if (!Shader_CompileProgram(&gl_fallback_shader, -1)) { - gl_shaderprogram_t *shader; - const GLchar* vert_shader = vertex_shaders[i]; - const GLchar* frag_shader = fragment_shaders[i]; - boolean custom = cv_grusecustomshaders.value && ((gl_customvertexshaders[i] || gl_customfragmentshaders[i]) && (i > 0)); - - // 18032019 - if (cv_grusecustomshaders.value && gl_customvertexshaders[i]) - vert_shader = gl_customvertexshaders[i]; - if (cv_grusecustomshaders.value && gl_customfragmentshaders[i]) - frag_shader = gl_customfragmentshaders[i]; - - - if (i >= MAXSHADERS) - break; - if (i >= MAXSHADERPROGRAMS) - break; - - // - // Load and compile vertex shader - // - gl_vertShader = pglCreateShader(GL_VERTEX_SHADER); - if (!gl_vertShader) - { - GL_MSG_Error("LoadShaders: Error creating vertex shader %d\n", i); - continue; - } - - 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) - { - GLchar* infoLog; - GLint logLength; - - pglGetShaderiv(gl_vertShader, GL_INFO_LOG_LENGTH, &logLength); - - infoLog = malloc(logLength); - pglGetShaderInfoLog(gl_vertShader, logLength, NULL, infoLog); - - GL_MSG_Error("LoadShaders: Error compiling vertex shader %d\n%s", i, infoLog); - continue; - } - - // - // Load and compile fragment shader - // - gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER); - if (!gl_fragShader) - { - GL_MSG_Error("LoadShaders: Error creating fragment shader %d\n", i); - continue; - } - - 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) - { - GLchar* infoLog; - GLint logLength; - - pglGetShaderiv(gl_fragShader, GL_INFO_LOG_LENGTH, &logLength); - - infoLog = malloc(logLength); - pglGetShaderInfoLog(gl_fragShader, logLength, NULL, infoLog); - - GL_MSG_Error("LoadShaders: Error compiling fragment shader %d\n%s", i, infoLog); - continue; - } - - shader = &gl_shaderprograms[i]; - shader->program = pglCreateProgram(); - shader->custom = custom; - pglAttachShader(shader->program, gl_vertShader); - 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); - - // couldn't link? - if (result != GL_TRUE) - { - shader->program = 0; - shader->custom = false; - GL_MSG_Error("LoadShaders: Error linking shader program %d\n", i); - continue; - } - - // 13062019 -#define GETUNI(uniform) pglGetUniformLocation(shader->program, uniform); - - // lighting - shader->uniforms[gluniform_poly_color] = GETUNI("poly_color"); - shader->uniforms[gluniform_tint_color] = GETUNI("tint_color"); - shader->uniforms[gluniform_fade_color] = GETUNI("fade_color"); - shader->uniforms[gluniform_lighting] = GETUNI("lighting"); - shader->uniforms[gluniform_fade_start] = GETUNI("fade_start"); - shader->uniforms[gluniform_fade_end] = GETUNI("fade_end"); - - // palette rendering - shader->uniforms[gluniform_palette_tex] = GETUNI("palette_tex"); - shader->uniforms[gluniform_palette_lookup_tex] = GETUNI("palette_lookup_tex"); - shader->uniforms[gluniform_lighttable_tex] = GETUNI("lighttable_tex"); - - // misc. - shader->uniforms[gluniform_leveltime] = GETUNI("leveltime"); -#undef GETUNI - -// set permanent uniform values -#define UNIFORM_1(uniform, a, function) \ - if (uniform != -1) \ - function (uniform, a); - - pglUseProgram(shader->program); - - // texture unit numbers for the samplers used for palette rendering - UNIFORM_1(shader->uniforms[gluniform_palette_tex], 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); - pglUseProgram(gl_currentshaderprogram); - //pglUseProgram(0); // dont remember why this was here in the first place, but seems fine? -#undef UNIFORM_1 + GL_MSG_Error("Failed to compile the fallback shader program!\n"); + return false; } -#endif + return true; +#else + return false; +#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 @@ -1251,7 +846,7 @@ EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value) switch (info) { case HWD_SHADERINFO_LEVELTIME: - shader_leveltime = (((float)(value-1)) + FIXED_TO_FLOAT(rendertimefrac)) / TICRATE; + shader_leveltime = value; break; default: break; @@ -1262,62 +857,31 @@ EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value) #endif } -// -// Custom shader loading -// -EXPORT void HWRAPI(LoadCustomShader) (int number, char *shader, size_t size, boolean fragment) -{ -#ifdef GL_SHADERS - if (!pglUseProgram) - return; - - if (number < 1 || number > MAXSHADERS) - I_Error("LoadCustomShader(): cannot load shader %d (max %d)", number, MAXSHADERS); - - if (fragment) - { - gl_customfragmentshaders[number] = malloc(size+1); - strncpy(gl_customfragmentshaders[number], shader, size); - gl_customfragmentshaders[number][size] = 0; - } - else - { - gl_customvertexshaders[number] = malloc(size+1); - strncpy(gl_customvertexshaders[number], shader, size); - gl_customvertexshaders[number][size] = 0; - } -#else - (void)number; - (void)shader; - (void)size; - (void)fragment; -#endif -} - -EXPORT boolean HWRAPI(InitCustomShaders) (void) -{ -#ifdef GL_SHADERS - KillShaders(); - return LoadShaders(); -#endif -} - - -EXPORT void HWRAPI(SetShader) (int shader) +EXPORT void HWRAPI(SetShader) (int slot) { #ifdef GL_SHADERS if (gl_allowshaders) { - if ((GLuint)shader != gl_currentshaderprogram) + gl_shader_t *next_shader = &gl_shaders[slot]; // the gl_shader_t we are going to switch to + + if (!next_shader->program) + next_shader = &gl_fallback_shader; // unusable shader, use fallback instead + + // update gl_shaderstate if an actual shader switch is needed + if (gl_shaderstate.current != next_shader) { - gl_currentshaderprogram = shader; - gl_shaderprogramchanged = true; + gl_shaderstate.current = next_shader; + gl_shaderstate.program = next_shader->program; + gl_shaderstate.type = slot; + gl_shaderstate.changed = true; } + gl_shadersenabled = true; + return; } #else - (void)shader; + (void)slot; #endif gl_shadersenabled = false; } @@ -1325,17 +889,15 @@ EXPORT void HWRAPI(SetShader) (int shader) EXPORT void HWRAPI(UnSetShader) (void) { #ifdef GL_SHADERS - gl_shadersenabled = false; - gl_currentshaderprogram = 0; - gl_shaderprogramchanged = true;// not sure if this is needed - if (!pglUseProgram) return; - pglUseProgram(0); -#endif -} + gl_shaderstate.current = NULL; + gl_shaderstate.type = 0; + gl_shaderstate.program = 0; -EXPORT void HWRAPI(KillShaders) (void) -{ - // unused......................... + if (pglUseProgram) + pglUseProgram(0); +#endif + + gl_shadersenabled = false; } // -----------------+ @@ -1344,7 +906,7 @@ EXPORT void HWRAPI(KillShaders) (void) static void SetNoTexture(void) { // Disable texture. - if (tex_downloaded != NOTEXTURE_NUM && !gl_batching) + if (tex_downloaded != NOTEXTURE_NUM) { pglBindTexture(GL_TEXTURE_2D, NOTEXTURE_NUM); tex_downloaded = NOTEXTURE_NUM; @@ -1525,58 +1087,40 @@ EXPORT void HWRAPI(ClearMipMapCache) (void) Flush(); } -// -----------------+ -// 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. +EXPORT void HWRAPI(ReadScreenTexture) (int tex, UINT16 *dst_data) { INT32 i; - //GL_DBG_Printf("ReadRect()\n"); - if (dst_stride == width*3) + int dst_stride = screen_width * 3; // stride between rows of image data + GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (screen_height - 1); + GLubyte *row; + row = malloc(dst_stride); + if (!row) return; + // at the time this function is called, generic2 can be found drawn on the framebuffer + // if some other screen texture is needed, draw it to the framebuffer + // and draw generic2 back after reading the framebuffer. + // this hack is for some reason **much** faster than the simple solution of using glGetTexImage. + if (tex != HWD_SCREENTEXTURE_GENERIC2) + DrawScreenTexture(tex, NULL, 0); + 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, 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++) { - 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); + memcpy(row, top, dst_stride); + memcpy(top, bottom, dst_stride); + memcpy(bottom, row, dst_stride); + top += dst_stride; + bottom -= dst_stride; } + free(row); } - // -----------------+ // GClipRect : Defines the 2D hardware clipping window // -----------------+ @@ -2103,43 +1647,32 @@ EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo) } } - -static void *Shader_Load(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade) -{ -#ifdef GL_SHADERS - if (gl_shadersenabled && pglUseProgram) - { - gl_shaderprogram_t *shader = &gl_shaderprograms[gl_currentshaderprogram]; - if (shader->program) - { - if (gl_shaderprogramchanged) - { - pglUseProgram(gl_shaderprograms[gl_currentshaderprogram].program); - gl_shaderprogramchanged = false; - } - Shader_SetUniforms(Surface, poly, tint, fade); - return shader; - } - else - pglUseProgram(0); - } -#else - (void)Surface; - (void)poly; - (void)tint; - (void)fade; -#endif - return NULL; -} - static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade) { #ifdef GL_SHADERS - if (gl_shadersenabled) + gl_shader_t *shader = gl_shaderstate.current; + + if (gl_shadersenabled && (shader != NULL) && pglUseProgram) { - gl_shaderprogram_t *shader = &gl_shaderprograms[gl_currentshaderprogram]; if (!shader->program) + { + pglUseProgram(0); return; + } + + if (gl_shaderstate.changed) + { + pglUseProgram(shader->program); + gl_shaderstate.changed = false; + } + + // Color uniforms can be left NULL and will be set to white (1.0f, 1.0f, 1.0f, 1.0f) + if (poly == NULL) + poly = &shader_defaultcolor; + if (tint == NULL) + tint = &shader_defaultcolor; + if (fade == NULL) + fade = &shader_defaultcolor; #define UNIFORM_1(uniform, a, function) \ if (uniform != -1) \ @@ -2161,13 +1694,15 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF UNIFORM_4(shader->uniforms[gluniform_poly_color], poly->red, poly->green, poly->blue, poly->alpha, pglUniform4f); UNIFORM_4(shader->uniforms[gluniform_tint_color], tint->red, tint->green, tint->blue, tint->alpha, pglUniform4f); UNIFORM_4(shader->uniforms[gluniform_fade_color], fade->red, fade->green, fade->blue, fade->alpha, pglUniform4f); + if (Surface != NULL) { UNIFORM_1(shader->uniforms[gluniform_lighting], Surface->LightInfo.light_level, pglUniform1f); UNIFORM_1(shader->uniforms[gluniform_fade_start], Surface->LightInfo.fade_start, pglUniform1f); UNIFORM_1(shader->uniforms[gluniform_fade_end], Surface->LightInfo.fade_end, pglUniform1f); } - UNIFORM_1(shader->uniforms[gluniform_leveltime], shader_leveltime, pglUniform1f); + + UNIFORM_1(shader->uniforms[gluniform_leveltime], ((float)shader_leveltime) / TICRATE, pglUniform1f); #undef UNIFORM_1 #undef UNIFORM_2 @@ -2182,636 +1717,219 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF #endif } - -// unfinished draw call batching - -// Note: could use realloc in the array reallocation code - -typedef struct +static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i) { - FSurfaceInfo surf;// surf also has its own polyflags for some reason, but it seems unused - unsigned int vertsIndex;// location of verts in unsortedVertexArray - FUINT numVerts; - FBITFIELD polyFlags; - GLuint texNum; - GLuint shader; - // this tells batching that the plane belongs to a horizon line and must be drawn in correct order with the skywalls - boolean horizonSpecial; -} PolygonArrayEntry; + GLuint gl_vertShader = 0; + GLuint gl_fragShader = 0; + GLint result; + const GLchar *vert_shader = shader->vertex_shader; + const GLchar *frag_shader = shader->fragment_shader; -FOutVector* finalVertexArray = NULL;// contains subset of sorted vertices and texture coordinates to be sent to gpu -UINT32* finalVertexIndexArray = NULL;// contains indexes for glDrawElements, taking into account fan->triangles conversion -// NOTE have this alloced as 3x finalVertexArray size -int finalVertexArrayAllocSize = 65536; -//GLubyte* colorArray = NULL;// contains color data to be sent to gpu, if needed -//int colorArrayAllocSize = 65536; -// not gonna use this for now, just sort by color and change state when it changes -// later maybe when using vertex attributes if it's needed + if (shader->program) + pglDeleteProgram(shader->program); -PolygonArrayEntry* polygonArray = NULL;// contains the polygon data from DrawPolygon, waiting to be processed -int polygonArraySize = 0; -UINT32* polygonIndexArray = NULL;// contains sorting pointers for polygonArray -int polygonArrayAllocSize = 65536; - -FOutVector* unsortedVertexArray = NULL;// contains unsorted vertices and texture coordinates from DrawPolygon -int unsortedVertexArraySize = 0; -int unsortedVertexArrayAllocSize = 65536; - -EXPORT void HWRAPI(StartBatching) (void) -{ - //CONS_Printf("StartBatching begin\n"); - // init arrays if that has not been done yet - if (!finalVertexArray) + if (!vert_shader && !frag_shader) { - finalVertexArray = malloc(finalVertexArrayAllocSize * sizeof(FOutVector)); - finalVertexIndexArray = malloc(finalVertexArrayAllocSize * 3 * sizeof(UINT32)); - polygonArray = malloc(polygonArrayAllocSize * sizeof(PolygonArrayEntry)); - polygonIndexArray = malloc(polygonArrayAllocSize * sizeof(UINT32)); - unsortedVertexArray = malloc(unsortedVertexArrayAllocSize * sizeof(FOutVector)); + GL_MSG_Error("Shader_CompileProgram: Missing shaders for shader program %s\n", HWR_GetShaderName(i)); + return false; } - // drawing functions will now collect the drawing data instead of passing it to opengl - gl_batching = true; - //CONS_Printf("StartBatching end\n"); -} -static int comparePolygons(const void *p1, const void *p2) -{ - unsigned int index1 = *(const unsigned int*)p1; - unsigned int index2 = *(const unsigned int*)p2; - PolygonArrayEntry* poly1 = &polygonArray[index1]; - PolygonArrayEntry* poly2 = &polygonArray[index2]; - int diff; - INT64 diff64; + if (vert_shader) + { + // + // 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; + } - int shader1 = poly1->shader; - int shader2 = poly2->shader; - // make skywalls and horizon lines first in order - if (poly1->polyFlags & PF_NoTexture || poly1->horizonSpecial) - shader1 = -1; - if (poly2->polyFlags & PF_NoTexture || poly2->horizonSpecial) - shader2 = -1; - diff = shader1 - shader2; - if (diff != 0) return diff; + pglShaderSource(gl_vertShader, 1, &vert_shader, NULL); + pglCompileShader(gl_vertShader); - // skywalls and horizon lines must retain their order for horizon lines to work - if (shader1 == -1 && shader2 == -1) - return index1 - index2; + // check for compile errors + pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result); + if (result == GL_FALSE) + { + GL_MSG_Error("Error compiling vertex shader", gl_vertShader, i); + pglDeleteShader(gl_vertShader); + return false; + } + } - diff = poly1->texNum - poly2->texNum; - if (diff != 0) return diff; + if (frag_shader) + { + // + // 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); + + // check for compile errors + pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result); + if (result == GL_FALSE) + { + GL_MSG_Error("Error compiling fragment shader", gl_fragShader, i); + pglDeleteShader(gl_vertShader); + pglDeleteShader(gl_fragShader); + return false; + } + } + + shader->program = pglCreateProgram(); + 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 + if (vert_shader) + pglDeleteShader(gl_vertShader); + if (frag_shader) + pglDeleteShader(gl_fragShader); - if (HWR_ShouldUsePaletteRendering()) + // couldn't link? + if (result != GL_TRUE) { - diff = poly1->surf.LightTableId - poly2->surf.LightTableId; - if (diff != 0) return diff; + GL_MSG_Error("Shader_CompileProgram: Error linking shader program %s\n", HWR_GetShaderName(i)); + pglDeleteProgram(shader->program); + return false; } - diff = poly1->polyFlags - poly2->polyFlags; - if (diff != 0) return diff; + // 13062019 +#define GETUNI(uniform) pglGetUniformLocation(shader->program, uniform); - diff64 = poly1->surf.PolyColor.rgba - poly2->surf.PolyColor.rgba; - if (diff64 < 0) return -1; else if (diff64 > 0) return 1; - diff64 = poly1->surf.TintColor.rgba - poly2->surf.TintColor.rgba; - if (diff64 < 0) return -1; else if (diff64 > 0) return 1; - diff64 = poly1->surf.FadeColor.rgba - poly2->surf.FadeColor.rgba; - if (diff64 < 0) return -1; else if (diff64 > 0) return 1; + // lighting + shader->uniforms[gluniform_poly_color] = GETUNI("poly_color"); + shader->uniforms[gluniform_tint_color] = GETUNI("tint_color"); + shader->uniforms[gluniform_fade_color] = GETUNI("fade_color"); + shader->uniforms[gluniform_lighting] = GETUNI("lighting"); + shader->uniforms[gluniform_fade_start] = GETUNI("fade_start"); + shader->uniforms[gluniform_fade_end] = GETUNI("fade_end"); - diff = poly1->surf.LightInfo.light_level - poly2->surf.LightInfo.light_level; - if (diff != 0) return diff; - diff = poly1->surf.LightInfo.fade_start - poly2->surf.LightInfo.fade_start; - if (diff != 0) return diff; - diff = poly1->surf.LightInfo.fade_end - poly2->surf.LightInfo.fade_end; - return diff; + // palette rendering + shader->uniforms[gluniform_palette_tex] = GETUNI("palette_tex"); + shader->uniforms[gluniform_palette_lookup_tex] = GETUNI("palette_lookup_tex"); + shader->uniforms[gluniform_lighttable_tex] = GETUNI("lighttable_tex"); + + // misc. + shader->uniforms[gluniform_leveltime] = GETUNI("leveltime"); +#undef GETUNI + + // set permanent uniform values +#define UNIFORM_1(uniform, a, function) \ + if (uniform != -1) \ + function (uniform, a); + + pglUseProgram(shader->program); + + // texture unit numbers for the samplers used for palette rendering + UNIFORM_1(shader->uniforms[gluniform_palette_tex], 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; } -static int comparePolygonsNoShaders(const void *p1, const void *p2) +// 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) { - unsigned int index1 = *(const unsigned int*)p1; - unsigned int index2 = *(const unsigned int*)p2; - PolygonArrayEntry* poly1 = &polygonArray[index1]; - PolygonArrayEntry* poly2 = &polygonArray[index2]; - int diff; - INT64 diff64; + static GLRGBAFloat poly = {0,0,0,0}; + static GLRGBAFloat tint = {0,0,0,0}; + static GLRGBAFloat fade = {0,0,0,0}; - GLuint texNum1 = poly1->texNum; - GLuint texNum2 = poly2->texNum; - if (poly1->polyFlags & PF_NoTexture || poly1->horizonSpecial) - texNum1 = 0; - if (poly2->polyFlags & PF_NoTexture || poly2->horizonSpecial) - texNum2 = 0; - diff = texNum1 - texNum2; - if (diff != 0) return diff; + SetBlend(PolyFlags); //TODO: inline (#pragma..) - // skywalls and horizon lines must retain their order for horizon lines to work - if (texNum1 == 0 && texNum2 == 0) - return index1 - index2; - - diff = poly1->polyFlags - poly2->polyFlags; - if (diff != 0) return diff; - - diff64 = poly1->surf.PolyColor.rgba - poly2->surf.PolyColor.rgba; - if (diff64 < 0) return -1; else if (diff64 > 0) return 1; - - return 0; -} - -// the parameters for this functions (numPolys etc.) are used to return rendering stats -EXPORT void HWRAPI(RenderBatches) (precise_t *sSortTime, precise_t *sDrawTime, int *sNumPolys, int *sNumVerts, int *sNumCalls, int *sNumShaders, int *sNumTextures, int *sNumPolyFlags, int *sNumColors) -{ - int finalVertexWritePos = 0;// position in finalVertexArray - int finalIndexWritePos = 0;// position in finalVertexIndexArray - - int polygonReadPos = 0;// position in polygonIndexArray - - GLuint currentShader; - GLuint currentTexture; - FBITFIELD currentPolyFlags; - FSurfaceInfo currentSurfaceInfo; - - GLRGBAFloat firstPoly = {0,0,0,0}; // may be misleading but this means first PolyColor - GLRGBAFloat firstTint = {0,0,0,0}; - GLRGBAFloat firstFade = {0,0,0,0}; - - boolean needRebind = false; - - int i; - - //CONS_Printf("RenderBatches\n"); - gl_batching = false;// no longer collecting batches - if (!polygonArraySize) + // PolyColor + if (pSurf) { - *sSortTime = *sDrawTime = *sNumPolys = *sNumCalls = *sNumShaders = *sNumTextures = *sNumPolyFlags = *sNumColors = 0; - return;// nothing to draw - } - // init stats vars - *sNumPolys = polygonArraySize; - *sNumCalls = *sNumVerts = 0; - *sNumShaders = *sNumTextures = *sNumPolyFlags = *sNumColors = 1; - // init polygonIndexArray - for (i = 0; i < polygonArraySize; i++) - { - polygonIndexArray[i] = i; - } + // If Modulated, mix the surface colour to the texture + if (CurrentPolyFlags & PF_Modulated) + { + // Poly color + poly.red = byte2float[pSurf->PolyColor.s.red]; + poly.green = byte2float[pSurf->PolyColor.s.green]; + poly.blue = byte2float[pSurf->PolyColor.s.blue]; + poly.alpha = byte2float[pSurf->PolyColor.s.alpha]; - // sort polygons - //CONS_Printf("qsort polys\n"); - *sSortTime = I_GetPreciseTime(); - if (gl_allowshaders) - qsort(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygons); - else - qsort(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygonsNoShaders); - *sSortTime = I_GetPreciseTime() - *sSortTime; - //CONS_Printf("sort done\n"); - // sort order - // 1. shader - // 2. texture - // 3. polyflags - // 4. colors + light level - // not sure about order of last 2, or if it even matters + pglColor4ubv((GLubyte*)&pSurf->PolyColor.s); + } - *sDrawTime = I_GetPreciseTime(); + // Tint color + tint.red = byte2float[pSurf->TintColor.s.red]; + tint.green = byte2float[pSurf->TintColor.s.green]; + tint.blue = byte2float[pSurf->TintColor.s.blue]; + tint.alpha = byte2float[pSurf->TintColor.s.alpha]; - currentShader = polygonArray[polygonIndexArray[0]].shader; - currentTexture = polygonArray[polygonIndexArray[0]].texNum; - currentPolyFlags = polygonArray[polygonIndexArray[0]].polyFlags; - currentSurfaceInfo = polygonArray[polygonIndexArray[0]].surf; - // For now, will sort and track the colors. Vertex attributes could be used instead of uniforms - // and a color array could replace the color calls. - - // set state for first batch - //CONS_Printf("set first state\n"); - gl_currentshaderprogram = currentShader; - gl_shaderprogramchanged = true; - if (currentPolyFlags & PF_Modulated) - { - // Poly color - firstPoly.red = byte2float[currentSurfaceInfo.PolyColor.s.red]; - firstPoly.green = byte2float[currentSurfaceInfo.PolyColor.s.green]; - firstPoly.blue = byte2float[currentSurfaceInfo.PolyColor.s.blue]; - firstPoly.alpha = byte2float[currentSurfaceInfo.PolyColor.s.alpha]; - pglColor4ubv((GLubyte*)¤tSurfaceInfo.PolyColor.s); - } - // Tint color - firstTint.red = byte2float[currentSurfaceInfo.TintColor.s.red]; - firstTint.green = byte2float[currentSurfaceInfo.TintColor.s.green]; - firstTint.blue = byte2float[currentSurfaceInfo.TintColor.s.blue]; - firstTint.alpha = byte2float[currentSurfaceInfo.TintColor.s.alpha]; - // Fade color - firstFade.red = byte2float[currentSurfaceInfo.FadeColor.s.red]; - firstFade.green = byte2float[currentSurfaceInfo.FadeColor.s.green]; - firstFade.blue = byte2float[currentSurfaceInfo.FadeColor.s.blue]; - firstFade.alpha = byte2float[currentSurfaceInfo.FadeColor.s.alpha]; - - if (gl_allowshaders) - { - Shader_Load(¤tSurfaceInfo, &firstPoly, &firstTint, &firstFade); + // Fade color + fade.red = byte2float[pSurf->FadeColor.s.red]; + fade.green = byte2float[pSurf->FadeColor.s.green]; + fade.blue = byte2float[pSurf->FadeColor.s.blue]; + fade.alpha = byte2float[pSurf->FadeColor.s.alpha]; - //if (currentSurfaceInfo.LightTableId && currentSurfaceInfo.LightTableId != lt_downloaded) - if (HWR_ShouldUsePaletteRendering()) + if (pSurf->LightTableId && pSurf->LightTableId != lt_downloaded) { pglActiveTexture(GL_TEXTURE2); - pglBindTexture(GL_TEXTURE_2D, currentSurfaceInfo.LightTableId); + pglBindTexture(GL_TEXTURE_2D, pSurf->LightTableId); pglActiveTexture(GL_TEXTURE0); - //lt_downloaded = currentSurfaceInfo.LightTableId; + lt_downloaded = pSurf->LightTableId; } } - if (currentPolyFlags & PF_NoTexture) - currentTexture = 0; - pglBindTexture(GL_TEXTURE_2D, currentTexture); - tex_downloaded = currentTexture; - - SetBlend(currentPolyFlags); - - //CONS_Printf("first pointers to ogl\n"); - pglVertexPointer(3, GL_FLOAT, sizeof(FOutVector), &finalVertexArray[0].x); - pglTexCoordPointer(2, GL_FLOAT, sizeof(FOutVector), &finalVertexArray[0].s); - - while (1)// note: remember handling notexture polyflag as having texture number 0 (also in comparePolygons) - { - int firstIndex; - int lastIndex; - - boolean stopFlag = false; - boolean changeState = false; - boolean changeShader = false; - GLuint nextShader = 0U; - boolean changeTexture = false; - GLuint nextTexture = 0U; - boolean changePolyFlags = false; - FBITFIELD nextPolyFlags = 0U; - boolean changeSurfaceInfo = false; - FSurfaceInfo nextSurfaceInfo; - - //CONS_Printf("loop iter start\n"); - // new try: - // write vertices - // check for changes or end, otherwise go back to writing - // changes will affect the next vars and the change bools - // end could set flag for stopping - // execute draw call - // could check ending flag here - // change states according to next vars and change bools, updating the current vars and reseting the bools - // reset write pos - // repeat loop - - int index = polygonIndexArray[polygonReadPos++]; - int numVerts = polygonArray[index].numVerts; - // before writing, check if there is enough room - // using 'while' instead of 'if' here makes sure that there will *always* be enough room. - // probably never will this loop run more than once though - while (finalVertexWritePos + numVerts > finalVertexArrayAllocSize) - { - FOutVector* new_array; - unsigned int* new_index_array; - //CONS_Printf("final vert realloc\n"); - finalVertexArrayAllocSize *= 2; - new_array = malloc(finalVertexArrayAllocSize * sizeof(FOutVector)); - memcpy(new_array, finalVertexArray, finalVertexWritePos * sizeof(FOutVector)); - free(finalVertexArray); - finalVertexArray = new_array; - // also increase size of index array, 3x of vertex array since - // going from fans to triangles increases vertex count to 3x - new_index_array = malloc(finalVertexArrayAllocSize * 3 * sizeof(UINT32)); - memcpy(new_index_array, finalVertexIndexArray, finalIndexWritePos * sizeof(UINT32)); - free(finalVertexIndexArray); - finalVertexIndexArray = new_index_array; - // if vertex buffers are reallocated then opengl needs to know too - needRebind = true; - } - //CONS_Printf("write verts to final\n"); - // write the vertices of the polygon - memcpy(&finalVertexArray[finalVertexWritePos], &unsortedVertexArray[polygonArray[index].vertsIndex], - numVerts * sizeof(FOutVector)); - // write the indexes, pointing to the fan vertexes but in triangles format - firstIndex = finalVertexWritePos; - lastIndex = finalVertexWritePos + numVerts; - finalVertexWritePos += 2; - //CONS_Printf("write final vert indices\n"); - while (finalVertexWritePos < lastIndex) - { - finalVertexIndexArray[finalIndexWritePos++] = firstIndex; - finalVertexIndexArray[finalIndexWritePos++] = finalVertexWritePos - 1; - finalVertexIndexArray[finalIndexWritePos++] = finalVertexWritePos++; - } - - if (polygonReadPos >= polygonArraySize) - { - stopFlag = true; - } - else - { - //CONS_Printf("state change check\n"); - // check if a state change is required, set the change bools and next vars - int nextIndex = polygonIndexArray[polygonReadPos]; - nextShader = polygonArray[nextIndex].shader; - nextTexture = polygonArray[nextIndex].texNum; - nextPolyFlags = polygonArray[nextIndex].polyFlags; - nextSurfaceInfo = polygonArray[nextIndex].surf; - if (nextPolyFlags & PF_NoTexture) - nextTexture = 0; - if (currentShader != nextShader) - { - changeState = true; - changeShader = true; - } - if (currentTexture != nextTexture) - { - changeState = true; - changeTexture = true; - } - if (currentPolyFlags != nextPolyFlags) - { - changeState = true; - changePolyFlags = true; - } - if (gl_allowshaders && HWR_ShouldUsePaletteRendering()) - { - if (currentSurfaceInfo.PolyColor.rgba != nextSurfaceInfo.PolyColor.rgba || - currentSurfaceInfo.TintColor.rgba != nextSurfaceInfo.TintColor.rgba || - currentSurfaceInfo.FadeColor.rgba != nextSurfaceInfo.FadeColor.rgba || - currentSurfaceInfo.LightInfo.light_level != nextSurfaceInfo.LightInfo.light_level || - currentSurfaceInfo.LightInfo.fade_start != nextSurfaceInfo.LightInfo.fade_start || - currentSurfaceInfo.LightInfo.fade_end != nextSurfaceInfo.LightInfo.fade_end || - currentSurfaceInfo.LightTableId != nextSurfaceInfo.LightTableId) - { - changeState = true; - changeSurfaceInfo = true; - } - } - else if ((gl_allowshaders) && (!HWR_ShouldUsePaletteRendering())) - { - if (currentSurfaceInfo.PolyColor.rgba != nextSurfaceInfo.PolyColor.rgba || - currentSurfaceInfo.TintColor.rgba != nextSurfaceInfo.TintColor.rgba || - currentSurfaceInfo.FadeColor.rgba != nextSurfaceInfo.FadeColor.rgba || - currentSurfaceInfo.LightInfo.light_level != nextSurfaceInfo.LightInfo.light_level || - currentSurfaceInfo.LightInfo.fade_start != nextSurfaceInfo.LightInfo.fade_start || - currentSurfaceInfo.LightInfo.fade_end != nextSurfaceInfo.LightInfo.fade_end) - { - changeState = true; - changeSurfaceInfo = true; - } - } - else - { - if (currentSurfaceInfo.PolyColor.rgba != nextSurfaceInfo.PolyColor.rgba) - { - changeState = true; - changeSurfaceInfo = true; - } - } - } - - if (changeState || stopFlag) - { - if (needRebind) - { - //CONS_Printf("rebind\n"); - pglVertexPointer(3, GL_FLOAT, sizeof(FOutVector), &finalVertexArray[0].x); - pglTexCoordPointer(2, GL_FLOAT, sizeof(FOutVector), &finalVertexArray[0].s); - needRebind = false; - } - //CONS_Printf("exec draw call\n"); - // execute draw call - pglDrawElements(GL_TRIANGLES, finalIndexWritePos, GL_UNSIGNED_INT, finalVertexIndexArray); - //CONS_Printf("draw call done\n"); - // update stats - (*sNumCalls)++; - *sNumVerts += finalIndexWritePos; - // reset write positions - finalVertexWritePos = 0; - finalIndexWritePos = 0; - } - else continue; - - // if we're here then either its time to stop or time to change state - if (stopFlag) break; - - //CONS_Printf("state change\n"); - - // change state according to change bools and next vars, update current vars and reset bools - if (changeShader) - { - GLRGBAFloat poly = {0,0,0,0}; - GLRGBAFloat tint = {0,0,0,0}; - GLRGBAFloat fade = {0,0,0,0}; - gl_currentshaderprogram = nextShader; - gl_shaderprogramchanged = true; - if (nextPolyFlags & PF_Modulated) - { - // Poly color - poly.red = byte2float[nextSurfaceInfo.PolyColor.s.red]; - poly.green = byte2float[nextSurfaceInfo.PolyColor.s.green]; - poly.blue = byte2float[nextSurfaceInfo.PolyColor.s.blue]; - poly.alpha = byte2float[nextSurfaceInfo.PolyColor.s.alpha]; - } - // Tint color - tint.red = byte2float[nextSurfaceInfo.TintColor.s.red]; - tint.green = byte2float[nextSurfaceInfo.TintColor.s.green]; - tint.blue = byte2float[nextSurfaceInfo.TintColor.s.blue]; - tint.alpha = byte2float[nextSurfaceInfo.TintColor.s.alpha]; - // Fade color - fade.red = byte2float[nextSurfaceInfo.FadeColor.s.red]; - fade.green = byte2float[nextSurfaceInfo.FadeColor.s.green]; - fade.blue = byte2float[nextSurfaceInfo.FadeColor.s.blue]; - fade.alpha = byte2float[nextSurfaceInfo.FadeColor.s.alpha]; - - Shader_Load(&nextSurfaceInfo, &poly, &tint, &fade); - - currentShader = nextShader; - changeShader = false; - - (*sNumShaders)++; - } - if (changeTexture) - { - // texture should be already ready for use from calls to SetTexture during batch collection - pglBindTexture(GL_TEXTURE_2D, nextTexture); - tex_downloaded = nextTexture; - currentTexture = nextTexture; - changeTexture = false; - - (*sNumTextures)++; - } - if (changePolyFlags) - { - SetBlend(nextPolyFlags); - currentPolyFlags = nextPolyFlags; - changePolyFlags = false; - - (*sNumPolyFlags)++; - } - if (changeSurfaceInfo) - { - GLRGBAFloat poly = {0,0,0,0}; - GLRGBAFloat tint = {0,0,0,0}; - GLRGBAFloat fade = {0,0,0,0}; - gl_shaderprogramchanged = false; - if (nextPolyFlags & PF_Modulated) - { - // Poly color - poly.red = byte2float[nextSurfaceInfo.PolyColor.s.red]; - poly.green = byte2float[nextSurfaceInfo.PolyColor.s.green]; - poly.blue = byte2float[nextSurfaceInfo.PolyColor.s.blue]; - poly.alpha = byte2float[nextSurfaceInfo.PolyColor.s.alpha]; - pglColor4ubv((GLubyte*)&nextSurfaceInfo.PolyColor.s); - } - if (gl_allowshaders) - { - // Tint color - tint.red = byte2float[nextSurfaceInfo.TintColor.s.red]; - tint.green = byte2float[nextSurfaceInfo.TintColor.s.green]; - tint.blue = byte2float[nextSurfaceInfo.TintColor.s.blue]; - tint.alpha = byte2float[nextSurfaceInfo.TintColor.s.alpha]; - // Fade color - fade.red = byte2float[nextSurfaceInfo.FadeColor.s.red]; - fade.green = byte2float[nextSurfaceInfo.FadeColor.s.green]; - fade.blue = byte2float[nextSurfaceInfo.FadeColor.s.blue]; - fade.alpha = byte2float[nextSurfaceInfo.FadeColor.s.alpha]; - - Shader_Load(&nextSurfaceInfo, &poly, &tint, &fade); - - //if (nextSurfaceInfo.LightTableId && nextSurfaceInfo.LightTableId != lt_downloaded2) - if (HWR_ShouldUsePaletteRendering()) - { - pglActiveTexture(GL_TEXTURE2); - pglBindTexture(GL_TEXTURE_2D, nextSurfaceInfo.LightTableId); - pglActiveTexture(GL_TEXTURE0); - //lt_downloaded2 = nextSurfaceInfo.LightTableId; - } - } - - currentSurfaceInfo = nextSurfaceInfo; - changeSurfaceInfo = false; - - (*sNumColors)++; - } - // and that should be it? - } - // reset the arrays (set sizes to 0) - polygonArraySize = 0; - unsortedVertexArraySize = 0; - - *sDrawTime = I_GetPreciseTime() - *sDrawTime; + Shader_SetUniforms(pSurf, &poly, &tint, &fade); } // -----------------+ // DrawPolygon : Render a polygon, set the texture, set render mode // -----------------+ -EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, boolean horizonSpecial) +EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags) { - if (gl_batching) - { - //CONS_Printf("Batched DrawPolygon\n"); - if (!pSurf) - I_Error("Got a null FSurfaceInfo in batching");// nulls should only come in sky background pic drawing - if (polygonArraySize == polygonArrayAllocSize) - { - PolygonArrayEntry* new_array; - // ran out of space, make new array double the size - polygonArrayAllocSize *= 2; - new_array = malloc(polygonArrayAllocSize * sizeof(PolygonArrayEntry)); - memcpy(new_array, polygonArray, polygonArraySize * sizeof(PolygonArrayEntry)); - free(polygonArray); - polygonArray = new_array; - // also need to redo the index array, dont need to copy it though - free(polygonIndexArray); - polygonIndexArray = malloc(polygonArrayAllocSize * sizeof(unsigned int)); - } + PreparePolygon(pSurf, pOutVerts, PolyFlags); - while (unsortedVertexArraySize + (int)iNumPts > unsortedVertexArrayAllocSize) - { - FOutVector* new_array; - // need more space for vertices in unsortedVertexArray - unsortedVertexArrayAllocSize *= 2; - new_array = malloc(unsortedVertexArrayAllocSize * sizeof(FOutVector)); - memcpy(new_array, unsortedVertexArray, unsortedVertexArraySize * sizeof(FOutVector)); - free(unsortedVertexArray); - unsortedVertexArray = new_array; - } + pglVertexPointer(3, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].x); + pglTexCoordPointer(2, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].s); + pglDrawArrays(GL_TRIANGLE_FAN, 0, iNumPts); - // add the polygon data to the arrays + if (PolyFlags & PF_RemoveYWrap) + pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - polygonArray[polygonArraySize].surf = *pSurf; - polygonArray[polygonArraySize].vertsIndex = unsortedVertexArraySize; - polygonArray[polygonArraySize].numVerts = iNumPts; - polygonArray[polygonArraySize].polyFlags = PolyFlags; - polygonArray[polygonArraySize].texNum = tex_downloaded; - polygonArray[polygonArraySize].shader = gl_currentshaderprogram; - polygonArray[polygonArraySize].horizonSpecial = horizonSpecial; - polygonArraySize++; + if (PolyFlags & PF_ForceWrapX) + Clamp2D(GL_TEXTURE_WRAP_S); - memcpy(&unsortedVertexArray[unsortedVertexArraySize], pOutVerts, iNumPts * sizeof(FOutVector)); - unsortedVertexArraySize += iNumPts; - } - else - { - static GLRGBAFloat poly = {0,0,0,0}; - static GLRGBAFloat tint = {0,0,0,0}; - static GLRGBAFloat fade = {0,0,0,0}; + if (PolyFlags & PF_ForceWrapY) + Clamp2D(GL_TEXTURE_WRAP_T); +} - SetBlend(PolyFlags); //TODO: inline (#pragma..) +EXPORT void HWRAPI(DrawIndexedTriangles) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, unsigned int *IndexArray) +{ + PreparePolygon(pSurf, pOutVerts, PolyFlags); - if (gl_portal_mode == HWD_PORTAL_NORMAL) - { - // PolyColor - if (pSurf) - { - // If modulated, mix the surface colour to the texture - if (CurrentPolyFlags & PF_Modulated) - pglColor4ubv((GLubyte*)&pSurf->PolyColor.s); + pglVertexPointer(3, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].x); + pglTexCoordPointer(2, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].s); + pglDrawElements(GL_TRIANGLES, iNumPts, GL_UNSIGNED_INT, IndexArray); - // If the surface is either modulated or colormapped, or both - if (CurrentPolyFlags & (PF_Modulated | PF_ColorMapped)) - { - poly.red = byte2float[pSurf->PolyColor.s.red]; - poly.green = byte2float[pSurf->PolyColor.s.green]; - poly.blue = byte2float[pSurf->PolyColor.s.blue]; - poly.alpha = byte2float[pSurf->PolyColor.s.alpha]; - } - - // Only if the surface is colormapped - if (CurrentPolyFlags & PF_ColorMapped) - { - tint.red = byte2float[pSurf->TintColor.s.red]; - tint.green = byte2float[pSurf->TintColor.s.green]; - tint.blue = byte2float[pSurf->TintColor.s.blue]; - tint.alpha = byte2float[pSurf->TintColor.s.alpha]; - - fade.red = byte2float[pSurf->FadeColor.s.red]; - 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_downloaded3) - if (HWR_ShouldUsePaletteRendering()) - { - pglActiveTexture(GL_TEXTURE2); - pglBindTexture(GL_TEXTURE_2D, pSurf->LightTableId); - pglActiveTexture(GL_TEXTURE0); - //lt_downloaded3 = pSurf->LightTableId; - } - } - } - - Shader_Load(pSurf, &poly, &tint, &fade); - } - else - UnSetShader(); - - pglVertexPointer(3, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].x); - pglTexCoordPointer(2, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].s); - pglDrawArrays(GL_TRIANGLE_FAN, 0, iNumPts); - - if (PolyFlags & PF_RemoveYWrap) - pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - - if (PolyFlags & PF_ForceWrapX) - Clamp2D(GL_TEXTURE_WRAP_S); - - if (PolyFlags & PF_ForceWrapY) - Clamp2D(GL_TEXTURE_WRAP_T); - } + // the DrawPolygon variant of this has some code about polyflags and wrapping here but havent noticed any problems from omitting it? } // Sky dome code, taken/backported from SRB2 @@ -3124,15 +2242,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value) switch (IdState) { case HWD_SET_SHADERS: - switch (Value) - { - case 1: - gl_allowshaders = true; - break; - default: - gl_allowshaders = false; - break; - } + gl_allowshaders = Value; break; case HWD_SET_TEXTUREFILTERMODE: @@ -3550,8 +2660,16 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float fade.green = byte2float[Surface->FadeColor.s.green]; fade.blue = byte2float[Surface->FadeColor.s.blue]; fade.alpha = byte2float[Surface->FadeColor.s.alpha]; + + if (Surface->LightTableId && Surface->LightTableId != lt_downloaded) + { + pglActiveTexture(GL_TEXTURE2); + pglBindTexture(GL_TEXTURE_2D, Surface->LightTableId); + pglActiveTexture(GL_TEXTURE0); + lt_downloaded = Surface->LightTableId; + } - Shader_Load(Surface, &poly, &tint, &fade); + Shader_SetUniforms(Surface, &poly, &tint, &fade); pglEnable(GL_CULL_FACE); pglEnable(GL_NORMALIZE); @@ -3836,7 +2954,7 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]) 16.0f, 16.0f, 6.0f, 16.0f, -16.0f, 6.0f }; - + if (!gl_enable_screen_textures) return; // look for power of two that is large enough for the screen @@ -3911,77 +3029,13 @@ 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) -{ - INT32 texsize = 512; - boolean firstTime = (startScreenWipe == 0); - - // 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, &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 = 512; - boolean firstTime = (endScreenWipe == 0); - - // 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, &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; -} - -// Draw the last scene under the intermission -EXPORT void HWRAPI(DrawIntermissionBG)(void) +EXPORT void HWRAPI(DrawScreenTexture)(int tex, FSurfaceInfo *surf, FBITFIELD polyflags) { float xfix, yfix; INT32 texsize = 512; @@ -3995,6 +3049,8 @@ EXPORT void HWRAPI(DrawIntermissionBG)(void) }; float fix[8]; + + if (!gl_enable_screen_textures) return; // look for power of two that is large enough for the screen while (texsize < screen_width || texsize < screen_height) @@ -4003,6 +3059,9 @@ EXPORT void HWRAPI(DrawIntermissionBG)(void) xfix = 1/((float)(texsize)/((float)((screen_width)))); yfix = 1/((float)(texsize)/((float)((screen_height)))); + // const float screenVerts[12] + + // float fix[8]; fix[0] = 0.0f; fix[1] = 0.0f; fix[2] = 0.0f; @@ -4013,17 +3072,23 @@ EXPORT void HWRAPI(DrawIntermissionBG)(void) fix[7] = 0.0f; pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - pglBindTexture(GL_TEXTURE_2D, screentexture); - pglColor4ubv(white); + + pglBindTexture(GL_TEXTURE_2D, screenTextures[tex]); + + PreparePolygon(surf, NULL, surf ? polyflags : (PF_NoDepthTest)); + if (!surf) + 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 = 512; float xfix, yfix; @@ -4055,6 +3120,9 @@ EXPORT void HWRAPI(DoScreenWipe)(void) xfix = 1/((float)(texsize)/((float)((screen_width)))); yfix = 1/((float)(texsize)/((float)((screen_height)))); + // const float screenVerts[12] + + // float fix[8]; fix[0] = 0.0f; fix[1] = 0.0f; fix[2] = 0.0f; @@ -4070,7 +3138,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); @@ -4081,7 +3149,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); @@ -4090,6 +3158,8 @@ EXPORT void HWRAPI(DoScreenWipe)(void) pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + // const float defaultST[8] + pglClientActiveTexture(GL_TEXTURE0); pglTexCoordPointer(2, GL_FLOAT, 0, fix); pglVertexPointer(3, GL_FLOAT, 0, screenVerts); @@ -4103,38 +3173,7 @@ EXPORT void HWRAPI(DoScreenWipe)(void) pglActiveTexture(GL_TEXTURE0); pglClientActiveTexture(GL_TEXTURE0); - tex_downloaded = endScreenWipe; -} - -// Create a texture from the screen. -EXPORT void HWRAPI(MakeScreenTexture) (void) -{ - INT32 texsize = 512; - boolean firstTime = (screentexture == 0); - - if (!gl_enable_screen_textures) return; - - // 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); - - 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 = screentexture; + tex_downloaded = screenTextures[wipeEnd]; } EXPORT void HWRAPI(RenderVhsEffect) (fixed_t upbary, fixed_t downbary, UINT8 updistort, UINT8 downdistort, UINT8 barsize) @@ -4161,9 +3200,9 @@ EXPORT void HWRAPI(RenderVhsEffect) (fixed_t upbary, fixed_t downbary, UINT8 upd yfix = 1/((float)(texsize)/((float)((screen_height)))); // Slight fuzziness - MakeScreenTexture(); + MakeScreenTexture(HWD_SCREENTEXTURE_GENERIC1); SetBlend(PF_Modulated|PF_Translucent|PF_NoDepthTest); - pglBindTexture(GL_TEXTURE_2D, screentexture); + //pglBindTexture(GL_TEXTURE_2D, screentexture); for (i = 0; i < 1; i += 2.f/vid.height) { @@ -4185,8 +3224,8 @@ EXPORT void HWRAPI(RenderVhsEffect) (fixed_t upbary, fixed_t downbary, UINT8 upd } // Upward bar - MakeScreenTexture(); - pglBindTexture(GL_TEXTURE_2D, screentexture); + MakeScreenTexture(HWD_SCREENTEXTURE_GENERIC1); + //pglBindTexture(GL_TEXTURE_2D, screentexture); color[0] = color[1] = color[2] = 190; color[3] = 250; pglColor4ubv(color); @@ -4213,8 +3252,8 @@ EXPORT void HWRAPI(RenderVhsEffect) (fixed_t upbary, fixed_t downbary, UINT8 upd pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); // Downward bar - MakeScreenTexture(); - pglBindTexture(GL_TEXTURE_2D, screentexture); + MakeScreenTexture(HWD_SCREENTEXTURE_GENERIC1); + //pglBindTexture(GL_TEXTURE_2D, screentexture); fix[0] = 0.0f; fix[6] = xfix; @@ -4238,11 +3277,12 @@ EXPORT void HWRAPI(RenderVhsEffect) (fixed_t upbary, fixed_t downbary, UINT8 upd pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); } -EXPORT void HWRAPI(MakeScreenFinalTexture) (void) +// Create a texture from the screen. +EXPORT void HWRAPI(MakeScreenTexture) (int tex) { INT32 texsize = 512; - boolean firstTime = (finalScreenTexture == 0); - + boolean firstTime = (screenTextures[tex] == 0); + if (!gl_enable_screen_textures) return; // look for power of two that is large enough for the screen @@ -4251,8 +3291,8 @@ EXPORT void HWRAPI(MakeScreenFinalTexture) (void) // Create screen texture if (firstTime) - pglGenTextures(1, &finalScreenTexture); - pglBindTexture(GL_TEXTURE_2D, finalScreenTexture); + pglGenTextures(1, &screenTextures[tex]); + pglBindTexture(GL_TEXTURE_2D, screenTextures[tex]); if (firstTime) { @@ -4265,10 +3305,10 @@ EXPORT void HWRAPI(MakeScreenFinalTexture) (void) else pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize); - tex_downloaded = finalScreenTexture; + tex_downloaded = screenTextures[tex]; } -EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) +EXPORT void HWRAPI(DrawScreenFinalTexture)(int tex, int width, int height) { float xfix, yfix; float origaspect, newaspect; @@ -4278,7 +3318,7 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) float off[12]; float fix[8]; - + if (!gl_enable_screen_textures) return; // look for power of two that is large enough for the screen @@ -4301,6 +3341,7 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) yoff = newaspect / origaspect; } + // float off[12]; off[0] = -xoff; off[1] = -yoff; off[2] = 1.0f; @@ -4314,6 +3355,7 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) off[10] = -yoff; off[11] = 1.0f; + // float fix[8]; fix[0] = 0.0f; fix[1] = 0.0f; fix[2] = 0.0f; @@ -4328,27 +3370,25 @@ EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height) clearColour.red = clearColour.green = clearColour.blue = 0; clearColour.alpha = 1; ClearBuffer(true, false, false, &clearColour); + SetBlend(PF_NoDepthTest); + pglBindTexture(GL_TEXTURE_2D, screenTextures[tex]); + if (HWR_ShouldUsePaletteRendering()) - SetBlend(PF_NoDepthTest); - - pglBindTexture(GL_TEXTURE_2D, finalScreenTexture); - - if (HWR_ShouldUsePaletteRendering()) // still quite hacky, but the replacement code in i_video didnt work and killed performance instead. somehow need to figure out whats up with that. - pglUseProgram(gl_shaderprograms[8].program); // palette postprocess shader + pglUseProgram(gl_shaders[SHADER_PALETTE_POSTPROCESS].program); // palette postprocess shader pglColor4ubv(white); + pglTexCoordPointer(2, GL_FLOAT, 0, fix); pglVertexPointer(3, GL_FLOAT, 0, off); pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - tex_downloaded = finalScreenTexture; if (HWR_ShouldUsePaletteRendering()) - pglUseProgram(0); -} + UnSetShader(); + tex_downloaded = screenTextures[tex]; +} EXPORT void HWRAPI(SetPaletteLookup)(UINT8 *lut) { @@ -4416,9 +3456,7 @@ EXPORT void HWRAPI(ClearLightTables)(void) LightTablesTail = NULL; // we no longer have a bound light table (if we had one), we just deleted it! - //lt_downloaded = 0; - //lt_downloaded2 = 0; - //lt_downloaded3 = 0; + lt_downloaded = 0; } // This palette is used for the palette rendering postprocessing step. diff --git a/src/hardware/r_opengl/r_opengl.h b/src/hardware/r_opengl/r_opengl.h index 6d11bf4e3..7991e19d2 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/m_menu.c b/src/m_menu.c index a74640600..8b14c651a 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1484,20 +1484,22 @@ static menuitem_t OP_ColorOptionsMenu[] = static menuitem_t OP_ExpOptionsMenu[] = { {IT_HEADER, NULL, "Experimental Options", NULL, 10}, - {IT_STRING | IT_CVAR, NULL, "Weather Interpolation", &cv_precipinterp, 35}, - {IT_STRING | IT_CVAR, NULL, "Less Weather Effects", &cv_lessprecip, 45}, + {IT_STRING | IT_CVAR, NULL, "Weather Interpolation", &cv_precipinterp, 25}, + {IT_STRING | IT_CVAR, NULL, "Less Weather Effects", &cv_lessprecip, 35}, - {IT_STRING | IT_CVAR, NULL, "VHS effect", &cv_vhseffect, 65}, + {IT_STRING | IT_CVAR, NULL, "VHS effect", &cv_vhseffect, 55}, - {IT_STRING | IT_CVAR, NULL, "FFloorclip", &cv_ffloorclip, 85}, - {IT_STRING | IT_CVAR, NULL, "Spriteclip", &cv_spriteclip, 95}, + {IT_STRING | IT_CVAR, NULL, "FFloorclip", &cv_ffloorclip, 75}, + {IT_STRING | IT_CVAR, NULL, "Spriteclip", &cv_spriteclip, 85}, #ifdef HWRENDER {IT_STRING | IT_CVAR, NULL, "Screen Textures", &cv_grscreentextures, 75}, + + {IT_STRING | IT_CVAR, NULL, "Palette Depth", &cv_grpalettedepth, 85}, - {IT_STRING | IT_CVAR, NULL, "Splitwall/Slope texture fix", &cv_splitwallfix, 95}, - {IT_STRING | IT_CVAR, NULL, "Slope midtexture peg fix", &cv_slopepegfix, 105}, - {IT_STRING | IT_CVAR, NULL, "ZFighting fix for fofs", &cv_fofzfightfix, 115}, - {IT_STRING | IT_CVAR, NULL, "FOF wall cutoff for slopes", &cv_grfofcut, 125}, + {IT_STRING | IT_CVAR, NULL, "Splitwall/Slope texture fix", &cv_splitwallfix, 105}, + {IT_STRING | IT_CVAR, NULL, "Slope midtexture peg fix", &cv_slopepegfix, 115}, + {IT_STRING | IT_CVAR, NULL, "ZFighting fix for fofs", &cv_fofzfightfix, 125}, + {IT_STRING | IT_CVAR, NULL, "FOF wall cutoff for slopes", &cv_grfofcut, 135}, #endif }; @@ -1511,7 +1513,8 @@ static const char* OP_ExpTooltips[] = "Hides Sprites which are not visible\npotentially resulting in a performance boost.", #ifdef HWRENDER "Should the game do Screen Textures? Provides a good boost to frames\nat the cost of some visual effects not working when disabled.", - "Fixes issues that resulted in Textures sticking from the\nground sometimes.\nThis may be CPU heavy and result in worse performance in some cases.", + "Change the depth of the Palette in Palette rendering mod\n 16 bits is like software looks ingame\nwhile 24 bits is how software looks in screenshots.", + "Fixes issues that resulted in Textures sticking from the ground sometimes.\n This may be CPU heavy and result in worse performance in some cases.", "Fixes issues that resulted in Textures not being properly skewed\n example: Fences on slopes that didnt show proper.\n This may be CPU heavy and result in worse performance in some cases.", "Fixes issues that resulted in Textures on Floor over Floors\nZFighting heavily.", "Toggle for FOF wall cutoff with slopes.", diff --git a/src/screen.h b/src/screen.h index 64c04dc15..478890c49 100644 --- a/src/screen.h +++ b/src/screen.h @@ -72,11 +72,18 @@ typedef struct viddef_s #ifdef HWRENDER INT32/*fixed_t*/ fsmalldupx, fsmalldupy; INT32/*fixed_t*/ fmeddupx, fmeddupy; + INT32 glstate; #endif } viddef_t; #define VIDWIDTH vid.width #define VIDHEIGHT vid.height +enum +{ + VID_GL_LIBRARY_LOADED = 1, + VID_GL_LIBRARY_ERROR = -1, +}; + // internal additional info for vesa modes only typedef struct { diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj index 813e31a98..e51799314 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj +++ b/src/sdl/Srb2SDL-vc10.vcxproj @@ -218,6 +218,7 @@ + @@ -364,6 +365,7 @@ + diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters index f197a394b..2234d7620 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj.filters +++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters @@ -215,6 +215,9 @@ Hw_Hardware + + + Hw_Hardware Hw_Hardware @@ -617,6 +620,9 @@ Hw_Hardware + + + Hw_Hardware Hw_Hardware diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index bbb5d9df3..64f9b7da9 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -81,11 +81,12 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(SetupGLInfo); GETFUNC(Draw2DLine); GETFUNC(DrawPolygon); + GETFUNC(DrawIndexedTriangles); GETFUNC(SetBlend); GETFUNC(ClearBuffer); GETFUNC(SetTexture); GETFUNC(UpdateTexture); - GETFUNC(ReadRect); + GETFUNC(ReadScreenTexture); GETFUNC(GClipRect); GETFUNC(ClearMipMapCache); GETFUNC(SetSpecialState); @@ -95,28 +96,21 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(SetTransform); GETFUNC(PostImgRedraw); GETFUNC(FlushScreenTextures); - GETFUNC(StartScreenWipe); - GETFUNC(EndScreenWipe); GETFUNC(DoScreenWipe); - GETFUNC(DrawIntermissionBG); + GETFUNC(DrawScreenTexture); GETFUNC(MakeScreenTexture); GETFUNC(RenderVhsEffect); - GETFUNC(MakeScreenFinalTexture); GETFUNC(DrawScreenFinalTexture); GETFUNC(RenderSkyDome); - GETFUNC(LoadShaders); - GETFUNC(KillShaders); + GETFUNC(InitShaders); + GETFUNC(LoadShader); + GETFUNC(CompileShader); GETFUNC(SetShader); GETFUNC(UnSetShader); GETFUNC(SetShaderInfo); - GETFUNC(LoadCustomShader); - GETFUNC(InitCustomShaders); - - GETFUNC(StartBatching); - GETFUNC(RenderBatches); GETFUNC(SetPaletteLookup); GETFUNC(CreateLightTable); diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index d3a7c8ae3..cbe0fac05 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1483,18 +1483,6 @@ 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(8); - HWR_DrawScreenFinalTexture(vid.width, vid.height); - HWD.pfnUnSetShader(); - HWD.pfnSetSpecialState(HWD_SET_SHADERS, 0); - }*/ //for some reason this does not work here,so ill keep it in DrawScreenFinalTexture itself for now - OglSdlFinishUpdate(cv_vidwait.value); } #endif @@ -1799,10 +1787,8 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen) flags |= SDL_WINDOW_BORDERLESS; #ifdef HWRENDER - if (rendermode == render_opengl) - { + if (vid.glstate == VID_GL_LIBRARY_LOADED) flags |= SDL_WINDOW_OPENGL; - } if (msaa) { @@ -1814,12 +1800,12 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen) // Some GPU drivers may give us a 16-bit depth buffer since the // default value for SDL_GL_DEPTH_SIZE is 16. SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); -#endif - + // request stencil buffer. If there are problems on weaker hw the bit count could be reduced // If only something like 1-bit or 2-bit stencil is available on some gpus then should implement limit for maxportals based on that. // 4 bits would be enough for current limit in maxportals (12) SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 4); +#endif // Create a window window = SDL_CreateWindow("SRB2Kart "VERSIONSTRING, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, @@ -1833,7 +1819,8 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen) // Renderer-specific stuff #ifdef HWRENDER - if (rendermode == render_opengl) + if ((rendermode == render_opengl) + && (vid.glstate != VID_GL_LIBRARY_ERROR)) { sdlglcontext = SDL_GL_CreateContext(window); if (sdlglcontext == NULL) @@ -2125,11 +2112,12 @@ void I_StartupGraphics(void) HWD.pfnFinishUpdate = NULL; HWD.pfnDraw2DLine = hwSym("Draw2DLine",NULL); HWD.pfnDrawPolygon = hwSym("DrawPolygon",NULL); + HWD.pfnDrawIndexedTriangles = hwSym("DrawIndexedTriangles",NULL); HWD.pfnSetBlend = hwSym("SetBlend",NULL); HWD.pfnClearBuffer = hwSym("ClearBuffer",NULL); HWD.pfnSetTexture = hwSym("SetTexture",NULL); HWD.pfnUpdateTexture = hwSym("UpdateTexture",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); @@ -2140,36 +2128,32 @@ void I_StartupGraphics(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.pfnDoScreenWipe = hwSym("DoScreenWipe",NULL); - HWD.pfnDrawIntermissionBG=hwSym("DrawIntermissionBG",NULL); + HWD.pfnDrawScreenTexture= hwSym("DrawScreenTexture",NULL); HWD.pfnMakeScreenTexture= hwSym("MakeScreenTexture",NULL); HWD.pfnRenderVhsEffect = hwSym("RenderVhsEffect",NULL); - HWD.pfnMakeScreenFinalTexture=hwSym("MakeScreenFinalTexture",NULL); HWD.pfnDrawScreenFinalTexture=hwSym("DrawScreenFinalTexture",NULL); HWD.pfnRenderSkyDome = hwSym("RenderSkyDome",NULL); - HWD.pfnLoadShaders = hwSym("LoadShaders",NULL); - HWD.pfnKillShaders = hwSym("KillShaders",NULL); - HWD.pfnSetShader = hwSym("SetShader",NULL); - HWD.pfnUnSetShader = hwSym("UnSetShader",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); - HWD.pfnInitCustomShaders = hwSym("InitCustomShaders",NULL); - - HWD.pfnStartBatching = hwSym("StartBatching",NULL); - HWD.pfnRenderBatches = hwSym("RenderBatches",NULL); HWD.pfnSetPaletteLookup = hwSym("SetPaletteLookup",NULL); HWD.pfnCreateLightTable = hwSym("CreateLightTable",NULL); HWD.pfnClearLightTables = hwSym("ClearLightTables",NULL); HWD.pfnSetScreenPalette = hwSym("SetScreenPalette",NULL); - if (!HWD.pfnInit()) // load the OpenGL library + vid.glstate = HWD.pfnInit() ? VID_GL_LIBRARY_LOADED : VID_GL_LIBRARY_ERROR; // let load the OpenGL library + if (vid.glstate == VID_GL_LIBRARY_ERROR) + { rendermode = render_soft; + } } #endif diff --git a/src/w_wad.c b/src/w_wad.c index 4989f497b..76c622999 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -693,18 +693,6 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) return lumpinfo; } -static void W_ReadFileShaders(wadfile_t *wadfile) -{ -#ifdef HWRENDER - if (rendermode == render_opengl) - { - HWR_LoadShaders(numwadfiles - 1, W_FileHasFolders(wadfile)); - } -#else - (void)wadfile; -#endif -} - // Allocate a wadfile, setup the lumpinfo (directory) and // lumpcache, add the wadfile to the current active wadfiles // @@ -838,7 +826,8 @@ UINT16 W_InitFile(const char *filename, const char *lumpname, UINT16 *wadnump, b numwadfiles++; // must come BEFORE W_LoadDehackedLumps, so any addfile called by COM_BufInsertText called by Lua doesn't overwrite what we just loaded // Read shaders from file - W_ReadFileShaders(wadfile); + if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED)) + HWR_LoadCustomShadersFromFile(numwadfiles - 1, (type == RET_PK3)); // 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. switch (wadfile->type)