NepDisk 2026-03-07 12:25:06 -05:00
parent 778de306c5
commit a739573ca1
16 changed files with 1015 additions and 300 deletions

View file

@ -33,28 +33,50 @@ typedef struct
GLMipmap_t *current_texture = NULL;
GLMipmap_t *current_brightmap = NULL;
boolean currently_batching = false;
//boolean currently_batching = false;
// Dynamic arrays for:
// - unsorted draw calls
// - sorted order of draw calls
// - unsorted vertices
// These can be postponed by pushing them to the batching state stack
typedef struct
{
boolean currently_batching;
DrawCallInfo *drawCalls;
int drawCallsSize;
int drawCallsCapacity;
FOutVector *unsortedVertices;
int unsortedVerticesSize;
int unsortedVerticesCapacity;
} BatchingState;
// used for postponing the rendering until after the skybox is done
#define STATE_STACK_SIZE 2
BatchingState stateStack[STATE_STACK_SIZE] = {0};
int stateStackLevel = 0; // currently used level in state stack
BatchingState *curState = &stateStack[0];
// Dynamic arrays for:
// - sorted order of draw calls
// - final (sorted) vertices
// - vertex indices for sorted vertices
// 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;
/*DrawCallInfo* drawCalls = NULL;
int drawCallsSize = 0;
int drawCallsCapacity = 65536;
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;
/*FOutVector* unsortedVertices = NULL;
int unsortedVerticesSize = 0;
int unsortedVerticesCapacity = 65536;
int unsortedVerticesCapacity = 65536;*/
// contains subset of sorted vertices and texture coordinates to be sent to gpu
FOutVector* finalVertices = NULL;
@ -70,20 +92,36 @@ int finalIndicesSize = 0;
// Call HWR_RenderBatches to render all the collected geometry.
void HWR_StartBatching(void)
{
if (currently_batching)
if (curState->currently_batching)
I_Error("Repeat call to HWR_StartBatching without HWR_RenderBatches");
// init arrays if that has not been done yet
if (!curState->drawCalls)
{
curState->drawCallsCapacity = curState->unsortedVerticesCapacity = 65536;
curState->drawCalls = malloc(
curState->drawCallsCapacity * sizeof(DrawCallInfo));
curState->unsortedVertices = malloc(
curState->unsortedVerticesCapacity * sizeof(FOutVector));
}
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));
drawCallOrder = malloc(curState->drawCallsCapacity * sizeof(UINT32));
}
currently_batching = true;
curState->currently_batching = true;
}
// Disable batching while keeping collected draw calls.
// Call HWR_StartBatching again to resume.
void HWR_PauseBatching(void)
{
if (!curState->currently_batching)
I_Error("HWR_PauseBatching: batching not started");
curState->currently_batching = false;
}
// This replaces the direct calls to pfnSetTexture in cases where batching is available.
@ -91,7 +129,7 @@ void HWR_StartBatching(void)
// Doing this was easier than getting a texture pointer to HWR_ProcessPolygon.
void HWR_SetCurrentTexture(GLMipmap_t *texture)
{
if (currently_batching)
if (curState->currently_batching)
{
if (texture != NULL)
{
@ -113,47 +151,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 (drawCallsSize == drawCallsCapacity)
if (curState->drawCallsSize == curState->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;
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;
// also need to redo the index array, dont need to copy it though
free(drawCallOrder);
drawCallOrder = malloc(drawCallsCapacity * sizeof(UINT32));
drawCallOrder = malloc(curState->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].brightmap = current_brightmap;
drawCalls[drawCallsSize].shader = (shader_target != -1) ? HWR_GetShaderFromTarget(shader_target) : shader_target;
drawCalls[drawCallsSize].horizonSpecial = horizonSpecial;
drawCallsSize++;
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++;
}
static void HWR_CollectDrawCallVertices(FOutVector *pOutVerts, FUINT iNumPts)
{
// make sure dynamic array has capacity
while (unsortedVerticesSize + (int)iNumPts > unsortedVerticesCapacity)
while (curState->unsortedVerticesSize + (int)iNumPts >
curState->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;
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;
}
// add vertices to array
memcpy(&unsortedVertices[unsortedVerticesSize], pOutVerts, iNumPts * sizeof(FOutVector));
unsortedVerticesSize += iNumPts;
memcpy(&curState->unsortedVertices[curState->unsortedVerticesSize], pOutVerts, iNumPts * sizeof(FOutVector));
curState->unsortedVerticesSize += iNumPts;
}
// If batching is enabled, this function collects the polygon data and the chosen texture
@ -161,7 +200,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 (currently_batching)
if (curState->currently_batching)
{
if (!pSurf)
{
@ -179,12 +218,33 @@ 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++;
}
// TODO as above
void HWR_PopBatchingState(void)
{
if (stateStackLevel == 0)
I_Error("HWR_PopBatchingState: State stack underflow");
stateStackLevel--;
curState--;
}
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];
DrawCallInfo* poly1 = &curState->drawCalls[index1];
DrawCallInfo* poly2 = &curState->drawCalls[index2];
int diff;
INT64 diff64;
UINT32 downloaded1 = 0;
@ -246,8 +306,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 = &drawCalls[index1];
DrawCallInfo* poly2 = &drawCalls[index2];
DrawCallInfo* poly1 = &curState->drawCalls[index1];
DrawCallInfo* poly2 = &curState->drawCalls[index2];
int diff;
INT64 diff64;
@ -303,7 +363,7 @@ static void HWR_CollectVerticesIntoBatch(DrawCallInfo *drawCall)
finalIndices = new_index_array;
}
// write the vertices of the polygon
memcpy(&finalVertices[finalVerticesSize], &unsortedVertices[drawCall->vertsIndex],
memcpy(&finalVertices[finalVerticesSize], &curState->unsortedVertices[drawCall->vertsIndex],
numVerts * sizeof(FOutVector));
// write the indexes, pointing to the fan vertexes but in triangles format
firstVIndex = finalVerticesSize;
@ -401,7 +461,7 @@ static void HWR_ExecuteStateChanges(unsigned int stateChanges, DrawCallInfo *dc)
static void HWR_InitBatchingStats(void)
{
ps_hw_numpolys = drawCallsSize;
ps_hw_numpolys = curState->drawCallsSize;
ps_hw_numcalls = ps_hw_numverts
= ps_hw_numshaders = ps_hw_numtextures
= ps_hw_numpolyflags = ps_hw_numcolors = 0;
@ -414,26 +474,26 @@ void HWR_RenderBatches(void)
int drawCallReadPos = 0; // position in drawCallOrder
int i;
if (!currently_batching)
if (!curState->currently_batching)
I_Error("HWR_RenderBatches called without starting batching");
currently_batching = false; // no longer collecting batches
curState->currently_batching = false; // no longer collecting batches
HWR_InitBatchingStats();
if (!drawCallsSize)
if (!curState->drawCallsSize)
return; // nothing to draw
// init drawCallOrder
for (i = 0; i < drawCallsSize; i++)
for (i = 0; i < curState->drawCallsSize; i++)
drawCallOrder[i] = i;
// sort the draw calls
ps_hw_batchsorttime = I_GetPreciseTime();
if (cv_glshaders.value && gl_shadersavailable)
qs22j(drawCallOrder, drawCallsSize, sizeof(UINT32), compareDrawCalls);
qs22j(drawCallOrder, curState->drawCallsSize, sizeof(UINT32), compareDrawCalls);
else
qs22j(drawCallOrder, drawCallsSize, sizeof(UINT32), compareDrawCallsNoShaders);
qs22j(drawCallOrder, curState->drawCallsSize, sizeof(UINT32), compareDrawCallsNoShaders);
ps_hw_batchsorttime = I_GetPreciseTime() - ps_hw_batchsorttime;
// sort grouping order
// 1. shader
@ -446,7 +506,7 @@ void HWR_RenderBatches(void)
ps_hw_batchdrawtime = I_GetPreciseTime();
// set state for first batch
HWR_ExecuteStateChanges(0xFFFF, &drawCalls[drawCallOrder[0]]);
HWR_ExecuteStateChanges(0xFFFF, &curState->drawCalls[drawCallOrder[0]]);
// - iterate through draw calls
// - accumulate converted vertices and indices into finalVertices and finalIndices
@ -467,18 +527,18 @@ void HWR_RenderBatches(void)
// repeat loop
unsigned int stateChanges = 0; // flags defined above HWR_MarkStateChanges
DrawCallInfo *currentDrawCall = &drawCalls[drawCallOrder[drawCallReadPos++]];
DrawCallInfo *currentDrawCall = &curState->drawCalls[drawCallOrder[drawCallReadPos++]];
DrawCallInfo *nextDrawCall = NULL;
HWR_CollectVerticesIntoBatch(currentDrawCall);
if (drawCallReadPos >= drawCallsSize) // was that the last draw call?
if (drawCallReadPos >= curState->drawCallsSize) // was that the last draw call?
{
stopFlag = true;
}
else
{
nextDrawCall = &drawCalls[drawCallOrder[drawCallReadPos]];
nextDrawCall = &curState->drawCalls[drawCallOrder[drawCallReadPos]];
stateChanges = HWR_MarkStateChanges(currentDrawCall, nextDrawCall);
}
@ -504,8 +564,8 @@ void HWR_RenderBatches(void)
HWR_ExecuteStateChanges(stateChanges, nextDrawCall);
}
// reset the arrays (set sizes to 0)
drawCallsSize = 0;
unsortedVerticesSize = 0;
curState->drawCallsSize = 0;
curState->unsortedVerticesSize = 0;
ps_hw_batchdrawtime = I_GetPreciseTime() - ps_hw_batchdrawtime;
}

View file

@ -21,8 +21,11 @@ extern "C" {
#endif
void HWR_StartBatching(void);
void HWR_PauseBatching(void);
void HWR_SetCurrentTexture(GLMipmap_t *texture);
void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, int shader, boolean horizonSpecial);
void HWR_PushBatchingState(void);
void HWR_PopBatchingState(void);
void HWR_RenderBatches(void);
#ifdef __cplusplus

View file

@ -13,10 +13,12 @@
#ifdef HWRENDER
#include "hw_clip.h"
#include "hw_glob.h"
#include "../p_local.h"
#include "../p_slopes.h"
#include "../r_local.h"
#include "../z_zone.h"
boolean gl_sky_found = true;
// From PrBoom:
//
@ -210,14 +212,30 @@ static boolean CheckClip(seg_t * seg, sector_t * afrontsector, sector_t * abacks
return false;
}
// -----------------+
// HWR_AddLine : Clips the given segment and adds any visible pieces to the line list.
// Notes : gl_cursectorlight is set to the current subsector -> sector -> light value
// : (it may be mixed with the wall's own flat colour in the future ...)
// -----------------+
// returns true if the point is on the correct (viewable) side of the
// portal destination line
static boolean HWR_PortalCheckPointSide(fixed_t x, fixed_t y)
{
// we are checking if the point is on the viewable side of the portal exit.
// being exactly on the portal exit line is not enough to pass the test.
// P_PointOnLineSide could behave differently from this expectation on this case,
// so first check if the point is precisely on the line, and then if not, check the side.
vertex_t closest_point;
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)
return true;
}
return false;
}
// Handles seg clipping and renders the seg if it could be visible.
static void HWR_AddLine(seg_t * line)
{
angle_t angle1, angle2;
boolean skipseg = false;
// SoM: Backsector needs to be run through R_FakeFlat
static sector_t tempsec;
@ -267,6 +285,42 @@ static void HWR_AddLine(seg_t * line)
checkforemptylines = true;
gl_backsector = line->backsector;
// do extra checks on the seg when rendering portals:
// don't render segs that are behind the portal destination line
if (gl_portalclipline &&
!HWR_PortalCheckPointSide(line->v1->x, line->v1->y) &&
!HWR_PortalCheckPointSide(line->v2->x, line->v2->y))
{
return;
}
// Portal line
if (line->linedef->special == 40 && line->side == 0)
{
size_t p;
mtag_t tag = Tag_FGet(&line->linedef->tags);
INT32 li1 = line->linedef-lines;
INT32 li2;
for (p = 0; (li2 = Tag_Iterate_Lines(tag, p)) >= 0; p++)
{
// Skip invalid lines.
if ((tag != Tag_FGet(&lines[li2].tags)) || (lines[li1].special != lines[li2].special) || (li1 == li2))
continue;
// call will bail and return false if recursion limit is reached
if (HWR_AddPortal(&lines[li1], &lines[li2], line))
{
skipseg = true; // TODO could this cause unintentional disappearing of some walls?
if (gl_printportals && !gl_portal_level && !gl_rendering_skybox)
{
// print some info about first level portals
CONS_Printf("line %d -> line %d\n", li1, li2);
}
}
}
}
if (!line->backsector)
{
gld_clipper_SafeAddClipRange(angle2, angle1);
@ -310,8 +364,8 @@ static void HWR_AddLine(seg_t * line)
return;
}
HWR_ProcessSeg(); // Doesn't need arguments because they're defined globally :D
return;
if (!skipseg)
HWR_ProcessSeg(); // Doesn't need arguments because they're defined globally :D
}
// HWR_CheckBBox
@ -329,16 +383,16 @@ static boolean HWR_CheckBBox(const fixed_t *bspcoord)
// Find the corners of the box
// that define the edges from current viewpoint.
if (dup_viewx <= bspcoord[BOXLEFT])
if (viewx <= bspcoord[BOXLEFT])
boxpos = 0;
else if (dup_viewx < bspcoord[BOXRIGHT])
else if (viewx < bspcoord[BOXRIGHT])
boxpos = 1;
else
boxpos = 2;
if (dup_viewy >= bspcoord[BOXTOP])
if (viewy >= bspcoord[BOXTOP])
boxpos |= 0;
else if (dup_viewy > bspcoord[BOXBOTTOM])
else if (viewy > bspcoord[BOXBOTTOM])
boxpos |= 1<<2;
else
boxpos |= 2<<2;
@ -357,6 +411,25 @@ static boolean HWR_CheckBBox(const fixed_t *bspcoord)
return gld_clipper_SafeCheckRange(angle2, angle1);
}
// Check if bounding box is (partially or fully) in the correct side
// of the portal destination.
static boolean HWR_PortalCheckBBox(const fixed_t *bspcoord)
{
if (!gl_portalclipline)
return true;
if (HWR_PortalCheckPointSide(bspcoord[BOXLEFT], bspcoord[BOXTOP]) ||
HWR_PortalCheckPointSide(bspcoord[BOXLEFT], bspcoord[BOXBOTTOM]) ||
HWR_PortalCheckPointSide(bspcoord[BOXRIGHT], bspcoord[BOXTOP]) ||
HWR_PortalCheckPointSide(bspcoord[BOXRIGHT], bspcoord[BOXBOTTOM]))
{
return true;
}
// we did not find any reason to pass the check, so return failure
return false;
}
//
// HWR_AddPolyObjectSegs
//
@ -485,6 +558,9 @@ static void HWR_Subsector(size_t num)
extracolormap_t *ceilingcolormap;
ffloor_t *rover;
//if (gl_printportals && gl_portalclipline)
// CONS_Printf("subsector %d in portal\n", (INT32)num);
#ifdef PARANOIA //no risk while developing, enough debugging nights!
if (num >= addsubsector)
I_Error("HWR_Subsector: ss %s with numss = %s, addss = %s\n",
@ -580,7 +656,7 @@ static void HWR_Subsector(size_t num)
// render floor ?
// yeah, easy backface cull! :)
if (cullFloorHeight < dup_viewz)
if (cullFloorHeight < viewz)
{
if (gl_frontsector->floorpic != skyflatnum)
{
@ -597,7 +673,7 @@ static void HWR_Subsector(size_t num)
}
}
if (cullCeilingHeight > dup_viewz)
if (cullCeilingHeight > viewz)
{
if (gl_frontsector->ceilingpic != skyflatnum)
{
@ -614,6 +690,11 @@ static void HWR_Subsector(size_t num)
}
}
// Moved here because before, when above the ceiling and the floor does not have the sky flat, it doesn't draw the sky
if (gl_frontsector->ceilingpic == skyflatnum || gl_frontsector->floorpic == skyflatnum)
gl_sky_found = true;
if (gl_frontsector->ffloors)
{
/// \todo fix light, xoffs, yoffs, extracolormap ?
@ -633,14 +714,14 @@ static void HWR_Subsector(size_t num)
if (centerHeight <= locCeilingHeight &&
centerHeight >= locFloorHeight &&
((dup_viewz < cullHeight && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) ||
(dup_viewz > cullHeight && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES))))
((viewz < cullHeight && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) ||
(viewz > cullHeight && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES))))
{
if (rover->fofflags & FOF_FOG)
{
UINT8 alpha;
light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < cullHeight ? true : false);
alpha = HWR_FogBlockAlpha(*gl_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap);
HWR_AddTransparentFloor(0,
@ -656,7 +737,7 @@ static void HWR_Subsector(size_t num)
{
FBITFIELD blendmode = HWR_GetBlendModeFlag(rover->blend) | HWR_RippleBlend(gl_frontsector, rover, false);
light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < cullHeight ? true : false);
HWR_AddTransparentFloor(&levelflats[*rover->bottompic],
&extrasubsectors[num],
@ -669,7 +750,7 @@ static void HWR_Subsector(size_t num)
else
{
HWR_GetLevelFlat(&levelflats[*rover->bottompic], R_NoEncore(gl_frontsector, &levelflats[*rover->bottompic], false));
light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < cullHeight ? true : false);
HWR_RenderPlane(sub, &extrasubsectors[num], false, *rover->bottomheight, HWR_RippleBlend(gl_frontsector, rover, false) | PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, &levelflats[*rover->bottompic],
rover->master->frontsector, 255, *gl_frontsector->lightlist[light].extra_colormap);
}
@ -681,14 +762,14 @@ static void HWR_Subsector(size_t num)
if (centerHeight >= locFloorHeight &&
centerHeight <= locCeilingHeight &&
((dup_viewz > cullHeight && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) ||
(dup_viewz < cullHeight && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES))))
((viewz > cullHeight && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) ||
(viewz < cullHeight && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES))))
{
if (rover->fofflags & FOF_FOG)
{
UINT8 alpha;
light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < cullHeight ? true : false);
alpha = HWR_FogBlockAlpha(*gl_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap);
HWR_AddTransparentFloor(0,
@ -704,7 +785,7 @@ static void HWR_Subsector(size_t num)
{
FBITFIELD blendmode = HWR_GetBlendModeFlag(rover->blend) | HWR_RippleBlend(gl_frontsector, rover, false);
light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < cullHeight ? true : false);
HWR_AddTransparentFloor(&levelflats[*rover->toppic],
&extrasubsectors[num],
@ -717,7 +798,7 @@ static void HWR_Subsector(size_t num)
else
{
HWR_GetLevelFlat(&levelflats[*rover->toppic], R_NoEncore(gl_frontsector, &levelflats[*rover->toppic], true));
light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < cullHeight ? true : false);
HWR_RenderPlane(sub, &extrasubsectors[num], true, *rover->topheight, HWR_RippleBlend(gl_frontsector, rover, true) | PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, &levelflats[*rover->toppic],
rover->master->frontsector, 255, *gl_frontsector->lightlist[light].extra_colormap);
}
@ -805,17 +886,39 @@ void HWR_RenderBSPNode(INT32 bspnum)
side = R_PointOnSideFast(viewx, viewy, bsp);
// Recursively divide front space.
HWR_RenderBSPNode(bsp->children[side]);
if (HWR_PortalCheckBBox(bsp->bbox[side]))
HWR_RenderBSPNode(bsp->children[side]);
// Possibly divide back space
if (!(HWR_CheckBBox(bsp->bbox[side^1])))
if (!(HWR_CheckBBox(bsp->bbox[side^1]) && HWR_PortalCheckBBox(bsp->bbox[side^1])))
return;
bspnum = bsp->children[side^1];
}
// e6y: support for extended nodes
HWR_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR);
if (bspnum & NF_SUBSECTOR)
{
if (bspnum == -1)
{
//*(gl_drawsubsector_p++) = 0;
HWR_Subsector(0);
}
else
{
if (gl_portalcullsector)
{
// skip all subsectors encountered before the portal
// destination's front sector
if (gl_portalcullsector != subsectors[bspnum & ~NF_SUBSECTOR].sector)
return;
else
gl_portalcullsector = NULL;
}
//*(gl_drawsubsector_p++) = bspnum&(~NF_SUBSECTOR);
HWR_Subsector(bspnum&(~NF_SUBSECTOR));
}
}
}
#endif

