From 0b1854ed3d72635c45e8d0f5477772f8dfdbaf55 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 7 Mar 2026 14:14:33 -0500 Subject: [PATCH] Portal Hell PT2 https://git.do.srb2.org/STJr/SRB2/-/merge_requests/1774/diffs\?commit_id\=f6638c0f90a35cc13d97b985389bc058e1d57c3e --- src/hardware/hw_batching.c | 133 ++++++++++++++----------------- src/hardware/hw_bsp.c | 2 +- src/hardware/hw_defs.h | 10 +-- src/hardware/hw_drawnodes.c | 10 +-- src/hardware/hw_gpu.h | 1 + src/hardware/hw_main.c | 114 ++++++++++++++------------ src/hardware/hw_main.h | 1 - src/hardware/hw_segs.c | 4 +- src/hardware/hw_things.c | 14 +--- src/hardware/r_opengl/r_opengl.c | 44 +++++----- src/r_main.cpp | 2 +- src/r_state.h | 3 + 12 files changed, 161 insertions(+), 177 deletions(-) diff --git a/src/hardware/hw_batching.c b/src/hardware/hw_batching.c index 41a7f5695..4960b7be6 100644 --- a/src/hardware/hw_batching.c +++ b/src/hardware/hw_batching.c @@ -33,8 +33,6 @@ typedef struct GLMipmap_t *current_texture = NULL; GLMipmap_t *current_brightmap = NULL; -//boolean currently_batching = false; - // Dynamic arrays for: // - unsorted draw calls // - unsorted vertices @@ -55,7 +53,7 @@ typedef struct #define STATE_STACK_SIZE 2 BatchingState stateStack[STATE_STACK_SIZE] = {0}; int stateStackLevel = 0; // currently used level in state stack -BatchingState *curState = &stateStack[0]; +BatchingState *cst = &stateStack[0]; // Dynamic arrays for: // - sorted order of draw calls @@ -64,20 +62,10 @@ BatchingState *curState = &stateStack[0]; // These are only used during HWR_RenderBatches so they don't need // to be in the state stac -// 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; @@ -92,36 +80,36 @@ int finalIndicesSize = 0; // Call HWR_RenderBatches to render all the collected geometry. void HWR_StartBatching(void) { - if (curState->currently_batching) + if (cst->currently_batching) I_Error("Repeat call to HWR_StartBatching without HWR_RenderBatches"); // init arrays if that has not been done yet - if (!curState->drawCalls) + if (!cst->drawCalls) { - curState->drawCallsCapacity = curState->unsortedVerticesCapacity = 65536; - curState->drawCalls = malloc( - curState->drawCallsCapacity * sizeof(DrawCallInfo)); - curState->unsortedVertices = malloc( - curState->unsortedVerticesCapacity * sizeof(FOutVector)); + cst->drawCallsCapacity = cst->unsortedVerticesCapacity = 65536; + cst->drawCalls = malloc( + cst->drawCallsCapacity * sizeof(DrawCallInfo)); + cst->unsortedVertices = malloc( + cst->unsortedVerticesCapacity * sizeof(FOutVector)); } if (!finalVertices) { finalVertices = malloc(finalVerticesCapacity * sizeof(FOutVector)); finalIndices = malloc(finalVerticesCapacity * 3 * sizeof(UINT32)); - drawCallOrder = malloc(curState->drawCallsCapacity * sizeof(UINT32)); + drawCallOrder = malloc(cst->drawCallsCapacity * sizeof(UINT32)); } - curState->currently_batching = true; + cst->currently_batching = true; } // Disable batching while keeping collected draw calls. // Call HWR_StartBatching again to resume. void HWR_PauseBatching(void) { - if (!curState->currently_batching) + if (!cst->currently_batching) I_Error("HWR_PauseBatching: batching not started"); - curState->currently_batching = false; + cst->currently_batching = false; } // This replaces the direct calls to pfnSetTexture in cases where batching is available. @@ -129,7 +117,7 @@ void HWR_PauseBatching(void) // Doing this was easier than getting a texture pointer to HWR_ProcessPolygon. void HWR_SetCurrentTexture(GLMipmap_t *texture) { - if (curState->currently_batching) + if (cst->currently_batching) { if (texture != NULL) { @@ -151,48 +139,48 @@ void HWR_SetCurrentTexture(GLMipmap_t *texture) static void HWR_CollectDrawCallInfo(FSurfaceInfo *pSurf, FUINT iNumPts, FBITFIELD PolyFlags, int shader_target, boolean horizonSpecial) { // make sure dynamic array has capacity - if (curState->drawCallsSize == curState->drawCallsCapacity) + if (cst->drawCallsSize == cst->drawCallsCapacity) { DrawCallInfo* new_array; // ran out of space, make new array double the size - curState->drawCallsCapacity *= 2; - new_array = malloc(curState->drawCallsCapacity * sizeof(DrawCallInfo)); - memcpy(new_array, curState->drawCalls, curState->drawCallsSize * sizeof(DrawCallInfo)); - free(curState->drawCalls); - curState->drawCalls = new_array; + cst->drawCallsCapacity *= 2; + new_array = malloc(cst->drawCallsCapacity * sizeof(DrawCallInfo)); + memcpy(new_array, cst->drawCalls, cst->drawCallsSize * sizeof(DrawCallInfo)); + free(cst->drawCalls); + cst->drawCalls = new_array; // also need to redo the index array, dont need to copy it though free(drawCallOrder); - drawCallOrder = malloc(curState->drawCallsCapacity * sizeof(UINT32)); + drawCallOrder = malloc(cst->drawCallsCapacity * sizeof(UINT32)); } // add entry to array - curState->drawCalls[curState->drawCallsSize].surf = *pSurf; - curState->drawCalls[curState->drawCallsSize].vertsIndex = curState->unsortedVerticesSize; - curState->drawCalls[curState->drawCallsSize].numVerts = iNumPts; - curState->drawCalls[curState->drawCallsSize].polyFlags = PolyFlags; - curState->drawCalls[curState->drawCallsSize].texture = current_texture; - curState->drawCalls[curState->drawCallsSize].brightmap = current_brightmap; - curState->drawCalls[curState->drawCallsSize].shader = (shader_target != -1) ? HWR_GetShaderFromTarget(shader_target) : shader_target; - curState->drawCalls[curState->drawCallsSize].horizonSpecial = horizonSpecial; - curState->drawCallsSize++; + cst->drawCalls[cst->drawCallsSize].surf = *pSurf; + cst->drawCalls[cst->drawCallsSize].vertsIndex = cst->unsortedVerticesSize; + cst->drawCalls[cst->drawCallsSize].numVerts = iNumPts; + cst->drawCalls[cst->drawCallsSize].polyFlags = PolyFlags; + cst->drawCalls[cst->drawCallsSize].texture = current_texture; + cst->drawCalls[cst->drawCallsSize].brightmap = current_brightmap; + cst->drawCalls[cst->drawCallsSize].shader = (shader_target != -1) ? HWR_GetShaderFromTarget(shader_target) : shader_target; + cst->drawCalls[cst->drawCallsSize].horizonSpecial = horizonSpecial; + cst->drawCallsSize++; } static void HWR_CollectDrawCallVertices(FOutVector *pOutVerts, FUINT iNumPts) { // make sure dynamic array has capacity - while (curState->unsortedVerticesSize + (int)iNumPts > - curState->unsortedVerticesCapacity) + while (cst->unsortedVerticesSize + (int)iNumPts > + cst->unsortedVerticesCapacity) { FOutVector* new_array; // need more space for vertices in unsortedVertices - curState->unsortedVerticesCapacity *= 2; - new_array = malloc(curState->unsortedVerticesCapacity * sizeof(FOutVector)); - memcpy(new_array, curState->unsortedVertices, curState->unsortedVerticesSize * sizeof(FOutVector)); - free(curState->unsortedVertices); - curState->unsortedVertices = new_array; + cst->unsortedVerticesCapacity *= 2; + new_array = malloc(cst->unsortedVerticesCapacity * sizeof(FOutVector)); + memcpy(new_array, cst->unsortedVertices, cst->unsortedVerticesSize * sizeof(FOutVector)); + free(cst->unsortedVertices); + cst->unsortedVertices = new_array; } // add vertices to array - memcpy(&curState->unsortedVertices[curState->unsortedVerticesSize], pOutVerts, iNumPts * sizeof(FOutVector)); - curState->unsortedVerticesSize += iNumPts; + memcpy(&cst->unsortedVertices[cst->unsortedVerticesSize], pOutVerts, iNumPts * sizeof(FOutVector)); + cst->unsortedVerticesSize += iNumPts; } // If batching is enabled, this function collects the polygon data and the chosen texture @@ -200,7 +188,7 @@ static void HWR_CollectDrawCallVertices(FOutVector *pOutVerts, FUINT iNumPts) // render the polygon immediately. void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, int shader_target, boolean horizonSpecial) { - if (curState->currently_batching) + if (cst->currently_batching) { if (!pSurf) { @@ -218,33 +206,30 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt } } -// TODO could alternatively save drawCalls and unsortedVertices variables here -// instead of having "curState->" everywhere void HWR_PushBatchingState(void) { if (stateStackLevel == STATE_STACK_SIZE - 1) I_Error("HWR_PushBatchingState: State stack overflow"); stateStackLevel++; - curState++; + cst++; } -// TODO as above void HWR_PopBatchingState(void) { if (stateStackLevel == 0) I_Error("HWR_PopBatchingState: State stack underflow"); stateStackLevel--; - curState--; + cst--; } static int compareDrawCalls(const void *p1, const void *p2) { UINT32 index1 = *(const UINT32*)p1; UINT32 index2 = *(const UINT32*)p2; - DrawCallInfo* poly1 = &curState->drawCalls[index1]; - DrawCallInfo* poly2 = &curState->drawCalls[index2]; + DrawCallInfo* poly1 = &cst->drawCalls[index1]; + DrawCallInfo* poly2 = &cst->drawCalls[index2]; int diff; INT64 diff64; UINT32 downloaded1 = 0; @@ -306,8 +291,8 @@ static int compareDrawCallsNoShaders(const void *p1, const void *p2) { unsigned int index1 = *(const unsigned int*)p1; unsigned int index2 = *(const unsigned int*)p2; - DrawCallInfo* poly1 = &curState->drawCalls[index1]; - DrawCallInfo* poly2 = &curState->drawCalls[index2]; + DrawCallInfo* poly1 = &cst->drawCalls[index1]; + DrawCallInfo* poly2 = &cst->drawCalls[index2]; int diff; INT64 diff64; @@ -363,7 +348,7 @@ static void HWR_CollectVerticesIntoBatch(DrawCallInfo *drawCall) finalIndices = new_index_array; } // write the vertices of the polygon - memcpy(&finalVertices[finalVerticesSize], &curState->unsortedVertices[drawCall->vertsIndex], + memcpy(&finalVertices[finalVerticesSize], &cst->unsortedVertices[drawCall->vertsIndex], numVerts * sizeof(FOutVector)); // write the indexes, pointing to the fan vertexes but in triangles format firstVIndex = finalVerticesSize; @@ -461,7 +446,7 @@ static void HWR_ExecuteStateChanges(unsigned int stateChanges, DrawCallInfo *dc) static void HWR_InitBatchingStats(void) { - ps_hw_numpolys = curState->drawCallsSize; + ps_hw_numpolys = cst->drawCallsSize; ps_hw_numcalls = ps_hw_numverts = ps_hw_numshaders = ps_hw_numtextures = ps_hw_numpolyflags = ps_hw_numcolors = 0; @@ -474,26 +459,26 @@ void HWR_RenderBatches(void) int drawCallReadPos = 0; // position in drawCallOrder int i; - if (!curState->currently_batching) + if (!cst->currently_batching) I_Error("HWR_RenderBatches called without starting batching"); - curState->currently_batching = false; // no longer collecting batches + cst->currently_batching = false; // no longer collecting batches HWR_InitBatchingStats(); - if (!curState->drawCallsSize) + if (!cst->drawCallsSize) return; // nothing to draw // init drawCallOrder - for (i = 0; i < curState->drawCallsSize; i++) + for (i = 0; i < cst->drawCallsSize; i++) drawCallOrder[i] = i; // sort the draw calls ps_hw_batchsorttime = I_GetPreciseTime(); if (cv_glshaders.value && gl_shadersavailable) - qs22j(drawCallOrder, curState->drawCallsSize, sizeof(UINT32), compareDrawCalls); + qs22j(drawCallOrder, cst->drawCallsSize, sizeof(UINT32), compareDrawCalls); else - qs22j(drawCallOrder, curState->drawCallsSize, sizeof(UINT32), compareDrawCallsNoShaders); + qs22j(drawCallOrder, cst->drawCallsSize, sizeof(UINT32), compareDrawCallsNoShaders); ps_hw_batchsorttime = I_GetPreciseTime() - ps_hw_batchsorttime; // sort grouping order // 1. shader @@ -506,7 +491,7 @@ void HWR_RenderBatches(void) ps_hw_batchdrawtime = I_GetPreciseTime(); // set state for first batch - HWR_ExecuteStateChanges(0xFFFF, &curState->drawCalls[drawCallOrder[0]]); + HWR_ExecuteStateChanges(0xFFFF, &cst->drawCalls[drawCallOrder[0]]); // - iterate through draw calls // - accumulate converted vertices and indices into finalVertices and finalIndices @@ -527,18 +512,18 @@ void HWR_RenderBatches(void) // repeat loop unsigned int stateChanges = 0; // flags defined above HWR_MarkStateChanges - DrawCallInfo *currentDrawCall = &curState->drawCalls[drawCallOrder[drawCallReadPos++]]; + DrawCallInfo *currentDrawCall = &cst->drawCalls[drawCallOrder[drawCallReadPos++]]; DrawCallInfo *nextDrawCall = NULL; HWR_CollectVerticesIntoBatch(currentDrawCall); - if (drawCallReadPos >= curState->drawCallsSize) // was that the last draw call? + if (drawCallReadPos >= cst->drawCallsSize) // was that the last draw call? { stopFlag = true; } else { - nextDrawCall = &curState->drawCalls[drawCallOrder[drawCallReadPos]]; + nextDrawCall = &cst->drawCalls[drawCallOrder[drawCallReadPos]]; stateChanges = HWR_MarkStateChanges(currentDrawCall, nextDrawCall); } @@ -564,8 +549,8 @@ void HWR_RenderBatches(void) HWR_ExecuteStateChanges(stateChanges, nextDrawCall); } // reset the arrays (set sizes to 0) - curState->drawCallsSize = 0; - curState->unsortedVerticesSize = 0; + cst->drawCallsSize = 0; + cst->unsortedVerticesSize = 0; ps_hw_batchdrawtime = I_GetPreciseTime() - ps_hw_batchdrawtime; } diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index 20f57ed73..cd7f8eb67 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -225,7 +225,7 @@ static boolean HWR_PortalCheckPointSide(fixed_t x, fixed_t y) P_ClosestPointOnLine(x, y, gl_portalclipline, &closest_point); if (closest_point.x != x || closest_point.y != y) { - if (P_PointOnLineSide(x, y, gl_portalclipline) != gl_portalviewside) + if (P_PointOnLineSide(x, y, gl_portalclipline) != 1) return true; } return false; diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index b27b01301..b2843728d 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -309,9 +309,7 @@ enum hwdsetspecialstate HWD_SET_SHADERS, HWD_SET_TEXTUREFILTERMODE, HWD_SET_TEXTUREANISOTROPICMODE, - HWD_SET_STENCIL_MODE, - HWD_SET_STENCIL_LEVEL, // must set mode afterwards for level to come into effect - HWD_NUMSTATE // (TODO could create separate stencil function in r_opengl.c to avoid hacky behaviour like this) + HWD_NUMSTATE }; typedef enum hwdsetspecialstate hwdspecialstate_t; @@ -323,8 +321,8 @@ enum hwdshaderstage typedef enum hwdshaderstage hwdshaderstage_t; -// stencil modes -enum +// Modes for SetStencilMode +enum hwdstencilmode { HWD_STENCIL_INACTIVE, HWD_STENCIL_PORTAL_BEGIN, @@ -332,6 +330,8 @@ enum HWD_STENCIL_PORTAL_FINISH }; +typedef enum hwdstencilmode hwdstencilmode_t; + // Lactozilla: Shader info // Generally set at the start of the frame. enum hwdshaderinfo diff --git a/src/hardware/hw_drawnodes.c b/src/hardware/hw_drawnodes.c index e255e47fb..f0030aeef 100644 --- a/src/hardware/hw_drawnodes.c +++ b/src/hardware/hw_drawnodes.c @@ -82,9 +82,6 @@ typedef struct // initial size of drawnode array #define DRAWNODES_INIT_SIZE 64 -/*gl_drawnode_t *drawnodes = NULL; -INT32 numdrawnodes = 0; -INT32 alloceddrawnodes = 0;*/ typedef struct { @@ -93,10 +90,9 @@ typedef struct INT32 alloceddrawnodes; } gl_drawnode_state_t; -// todo magic number 16 // portal rendering will push and pop this stack // to keep multiple drawnode lists around until they're needed -static gl_drawnode_state_t state_stack[16] = {0}; +static gl_drawnode_state_t state_stack[MAXPORTALS_CAP+1] = {0}; static int stack_level = 0; static gl_drawnode_state_t *cst = &state_stack[0]; // current state @@ -183,8 +179,7 @@ void HWR_AddTransparentPolyobjectFloor(levelflat_t *levelflat, polyobj_t *polyse // pushes all drawnode rendering state to stack void HWR_PushDrawNodeState(void) { - // todo magic number 16 - if (stack_level == 15) + if (stack_level == MAXPORTALS_CAP) I_Error("HWR_PushDrawNodeState: State stack overflow"); stack_level++; @@ -208,7 +203,6 @@ static int CompareDrawNodePlanes(const void *p1, const void *p2) return ABS(cst->drawnodes[n2].u.plane.fixedheight - viewz) - ABS(cst->drawnodes[n1].u.plane.fixedheight - viewz); } -// HWR_RenderDrawNodes // Sorts and renders the list of drawnodes for the scene being rendered. void HWR_RenderDrawNodes(void) { diff --git a/src/hardware/hw_gpu.h b/src/hardware/hw_gpu.h index ad3941caf..f45efcbe0 100644 --- a/src/hardware/hw_gpu.h +++ b/src/hardware/hw_gpu.h @@ -40,6 +40,7 @@ void GL_GClipRect(INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip void GL_ClearMipMapCache(void); void GL_SetSpecialState(hwdspecialstate_t IdState, INT32 Value); +void GL_SetStencilMode(hwdstencilmode_t mode, INT32 ref); // Hurdler: added for new development void GL_DrawModel(model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface); diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index a1bba84ed..7d944027d 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -157,14 +157,13 @@ typedef struct } gl_portal_array_t; // TODO magic number 16 -gl_portal_array_t gl_portal_arrays[16] = {0}; +gl_portal_array_t gl_portal_arrays[MAXPORTALS_CAP+1] = {0}; INT32 gl_portal_level = 0; // portal recursion level boolean gl_drawing_stencil = false; // used when drawing segs to stencil buffer sector_t *gl_portalcullsector = NULL; line_t *gl_portalclipline = NULL; -INT32 gl_portalviewside = 0; // debug tools boolean gl_printportals = false; // print info about portals on this frame @@ -186,9 +185,6 @@ static void HWR_PortalFrame(gl_portal_t *portal, boolean set_culling) { gl_portalcullsector = portal->clipline->frontsector; gl_portalclipline = portal->clipline; - gl_portalviewside = P_PointOnLineSide(viewx, viewy, gl_portalclipline); - // TODO check is gl_portalviewside always the same value? - // if it is then it's not needed to have this variable } } @@ -201,6 +197,38 @@ static gl_portal_array_t *HWR_GetPortalArray(void) return &gl_portal_arrays[level]; } +// TODO move to r_main.c next to fixed point functions? + +// More precise version of R_PointToAngle2 using floats and atan2. +static angle_t R_PointToAngle2Precise(fixed_t pviewx, fixed_t pviewy, fixed_t x, fixed_t y) +{ + fixed_t dx = x - pviewx; + fixed_t dy = y - pviewy; + float radians; + + if (!dx && !dy) + return 0; + + // no need for correct scale with FIXED_TO_FLOAT here + // since we're just calculating the angle + radians = atan2(dy, dx); + + return (angle_t)(radians / M_PI * ANGLE_180); +} + +// More precise version of R_PointToDist2 using floats and sqrt. +static fixed_t R_PointToDist2Precise(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1) +{ + // float-fixed conversions can be omitted here + // because they cancel each other out in this case + + float dx = px1 - px2; + float dy = py1 - py2; + double result = sqrt(dx*dx + dy*dy); + + return (fixed_t)result; +} + boolean HWR_AddPortal(line_t *start, line_t *dest, seg_t *seg) { gl_portal_array_t *array; @@ -212,8 +240,8 @@ boolean HWR_AddPortal(line_t *start, line_t *dest, seg_t *seg) vertex_t dest_c, start_c; if ((gl_portal_level + gl_rendering_skybox) >= cv_maxportals.value || - (gl_debugportal && - (gl_debugportal != (start-lines) || gl_portal_level))) + (gl_debugportal && + (gl_debugportal != (start-lines) || gl_portal_level))) { return false; } @@ -227,45 +255,51 @@ boolean HWR_AddPortal(line_t *start, line_t *dest, seg_t *seg) { array->capacity = INIT_PORTAL_ARRAY_SIZE; array->portals = Z_Malloc(sizeof(gl_portal_t) * array->capacity, PU_LEVEL, - &array->portals); + &array->portals); } else if (array->size == array->capacity) { array->capacity *= 2; array->portals = Z_Realloc(array->portals, sizeof(gl_portal_t) * array->capacity, - PU_LEVEL, &array->portals); + PU_LEVEL, &array->portals); } portal = &array->portals[array->size++]; - dangle = R_PointToAngle2(0,0,dest->dx,dest->dy) - R_PointToAngle2(start->dx,start->dy,0,0); - - // using this order of operations change fixes ante station island portal + // Most fixed-point calculations and trigonometric function tables are replaced by + // floats and cmath library calls in this part to improve the precision of the + // location and angle of the new viewpoint. + // + // This reduces artefacts on the edges of portals, showing thin lines/pixels + // of the underlying graphics. (for example the sky texture) It's not 100% + // perfectly aligned and artefact-free, but looks noticeably + // better than the original code. I'm not even sure if it's this + // code or the nodebuilder or hw_map or something else causing the remaining issues.. + //#define R_PointToAngle2Precise R_PointToAngle2 + //#define R_PointToDist2Precise R_PointToDist2 + dangle = R_PointToAngle2Precise(0,0,dest->dx,dest->dy) - R_PointToAngle2Precise(start->dx,start->dy,0,0); // looking glass center - //start_c.x = (start->v1->x + start->v2->x) / 2; - //start_c.y = (start->v1->y + start->v2->y) / 2; start_c.x = start->v1->x/2 + start->v2->x/2; start_c.y = start->v1->y/2 + start->v2->y/2; // other side center - //dest_c.x = (dest->v1->x + dest->v2->x) / 2; - //dest_c.y = (dest->v1->y + dest->v2->y) / 2; dest_c.x = dest->v1->x/2 + dest->v2->x/2; dest_c.y = dest->v1->y/2 + dest->v2->y/2; - disttopoint = R_PointToDist2(start_c.x, start_c.y, viewx, viewy); - angtopoint = R_PointToAngle2(start_c.x, start_c.y, viewx, viewy); + disttopoint = R_PointToDist2Precise(start_c.x, start_c.y, viewx, viewy); + angtopoint = R_PointToAngle2Precise(start_c.x, start_c.y, viewx, viewy); angtopoint += dangle; - // could using float or double here help with the slight impreciseness of - // the view coordinates? - //float fang = ((float)angtopoint / 4294967296.0f) * 2.0f * M_PI; + float fang = ((float)angtopoint / 4294967296.0f) * 2.0f * M_PI; - portal->viewx = dest_c.x + FixedMul(FINECOSINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); - portal->viewy = dest_c.y + FixedMul(FINESINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); + //portal->viewx = dest_c.x + FixedMul(FINECOSINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); + //portal->viewy = dest_c.y + FixedMul(FINESINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); //portal->viewx = dest_c.x + FixedMul(FLOAT_TO_FIXED(cos(fang)), disttopoint); //portal->viewy = dest_c.y + FixedMul(FLOAT_TO_FIXED(sin(fang)), disttopoint); + // cos and sin are just scaling disttopoint so no need for float-fixed conversions + portal->viewx = dest_c.x + (fixed_t)(cos(fang) * disttopoint); + portal->viewy = dest_c.y + (fixed_t)(sin(fang) * disttopoint); portal->viewz = viewz + dest->frontsector->floorheight - start->frontsector->floorheight; portal->viewangle = viewangle + dangle; portal->seg = seg; @@ -437,7 +471,7 @@ UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap) // Let's see if realcolor.rgba = (colormap != NULL) ? colormap->rgba : GL_DEFAULTMIX; - if (cv_glshaders.value && gl_shadersavailable) + if (HWR_UseShader()) { surfcolor.s.alpha = (255 - light); } @@ -565,20 +599,6 @@ boolean HWR_BlendMidtextureSurface(FSurfaceInfo *pSurf) return true; } -// -----------------+ -// HWR_ClearView : clear the viewwindow, with maximum z value -// -----------------+ -/*static inline void HWR_ClearView(void) -{ - GL_GClipRect((INT32)gl_viewwindowx, - (INT32)gl_viewwindowy, - (INT32)(gl_viewwindowx + gl_viewwidth), - (INT32)(gl_viewwindowy + gl_viewheight), - ZCLIP_PLANE); - GL_ClearBuffer(false, true, true, 0) -}*/ - - // -----------------+ // HWR_SetViewSize : set projection and scaling values // -----------------+ @@ -680,6 +700,7 @@ static void HWR_PortalClipping(gl_portal_t *portal) gld_clipper_SafeAddClipRange(portal->angle1, portal->angle2); } +// Tells the backend are shaders being used for 3d rendering. static void HWR_SetShaderState(void) { GL_SetSpecialState(HWD_SET_SHADERS, (INT32)HWR_UseShader()); @@ -741,9 +762,6 @@ static void HWR_EnterSkyboxState(void) HWR_PushBatchingState(); HWR_PushSpriteState(); HWR_PushDrawNodeState(); - // need to use the next level in the portal arrays - // so skybox doesn't interfere with previously collected portals - //gl_portal_level++; gl_rendering_skybox = true; } @@ -752,8 +770,6 @@ static void HWR_LeaveSkyboxState(void) HWR_PopBatchingState(); HWR_PopSpriteState(); HWR_PopDrawNodeState(); - // see above comment - //gl_portal_level--; gl_rendering_skybox = false; } @@ -767,16 +783,12 @@ static void HWR_RenderPortalSeg(seg_t *seg) gl_drawing_stencil = false; // need to work around the r_opengl PF_Invisible bug with this call // similarly as in the linkdraw hack in HWR_DrawSprites - // TODO not completely sure if this is needed, check it? (try without) GL_SetBlend(PF_Translucent|PF_Occlude|PF_Masked); } static void HWR_SetStencilState(INT32 state) { - // this order of calls must be used for the stencil - // level to take effect correctly - GL_SetSpecialState(HWD_SET_STENCIL_LEVEL, gl_portal_level); - GL_SetSpecialState(HWD_SET_STENCIL_MODE, state); + GL_SetStencilMode(state, gl_portal_level); } // clear the depth buffer from the stenciled area so portal @@ -784,7 +796,7 @@ static void HWR_SetStencilState(INT32 state) // (glClear ignores the stencil buffer so can't be used for this purpose) static void HWR_RenderDepthEraser(boolean visible) { - FOutVector verts[4] = {0}; // TODO not sure if PF_NoAlphaTest is needed? + FOutVector verts[4] = {0}; FBITFIELD blendflags = PF_Occlude|PF_NoDepthTest|PF_NoTexture|PF_NoAlphaTest; if (!visible) blendflags |= PF_Invisible; @@ -897,7 +909,6 @@ static void HWR_RenderViewpoint(player_t *player, boolean drawSkyTexture, boolea { //if (gl_printportals) // CONS_Printf("drawing a skybox\n"); - // TODO NOTE this probably wont set correct position under portals? R_SkyboxFrame(viewssnum); // render skybox while keeping batches, sprites and drawnodes // from the regular viewpoint stashed in the state stacks @@ -1250,6 +1261,9 @@ void CV_glpalettedepth_OnChange(void); consvar_t cv_glpaletterendering = CVAR_INIT ("gr_paletteshader", "Off", CV_CALL|CV_SAVE, CV_OnOff, CV_glpaletterendering_OnChange); consvar_t cv_glpalettedepth = CVAR_INIT ("gr_palettedepth", "16 bits", CV_SAVE|CV_CALL, glpalettedepth_cons_t, CV_glpalettedepth_OnChange); +// Isolates rendering to one of the top level portals. +// (Stencil cutting of the portal is also disabled) +// Use gr_printportals to find the number to use. consvar_t cv_gldebugportal = CVAR_INIT ("gr_debugportal", "0", 0, CV_Unsigned, NULL); consvar_t cv_glskydebug = CVAR_INIT ("gr_skydebug", "0", 0, CV_Unsigned, NULL); diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 0f03d5132..81e69fbfe 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -177,7 +177,6 @@ extern INT32 gl_portal_level; extern boolean gl_drawing_stencil; extern sector_t *gl_portalcullsector; extern line_t *gl_portalclipline; -extern INT32 gl_portalviewside; extern boolean gl_printportals; extern INT32 gl_debugportal; diff --git a/src/hardware/hw_segs.c b/src/hardware/hw_segs.c index e8f42d593..ac1683897 100644 --- a/src/hardware/hw_segs.c +++ b/src/hardware/hw_segs.c @@ -479,9 +479,9 @@ static void HWR_ProcessTwoSidedSegMiddle(FOutVector *wallVerts, FSurfaceInfo *Su sector_t *front, *back; fixed_t h, l; // 2s middle textures fixed_t hS, lS; - fixed_t popentop, popenbottom, polytop, polybottom, lowcut, highcut; + fixed_t popentop, popenbottom, polytop, polybottom, lowcut, highcut; fixed_t popentopslope, popenbottomslope, polytopslope, polybottomslope, lowcutslope, highcutslope; - fixed_t texturevpeg = 0; + fixed_t texturevpeg = 0; INT32 repeats; fixed_t midtexheight = 0; fixed_t texturevpegslope = 0; diff --git a/src/hardware/hw_things.c b/src/hardware/hw_things.c index 83f50709b..65db7857b 100644 --- a/src/hardware/hw_things.c +++ b/src/hardware/hw_things.c @@ -28,9 +28,6 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing); // sprites are drawn after all wall and planes are rendered, so that // sprite translucency effects apply on the rendered view (instead of the background sky!!) -//UINT32 gl_visspritecount; -//static gl_vissprite_t *gl_visspritechunks[MAXVISSPRITES >> VISSPRITECHUNKBITS] = {NULL}; - typedef struct { FOutVector verts[4]; @@ -47,8 +44,7 @@ typedef struct // TODO this array is ~3 megabytes because of linkdrawlist... // maybe turn that into a dynamic array -// TODO magic number 16 -static gl_sprite_state_t state_stack[16] = {0}; +static gl_sprite_state_t state_stack[MAXPORTALS_CAP+1] = {0}; static int stack_level = 0; static gl_sprite_state_t *cst = &state_stack[0]; // current state @@ -64,8 +60,7 @@ void HWR_ClearSprites(void) // pushes all sprite rendering state to stack void HWR_PushSpriteState(void) { - // todo magic number 16 - if (stack_level == 15) + if (stack_level == MAXPORTALS_CAP) I_Error("HWR_PushSpriteState: State stack overflow"); stack_level++; @@ -111,11 +106,6 @@ static gl_vissprite_t *HWR_NewVisSprite(void) // NOTE: This will no longer be necessary once full translucent sorting is implemented, where // translucent sprites and surfaces are sorted together. -/* -// this list is used to store data about linkdraw sprites -zbuffersprite_t linkdrawlist[MAXVISSPRITES]; -UINT32 linkdrawcount = 0;*/ - // add the necessary data to the list for delayed z-buffer drawing static void HWR_LinkDrawHackAdd(FOutVector *verts, gl_vissprite_t *spr) { diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index a2a015578..1b1ae2b1a 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -73,7 +73,6 @@ static GLuint tex_downloaded = 0; static GLuint lt_downloaded = 0; // currently bound lighttable texture static GLfloat fov = 90.0f; static FBITFIELD CurrentPolyFlags; -static GLint gl_stencil_ref = 0; // Linked list of all textures. static FTextureInfo *TexCacheTail = NULL; @@ -2400,33 +2399,32 @@ void GL_SetSpecialState(hwdspecialstate_t IdState, INT32 Value) Flush(); //??? if we want to change filter mode by texture, remove this break; - case HWD_SET_STENCIL_MODE: - switch (Value) - { - case HWD_STENCIL_INACTIVE: - pglStencilFunc(GL_ALWAYS, gl_stencil_ref, 0xFF); - pglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - break; - case HWD_STENCIL_PORTAL_BEGIN: - pglStencilFunc(GL_EQUAL, gl_stencil_ref, 0xFF); - pglStencilOp(GL_KEEP, GL_KEEP, GL_INCR); - break; - case HWD_STENCIL_PORTAL_INSIDE: - pglStencilFunc(GL_EQUAL, gl_stencil_ref, 0xFF); - pglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - break; - case HWD_STENCIL_PORTAL_FINISH: - pglStencilFunc(GL_EQUAL, gl_stencil_ref, 0xFF); - pglStencilOp(GL_KEEP, GL_KEEP, GL_DECR); - break; - } + default: break; + } +} - case HWD_SET_STENCIL_LEVEL: - gl_stencil_ref = Value; +void GL_SetStencilMode(hwdstencilmode_t mode, INT32 ref) +{ + switch (mode) + { + case HWD_STENCIL_INACTIVE: + pglStencilFunc(GL_ALWAYS, ref, 0xFF); + pglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); break; default: + case HWD_STENCIL_PORTAL_BEGIN: + pglStencilFunc(GL_EQUAL, ref, 0xFF); + pglStencilOp(GL_KEEP, GL_KEEP, GL_INCR); + break; + case HWD_STENCIL_PORTAL_INSIDE: + pglStencilFunc(GL_EQUAL, ref, 0xFF); + pglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + break; + case HWD_STENCIL_PORTAL_FINISH: + pglStencilFunc(GL_EQUAL, ref, 0xFF); + pglStencilOp(GL_KEEP, GL_KEEP, GL_DECR); break; } } diff --git a/src/r_main.cpp b/src/r_main.cpp index 46a367007..1f6e9f080 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -138,7 +138,7 @@ static CV_PossibleValue_t drawdist_precip_cons_t[] = { static CV_PossibleValue_t fov_cons_t[] = {{60*FRACUNIT, "MIN"}, {179*FRACUNIT, "MAX"}, {0, NULL}}; static CV_PossibleValue_t translucenthud_cons_t[] = {{0, "MIN"}, {10, "MAX"}, {0, NULL}}; -static CV_PossibleValue_t maxportals_cons_t[] = {{0, "MIN"}, {12, "MAX"}, {0, NULL}}; // lmao rendering 32 portals, you're a card +static CV_PossibleValue_t maxportals_cons_t[] = {{0, "MIN"}, {MAXPORTALS_CAP, "MAX"}, {0, NULL}}; // lmao rendering 32 portals, you're a card static CV_PossibleValue_t homremoval_cons_t[] = {{0, "No"}, {1, "Yes"}, {2, "Flash"}, {0, NULL}}; static CV_PossibleValue_t secbright_cons_t[] = {{0, "MIN"}, {255, "MAX"}, {0, NULL}}; diff --git a/src/r_state.h b/src/r_state.h index fa6c518e1..ed549f88f 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -108,6 +108,9 @@ extern player_t *viewplayer; extern mobj_t *r_viewmobj; extern consvar_t cv_allowmlook; + +// maximum value for maxportals cvar +#define MAXPORTALS_CAP 12 extern consvar_t cv_maxportals; extern angle_t clipangle[MAXSPLITSCREENPLAYERS];