Portal Hell PT1
https://git.do.srb2.org/STJr/SRB2/-/merge_requests/1774/diffs\?commit_id\=c2103e52c259bb14d5d4b40c8bb9b131d5a78169
This commit is contained in:
parent
778de306c5
commit
a739573ca1
16 changed files with 1015 additions and 300 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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 = §ors[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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue