diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8f6a56235..d2985dc21 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -452,6 +452,7 @@ 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_bsp.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_cache.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_clip.c @@ -467,6 +468,7 @@ if(${SRB2_CONFIG_HWRENDER}) ) set (SRB2_HWRENDER_HEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_batching.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..8af668744 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 endif OPTS += -DCOMPVERSION diff --git a/src/hardware/hw_batching.c b/src/hardware/hw_batching.c new file mode 100644 index 000000000..e3d02c4b4 --- /dev/null +++ b/src/hardware/hw_batching.c @@ -0,0 +1,463 @@ +// 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, 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; + 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, 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, horizonSpecial); + HWR_CollectDrawCallVertices(pOutVerts, iNumPts); + } + else + { + if (shader) + HWD.pfnSetShader(shader); + 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_draw.c b/src/hardware/hw_draw.c index 653157990..f35ee6fde 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); } @@ -576,7 +576,7 @@ void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength) Surf.PolyColor.s.alpha = (UINT8)(strength*25.5f); } - 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); } // Draw the console background with translucency support @@ -603,7 +603,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 +854,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 +963,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 +1081,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 diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 60ea552b2..66ddf3a33 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -32,7 +32,8 @@ 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); @@ -77,9 +78,6 @@ 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); EXPORT void HWRAPI(ClearLightTables)(void); @@ -99,6 +97,7 @@ struct hwdriver_s FinishUpdate pfnFinishUpdate; Draw2DLine pfnDraw2DLine; DrawPolygon pfnDrawPolygon; + DrawIndexedTriangles pfnDrawIndexedTriangles; SetBlend pfnSetBlend; ClearBuffer pfnClearBuffer; SetTexture pfnSetTexture; @@ -133,9 +132,6 @@ struct hwdriver_s LoadCustomShader pfnLoadCustomShader; InitCustomShaders pfnInitCustomShaders; - StartBatching pfnStartBatching; - RenderBatches pfnRenderBatches; - SetPaletteLookup pfnSetPaletteLookup; CreateLightTable pfnCreateLightTable; ClearLightTables pfnClearLightTables; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index f927eb9e3..a7fca8729 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" @@ -649,6 +650,8 @@ void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, boolean isc static FOutVector *planeVerts = NULL; static UINT16 numAllocedPlaneVerts = 0; + + INT32 shader = 0; // no convex poly were generated for this subsector if (!xsub->planepoly) @@ -826,16 +829,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 = 6; // fog shader else if (PolyFlags & PF_Ripple) - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 11 : 5); // water shader + shader = (HWR_ShouldUsePaletteRendering() ? 11 : 5); // water shader else - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 9 : 1); // floor shader + shader = (HWR_ShouldUsePaletteRendering() ? 9 : 1); // floor shader PolyFlags |= PF_ColorMapped; } - HWD.pfnDrawPolygon(&Surf, planeVerts, nrPlaneVerts, PolyFlags, false); + HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, PolyFlags, shader, false); if (subsector) { @@ -920,7 +923,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); } } } @@ -936,6 +939,8 @@ static void HWR_DrawSegsSplats(FSurfaceInfo * pSurf) fixed_t i; // seg bbox fixed_t segbbox[4]; + + INT32 shader = 0; M_ClearBox(segbbox); M_AddToBox(segbbox, @@ -989,10 +994,10 @@ static void HWR_DrawSegsSplats(FSurfaceInfo * pSurf) if (HWR_UseShader()) { - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 10 : 2); // wall shader + shader = (HWR_ShouldUsePaletteRendering() ? 10 : 2); // 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 @@ -1023,11 +1028,13 @@ FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf) // void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blendmode, INT32 lightlevel, extracolormap_t *wallcolormap) { + INT32 shader = 0; + HWR_Lighting(pSurf, lightlevel, wallcolormap); if (HWR_UseShader()) { - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 10 : 2); // wall shader + shader = (HWR_ShouldUsePaletteRendering() ? 10 : 2); // wall shader blendmode |= PF_ColorMapped; } @@ -1038,7 +1045,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) @@ -1394,11 +1401,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); } } @@ -1419,7 +1426,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 @@ -3114,6 +3121,8 @@ void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fixed_t static FOutVector *planeVerts = NULL; static UINT16 numAllocedPlaneVerts = 0; + + INT32 shader = 0; nrPlaneVerts = polysector->numVertices; @@ -3259,11 +3268,11 @@ void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fixed_t if (HWR_UseShader()) { - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 9 : 1); // floor shader + shader = (HWR_ShouldUsePaletteRendering() ? 9 : 1); // 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) @@ -3919,6 +3928,8 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t fixed_t slopez; float offset = 0; + INT32 shader = 0; + R_GetShadowZ(spr->mobj, &floorslope); mobjfloor = HWR_OpaqueFloorAtPos( @@ -4068,10 +4079,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 = (HWR_ShouldUsePaletteRendering() ? 9 : 1); // floor shader } - - HWD.pfnDrawPolygon(&sSurf, swallVerts, 4, PF_Translucent|PF_Modulated, false); + + HWR_ProcessPolygon(&sSurf, swallVerts, 4, PF_Translucent|PF_Modulated, shader, false); } } @@ -4167,6 +4178,8 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) fixed_t v1x, v1y, v2x, v2y; #endif + INT32 shader = 0; + this_scale = FIXED_TO_FLOAT(spr->mobj->scale); if (hires) @@ -4440,11 +4453,11 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) if (HWR_UseShader()) { - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 10 : 3); // sprite shader + shader = (HWR_ShouldUsePaletteRendering() ? 10 : 3); // 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 @@ -4485,11 +4498,11 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) if (HWR_UseShader()) { - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 10 : 3); // sprite shader + shader = (HWR_ShouldUsePaletteRendering() ? 10 : 3); // 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 } // -----------------+ @@ -4503,6 +4516,9 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) FOutVector wallVerts[4]; GLPatch_t *gpatch; // sprite patch converted to hardware FSurfaceInfo Surf; + + INT32 shader = 0; + 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); @@ -4643,11 +4659,11 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) if (HWR_UseShader()) { - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 10 : 3); // sprite shader + shader = (HWR_ShouldUsePaletteRendering() ? 10 : 3); // sprite shader blend |= PF_ColorMapped; } - HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, false); + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, shader, false); } } @@ -4658,6 +4674,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 = 0; if (!spr->mobj) return; @@ -4742,11 +4760,11 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) if (HWR_UseShader()) { - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 10 : 3); // sprite shader + shader = (HWR_ShouldUsePaletteRendering() ? 10 : 3); // sprite shader blend |= PF_ColorMapped; } - HWD.pfnDrawPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, false); + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, shader, false); } // -------------------------------------------------------------------------- @@ -6043,8 +6061,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; @@ -6065,14 +6084,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); @@ -6362,7 +6377,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); @@ -6452,6 +6467,8 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, { FBITFIELD blendmode = blend; UINT8 alpha = pSurf->PolyColor.s.alpha; // retain the alpha + + INT32 shader = 0; // Lighting is done here instead so that fog isn't drawn incorrectly on transparent walls after sorting HWR_Lighting(pSurf, lightlevel, wallcolormap); @@ -6464,7 +6481,7 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, if (fogwall) { blendmode |= PF_Fog; - HWD.pfnSetShader(6); // fog shader + shader = 6; // fog shader } blendmode |= PF_Modulated; // No PF_Occlude means overlapping (incorrect) transparency @@ -6473,12 +6490,12 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, { if (HWR_UseShader()) { - HWD.pfnSetShader(HWR_ShouldUsePaletteRendering() ? 10 : 2); // wall shader + shader = (HWR_ShouldUsePaletteRendering() ? 10 : 2); // 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) @@ -6529,7 +6546,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 diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index b1c18518a..dbcb93bb1 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); diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 6a17f6524..581fa8625 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -31,6 +31,7 @@ #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; @@ -78,10 +79,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; @@ -132,9 +130,10 @@ 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 GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f}; + // shortcut for ((float)1/i) static const GLfloat byte2float[256] = { 0.000000f, 0.003922f, 0.007843f, 0.011765f, 0.015686f, 0.019608f, 0.023529f, 0.027451f, @@ -1344,7 +1343,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; @@ -2103,43 +2102,33 @@ 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) { + gl_shaderprogram_t *shader = &gl_shaderprograms[gl_currentshaderprogram]; + #ifdef GL_SHADERS - if (gl_shadersenabled) + if (gl_shadersenabled && (shader != NULL) && pglUseProgram) { - gl_shaderprogram_t *shader = &gl_shaderprograms[gl_currentshaderprogram]; + if (!shader->program) + { + pglUseProgram(0); return; + } + + if (gl_shaderprogramchanged) + { + pglUseProgram(gl_shaderprograms[gl_currentshaderprogram].program); + gl_shaderprogramchanged = 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) \ @@ -2182,636 +2171,85 @@ 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 +// code that is common between DrawPolygon and DrawIndexedTriangles +// 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) { - 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; + static GLRGBAFloat poly = {0,0,0,0}; + static GLRGBAFloat tint = {0,0,0,0}; + static GLRGBAFloat fade = {0,0,0,0}; -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 + SetBlend(PolyFlags); //TODO: inline (#pragma..) -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) + // PolyColor + if (pSurf) { - 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)); - } - // drawing functions will now collect the drawing data instead of passing it to opengl - gl_batching = true; - //CONS_Printf("StartBatching end\n"); -} + // 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]; -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; + pglColor4ubv((GLubyte*)&pSurf->PolyColor.s); + } - 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; + // 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]; - // skywalls and horizon lines must retain their order for horizon lines to work - if (shader1 == -1 && shader2 == -1) - return index1 - index2; - - diff = poly1->texNum - poly2->texNum; - if (diff != 0) return diff; - - if (HWR_ShouldUsePaletteRendering()) - { - diff = poly1->surf.LightTableId - poly2->surf.LightTableId; - if (diff != 0) return diff; - } - - 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 comparePolygonsNoShaders(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; - - 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; - - // 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) - { - *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; - } - - // 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 - - *sDrawTime = I_GetPreciseTime(); - - 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 @@ -3550,8 +2988,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); @@ -4416,9 +3862,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/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..1ea07f3d4 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -81,6 +81,7 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(SetupGLInfo); GETFUNC(Draw2DLine); GETFUNC(DrawPolygon); + GETFUNC(DrawIndexedTriangles); GETFUNC(SetBlend); GETFUNC(ClearBuffer); GETFUNC(SetTexture); @@ -115,9 +116,6 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(LoadCustomShader); GETFUNC(InitCustomShaders); - GETFUNC(StartBatching); - GETFUNC(RenderBatches); - GETFUNC(SetPaletteLookup); GETFUNC(CreateLightTable); GETFUNC(ClearLightTables); diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index d3a7c8ae3..4e9a98433 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -2125,6 +2125,7 @@ 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); @@ -2160,9 +2161,6 @@ void I_StartupGraphics(void) 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);