View file

@ -19,6 +19,7 @@
extern "C" {
#endif
#define FAR_CLIPPING_PLANE 32768.0f // Draw further! Tails 01-21-2001
#define ZCLIP_PLANE 4.0f // Used for the actual game drawing
#define NZCLIP_PLANE 0.9f // Seems to be only used for the HUD and screen textures
@ -308,8 +309,9 @@ enum hwdsetspecialstate
HWD_SET_SHADERS,
HWD_SET_TEXTUREFILTERMODE,
HWD_SET_TEXTUREANISOTROPICMODE,
HWD_NUMSTATE
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)
};
typedef enum hwdsetspecialstate hwdspecialstate_t;
@ -321,6 +323,15 @@ enum hwdshaderstage
typedef enum hwdshaderstage hwdshaderstage_t;
// stencil modes
enum
{
HWD_STENCIL_INACTIVE,
HWD_STENCIL_PORTAL_BEGIN,
HWD_STENCIL_PORTAL_INSIDE,
HWD_STENCIL_PORTAL_FINISH
};
// Lactozilla: Shader info
// Generally set at the start of the frame.
enum hwdshaderinfo

View file

@ -1067,7 +1067,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
clearColour.green = (float)rgbaColour.s.green / 255;
clearColour.blue = (float)rgbaColour.s.blue / 255;
clearColour.alpha = 1;
GL_ClearBuffer(true, false, &clearColour);
GL_ClearBuffer(true, false, false, &clearColour);
return;
}
}

View file

@ -82,26 +82,40 @@ typedef struct
// initial size of drawnode array
#define DRAWNODES_INIT_SIZE 64
gl_drawnode_t *drawnodes = NULL;
/*gl_drawnode_t *drawnodes = NULL;
INT32 numdrawnodes = 0;
INT32 alloceddrawnodes = 0;
INT32 alloceddrawnodes = 0;*/
typedef struct
{
gl_drawnode_t *drawnodes;
INT32 numdrawnodes;
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 int stack_level = 0;
static gl_drawnode_state_t *cst = &state_stack[0]; // current state
static void *HWR_CreateDrawNode(gl_drawnode_type_t type)
{
gl_drawnode_t *drawnode;
if (!drawnodes)
if (!cst->drawnodes)
{
alloceddrawnodes = DRAWNODES_INIT_SIZE;
drawnodes = Z_Malloc(alloceddrawnodes * sizeof(gl_drawnode_t), PU_LEVEL, &drawnodes);
cst->alloceddrawnodes = DRAWNODES_INIT_SIZE;
cst->drawnodes = Z_Malloc(cst->alloceddrawnodes * sizeof(gl_drawnode_t), PU_LEVEL, &cst->drawnodes);
}
else if (numdrawnodes >= alloceddrawnodes)
else if (cst->numdrawnodes >= cst->alloceddrawnodes)
{
alloceddrawnodes *= 2;
Z_Realloc(drawnodes, alloceddrawnodes * sizeof(gl_drawnode_t), PU_LEVEL, &drawnodes);
cst->alloceddrawnodes *= 2;
Z_Realloc(cst->drawnodes, cst->alloceddrawnodes * sizeof(gl_drawnode_t), PU_LEVEL, &cst->drawnodes);
}
drawnode = &drawnodes[numdrawnodes++];
drawnode = &cst->drawnodes[cst->numdrawnodes++];
drawnode->type = type;
// not sure if returning different pointers to a union is necessary
@ -166,12 +180,32 @@ void HWR_AddTransparentPolyobjectFloor(levelflat_t *levelflat, polyobj_t *polyse
polyplaneinfo->planecolormap = planecolormap;
}
// pushes all drawnode rendering state to stack
void HWR_PushDrawNodeState(void)
{
// todo magic number 16
if (stack_level == 15)
I_Error("HWR_PushDrawNodeState: State stack overflow");
stack_level++;
cst++;
}
void HWR_PopDrawNodeState(void)
{
if (stack_level == 0)
I_Error("HWR_PopDrawNodeState: State stack underflow");
stack_level--;
cst--;
}
static int CompareDrawNodePlanes(const void *p1, const void *p2)
{
INT32 n1 = *(const INT32*)p1;
INT32 n2 = *(const INT32*)p2;
return ABS(drawnodes[n2].u.plane.fixedheight - viewz) - ABS(drawnodes[n1].u.plane.fixedheight - viewz);
return ABS(cst->drawnodes[n2].u.plane.fixedheight - viewz) - ABS(cst->drawnodes[n1].u.plane.fixedheight - viewz);
}
// HWR_RenderDrawNodes
@ -184,34 +218,34 @@ void HWR_RenderDrawNodes(void)
// A list of indices into the drawnodes array.
INT32 *sortindex;
if (!numdrawnodes)
if (!cst->numdrawnodes)
return;
ps_numdrawnodes = numdrawnodes;
ps_numdrawnodes = cst->numdrawnodes;
ps_hw_nodesorttime = I_GetPreciseTime();
sortindex = Z_Malloc(sizeof(INT32) * numdrawnodes, PU_STATIC, NULL);
sortindex = Z_Malloc(sizeof(INT32) * cst->numdrawnodes, PU_STATIC, NULL);
// Reversed order
for (i = 0; i < numdrawnodes; i++)
sortindex[i] = numdrawnodes - i - 1;
for (i = 0; i < cst->numdrawnodes; i++)
sortindex[i] = cst->numdrawnodes - i - 1;
// The order is correct apart from planes in the same subsector.
// So scan the list and sort out these cases.
// For each consecutive run of planes in the list, sort that run based on
// plane height and view height.
while (run_start < numdrawnodes-1) // numdrawnodes-1 because a 1 plane run at the end of the list does not count
while (run_start < cst->numdrawnodes-1) // numdrawnodes-1 because a 1 plane run at the end of the list does not count
{
// locate run start
if (drawnodes[sortindex[run_start]].type == DRAWNODE_PLANE)
if (cst->drawnodes[sortindex[run_start]].type == DRAWNODE_PLANE)
{
// found it, now look for run end
INT32 run_end;// (inclusive)
for (i = run_start+1; i < numdrawnodes; i++)
for (i = run_start+1; i < cst->numdrawnodes; i++)
{
if (drawnodes[sortindex[i]].type != DRAWNODE_PLANE) break;
if (cst->drawnodes[sortindex[i]].type != DRAWNODE_PLANE) break;
}
run_end = i-1;
if (run_end > run_start) // if there are multiple consecutive planes, not just one
@ -235,9 +269,9 @@ void HWR_RenderDrawNodes(void)
// Okay! Let's draw it all! Woo!
GL_SetTransform(&atransform);
for (i = 0; i < numdrawnodes; i++)
for (i = 0; i < cst->numdrawnodes; i++)
{
gl_drawnode_t *drawnode = &drawnodes[sortindex[i]];
gl_drawnode_t *drawnode = &cst->drawnodes[sortindex[i]];
if (drawnode->type == DRAWNODE_PLANE)
{
@ -279,7 +313,7 @@ void HWR_RenderDrawNodes(void)
ps_hw_nodedrawtime = I_GetPreciseTime() - ps_hw_nodedrawtime;
numdrawnodes = 0;
cst->numdrawnodes = 0;
// No mem leaks, please.
Z_Free(sortindex);

View file

@ -166,6 +166,7 @@ void HWR_ClearLightTables(void);
// hw_bsp.c
// --------
void HWR_RenderBSPNode(INT32 bspnum);
extern boolean gl_sky_found;
// --------
// hw_draw.c
@ -188,6 +189,8 @@ void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, INT32 te
void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap);
void HWR_AddTransparentPolyobjectFloor(levelflat_t *levelflat, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight,
INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap);
void HWR_PushDrawNodeState(void);
void HWR_PopDrawNodeState(void);
void HWR_RenderDrawNodes(void);
// --------
@ -220,12 +223,13 @@ void HWR_DrawSkyBackground(player_t *player);
// --------
// hw_things.c
// --------
extern UINT32 gl_visspritecount;
void HWR_ClearSprites(void);
void HWR_PushSpriteState(void);
void HWR_PopSpriteState(void);
void HWR_AddSprites(sector_t *sec);
void HWR_AddPrecipitationSprites(void);
void HWR_SortVisSprites(void);
UINT32 HWR_SortVisSprites(void);
void HWR_DrawSprites(void);
void HWR_ProjectBoundingBox(mobj_t *thing);

View file

@ -31,7 +31,7 @@ void GL_DrawPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, F
void GL_DrawIndexedTriangles(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, UINT32 *IndexArray);
void GL_RenderSkyDome(gl_sky_t *sky);
void GL_SetBlend(FBITFIELD PolyFlags);
void GL_ClearBuffer(FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFloat *ClearColor);
void GL_ClearBuffer(FBOOLEAN ColorMask, FBOOLEAN DepthMask, FBOOLEAN StencilMask, FRGBAFloat *ClearColor);
void GL_SetTexture(GLMipmap_t *pTexInfo);
void GL_UpdateTexture(GLMipmap_t *pTexInfo);
void GL_DeleteTexture(GLMipmap_t *pTexInfo);

View file

@ -110,15 +110,13 @@ boolean gl_shadersavailable = false;
// Whether the internal state is set to palette rendering or not.
static boolean gl_palette_rendering_state = false;
boolean gl_rendering_skybox = false;
// --------------------------------------------------------------------------
// STUFF FOR THE PROJECTION CODE
// --------------------------------------------------------------------------
FTransform atransform;
// duplicates of the main code, set after R_SetupFrame() passed them into sharedstruct,
// copied here for local use
fixed_t dup_viewx, dup_viewy, dup_viewz;
angle_t dup_viewangle;
float gl_viewx, gl_viewy, gl_viewz;
float gl_viewsin, gl_viewcos;
@ -129,6 +127,161 @@ static float gl_fovlud;
static angle_t gl_aimingangle;
/* Portal stuff */
// TODO probably put this to a separate file?
typedef struct
{
// Viewport.
fixed_t viewx;
fixed_t viewy;
fixed_t viewz;
angle_t viewangle;
seg_t *seg; // seg that is used for drawing to the stencil buffer
line_t *clipline;
// angles for the left and right edges of the portal
// relative to the viewpoint
angle_t angle1;
angle_t angle2;
} gl_portal_t;
#define INIT_PORTAL_ARRAY_SIZE 4
typedef struct
{
gl_portal_t *portals;
unsigned int size;
unsigned int capacity;
} gl_portal_array_t;
// TODO magic number 16
gl_portal_array_t gl_portal_arrays[16] = {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
INT32 gl_debugportal = 0; // hide main viewpoint and only render this portal without stencil
static void HWR_PortalFrame(gl_portal_t *portal, boolean set_culling)
{
viewx = portal->viewx;
viewy = portal->viewy;
viewz = portal->viewz;
viewangle = portal->viewangle;
viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT);
viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
// set_culling will be true if RenderBSPNode is about to be called
// so need to enable portal culling for that
if (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
}
}
// get currently used portal array
static gl_portal_array_t *HWR_GetPortalArray(void)
{
INT32 level = gl_portal_level;
if (gl_rendering_skybox)
level++;
return &gl_portal_arrays[level];
}
boolean HWR_AddPortal(line_t *start, line_t *dest, seg_t *seg)
{
gl_portal_array_t *array;
gl_portal_t *portal;
angle_t dangle;
fixed_t disttopoint;
angle_t angtopoint;
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)))
{
return false;
}
if (gl_debugportal)
gl_debugportal = -1; // skip other portal segs from the same line
array = HWR_GetPortalArray();
// yet another dynamic array
if (!array->portals)
{
array->capacity = INIT_PORTAL_ARRAY_SIZE;
array->portals = Z_Malloc(sizeof(gl_portal_t) * array->capacity, PU_LEVEL,
&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);
}
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
// 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);
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;
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);
portal->viewz = viewz + dest->frontsector->floorheight - start->frontsector->floorheight;
portal->viewangle = viewangle + dangle;
portal->seg = seg;
portal->clipline = dest;
portal->angle1 = R_PointToAngle64(seg->v1->x, seg->v1->y) + dangle;
portal->angle2 = R_PointToAngle64(seg->v2->x, seg->v2->y) + dangle;
return true;
}
static void HWR_ClearPortals(void)
{
HWR_GetPortalArray()->size = 0;
}
// ==========================================================================
// Lighting
// ==========================================================================
@ -415,26 +568,15 @@ boolean HWR_BlendMidtextureSurface(FSurfaceInfo *pSurf)
// -----------------+
// HWR_ClearView : clear the viewwindow, with maximum z value
// -----------------+
static inline void HWR_ClearView(void)
/*static inline void HWR_ClearView(void)
{
// 3--2
// | /|
// |/ |
// 0--1
/// \bug faB - enable depth mask, disable color mask
GL_GClipRect((INT32)gl_viewwindowx,
(INT32)gl_viewwindowy,
(INT32)(gl_viewwindowx + gl_viewwidth),
(INT32)(gl_viewwindowy + gl_viewheight),
ZCLIP_PLANE);
GL_ClearBuffer(false, true, 0);
//disable clip window - set to full size
// rem by Hurdler
// GL_GClipRect(0, 0, vid.width, vid.height);
}
GL_ClearBuffer(false, true, true, 0)
}*/
// -----------------+
@ -499,8 +641,9 @@ static void HWR_ShiftViewPort(void)
// Set view aiming, for the sky dome, the skybox,
// and the normal view, all with a single function.
void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox)
void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox, boolean side_effect)
{
angle_t temp_aimingangle;
// 1 = always on
// 2 = chasecam only
if (cv_glshearing.value == 1 || (cv_glshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox)))
@ -508,26 +651,20 @@ void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox)
fixed_t fixedaiming = AIMINGTODY(aimingangle);
trans->viewaiming = FIXED_TO_FLOAT(fixedaiming);
trans->shearing = true;
gl_aimingangle = 0;
temp_aimingangle = 0;
}
else
{
trans->shearing = false;
gl_aimingangle = aimingangle;
temp_aimingangle = aimingangle;
}
trans->anglex = (float)(gl_aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
trans->anglex = (float)(temp_aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
if (side_effect)
gl_aimingangle = temp_aimingangle;
}
//
// Sets the shader state.
//
static void HWR_SetShaderState(void)
{
GL_SetSpecialState(HWD_SET_SHADERS, (INT32)HWR_UseShader());
}
static void HWR_ClearClipper(void)
static void HWR_ResetClipper(void)
{
angle_t a1 = gld_FrustumAngle(gl_aimingangle);
gld_clipper_Clear();
@ -537,39 +674,28 @@ static void HWR_ClearClipper(void)
#endif
}
static void HWR_RenderViewpoint(player_t *player, boolean drawSkyTexture, boolean timing)
// clip the area outside the portal destination window
static void HWR_PortalClipping(gl_portal_t *portal)
{
gld_clipper_SafeAddClipRange(portal->angle1, portal->angle2);
}
static void HWR_SetShaderState(void)
{
GL_SetSpecialState(HWD_SET_SHADERS, (INT32)HWR_UseShader());
}
// prepare all transform related variables based on the current "frame"
// (R_SetupFrame etc)
static void HWR_PrepareTransform(player_t *player, boolean is_skybox)
{
UINT8 viewnum = R_GetViewNumber();
camera_t *thiscam = &camera[viewnum];
const float fpov = FIXED_TO_FLOAT(cv_fov[viewssnum].value+player->fovadd);
if (!HWR_ShouldUsePaletteRendering())
{
// do we really need to save player (is it not the same)?
player_t *saved_player = stplyr;
stplyr = player;
ST_doPaletteStuff();
stplyr = saved_player;
#ifdef ALAM_LIGHTING
HWR_SetLights(viewssnum);
#endif
}
// copy view cam position for local use
dup_viewx = viewx;
dup_viewy = viewy;
dup_viewz = viewz;
dup_viewangle = viewangle;
// set window position
HWR_ShiftViewPort();
// check for new console commands.
NetUpdate();
gl_viewx = FIXED_TO_FLOAT(dup_viewx);
gl_viewy = FIXED_TO_FLOAT(dup_viewy);
gl_viewz = FIXED_TO_FLOAT(dup_viewz);
gl_viewx = FIXED_TO_FLOAT(viewx);
gl_viewy = FIXED_TO_FLOAT(viewy);
gl_viewz = FIXED_TO_FLOAT(viewz);
gl_viewsin = FIXED_TO_FLOAT(viewsin);
gl_viewcos = FIXED_TO_FLOAT(viewcos);
@ -577,7 +703,7 @@ static void HWR_RenderViewpoint(player_t *player, boolean drawSkyTexture, boolea
// It should replace all other gl_viewxxx when finished
memset(&atransform, 0x00, sizeof(FTransform));
HWR_SetTransformAiming(&atransform, player, false);
HWR_SetTransformAiming(&atransform, player, is_skybox, true);
atransform.angley = (float)(viewangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
gl_viewludsin = FIXED_TO_FLOAT(FINECOSINE(gl_aimingangle>>ANGLETOFINESHIFT));
@ -608,23 +734,129 @@ static void HWR_RenderViewpoint(player_t *player, boolean drawSkyTexture, boolea
atransform.splitscreen = r_splitscreen;
gl_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l)));
}
//------------------------------------------------------------------------
HWR_ClearView(); // Clears the depth buffer and resets the view I believe
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;
}
if (drawSkyTexture)
HWR_DrawSkyBackground(player);
static void HWR_LeaveSkyboxState(void)
{
HWR_PopBatchingState();
HWR_PopSpriteState();
HWR_PopDrawNodeState();
// see above comment
//gl_portal_level--;
gl_rendering_skybox = false;
}
static void HWR_RenderPortalSeg(seg_t *seg)
{
gl_drawing_stencil = true;
gl_curline = seg;
gl_frontsector = seg->frontsector;
gl_backsector = seg->backsector;
HWR_ProcessSeg();
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);
}
// clear the depth buffer from the stenciled area so portal
// content doesn't get clipped by previous buffer content
// (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?
FBITFIELD blendflags = PF_Occlude|PF_NoDepthTest|PF_NoTexture|PF_NoAlphaTest;
if (!visible)
blendflags |= PF_Invisible;
// so this is apparently how you draw the far clipping plane when
// pfnSetTransform(NULL) is active
const float a = FAR_CLIPPING_PLANE;
verts[0].x = -a; verts[0].y = -a; verts[0].z = a;
verts[1].x = -a; verts[1].y = a; verts[1].z = a;
verts[2].x = a; verts[2].y = a; verts[2].z = a;
verts[3].x = a; verts[3].y = -a; verts[3].z = a;
GL_SetTransform(NULL);
GL_DrawPolygon(NULL, verts, 4, blendflags);
}
static void HWR_RenderViewpoint(player_t *player, boolean drawSkyTexture, boolean is_skybox, boolean timing, gl_portal_t *rootportal);
static void HWR_RenderPortal(gl_portal_t *portal, gl_portal_t *rootportal, player_t *player, boolean is_skybox)
{
HWR_PushSpriteState();
HWR_PushDrawNodeState();
if (!gl_debugportal)
{
HWR_SetStencilState(HWD_STENCIL_PORTAL_BEGIN);
HWR_RenderPortalSeg(portal->seg);
}
gl_portal_level++;
if (!gl_debugportal)
HWR_SetStencilState(HWD_STENCIL_PORTAL_INSIDE);
HWR_RenderDepthEraser(true);
HWR_PortalFrame(portal, true);
HWR_RenderViewpoint(player, true, is_skybox, false, portal);
// restore previous frame and transform
if (rootportal)
HWR_PortalFrame(rootportal, false);
else if (is_skybox)
R_SkyboxFrame(viewssnum);
else
R_SetupFrame(viewssnum, is_skybox);
HWR_PrepareTransform(player, is_skybox);
GL_SetTransform(&atransform);
if (!gl_debugportal)
{
HWR_SetStencilState(HWD_STENCIL_PORTAL_FINISH);
HWR_RenderPortalSeg(portal->seg);
}
gl_portal_level--;
HWR_PopSpriteState();
HWR_PopDrawNodeState();
}
static void HWR_RenderViewpoint(player_t *player, boolean drawSkyTexture, boolean is_skybox, boolean timing, gl_portal_t *rootportal)
{
unsigned int i;
gl_portal_array_t *portal_array;
HWR_PrepareTransform(player, is_skybox);
HWR_ClearSprites();
//04/01/2000: Hurdler: added for T&L
// Actually it only works on Walls and Planes
GL_SetTransform(&atransform);
HWR_ResetClipper();
HWR_ClearClipper();
if (rootportal)
HWR_PortalClipping(rootportal);
// Reset the shader state.
HWR_SetShaderState();
// check for new console commands.
NetUpdate();
if (timing)
{
@ -634,21 +866,99 @@ static void HWR_RenderViewpoint(player_t *player, boolean drawSkyTexture, boolea
}
validcount++;
gl_sky_found = false;
if (LIKELY(cv_glbatching.value))
HWR_StartBatching();
HWR_StartBatching();
HWR_AddPrecipitationSprites();
HWR_RenderBSPNode((INT32)numnodes-1);
// restore portal clipping variables
gl_portalcullsector = NULL;
gl_portalclipline = NULL;
if (timing)
{
ps_bsptime = I_GetPreciseTime() - ps_bsptime;
}
if (LIKELY(cv_glbatching.value))
HWR_RenderBatches();
if (gl_printportals && !gl_portal_level && !gl_rendering_skybox)
CONS_Printf("Portal recursion summary:\n");
//if (gl_printportals)
// CONS_Printf("%d bsp calls\n", ps_numbspcalls);
if (gl_sky_found)
{
// HWR_DrawSkyBackground is not able to set the texture without
// pausing batching first
HWR_PauseBatching();
if (skyboxmo[0] && cv_skybox.value && !is_skybox && !rootportal && !gl_debugportal)
{
//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
HWR_EnterSkyboxState();
HWR_RenderViewpoint(player, true, true, false, rootportal);
HWR_LeaveSkyboxState();
// restore (=clear) z-buffer, but only in the portal window
if (rootportal)
HWR_RenderDepthEraser(false);
else
GL_ClearBuffer(false, true, false, 0);
// restore transform
if (rootportal)
HWR_PortalFrame(rootportal, false);
else
R_SetupFrame(viewssnum, is_skybox);
HWR_PrepareTransform(player, is_skybox);
}
else
{
if (drawSkyTexture)
HWR_DrawSkyBackground(player);
}
// turn batching back on
HWR_StartBatching();
}
// apply transform to backend now when we're actually drawing to the screen
GL_SetTransform(&atransform);
HWR_RenderBatches();
// this is a hacky way to get rid of the main viewpoint for the debugportal
// command but maybe simpler than other options
if (gl_debugportal && !gl_portal_level)
GL_ClearBuffer(true, true, true, 0);
portal_array = HWR_GetPortalArray();
for (i = 0; i < portal_array->size; i++)
HWR_RenderPortal(&portal_array->portals[i], rootportal, player, is_skybox);
HWR_ClearPortals();
// if there was portals, restore stencil state since HWR_RenderPortal
// has altered it
if (i)
{
HWR_SetStencilState(gl_portal_level ?
HWD_STENCIL_PORTAL_INSIDE : HWD_STENCIL_INACTIVE);
if (gl_printportals && !gl_rendering_skybox)
{
CONS_Printf("%*c%d: %u portals rendered\n", gl_portal_level+1, 'L',
gl_portal_level, i);
}
}
// hack for debugportal, see earlier comment
if (gl_debugportal && !gl_portal_level)
{
gl_portal_level = 15; // this will make the sprites and drawnodes get discarded
HWR_SetStencilState(HWD_STENCIL_PORTAL_INSIDE);
gl_portal_level = 0;
}
// Check for new console commands.
NetUpdate();
@ -663,11 +973,14 @@ static void HWR_RenderViewpoint(player_t *player, boolean drawSkyTexture, boolea
if (timing)
{
ps_numsprites = gl_visspritecount;
ps_hw_spritesorttime = I_GetPreciseTime();
}
HWR_SortVisSprites();
UINT32 count = HWR_SortVisSprites();
if (timing)
ps_numsprites = count;
if (timing)
{
@ -696,15 +1009,12 @@ static void HWR_RenderViewpoint(player_t *player, boolean drawSkyTexture, boolea
HWR_RenderDrawNodes(); //Hurdler: render 3D water and transparent walls after everything
GL_SetTransform(NULL);
GL_UnSetShader();
// hack for debugportal, see earlier comment
if (gl_debugportal && !gl_portal_level)
HWR_SetStencilState(HWD_STENCIL_INACTIVE);
// Check for new console commands.
NetUpdate();
// added by Hurdler for correct splitscreen
// moved here by hurdler so it works with the new near clipping plane
GL_GClipRect(0, 0, vid.width, vid.height, NZCLIP_PLANE);
}
// ==========================================================================
@ -715,7 +1025,7 @@ void HWR_RenderSkyboxView(player_t *player)
// note: sets viewangle, viewx, viewy, viewz
R_SkyboxFrame(viewssnum);
HWR_RenderViewpoint(player, true, false);
HWR_RenderViewpoint(player, true, true, false, NULL);
}
// ==========================================================================
@ -746,11 +1056,37 @@ void HWR_RenderPlayerView(void)
ClearColor.blue = 0.0f;
ClearColor.alpha = 1.0f;
GL_ClearBuffer(true, true, true, &ClearColor);
if (!HWR_ShouldUsePaletteRendering())
{
// do we really need to save player (is it not the same)?
player_t *saved_player = stplyr;
stplyr = player;
ST_doPaletteStuff();
stplyr = saved_player;
#ifdef ALAM_LIGHTING
HWR_SetLights(viewssnum);
#endif
}
// set window position
HWR_ShiftViewPort();
GL_GClipRect((INT32)gl_viewwindowx,
(INT32)gl_viewwindowy,
(INT32)(gl_viewwindowx + gl_viewwidth),
(INT32)(gl_viewwindowy + gl_viewheight),
ZCLIP_PLANE);
// Reset the shader state.
HWR_SetShaderState();
if (cv_glshaders.value)
GL_SetShaderInfo(HWD_SHADERINFO_LEVELTIME, (INT32)leveltime); // The water surface shader needs the leveltime.
if (viewssnum == 0) // Only do it if it's the first screen being rendered
GL_ClearBuffer(true, false, &ClearColor); // Clear the Color Buffer, stops HOMs. Also seems to fix the skybox issue on Intel GPUs.
GL_ClearBuffer(true, false, false, &ClearColor); // Clear the Color Buffer, stops HOMs. Also seems to fix the skybox issue on Intel GPUs.
ps_hw_skyboxtime = I_GetPreciseTime();
if (skybox) // If there's a skybox and we should be drawing the sky, draw the skybox
@ -766,12 +1102,24 @@ void HWR_RenderPlayerView(void)
HWR_RenderViewpoint(player,
!skybox, // Don't draw the regular sky if there's a skybox
true); // Main view is profiled
false,
true, // Main view is profiled
NULL);
gl_printportals = false;
gl_debugportal = 0;
GL_SetTransform(NULL);
GL_UnSetShader();
HWR_DoPostProcessor(player);
// Check for new console commands.
NetUpdate();
// added by Hurdler for correct splitscreen
// moved here by hurdler so it works with the new near clipping plane
GL_GClipRect(0, 0, vid.width, vid.height, NZCLIP_PLANE);
}
// Returns whether palette rendering is "actually enabled."
@ -902,6 +1250,10 @@ 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);
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);
#define ONLY_IF_GL_LOADED if (vid.glstate != VID_GL_LIBRARY_LOADED) return;
static void CV_glfiltermode_OnChange(void)
@ -956,6 +1308,19 @@ void CV_glshaders_OnChange(void)
}
}
static void Command_Glprintportals_f(void)
{
if (cht_debug)
{
gl_printportals = true;
CONS_Printf("List of top level portals:\n");
}
else
{
CONS_Printf("This command is only available in devmode.\n");
}
}
//added by Hurdler: console varibale that are saved
void HWR_AddCommands(void)
{
@ -991,6 +1356,11 @@ void HWR_AddCommands(void)
CV_RegisterVar(&cv_glpaletterendering);
CV_RegisterVar(&cv_glpalettedepth);
COM_AddCommand("gr_printportals", Command_Glprintportals_f);
CV_RegisterVar(&cv_gldebugportal);
CV_RegisterVar(&cv_glskydebug);
}
void HWR_AddSessionCommands(void)

View file

@ -38,7 +38,7 @@ void HWR_RenderSkyboxView(player_t *player);
void HWR_RenderPlayerView(void);
void HWR_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum);
void HWR_SetViewSize(void);
void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox);
void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox, boolean side_effect);
void HWR_RollTransform(FTransform *tr, angle_t roll);
boolean HWR_BlendMidtextureSurface(FSurfaceInfo *pSurf);
void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap);
@ -118,6 +118,9 @@ extern consvar_t cv_glskydome;
extern consvar_t cv_glbatching;
extern consvar_t cv_glpaletterendering;
extern consvar_t cv_glpalettedepth;
extern consvar_t cv_gldebugportal;
extern consvar_t cv_glskydebug;
extern float gl_viewwidth, gl_viewheight, gl_baseviewwindowy;
@ -133,9 +136,6 @@ extern sector_t *gl_backsector;
extern FTransform atransform;
extern float gl_viewsin, gl_viewcos;
extern fixed_t dup_viewx, dup_viewy, dup_viewz;
extern angle_t dup_viewangle;
extern float gl_viewx, gl_viewy, gl_viewz;
extern float gl_viewsin, gl_viewcos;
@ -164,6 +164,24 @@ extern boolean gl_maploaded;
extern boolean gl_sessioncommandsadded;
extern boolean gl_shadersavailable;
extern boolean gl_rendering_skybox;
/* Portal stuff */
// TODO probably put this to a separate file?
boolean HWR_AddPortal(line_t *start, line_t *dest, seg_t *seg);
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;
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -218,7 +218,7 @@ void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, boolean isc
for (i = 0; i < subsector->numlines; i++, line++)
{
if (!line->glseg && line->linedef->special == HORIZONSPECIAL && R_PointOnSegSide(dup_viewx, dup_viewy, line) == 0)
if (!line->glseg && line->linedef->special == HORIZONSPECIAL && R_PointOnSegSide(viewx, viewy, line) == 0)
{
P_ClosestPointOnLine(viewx, viewy, line->linedef, &v);
dist = FIXED_TO_FLOAT(R_PointToDist(v.x, v.y));

View file

@ -92,6 +92,13 @@ static void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIEL
blendmode |= PF_ColorMapped;
}
// don't draw to color buffer when drawing to stencil
if (gl_drawing_stencil)
{
blendmode |= PF_Invisible|PF_NoAlphaTest; // TODO not sure if any others than PF_Invisible are needed??
blendmode &= ~PF_Masked;
}
HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode|PF_Modulated|PF_Occlude, shader, false);
}
@ -287,6 +294,17 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum,
// Draw walls into the depth buffer so that anything behind is culled properly
static void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf)
{
if (cv_glskydebug.value)
{
wallVerts[3].t = wallVerts[2].t = 4;
wallVerts[0].t = wallVerts[1].t = 0;
wallVerts[0].s = wallVerts[3].s = 0.1;
wallVerts[2].s = wallVerts[1].s = 0;
HWR_GetTexture(cv_glskydebug.value, false);
HWR_ProjectWall(wallVerts, Surf, 0, 255, NULL);
return;
}
HWR_SetCurrentTexture(NULL);
// no texture
wallVerts[3].t = wallVerts[2].t = 0;
@ -373,9 +391,9 @@ static void HWR_ProcessTwoSidedSegTop(FOutVector *wallVerts, FSurfaceInfo *Surf,
if (grTex->mipmap.flags & TF_TRANSPARENT)
polyflags = PF_Environment;
if (gl_frontsector->numlights)
if (!gl_drawing_stencil && gl_frontsector->numlights)
HWR_SplitWall(gl_frontsector, wallVerts, gl_toptexture, noencore, Surf, FOF_CUTLEVEL, NULL, polyflags);
else if (grTex->mipmap.flags & TF_TRANSPARENT)
else if (!gl_drawing_stencil && (grTex->mipmap.flags & TF_TRANSPARENT))
HWR_AddTransparentWall(wallVerts, Surf, gl_toptexture, noencore, polyflags, false, lightnum, gl_frontsector->extra_colormap);
else
HWR_ProjectWall(wallVerts, Surf, polyflags, lightnum, gl_frontsector->extra_colormap);
@ -441,14 +459,17 @@ static void HWR_ProcessTwoSidedSegBottom(FOutVector *wallVerts, FSurfaceInfo *Su
if (grTex->mipmap.flags & TF_TRANSPARENT)
polyflags = PF_Environment;
if (gl_frontsector->numlights)
if (!gl_drawing_stencil && gl_frontsector->numlights)
HWR_SplitWall(gl_frontsector, wallVerts, gl_bottomtexture, noencore, Surf, FOF_CUTLEVEL, NULL, polyflags);
else if (grTex->mipmap.flags & TF_TRANSPARENT)
else if (!gl_drawing_stencil && (grTex->mipmap.flags & TF_TRANSPARENT))
HWR_AddTransparentWall(wallVerts, Surf, gl_bottomtexture, noencore, polyflags, false, lightnum, gl_frontsector->extra_colormap);
else
HWR_ProjectWall(wallVerts, Surf, polyflags, lightnum, gl_frontsector->extra_colormap);
}
// gl_midtexture can be inactive for this function
// when rendering twosided portal midtextures
static void HWR_ProcessTwoSidedSegMiddle(FOutVector *wallVerts, FSurfaceInfo *Surf, gl_seg_bounds *b,
float cliplow, float cliphigh, FUINT lightnum, INT32 gl_midtexture, boolean noencore, boolean tripwire)
{
@ -462,6 +483,8 @@ static void HWR_ProcessTwoSidedSegMiddle(FOutVector *wallVerts, FSurfaceInfo *Su
fixed_t popentopslope, popenbottomslope, polytopslope, polybottomslope, lowcutslope, highcutslope;
fixed_t texturevpeg = 0;
INT32 repeats;
fixed_t midtexheight = 0;
fixed_t texturevpegslope = 0;
if (gl_linedef->frontsector->heightsec != -1)
front = &sectors[gl_linedef->frontsector->heightsec];
@ -473,28 +496,31 @@ static void HWR_ProcessTwoSidedSegMiddle(FOutVector *wallVerts, FSurfaceInfo *Su
else
back = gl_linedef->backsector;
if (gl_sidedef->repeatcnt)
repeats = 1 + gl_sidedef->repeatcnt;
else if (gl_linedef->flags & ML_WRAPMIDTEX)
if (gl_midtexture)
{
fixed_t high, low;
if (gl_sidedef->repeatcnt)
repeats = 1 + gl_sidedef->repeatcnt;
else if (gl_linedef->flags & ML_WRAPMIDTEX)
{
fixed_t high, low;
if (front->ceilingheight > back->ceilingheight)
high = back->ceilingheight;
if (front->ceilingheight > back->ceilingheight)
high = back->ceilingheight;
else
high = front->ceilingheight;
if (front->floorheight > back->floorheight)
low = front->floorheight;
else
low = back->floorheight;
repeats = (high - low) / textureheight[gl_midtexture];
if ((high - low) % textureheight[gl_midtexture])
repeats++; // tile an extra time to fill the gap -- Monster Iestyn
}
else
high = front->ceilingheight;
if (front->floorheight > back->floorheight)
low = front->floorheight;
else
low = back->floorheight;
repeats = (high - low) / textureheight[gl_midtexture];
if ((high - low) % textureheight[gl_midtexture])
repeats++; // tile an extra time to fill the gap -- Monster Iestyn
repeats = 1;
}
else
repeats = 1;
// NOTE: With polyobjects, whenever you need to check the properties of the polyobject sector it belongs to,
// you must use the linedef's backsector to be correct
@ -512,40 +538,43 @@ static void HWR_ProcessTwoSidedSegMiddle(FOutVector *wallVerts, FSurfaceInfo *Su
popenbottomslope = max(b->worldbottomslope, b->worldlowslope);
}
// Find the wall's coordinates
fixed_t midtexheight = textureheight[gl_midtexture] * repeats;
// Texture is not skewed
if (gl_linedef->flags & ML_NOSKEW)
if (gl_midtexture)
{
if (gl_linedef->flags & ML_MIDPEG) // Peg it to the floor
// Find the wall's coordinates
midtexheight = textureheight[gl_midtexture] * repeats;
// Texture is not skewed
if (gl_linedef->flags & ML_NOSKEW)
{
polybottom = max(front->floorheight, back->floorheight) + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
if (gl_linedef->flags & ML_MIDPEG) // Peg it to the floor
{
polybottom = max(front->floorheight, back->floorheight) + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
polytop = polybottom + midtexheight;
}
else // Peg it to the ceiling
{
polytop = min(front->ceilingheight, back->ceilingheight) + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
polybottom = polytop - midtexheight;
}
// The right side's coordinates are the the same as the left side
polytopslope = polytop;
polybottomslope = polybottom;
}
else if (gl_linedef->flags & ML_MIDPEG) // Skew the texture, but peg it to the floor
{
polybottom = popenbottom + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
polytop = polybottom + midtexheight;
polybottomslope = popenbottomslope + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
polytopslope = polybottomslope + midtexheight;
}
else // Peg it to the ceiling
else // Skew it according to the ceiling's slope
{
polytop = min(front->ceilingheight, back->ceilingheight) + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
polytop = popentop + gl_sidedef->rowoffset;
polybottom = polytop - midtexheight;
polytopslope = popentopslope + gl_sidedef->rowoffset;
polybottomslope = polytopslope - midtexheight;
}
// The right side's coordinates are the the same as the left side
polytopslope = polytop;
polybottomslope = polybottom;
}
else if (gl_linedef->flags & ML_MIDPEG) // Skew the texture, but peg it to the floor
{
polybottom = popenbottom + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
polytop = polybottom + midtexheight;
polybottomslope = popenbottomslope + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
polytopslope = polybottomslope + midtexheight;
}
else // Skew it according to the ceiling's slope
{
polytop = popentop + gl_sidedef->rowoffset;
polybottom = polytop - midtexheight;
polytopslope = popentopslope + gl_sidedef->rowoffset;
polybottomslope = polytopslope - midtexheight;
}
// CB
@ -572,18 +601,22 @@ static void HWR_ProcessTwoSidedSegMiddle(FOutVector *wallVerts, FSurfaceInfo *Su
hS = min(highcutslope, polytopslope);
lS = max(polybottomslope, lowcutslope);
// PEGGING
fixed_t texturevpegslope;
// gl_midtexture can be inactive when rendering twosided portal midtextures
if (gl_midtexture)
{
// PEGGING
if (gl_linedef->flags & ML_MIDPEG)
{
texturevpeg = midtexheight - h + polybottom;
texturevpegslope = midtexheight - hS + polybottomslope;
}
else
{
texturevpeg = polytop - h;
texturevpegslope = polytopslope - hS;
}
if (gl_linedef->flags & ML_MIDPEG)
{
texturevpeg = midtexheight - h + polybottom;
texturevpegslope = midtexheight - hS + polybottomslope;
}
else
{
texturevpeg = polytop - h;
texturevpegslope = polytopslope - hS;
}
grTex = HWR_GetTexture(gl_midtexture, noencore);
@ -639,6 +672,7 @@ static void HWR_ProcessTwoSidedSegMiddle(FOutVector *wallVerts, FSurfaceInfo *Su
h = min(highcut, polytop);
l = max(polybottom, lowcut);
if (grTex)
{
// PEGGING
if (gl_linedef->flags & ML_MIDPEG)
@ -657,7 +691,10 @@ static void HWR_ProcessTwoSidedSegMiddle(FOutVector *wallVerts, FSurfaceInfo *Su
// This will cause the midtexture appear on top, if a FOF overlaps with it.
blendmode |= PF_Decal;
if (tripwire == false && gl_frontsector->numlights)
if (!grTex)
blendmode |= PF_NoTexture;
if (!gl_drawing_stencil && tripwire == false && gl_frontsector->numlights)
{
if (!(blendmode & PF_Masked))
HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, noencore, Surf, FOF_TRANSLUCENT, NULL, blendmode); // vanilla just uses PF_Masked here - if we run into any issues, maybe change to that
@ -666,7 +703,7 @@ static void HWR_ProcessTwoSidedSegMiddle(FOutVector *wallVerts, FSurfaceInfo *Su
HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, noencore, Surf, FOF_CUTLEVEL, NULL, blendmode); // vanilla just uses PF_Masked here - if we run into any issues, maybe change to that
}
}
else if (!(blendmode & PF_Masked))
else if (!gl_drawing_stencil && !(blendmode & PF_Masked))
HWR_AddTransparentWall(wallVerts, Surf, gl_midtexture, noencore, blendmode, false, lightnum, gl_frontsector->extra_colormap);
else
HWR_ProjectWall(wallVerts, Surf, blendmode, lightnum, gl_frontsector->extra_colormap);
@ -803,7 +840,7 @@ static void HWR_ProcessTwoSidedSeg(FOutVector *wallVerts, gl_seg_bounds *b,
}
gl_midtexture = R_GetTextureNum(gl_sidedef->midtexture);
if (gl_midtexture && HWR_BlendMidtextureSurface(&Surf))
if ((gl_midtexture && HWR_BlendMidtextureSurface(&Surf)) || gl_drawing_stencil)
{
HWR_ProcessTwoSidedSegMiddle(wallVerts, &Surf, b, cliplow, cliphigh, lightnum, gl_midtexture, noencore, tripwire);
}
@ -888,7 +925,7 @@ static void HWR_ProcessSingleSidedSeg(FOutVector *wallVerts, gl_seg_bounds *b,
wallVerts[1].y = FIXED_TO_FLOAT(b->worldbottomslope);
// I don't think that solid walls can use translucent linedef types...
if (gl_frontsector->numlights)
if (!gl_drawing_stencil && gl_frontsector->numlights)
HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, noencore, &Surf, FOF_CUTLEVEL, NULL, 0);
else
{
@ -901,7 +938,7 @@ static void HWR_ProcessSingleSidedSeg(FOutVector *wallVerts, gl_seg_bounds *b,
HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, noencore, &Surf, FOF_CUTLEVEL, NULL, blendmode);
else
{
if (grTex->mipmap.flags & TF_TRANSPARENT)
if (!gl_drawing_stencil && (grTex->mipmap.flags & TF_TRANSPARENT))
HWR_AddTransparentWall(wallVerts, &Surf, gl_midtexture, noencore, blendmode, false, lightnum, gl_frontsector->extra_colormap);
else
HWR_ProjectWall(wallVerts, &Surf, blendmode, lightnum, gl_frontsector->extra_colormap);
@ -1188,7 +1225,7 @@ static void HWR_ProcessSegFOFs(FOutVector *wallVerts, gl_seg_bounds *b,
void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
{
FOutVector wallVerts[4];
FOutVector wallVerts[4] = {0};
v2d_t vs, ve; // start, end vertices of 2d line (view from above)
gl_seg_bounds b = {0};
@ -1275,7 +1312,7 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
HWR_ProcessSingleSidedSeg(wallVerts, &b, cliplow, cliphigh, lightnum, noencore);
}
if (gl_backsector && !Tag_Compare(&gl_frontsector->tags, &gl_backsector->tags) && (gl_backsector->ffloors || gl_frontsector->ffloors))
if (!gl_drawing_stencil && gl_backsector && !Tag_Compare(&gl_frontsector->tags, &gl_backsector->tags) && (gl_backsector->ffloors || gl_frontsector->ffloors))
{
HWR_ProcessSegFOFs(wallVerts, &b, cliplow, cliphigh, lightnum,
v1x, v1y, v2x, v2y, noencore);

View file

@ -175,9 +175,7 @@ void HWR_DrawSkyBackground(player_t *player)
memset(&dometransform, 0x00, sizeof(FTransform));
//04/01/2000: Hurdler: added for T&L
// It should replace all other gl_viewxxx when finished
HWR_SetTransformAiming(&dometransform, player, false);
HWR_SetTransformAiming(&dometransform, player, false, true);
dometransform.angley = (float)((viewangle-ANGLE_270)>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
dometransform.flip = false;
@ -247,7 +245,7 @@ void HWR_DrawSkyBackground(player_t *player)
// software doesn't draw any further than 1024 for skies anyway, but this doesn't overlap properly
// The only time this will probably be an issue is when a sky wider than 1024 is used as a sky AND a regular wall texture
angle = (dup_viewangle + ANGLE_45);
angle = (viewangle + ANGLE_45);
dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f);

View file

@ -28,16 +28,57 @@ 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};
//UINT32 gl_visspritecount;
//static gl_vissprite_t *gl_visspritechunks[MAXVISSPRITES >> VISSPRITECHUNKBITS] = {NULL};
typedef struct
{
FOutVector verts[4];
gl_vissprite_t *spr;
} zbuffersprite_t;
typedef struct
{
UINT32 gl_visspritecount;
gl_vissprite_t *gl_visspritechunks[MAXVISSPRITES >> VISSPRITECHUNKBITS];
zbuffersprite_t linkdrawlist[MAXVISSPRITES];
UINT32 linkdrawcount;
} gl_sprite_state_t;
// 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 int stack_level = 0;
static gl_sprite_state_t *cst = &state_stack[0]; // current state
// --------------------------------------------------------------------------
// HWR_ClearSprites
// Called at frame start.
// Called at viewpoint start.
// --------------------------------------------------------------------------
void HWR_ClearSprites(void)
{
gl_visspritecount = 0;
cst->gl_visspritecount = 0;
}
// pushes all sprite rendering state to stack
void HWR_PushSpriteState(void)
{
// todo magic number 16
if (stack_level == 15)
I_Error("HWR_PushSpriteState: State stack overflow");
stack_level++;
cst++;
}
void HWR_PopSpriteState(void)
{
if (stack_level == 0)
I_Error("HWR_PopSpriteState: State stack underflow");
stack_level--;
cst--;
}
// --------------------------------------------------------------------------
@ -50,18 +91,18 @@ static gl_vissprite_t *HWR_GetVisSprite(UINT32 num)
UINT32 chunk = num >> VISSPRITECHUNKBITS;
// Allocate chunk if necessary
if (!gl_visspritechunks[chunk])
Z_Malloc(sizeof(gl_vissprite_t) * VISSPRITESPERCHUNK, PU_LEVEL, &gl_visspritechunks[chunk]);
if (!cst->gl_visspritechunks[chunk])
Z_Malloc(sizeof(gl_vissprite_t) * VISSPRITESPERCHUNK, PU_LEVEL, &cst->gl_visspritechunks[chunk]);
return gl_visspritechunks[chunk] + (num & VISSPRITEINDEXMASK);
return cst->gl_visspritechunks[chunk] + (num & VISSPRITEINDEXMASK);
}
static gl_vissprite_t *HWR_NewVisSprite(void)
{
if (gl_visspritecount == MAXVISSPRITES)
if (cst->gl_visspritecount == MAXVISSPRITES)
return &gl_overflowsprite;
return HWR_GetVisSprite(gl_visspritecount++);
return HWR_GetVisSprite(cst->gl_visspritecount++);
}
// A hack solution for transparent surfaces appearing on top of linkdraw sprites.
@ -70,24 +111,19 @@ 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.
typedef struct
{
FOutVector verts[4];
gl_vissprite_t *spr;
} zbuffersprite_t;
/*
// this list is used to store data about linkdraw sprites
zbuffersprite_t linkdrawlist[MAXVISSPRITES];
UINT32 linkdrawcount = 0;
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)
{
if (linkdrawcount < MAXVISSPRITES)
if (cst->linkdrawcount < MAXVISSPRITES)
{
memcpy(linkdrawlist[linkdrawcount].verts, verts, sizeof(FOutVector) * 4);
linkdrawlist[linkdrawcount].spr = spr;
linkdrawcount++;
memcpy(cst->linkdrawlist[cst->linkdrawcount].verts, verts, sizeof(FOutVector) * 4);
cst->linkdrawlist[cst->linkdrawcount].spr = spr;
cst->linkdrawcount++;
}
}
@ -103,14 +139,14 @@ static void HWR_LinkDrawHackFinish(void)
surf.LightInfo.fade_start = 0;
surf.LightInfo.fade_end = 31;
surf.LightInfo.newfade = false;
for (i = 0; i < linkdrawcount; i++)
for (i = 0; i < cst->linkdrawcount; i++)
{
// draw sprite shape, only to z-buffer
HWR_GetPatch(linkdrawlist[i].spr->gpatch);
HWR_ProcessPolygon(&surf, linkdrawlist[i].verts, 4, PF_Translucent|PF_Occlude|PF_Invisible, 0, false);
HWR_GetPatch(cst->linkdrawlist[i].spr->gpatch);
HWR_ProcessPolygon(&surf, cst->linkdrawlist[i].verts, 4, PF_Translucent|PF_Occlude|PF_Invisible, 0, false);
}
// reset list
linkdrawcount = 0;
cst->linkdrawcount = 0;
}
//
@ -1352,14 +1388,15 @@ static int CompareVisSprites(const void *p1, const void *p2)
return -1;
}
void HWR_SortVisSprites(void)
UINT32 HWR_SortVisSprites(void)
{
UINT32 i;
for (i = 0; i < gl_visspritecount; i++)
for (i = 0; i < cst->gl_visspritecount; i++)
{
gl_vsprorder[i] = HWR_GetVisSprite(i);
}
qs22j(gl_vsprorder, gl_visspritecount, sizeof(gl_vissprite_t*), CompareVisSprites);
qs22j(gl_vsprorder, cst->gl_visspritecount, sizeof(gl_vissprite_t*), CompareVisSprites);
return cst->gl_visspritecount;
}
// --------------------------------------------------------------------------
@ -1378,7 +1415,7 @@ void HWR_DrawSprites(void)
GL_SetSpecialState(HWD_SET_MODEL_LIGHTING, 1);
#endif
for (i = 0; i < gl_visspritecount; i++)
for (i = 0; i < cst->gl_visspritecount; i++)
{
gl_vissprite_t *spr = gl_vsprorder[i];
if (spr->bbox)

View file

@ -62,7 +62,6 @@ static GLuint NOTEXTURE_NUM = 0;
#define N_PI_DEMI (M_PIl/2.0f) //(1.5707963268f)
#define ASPECT_RATIO (1.0f) //(320.0f/200.0f)
#define FAR_CLIPPING_PLANE 32768.0f // Draw further! Tails 01-21-2001
static float NEAR_CLIPPING_PLANE = NZCLIP_PLANE;
// **************************************************************************
@ -74,6 +73,7 @@ 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;
@ -339,6 +339,12 @@ static PFNglDepthMask pglDepthMask;
typedef void (APIENTRY * PFNglDepthRange) (GLclampd near_val, GLclampd far_val);
static PFNglDepthRange pglDepthRange;
/* Stencil Buffer */
typedef void (APIENTRY * PFNglStencilFunc) (GLenum func, GLint ref, GLuint mask);
static PFNglStencilFunc pglStencilFunc;
typedef void (APIENTRY * PFNglStencilOp) (GLenum sfail, GLenum dpfail, GLenum dppass);
static PFNglStencilOp pglStencilOp;
/* Transformation */
typedef void (APIENTRY * PFNglMatrixMode) (GLenum mode);
static PFNglMatrixMode pglMatrixMode;
@ -521,6 +527,9 @@ boolean SetupGLfunc(void)
GETOPENGLFUNC(pglDepthMask, glDepthMask)
GETOPENGLFUNC(pglDepthRange, glDepthRange)
GETOPENGLFUNC(pglStencilFunc, glStencilFunc)
GETOPENGLFUNC(pglStencilOp, glStencilOp)
GETOPENGLFUNC(pglMatrixMode, glMatrixMode)
GETOPENGLFUNC(pglViewport, glViewport)
GETOPENGLFUNC(pglPushMatrix, glPushMatrix)
@ -1107,6 +1116,7 @@ void SetStates(void)
//pglDisable(GL_DITHER); // faB: ??? (undocumented in OpenGL 1.1)
// Hurdler: yes, it is!
pglEnable(GL_STENCIL_TEST);
pglEnable(GL_DEPTH_TEST); // check the depth buffer
pglDepthMask(GL_TRUE); // enable writing to depth buffer
pglClearDepth(1.0f);
@ -1344,6 +1354,7 @@ void GL_GClipRect(INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip
// -----------------+
void GL_ClearBuffer(FBOOLEAN ColorMask,
FBOOLEAN DepthMask,
FBOOLEAN StencilMask,
FRGBAFloat * ClearColor)
{
// GL_DBG_Printf ("ClearBuffer(%d)\n", alpha);
@ -1365,6 +1376,8 @@ void GL_ClearBuffer(FBOOLEAN ColorMask,
pglDepthFunc(GL_LEQUAL);
ClearMask |= GL_DEPTH_BUFFER_BIT;
}
if (StencilMask)
ClearMask |= GL_STENCIL_BUFFER_BIT;
GL_SetBlend(DepthMask ? PF_Occlude | CurrentPolyFlags : CurrentPolyFlags&~PF_Occlude);
@ -2387,6 +2400,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;
}
break;
case HWD_SET_STENCIL_LEVEL:
gl_stencil_ref = Value;
break;
default:
break;
}
@ -3384,7 +3423,7 @@ void GL_DrawScreenFinalTexture(int tex, int width, int height)
clearColour.red = clearColour.green = clearColour.blue = 0;
clearColour.alpha = 1;
GL_ClearBuffer(true, false, &clearColour);
GL_ClearBuffer(true, false, false, &clearColour);
pglBindTexture(GL_TEXTURE_2D, screenTextures[tex]);
pglColor4ubv(white);

View file

@ -1655,6 +1655,7 @@ static SDL_Window *Impl_CreateWindow(void)
// Some GPU drivers may give us a 16-bit depth buffer since the
// default value for SDL_GL_DEPTH_SIZE is 16.
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 4);
#endif
SDL_Window *win = NULL;