mirror of
https://bitbucket.org/CPMADevs/cnq3
synced 2024-11-10 06:31:48 +00:00
implemented dynamic lights
This commit is contained in:
parent
ccb9827b03
commit
ffde1f2b1b
16 changed files with 602 additions and 100 deletions
|
@ -304,6 +304,16 @@ struct FrameStats
|
|||
int skippedFrames;
|
||||
};
|
||||
|
||||
struct BatchType
|
||||
{
|
||||
enum Id
|
||||
{
|
||||
Standard,
|
||||
DynamicLight,
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
struct World
|
||||
{
|
||||
void Init();
|
||||
|
@ -312,7 +322,7 @@ struct World
|
|||
void Begin();
|
||||
void End();
|
||||
void DrawPrePass(const drawSceneViewCommand_t& cmd);
|
||||
void BeginBatch(const shader_t* shader, bool hasStaticGeo);
|
||||
void BeginBatch(const shader_t* shader, bool hasStaticGeo, BatchType::Id batchType);
|
||||
void EndBatch();
|
||||
void EndSkyBatch();
|
||||
void RestartBatch();
|
||||
|
@ -322,6 +332,8 @@ struct World
|
|||
void BindVertexBuffers(bool staticGeo, uint32_t firstStage, uint32_t stageCount);
|
||||
void BindIndexBuffer(bool staticGeo);
|
||||
void DrawFog();
|
||||
void DrawLitSurfaces(dlight_t* dl, bool opaque);
|
||||
void DrawDynamicLights(bool opaque);
|
||||
void DrawSkyBox();
|
||||
void DrawClouds();
|
||||
|
||||
|
@ -356,6 +368,7 @@ struct World
|
|||
uint32_t boundStaticVertexBuffersFirst;
|
||||
uint32_t boundStaticVertexBuffersCount;
|
||||
HPipeline batchPSO;
|
||||
BatchType::Id batchType;
|
||||
bool batchHasStaticGeo;
|
||||
int psoChangeCount;
|
||||
bool batchDepthHack;
|
||||
|
@ -384,6 +397,17 @@ struct World
|
|||
// shader trace
|
||||
HBuffer traceRenderBuffer;
|
||||
HBuffer traceReadbackBuffer;
|
||||
|
||||
// dynamic lights
|
||||
HRootSignature dlRootSignature;
|
||||
HPipeline dlPipelines[CT_COUNT * 2 * 2]; // { cull type, polygon offset, depth test }
|
||||
bool dlOpaque;
|
||||
float dlIntensity; // 1 for most surfaces, but can be scaled down for liquids etc.
|
||||
bool dlDepthTestEqual;
|
||||
// quick explanation on why dlOpaque is useful in the first place:
|
||||
// - opaque surfaces can have a diffuse texture whose alpha isn't 255 everywhere
|
||||
// - when that happens and we multiply the color by the the alpha (DL uses additive blending),
|
||||
// we get "light holes" in opaque surfaces, which is not what we want
|
||||
};
|
||||
|
||||
struct UI
|
||||
|
|
|
@ -43,6 +43,11 @@ namespace fog_outside
|
|||
{
|
||||
#include "hlsl/fog_outside_ps.h"
|
||||
}
|
||||
namespace dyn_light
|
||||
{
|
||||
#include "hlsl/dynamic_light_vs.h"
|
||||
#include "hlsl/dynamic_light_ps.h"
|
||||
}
|
||||
|
||||
|
||||
#pragma pack(push, 4)
|
||||
|
@ -66,6 +71,26 @@ struct FogPixelRC
|
|||
float colorDepth[4];
|
||||
};
|
||||
|
||||
struct DynLightVertexRC
|
||||
{
|
||||
float modelViewMatrix[16];
|
||||
float projectionMatrix[16];
|
||||
float osLightPos[4];
|
||||
float osEyePos[4];
|
||||
};
|
||||
|
||||
struct DynLightPixelRC
|
||||
{
|
||||
uint32_t stageIndices; // low 16 = texture, high 16 = sampler
|
||||
uint32_t pad0[3];
|
||||
float color[3];
|
||||
float recSqrRadius; // 1 / (r * r)
|
||||
float greyscale;
|
||||
float intensity;
|
||||
float opaque;
|
||||
float pad1;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
|
@ -85,15 +110,20 @@ static const uint32_t zppMaxIndexCount = 8 * zppMaxVertexCount;
|
|||
static uint32_t zppIndices[zppMaxIndexCount];
|
||||
|
||||
|
||||
static bool HasStaticGeo(const drawSurf_t* drawSurf, const shader_t* shader)
|
||||
static bool HasStaticGeo(int staticGeoChunk, const shader_t* shader)
|
||||
{
|
||||
if(forceDynamic)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// @NOTE: the shader->isDynamic check is needed because of the shader editing feature
|
||||
// without it, an edited shader that changes vertex attributes won't display correctly
|
||||
// because the original "baked" vertex attributes would be used instead
|
||||
return
|
||||
!shader->isDynamic &&
|
||||
drawSurf->staticGeoChunk > 0 &&
|
||||
drawSurf->staticGeoChunk < ARRAY_LEN(grp.world.statChunks);
|
||||
staticGeoChunk > 0 &&
|
||||
staticGeoChunk < ARRAY_LEN(grp.world.statChunks);
|
||||
}
|
||||
|
||||
static void UpdateEntityData(bool& depthHack, int entityNum, double originalTime)
|
||||
|
@ -130,6 +160,11 @@ static void UpdateEntityData(bool& depthHack, int entityNum, double originalTime
|
|||
}
|
||||
}
|
||||
|
||||
static int GetDynamicLightPipelineIndex(cullType_t cullType, qbool polygonOffset, qbool depthTestEquals)
|
||||
{
|
||||
return (int)cullType + CT_COUNT * (int)polygonOffset + CT_COUNT * 2 * (int)depthTestEquals;
|
||||
}
|
||||
|
||||
|
||||
void World::Init()
|
||||
{
|
||||
|
@ -294,6 +329,22 @@ void World::Init()
|
|||
desc.memoryUsage = MemoryUsage::Readback;
|
||||
traceReadbackBuffer = CreateBuffer(desc);
|
||||
}
|
||||
|
||||
//
|
||||
// dynamic lights
|
||||
//
|
||||
{
|
||||
RootSignatureDesc desc("dynamic lights");
|
||||
desc.usingVertexBuffers = true;
|
||||
desc.samplerCount = ARRAY_LEN(grp.samplers);
|
||||
desc.samplerVisibility = ShaderStages::PixelBit;
|
||||
desc.genericVisibility = ShaderStages::VertexBit | ShaderStages::PixelBit;
|
||||
desc.AddRange(DescriptorType::Texture, 0, MAX_DRAWIMAGES * 2);
|
||||
desc.AddRange(DescriptorType::RWBuffer, MAX_DRAWIMAGES * 2, 1);
|
||||
desc.constants[ShaderStage::Vertex].byteCount = sizeof(DynLightVertexRC);
|
||||
desc.constants[ShaderStage::Pixel].byteCount = sizeof(DynLightPixelRC);
|
||||
dlRootSignature = CreateRootSignature(desc);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -325,6 +376,37 @@ void World::Init()
|
|||
desc.vertexLayout.AddAttribute(0, ShaderSemantic::Position, DataType::Float32, 3, 0);
|
||||
fogInsidePipeline = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
|
||||
//
|
||||
// dynamic lights
|
||||
//
|
||||
{
|
||||
GraphicsPipelineDesc desc("dynamic light opaque", dlRootSignature);
|
||||
desc.shortLifeTime = true;
|
||||
desc.vertexShader = ShaderByteCode(dyn_light::g_vs);
|
||||
desc.pixelShader = ShaderByteCode(dyn_light::g_ps);
|
||||
desc.depthStencil.enableDepthWrites = false;
|
||||
desc.rasterizer.clampDepth = r_depthClamp->integer != 0;
|
||||
desc.AddRenderTarget(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE, grp.renderTargetFormat);
|
||||
desc.vertexLayout.AddAttribute(0, ShaderSemantic::Position, DataType::Float32, 3, 0);
|
||||
desc.vertexLayout.AddAttribute(1, ShaderSemantic::Normal, DataType::Float32, 3, 0);
|
||||
desc.vertexLayout.AddAttribute(2, ShaderSemantic::TexCoord, DataType::Float32, 2, 0);
|
||||
desc.vertexLayout.AddAttribute(3, ShaderSemantic::Color, DataType::UNorm8, 4, 0);
|
||||
for(int cullType = 0; cullType < CT_COUNT; ++cullType)
|
||||
{
|
||||
desc.rasterizer.cullMode = (cullType_t)cullType;
|
||||
for(int polygonOffset = 0; polygonOffset < 2; ++polygonOffset)
|
||||
{
|
||||
desc.rasterizer.polygonOffset = polygonOffset != 0;
|
||||
for(int depthTestEquals = 0; depthTestEquals < 2; ++depthTestEquals)
|
||||
{
|
||||
desc.depthStencil.depthComparison = depthTestEquals ? ComparisonFunction::Equal : ComparisonFunction::GreaterEqual;
|
||||
const int index = GetDynamicLightPipelineIndex((cullType_t)cullType, (qbool)polygonOffset, (qbool)depthTestEquals);
|
||||
dlPipelines[index] = CreateGraphicsPipeline(desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void World::BeginFrame()
|
||||
|
@ -413,8 +495,6 @@ void World::Begin()
|
|||
|
||||
void World::End()
|
||||
{
|
||||
EndBatch();
|
||||
|
||||
grp.renderMode = RenderMode::None;
|
||||
}
|
||||
|
||||
|
@ -482,7 +562,7 @@ void World::DrawPrePass(const drawSceneViewCommand_t& cmd)
|
|||
CmdDrawIndexed(fullIndexCount, firstIndex, 0);
|
||||
}
|
||||
|
||||
void World::BeginBatch(const shader_t* shader, bool hasStaticGeo)
|
||||
void World::BeginBatch(const shader_t* shader, bool hasStaticGeo, BatchType::Id type)
|
||||
{
|
||||
tess.numVertexes = 0;
|
||||
tess.numIndexes = 0;
|
||||
|
@ -497,6 +577,7 @@ void World::BeginBatch(const shader_t* shader, bool hasStaticGeo)
|
|||
tess.shaderTime = tess.shader->clampTime;
|
||||
}
|
||||
batchHasStaticGeo = hasStaticGeo;
|
||||
batchType = type;
|
||||
}
|
||||
|
||||
void World::EndBatch()
|
||||
|
@ -508,17 +589,23 @@ void World::EndBatch()
|
|||
tess.shader->numStages == 0 ||
|
||||
tess.shader->numPipelines <= 0)
|
||||
{
|
||||
// @TODO: make sure we never get tess.shader->numStages 0 here in the first place
|
||||
tess.numVertexes = 0;
|
||||
tess.numIndexes = 0;
|
||||
return;
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
if(batchType == BatchType::DynamicLight)
|
||||
{
|
||||
if(tess.shader->lightingStages[ST_DIFFUSE] < 0 ||
|
||||
tess.shader->lightingStages[ST_DIFFUSE] >= MAX_SHADER_STAGES)
|
||||
{
|
||||
goto clean_up;
|
||||
}
|
||||
}
|
||||
|
||||
// for debugging of sort order issues, stop rendering after a given sort value
|
||||
if(r_debugSort->value > 0.0f &&
|
||||
r_debugSort->value < tess.shader->sort)
|
||||
{
|
||||
return;
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
GeometryBuffers& db = dynBuffers[GetFrameIndex()];
|
||||
|
@ -526,17 +613,29 @@ void World::EndBatch()
|
|||
!db.indexBuffer.CanAdd(indexCount))
|
||||
{
|
||||
Q_assert(!"Dynamic buffer too small!");
|
||||
return;
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
const shader_t* const shader = tess.shader;
|
||||
if(!tess.deformsPreApplied)
|
||||
{
|
||||
RB_DeformTessGeometry(0, vertexCount, 0, indexCount);
|
||||
for(int s = 0; s < shader->numStages; ++s)
|
||||
if(batchType == BatchType::DynamicLight)
|
||||
{
|
||||
R_ComputeColors(shader->stages[s], tess.svars[s], 0, vertexCount);
|
||||
R_ComputeTexCoords(shader->stages[s], tess.svars[s], 0, vertexCount, qfalse);
|
||||
const int stageIndex = shader->lightingStages[ST_DIFFUSE];
|
||||
if(stageIndex >= 0 && stageIndex < MAX_SHADER_STAGES)
|
||||
{
|
||||
R_ComputeColors(shader->stages[stageIndex], tess.svars[0], 0, vertexCount);
|
||||
R_ComputeTexCoords(shader->stages[stageIndex], tess.svars[0], 0, vertexCount, qfalse);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int s = 0; s < shader->numStages; ++s)
|
||||
{
|
||||
R_ComputeColors(shader->stages[s], tess.svars[s], 0, vertexCount);
|
||||
R_ComputeTexCoords(shader->stages[s], tess.svars[s], 0, vertexCount, qfalse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -575,53 +674,96 @@ void World::EndBatch()
|
|||
batchOldShadingRate = batchShadingRate;
|
||||
}
|
||||
|
||||
for(int p = 0; p < shader->numPipelines; ++p)
|
||||
if(batchType == BatchType::DynamicLight)
|
||||
{
|
||||
const pipeline_t& pipeline = shader->pipelines[p];
|
||||
const int psoIndex = backEnd.viewParms.isMirror ? pipeline.mirrorPipeline : pipeline.pipeline;
|
||||
if(batchPSO != grp.psos[psoIndex].pipeline)
|
||||
const dlight_t* const dl = tess.light;
|
||||
const int stageIndex = tess.shader->lightingStages[ST_DIFFUSE];
|
||||
const image_t* image = GetBundleImage(shader->stages[stageIndex]->bundle);
|
||||
const uint32_t texIdx = image->textureIndex;
|
||||
const uint32_t sampIdx = GetSamplerIndex(image);
|
||||
Q_assert(texIdx > 0);
|
||||
|
||||
const int pipelineIndex = GetDynamicLightPipelineIndex(shader->cullType, shader->polygonOffset, dlDepthTestEqual);
|
||||
const HPipeline pipeline = dlPipelines[pipelineIndex];
|
||||
if(batchPSO != pipeline)
|
||||
{
|
||||
batchPSO = grp.psos[psoIndex].pipeline;
|
||||
batchPSO = pipeline;
|
||||
CmdBindPipeline(batchPSO);
|
||||
psoChangeCount++;
|
||||
}
|
||||
|
||||
WorldVertexRC vertexRC = {};
|
||||
DynLightVertexRC vertexRC = {};
|
||||
memcpy(vertexRC.modelViewMatrix, backEnd.orient.modelMatrix, sizeof(vertexRC.modelViewMatrix));
|
||||
memcpy(vertexRC.projectionMatrix, backEnd.viewParms.projectionMatrix, sizeof(vertexRC.projectionMatrix));
|
||||
memcpy(vertexRC.clipPlane, clipPlane, sizeof(vertexRC.clipPlane));
|
||||
CmdSetRootConstants(grp.uberRootSignature, ShaderStage::Vertex, &vertexRC);
|
||||
VectorCopy(dl->transformed, vertexRC.osLightPos);
|
||||
vertexRC.osLightPos[3] = 1.0f;
|
||||
VectorCopy(backEnd.orient.viewOrigin, vertexRC.osEyePos);
|
||||
vertexRC.osEyePos[3] = 1.0f;
|
||||
CmdSetRootConstants(dlRootSignature, ShaderStage::Vertex, &vertexRC);
|
||||
|
||||
WorldPixelRC pixelRC = {};
|
||||
DynLightPixelRC pixelRC = {};
|
||||
pixelRC.greyscale = tess.greyscale;
|
||||
pixelRC.frameSeed = grp.frameSeed;
|
||||
pixelRC.noiseScale = r_ditherStrength->value;
|
||||
pixelRC.invBrightness = 1.0f / r_brightness->value;
|
||||
pixelRC.invGamma = 1.0f / r_gamma->value;
|
||||
pixelRC.shaderTrace = (uint32_t)!!tr.traceWorldShader;
|
||||
pixelRC.shaderIndex = (uint32_t)shader->index;
|
||||
pixelRC.frameIndex = RHI::GetFrameIndex();
|
||||
pixelRC.centerPixel = (glConfig.vidWidth / 2) | ((glConfig.vidHeight / 2) << 16);
|
||||
for(int s = 0; s < pipeline.numStages; ++s)
|
||||
{
|
||||
const image_t* image = GetBundleImage(shader->stages[pipeline.firstStage + s]->bundle);
|
||||
const uint32_t texIdx = image->textureIndex;
|
||||
const uint32_t sampIdx = GetSamplerIndex(image);
|
||||
Q_assert(texIdx > 0);
|
||||
pixelRC.stageIndices[s] = (sampIdx << 16) | (texIdx);
|
||||
}
|
||||
CmdSetRootConstants(grp.uberRootSignature, ShaderStage::Pixel, &pixelRC);
|
||||
pixelRC.stageIndices = (sampIdx << 16) | (texIdx);
|
||||
VectorCopy(tess.light->color, pixelRC.color);
|
||||
pixelRC.recSqrRadius = 1.0f / Square(dl->radius);
|
||||
pixelRC.intensity = dlIntensity;
|
||||
pixelRC.opaque = dlOpaque ? 1.0f : 0.0f;
|
||||
CmdSetRootConstants(dlRootSignature, ShaderStage::Pixel, &pixelRC);
|
||||
|
||||
BindVertexBuffers(batchHasStaticGeo, pipeline.firstStage, pipeline.numStages);
|
||||
|
||||
BindVertexBuffers(batchHasStaticGeo, 0, 1);
|
||||
CmdDrawIndexed(indexCount, db.indexBuffer.batchFirst, batchHasStaticGeo ? 0 : db.vertexBuffers.batchFirst);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int p = 0; p < shader->numPipelines; ++p)
|
||||
{
|
||||
const pipeline_t& pipeline = shader->pipelines[p];
|
||||
const int psoIndex = backEnd.viewParms.isMirror ? pipeline.mirrorPipeline : pipeline.pipeline;
|
||||
if(batchPSO != grp.psos[psoIndex].pipeline)
|
||||
{
|
||||
batchPSO = grp.psos[psoIndex].pipeline;
|
||||
CmdBindPipeline(batchPSO);
|
||||
psoChangeCount++;
|
||||
}
|
||||
|
||||
WorldVertexRC vertexRC = {};
|
||||
memcpy(vertexRC.modelViewMatrix, backEnd.orient.modelMatrix, sizeof(vertexRC.modelViewMatrix));
|
||||
memcpy(vertexRC.projectionMatrix, backEnd.viewParms.projectionMatrix, sizeof(vertexRC.projectionMatrix));
|
||||
memcpy(vertexRC.clipPlane, clipPlane, sizeof(vertexRC.clipPlane));
|
||||
CmdSetRootConstants(grp.uberRootSignature, ShaderStage::Vertex, &vertexRC);
|
||||
|
||||
WorldPixelRC pixelRC = {};
|
||||
pixelRC.greyscale = tess.greyscale;
|
||||
pixelRC.frameSeed = grp.frameSeed;
|
||||
pixelRC.noiseScale = r_ditherStrength->value;
|
||||
pixelRC.invBrightness = 1.0f / r_brightness->value;
|
||||
pixelRC.invGamma = 1.0f / r_gamma->value;
|
||||
pixelRC.shaderTrace = (uint32_t)!!tr.traceWorldShader;
|
||||
pixelRC.shaderIndex = (uint32_t)shader->index;
|
||||
pixelRC.frameIndex = RHI::GetFrameIndex();
|
||||
pixelRC.centerPixel = (glConfig.vidWidth / 2) | ((glConfig.vidHeight / 2) << 16);
|
||||
for(int s = 0; s < pipeline.numStages; ++s)
|
||||
{
|
||||
const image_t* image = GetBundleImage(shader->stages[pipeline.firstStage + s]->bundle);
|
||||
const uint32_t texIdx = image->textureIndex;
|
||||
const uint32_t sampIdx = GetSamplerIndex(image);
|
||||
Q_assert(texIdx > 0);
|
||||
pixelRC.stageIndices[s] = (sampIdx << 16) | (texIdx);
|
||||
}
|
||||
CmdSetRootConstants(grp.uberRootSignature, ShaderStage::Pixel, &pixelRC);
|
||||
|
||||
BindVertexBuffers(batchHasStaticGeo, pipeline.firstStage, pipeline.numStages);
|
||||
CmdDrawIndexed(indexCount, db.indexBuffer.batchFirst, batchHasStaticGeo ? 0 : db.vertexBuffers.batchFirst);
|
||||
}
|
||||
}
|
||||
|
||||
if(!batchHasStaticGeo)
|
||||
{
|
||||
db.vertexBuffers.EndBatch(tess.numVertexes);
|
||||
}
|
||||
db.indexBuffer.EndBatch(tess.numIndexes);
|
||||
|
||||
clean_up:
|
||||
tess.numVertexes = 0;
|
||||
tess.numIndexes = 0;
|
||||
}
|
||||
|
@ -662,7 +804,7 @@ void World::EndSkyBatch()
|
|||
void World::RestartBatch()
|
||||
{
|
||||
EndBatch();
|
||||
BeginBatch(tess.shader, batchHasStaticGeo);
|
||||
BeginBatch(tess.shader, batchHasStaticGeo, BatchType::Standard);
|
||||
}
|
||||
|
||||
void World::DrawGUI()
|
||||
|
@ -935,6 +1077,7 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd)
|
|||
const shader_t* oldShader = NULL;
|
||||
int oldEntityNum = -1;
|
||||
bool oldHasStaticGeo = false;
|
||||
bool forceEntityChange = false;
|
||||
backEnd.currentEntity = &tr.worldEntity;
|
||||
|
||||
ShadingRate::Id lowShadingRate = (ShadingRate::Id)r_shadingRate->integer;
|
||||
|
@ -955,20 +1098,21 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd)
|
|||
|
||||
CmdSetShadingRate(lowShadingRate);
|
||||
batchOldShadingRate = lowShadingRate;
|
||||
DrawDynamicLights(qtrue);
|
||||
DrawFog();
|
||||
|
||||
if(transpCount > 0)
|
||||
{
|
||||
CmdBindRootSignature(grp.uberRootSignature);
|
||||
CmdBindDescriptorTable(grp.uberRootSignature, grp.descriptorTable);
|
||||
CmdBindRenderTargets(1, &grp.renderTarget, &depthTexture);
|
||||
batchPSO = RHI_MAKE_NULL_HANDLE();
|
||||
boundVertexBuffers = BufferFamily::Invalid;
|
||||
boundIndexBuffer = BufferFamily::Invalid;
|
||||
// needed after DrawDynamicLights
|
||||
forceEntityChange = true;
|
||||
|
||||
const TextureBarrier depthWriteBarrier(depthTexture, ResourceStates::DepthWriteBit);
|
||||
CmdBarrier(1, &depthWriteBarrier);
|
||||
}
|
||||
CmdBindRootSignature(grp.uberRootSignature);
|
||||
CmdBindDescriptorTable(grp.uberRootSignature, grp.descriptorTable);
|
||||
CmdBindRenderTargets(1, &grp.renderTarget, &depthTexture);
|
||||
batchPSO = RHI_MAKE_NULL_HANDLE();
|
||||
boundVertexBuffers = BufferFamily::Invalid;
|
||||
boundIndexBuffer = BufferFamily::Invalid;
|
||||
|
||||
const TextureBarrier depthWriteBarrier(depthTexture, ResourceStates::DepthWriteBit);
|
||||
CmdBarrier(1, &depthWriteBarrier);
|
||||
}
|
||||
|
||||
int entityNum;
|
||||
|
@ -985,7 +1129,7 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd)
|
|||
}
|
||||
}
|
||||
|
||||
const bool hasStaticGeo = forceDynamic ? false : HasStaticGeo(drawSurf, shader);
|
||||
const bool hasStaticGeo = HasStaticGeo(drawSurf->staticGeoChunk, shader);
|
||||
const bool staticChanged = hasStaticGeo != oldHasStaticGeo;
|
||||
const bool shaderChanged = shader != oldShader;
|
||||
bool entityChanged = entityNum != oldEntityNum;
|
||||
|
@ -1006,14 +1150,15 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd)
|
|||
oldHasStaticGeo = hasStaticGeo;
|
||||
EndSkyBatch();
|
||||
EndBatch();
|
||||
BeginBatch(shader, hasStaticGeo);
|
||||
BeginBatch(shader, hasStaticGeo, BatchType::Standard);
|
||||
tess.greyscale = drawSurf->greyscale;
|
||||
batchShadingRate = lowShadingRate;
|
||||
}
|
||||
|
||||
if(entityChanged)
|
||||
if(entityChanged || forceEntityChange)
|
||||
{
|
||||
UpdateEntityData(batchDepthHack, entityNum, originalTime);
|
||||
forceEntityChange = false;
|
||||
}
|
||||
|
||||
if(hasStaticGeo)
|
||||
|
@ -1022,7 +1167,7 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd)
|
|||
if(tess.numIndexes + chunk.indexCount > SHADER_MAX_INDEXES)
|
||||
{
|
||||
EndBatch();
|
||||
BeginBatch(tess.shader, batchHasStaticGeo);
|
||||
BeginBatch(tess.shader, batchHasStaticGeo, BatchType::Standard);
|
||||
batchShadingRate = lowShadingRate;
|
||||
}
|
||||
|
||||
|
@ -1053,12 +1198,17 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd)
|
|||
EndSkyBatch();
|
||||
EndBatch();
|
||||
|
||||
CmdSetShadingRate(ShadingRate::SR_1x1);
|
||||
|
||||
if(transpCount <= 0)
|
||||
{
|
||||
DrawDynamicLights(qtrue);
|
||||
CmdSetShadingRate(lowShadingRate);
|
||||
batchOldShadingRate = lowShadingRate;
|
||||
DrawFog();
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawDynamicLights(qfalse);
|
||||
}
|
||||
|
||||
db.vertexBuffers.EndUpload();
|
||||
db.indexBuffer.EndUpload();
|
||||
|
@ -1205,6 +1355,154 @@ void World::DrawFog()
|
|||
}
|
||||
}
|
||||
|
||||
void World::DrawLitSurfaces(dlight_t* dl, bool opaque)
|
||||
{
|
||||
if(dl->head == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(!opaque && !drawTransparents)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const shader_t* shader = NULL;
|
||||
const shader_t* oldShader = NULL;
|
||||
int oldEntityNum = -666;
|
||||
bool oldHasStaticGeo = false;
|
||||
|
||||
// save original time for entity shader offsets
|
||||
const double originalTime = backEnd.refdef.floatTime;
|
||||
|
||||
// draw everything
|
||||
const int liquidFlags = CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER;
|
||||
oldEntityNum = -1;
|
||||
dlOpaque = opaque;
|
||||
backEnd.currentEntity = &tr.worldEntity;
|
||||
tess.light = dl;
|
||||
tess.numVertexes = 0;
|
||||
tess.numIndexes = 0;
|
||||
|
||||
for(litSurf_t* litSurf = dl->head; litSurf != NULL; litSurf = litSurf->next)
|
||||
{
|
||||
backEnd.pc3D[RB_LIT_SURFACES]++;
|
||||
|
||||
int entityNum;
|
||||
R_DecomposeLitSort(litSurf->sort, &entityNum, &shader);
|
||||
|
||||
if(opaque && shader->sort > SS_OPAQUE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(!opaque && shader->sort <= SS_OPAQUE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const int stageIndex = shader->lightingStages[ST_DIFFUSE];
|
||||
if(stageIndex < 0 || stageIndex >= shader->numStages)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool hasStaticGeo = HasStaticGeo(litSurf->staticGeoChunk, shader);
|
||||
const bool staticChanged = hasStaticGeo != oldHasStaticGeo;
|
||||
const bool shaderChanged = shader != oldShader;
|
||||
bool entityChanged = entityNum != oldEntityNum;
|
||||
Q_assert(shader != NULL);
|
||||
if(!hasStaticGeo && !drawDynamic)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(staticChanged || shaderChanged || entityChanged)
|
||||
{
|
||||
oldShader = shader;
|
||||
oldEntityNum = entityNum;
|
||||
oldHasStaticGeo = hasStaticGeo;
|
||||
EndBatch();
|
||||
BeginBatch(shader, hasStaticGeo, BatchType::DynamicLight);
|
||||
tess.greyscale = litSurf->greyscale;
|
||||
|
||||
const shaderStage_t* const stage = shader->stages[stageIndex];
|
||||
dlIntensity = (shader->contentFlags & liquidFlags) != 0 ? 0.5f : 1.0f;
|
||||
dlDepthTestEqual = opaque || (stage->stateBits & GLS_ATEST_BITS) != 0;
|
||||
}
|
||||
|
||||
if(entityChanged)
|
||||
{
|
||||
UpdateEntityData(batchDepthHack, entityNum, originalTime);
|
||||
}
|
||||
|
||||
R_TransformDlights(1, dl, &backEnd.orient);
|
||||
|
||||
if(hasStaticGeo)
|
||||
{
|
||||
const StaticGeometryChunk& chunk = statChunks[litSurf->staticGeoChunk];
|
||||
if(tess.numIndexes + chunk.indexCount > SHADER_MAX_INDEXES)
|
||||
{
|
||||
EndBatch();
|
||||
BeginBatch(tess.shader, batchHasStaticGeo, BatchType::DynamicLight);
|
||||
}
|
||||
|
||||
memcpy(tess.indexes + tess.numIndexes, statIndices + chunk.firstCPUIndex, chunk.indexCount * sizeof(uint32_t));
|
||||
tess.numIndexes += chunk.indexCount;
|
||||
backEnd.pc3D[RB_LIT_INDICES_LATECULL_IN] += chunk.indexCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int oldNumIndexes = tess.numIndexes;
|
||||
R_TessellateSurface(litSurf->surface);
|
||||
backEnd.pc3D[RB_LIT_INDICES_LATECULL_IN] += tess.numIndexes - oldNumIndexes;
|
||||
}
|
||||
}
|
||||
|
||||
// draw the contents of the last shader batch
|
||||
if(shader != NULL)
|
||||
{
|
||||
EndBatch();
|
||||
}
|
||||
|
||||
backEnd.refdef.floatTime = originalTime;
|
||||
}
|
||||
|
||||
void World::DrawDynamicLights(bool opaque)
|
||||
{
|
||||
SCOPED_RENDER_PASS("Dynamic Lights", 1.0f, 0.25f, 0.25f);
|
||||
|
||||
if(r_dynamiclight->integer == 0 ||
|
||||
backEnd.refdef.num_dlights == 0 ||
|
||||
backEnd.viewParms.isMirror)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CmdBindRootSignature(dlRootSignature);
|
||||
CmdBindDescriptorTable(dlRootSignature, grp.descriptorTable);
|
||||
CmdBindRenderTargets(1, &grp.renderTarget, &depthTexture);
|
||||
batchPSO = RHI_MAKE_NULL_HANDLE();
|
||||
boundVertexBuffers = BufferFamily::Invalid;
|
||||
boundIndexBuffer = BufferFamily::Invalid;
|
||||
|
||||
ShadingRate::Id lowShadingRate = (ShadingRate::Id)r_shadingRate->integer;
|
||||
batchShadingRate = lowShadingRate;
|
||||
batchOldShadingRate = ShadingRate::SR_1x1;
|
||||
CmdSetShadingRate(lowShadingRate);
|
||||
|
||||
CmdSetViewportAndScissor(backEnd.viewParms);
|
||||
batchOldDepthHack = false;
|
||||
batchDepthHack = false;
|
||||
|
||||
tess.numVertexes = 0;
|
||||
tess.numIndexes = 0;
|
||||
|
||||
for(int i = 0; i < backEnd.refdef.num_dlights; ++i)
|
||||
{
|
||||
DrawLitSurfaces(&backEnd.refdef.dlights[i], opaque);
|
||||
}
|
||||
}
|
||||
|
||||
void World::DrawSkyBox()
|
||||
{
|
||||
if(!drawSky)
|
||||
|
|
128
code/renderer/hlsl/dynamic_light.hlsl
Normal file
128
code/renderer/hlsl/dynamic_light.hlsl
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2019-2023 Gian 'myT' Schellenbaum
|
||||
|
||||
This file is part of Challenge Quake 3 (CNQ3).
|
||||
|
||||
Challenge Quake 3 is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Challenge Quake 3 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
|
||||
===========================================================================
|
||||
*/
|
||||
// dynamic light shader
|
||||
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
struct VIn
|
||||
{
|
||||
float3 position : POSITION;
|
||||
float3 normal : NORMAL;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
float4 color : COLOR0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
struct VOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float3 normal : NORMAL;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
float4 color : COLOR0;
|
||||
float3 osLightVec : TEXCOORD1;
|
||||
float3 osEyeVec : TEXCOORD2;
|
||||
};
|
||||
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
matrix modelViewMatrix;
|
||||
matrix projectionMatrix;
|
||||
float4 osLightPos;
|
||||
float4 osEyePos;
|
||||
};
|
||||
|
||||
VOut vs(VIn input)
|
||||
{
|
||||
float4 positionVS = mul(modelViewMatrix, float4(input.position.xyz, 1));
|
||||
|
||||
VOut output;
|
||||
output.position = mul(projectionMatrix, positionVS);
|
||||
output.normal = input.normal;
|
||||
output.texCoords = input.texCoords;
|
||||
output.color = input.color;
|
||||
output.osLightVec = osLightPos.xyz - input.position.xyz;
|
||||
output.osEyeVec = osEyePos.xyz - input.position.xyz;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if PIXEL_SHADER
|
||||
|
||||
#include "shared.hlsli"
|
||||
|
||||
cbuffer RootConstants
|
||||
{
|
||||
uint4 stageIndices; // low 16 = texture, high 16 = sampler
|
||||
float3 color;
|
||||
float recSqrRadius; // 1 / (r * r)
|
||||
float greyscale;
|
||||
float intensity;
|
||||
float opaque;
|
||||
};
|
||||
|
||||
Texture2D textures2D[4096] : register(t0);
|
||||
SamplerState samplers[96] : register(s0);
|
||||
|
||||
float BezierEase(float t)
|
||||
{
|
||||
return t * t * (3.0 - 2.0 * t);
|
||||
}
|
||||
|
||||
[earlydepthstencil]
|
||||
float4 ps(VOut input) : SV_Target
|
||||
{
|
||||
// fetch data
|
||||
uint textureIndex = stageIndices.x & 0xFFFF;
|
||||
uint samplerIndex = stageIndices.x >> 16;
|
||||
float lightRecSqrRadius = recSqrRadius;
|
||||
float3 lightColor = color;
|
||||
float4 baseColored = input.color * textures2D[textureIndex].Sample(samplers[samplerIndex], input.texCoords);
|
||||
float4 base = MakeGreyscale(baseColored, greyscale);
|
||||
float3 nL = normalize(input.osLightVec); // normalized object-space light vector
|
||||
float3 nV = normalize(input.osEyeVec); // normalized object-space view vector
|
||||
float3 nN = input.normal; // normalized object-space normal vector
|
||||
|
||||
// light intensity
|
||||
float intensFactor = min(dot(input.osLightVec, input.osLightVec) * lightRecSqrRadius, 1.0);
|
||||
float3 intens = lightColor * BezierEase(1.0 - sqrt(intensFactor));
|
||||
|
||||
// specular reflection term (N.H)
|
||||
float specFactor = min(abs(dot(nN, normalize(nL + nV))), 1.0);
|
||||
float spec = pow(specFactor, 16.0) * 0.25;
|
||||
|
||||
// Lambertian diffuse reflection term (N.L)
|
||||
float diffuse = min(abs(dot(nN, nL)), 1.0);
|
||||
float3 color = (base.rgb * diffuse.rrr + spec.rrr) * intens * intensity;
|
||||
float alpha = lerp(opaque, 1.0, base.a);
|
||||
float4 final = float4(color.rgb * alpha, alpha);
|
||||
|
||||
return final;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -29,22 +29,10 @@ to do:
|
|||
- git cherry-pick c75b2b27fa936854d27dadf458e3ec3b03829561
|
||||
- https://asawicki.info/news_1758_an_idea_for_visualization_of_frame_times
|
||||
- GPU resident vertex data for models: load on demand based on submitted { surface, shader } pairs
|
||||
- reloading a map can lead to a TDR timeout
|
||||
could it be related to the copy queue?
|
||||
use PIX to capture and replay the bad command list?
|
||||
seems to not happen ever since I fixed the usage of the stale depth buffer?!
|
||||
- transparents don't batch properly I think -> entityMergeable support? ("entityMergable" in the code)
|
||||
- use Application Verifier to catch issues
|
||||
- tone mapping: look at https://github.com/h3r2tic/tony-mc-mapface
|
||||
- ubershader PS: run-time alpha test evaluation to reduce PSO count?
|
||||
- mip-map generation: figure out whether out of bounds texture UAV writes are OK or not
|
||||
I think they are in this use case but an explicit confirmation would be nice...
|
||||
- working depth pre-pass (account for cull mode, generate buffers on demand)
|
||||
full depth pre-pass -> Z-buffer is complete and won't get updated by opaque drawing
|
||||
1 full-screen pass per dynamic light, culled early with the depth bounds test -> write out to a light buffer
|
||||
draw opaques, locate the light stage and add the light buffer data to the light stage result
|
||||
- r_depthFade
|
||||
- r_dynamiclight
|
||||
- when creating the root signature, validate that neither of the tables have any gap
|
||||
- use root signature 1.1 to use the hints that help the drivers optimize out static resources
|
||||
- is it possible to force Resource Binding Tier 2 somehow? are we supposed to run on old HW to test? :(
|
||||
|
@ -57,7 +45,6 @@ to do:
|
|||
- move UI to the uber shader system, tessellate to generate proper data
|
||||
- share structs between HLSL and C++ with .hlsli files -> change cbuffer to ConstantBuffer<MyStruct>
|
||||
- share texture and sampler array sizes between HLSL and C++ with .hlsli files
|
||||
- what's the actual fog curve used by Q3?
|
||||
- roq video textures support?
|
||||
*/
|
||||
|
||||
|
@ -826,6 +813,7 @@ namespace RHI
|
|||
else
|
||||
{
|
||||
mapped = (uint8_t*)MapBuffer(userHBuffer);
|
||||
Q_assert(mapped != NULL);
|
||||
}
|
||||
|
||||
userBuffer.uploading = true;
|
||||
|
@ -3108,9 +3096,10 @@ namespace RHI
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void* mappedPtr;
|
||||
void* mappedPtr = NULL;
|
||||
D3D(buffer.buffer->Map(0, NULL, &mappedPtr));
|
||||
buffer.mapped = true;
|
||||
Q_assert(mappedPtr != NULL);
|
||||
|
||||
return (uint8_t*)mappedPtr;
|
||||
}
|
||||
|
|
|
@ -25,11 +25,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
backEndData_t* backEndData;
|
||||
backEndState_t backEnd;
|
||||
|
||||
|
||||
// @TODO: remove all this
|
||||
#if 0
|
||||
|
||||
|
||||
static int64_t startTime;
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
static void RB_Set2D()
|
||||
{
|
||||
backEnd.projection2D = qtrue;
|
||||
|
|
|
@ -511,7 +511,7 @@ static const cvarTableItem_t r_cvars[] =
|
|||
},
|
||||
{
|
||||
&r_dynamiclight, "r_dynamiclight", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "enables dynamic lights",
|
||||
"", 0, "", "" // @TODO: CVARCAT_GRAPHICS | CVARCAT_PERFORMANCE once implemented
|
||||
"Enable dynamic lights", CVARCAT_GRAPHICS | CVARCAT_PERFORMANCE, "For power-ups, muzzle flashes, rockets, explosions, ...", ""
|
||||
},
|
||||
{
|
||||
&r_lego, "r_lego", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "LEGO(R) texture filtering",
|
||||
|
|
|
@ -552,6 +552,7 @@ struct litSurf_t {
|
|||
const surfaceType_t* surface; // any of surface*_t
|
||||
litSurf_t* next;
|
||||
float greyscale;
|
||||
int staticGeoChunk;
|
||||
};
|
||||
|
||||
struct dlight_t {
|
||||
|
@ -837,6 +838,24 @@ enum drawSurfGeneralSort_t {
|
|||
};
|
||||
|
||||
|
||||
enum litSurfGeneralSort_t {
|
||||
// dimensions - the sum should stay within 32 bits
|
||||
LITSORT_ENTITY_BITS = 10, // GENTITYNUM_BITS
|
||||
LITSORT_SHADER_BITS = 14, // log2 MAX_SHADERS
|
||||
LITSORT_STATICGEO_BITS = 1,
|
||||
LITSORT_CULLTYPE_BITS = 2, // PSO part 1
|
||||
LITSORT_POLYGONOFFSET_BITS = 1, // PSO part 2
|
||||
LITSORT_DEPTHTEST_BITS = 1, // PSO part 3
|
||||
// offsets
|
||||
LITSORT_ENTITY_INDEX = 0,
|
||||
LITSORT_SHADER_INDEX = LITSORT_ENTITY_INDEX + LITSORT_ENTITY_BITS,
|
||||
LITSORT_STATICGEO_INDEX = LITSORT_SHADER_INDEX + LITSORT_SHADER_BITS,
|
||||
LITSORT_CULLTYPE_INDEX = LITSORT_STATICGEO_INDEX + LITSORT_STATICGEO_BITS,
|
||||
LITSORT_POLYGONOFFSET_INDEX = LITSORT_CULLTYPE_INDEX + LITSORT_CULLTYPE_BITS,
|
||||
LITSORT_DEPTHTEST_INDEX = LITSORT_POLYGONOFFSET_INDEX + LITSORT_POLYGONOFFSET_BITS
|
||||
};
|
||||
|
||||
|
||||
#define MAX_TMUS 4
|
||||
|
||||
|
||||
|
@ -852,15 +871,6 @@ typedef struct {
|
|||
byte color2D[4];
|
||||
trRefEntity_t entity2D; // currentEntity will point at this when doing 2D rendering
|
||||
|
||||
// dynamic lights data set by the back-end for the GAL
|
||||
qbool dlOpaque; // qtrue when drawing an opaque surface
|
||||
float dlIntensity; // 1 for most surfaces, but can be scaled down for liquids etc.
|
||||
unsigned int dlStateBits; // the state bits to apply for this draw call
|
||||
// quick explanation on why dlOpaque is useful in the first place:
|
||||
// - opaque surfaces can have a diffuse texture whose alpha isn't 255 everywhere
|
||||
// - when that happens and we multiply the color by the the alpha (DL uses additive blending),
|
||||
// we get "light holes" in opaque surfaces, which is not what we want
|
||||
|
||||
qbool renderFrame;
|
||||
|
||||
int* pc; // current stats set, depending on projection2D
|
||||
|
@ -1119,9 +1129,11 @@ void R_AddMD3Surfaces( trRefEntity_t *e );
|
|||
void R_AddPolygonSurfaces();
|
||||
|
||||
void R_AddDrawSurf(const surfaceType_t* surface, const shader_t* shader, int fogIndex, int staticGeoChunk = 0, int zppFirstIndex = 0, int zppIndexCount = 0, float radiusOverZ = 666.0f );
|
||||
void R_AddLitSurf( const surfaceType_t* surface, const shader_t* shader, int fogIndex );
|
||||
void R_AddLitSurf( const surfaceType_t* surface, const shader_t* shader, int fogIndex, int staticGeoChunk );
|
||||
uint64_t R_ComposeSort( int entityNum, const shader_t* shader, int staticGeoChunk );
|
||||
void R_DecomposeSort( uint64_t sort, int* entityNum, const shader_t** shader );
|
||||
uint32_t R_ComposeLitSort( int entityNum, const shader_t* shader, int staticGeoChunk );
|
||||
void R_DecomposeLitSort( uint32_t sort, int* entityNum, const shader_t** shader );
|
||||
|
||||
|
||||
#define CULL_IN 0 // completely unclipped
|
||||
|
@ -1311,7 +1323,6 @@ struct shaderCommands_t
|
|||
vec2_t texCoords[SHADER_MAX_VERTEXES];
|
||||
vec2_t texCoords2[SHADER_MAX_VERTEXES];
|
||||
color4ub_t vertexColors[SHADER_MAX_VERTEXES];
|
||||
unsigned int dlIndexes[SHADER_MAX_INDEXES];
|
||||
stageVars_t svars[MAX_SHADER_STAGES];
|
||||
stageVars_t svarsFog;
|
||||
|
||||
|
@ -1323,7 +1334,6 @@ struct shaderCommands_t
|
|||
|
||||
int numIndexes;
|
||||
int numVertexes;
|
||||
int dlNumIndexes;
|
||||
|
||||
const dlight_t* light;
|
||||
|
||||
|
|
|
@ -1280,13 +1280,14 @@ static float SurfGreyscaleAmount( const shader_t* shader )
|
|||
}
|
||||
|
||||
|
||||
void R_AddDrawSurf( const surfaceType_t* surface, const shader_t* shader, int fogIndex, int staticGeoChunk, int zppFirstIndex, int zppIndexCount, float radiusOverZ )
|
||||
// @TODO: remove the fogIndex argument
|
||||
void R_AddDrawSurf( const surfaceType_t* surface, const shader_t* shader, int /*fogIndex*/, int staticGeoChunk, int zppFirstIndex, int zppIndexCount, float radiusOverZ )
|
||||
{
|
||||
if (tr.refdef.numDrawSurfs >= MAX_DRAWSURFS)
|
||||
return;
|
||||
|
||||
drawSurf_t* const drawSurf = &tr.refdef.drawSurfs[tr.refdef.numDrawSurfs++];
|
||||
drawSurf->sort = R_ComposeSort( tr.currentEntityNum, shader, fogIndex );
|
||||
drawSurf->sort = R_ComposeSort( tr.currentEntityNum, shader, staticGeoChunk );
|
||||
drawSurf->surface = surface;
|
||||
drawSurf->model = tr.currentModel != NULL ? tr.currentModel->index : 0;
|
||||
drawSurf->shaderNum = shader->index;
|
||||
|
@ -1298,7 +1299,8 @@ void R_AddDrawSurf( const surfaceType_t* surface, const shader_t* shader, int fo
|
|||
}
|
||||
|
||||
|
||||
void R_AddLitSurf( const surfaceType_t* surface, const shader_t* shader, int fogIndex )
|
||||
// @TODO: remove the fogIndex argument
|
||||
void R_AddLitSurf( const surfaceType_t* surface, const shader_t* shader, int /*fogIndex*/, int staticGeoChunk )
|
||||
{
|
||||
if (tr.refdef.numLitSurfs >= MAX_DRAWSURFS)
|
||||
return;
|
||||
|
@ -1306,10 +1308,11 @@ void R_AddLitSurf( const surfaceType_t* surface, const shader_t* shader, int fog
|
|||
tr.pc[RF_LIT_SURFS]++;
|
||||
|
||||
litSurf_t* const litSurf = &tr.refdef.litSurfs[tr.refdef.numLitSurfs++];
|
||||
litSurf->sort = R_ComposeSort( tr.currentEntityNum, shader, fogIndex );
|
||||
litSurf->sort = R_ComposeLitSort( tr.currentEntityNum, shader, staticGeoChunk );
|
||||
litSurf->surface = surface;
|
||||
litSurf->shaderNum = shader->index;
|
||||
litSurf->greyscale = SurfGreyscaleAmount( shader );
|
||||
litSurf->staticGeoChunk = staticGeoChunk;
|
||||
|
||||
if (!tr.light->head)
|
||||
tr.light->head = litSurf;
|
||||
|
@ -1339,7 +1342,28 @@ void R_DecomposeSort( uint64_t sort, int* entityNum, const shader_t** shader )
|
|||
{
|
||||
*entityNum = ( sort >> DRAWSORT_ENTITY_INDEX ) & MAX_REFENTITIES;
|
||||
*shader = tr.sortedShaders[ ( sort >> DRAWSORT_SHADER_INDEX ) & (MAX_SHADERS-1) ];
|
||||
|
||||
}
|
||||
|
||||
|
||||
uint32_t R_ComposeLitSort( int entityNum, const shader_t* shader, int staticGeoChunk )
|
||||
{
|
||||
const int stageIndex = max( shader->lightingStages[ST_DIFFUSE], 0 );
|
||||
const int depthTestEquals = ( shader->stages[stageIndex]->stateBits & GLS_DEPTHFUNC_EQUAL ) != 0;
|
||||
|
||||
return
|
||||
( (uint32_t)entityNum << LITSORT_ENTITY_INDEX ) |
|
||||
( (uint32_t)shader->sortedIndex << LITSORT_SHADER_INDEX ) |
|
||||
( (uint32_t)( staticGeoChunk > 0 ? 0 : 1 ) << LITSORT_STATICGEO_INDEX ) |
|
||||
( (uint32_t)shader->cullType << LITSORT_CULLTYPE_INDEX ) |
|
||||
( (uint32_t)shader->polygonOffset << LITSORT_POLYGONOFFSET_INDEX ) |
|
||||
( (uint32_t)depthTestEquals << LITSORT_DEPTHTEST_INDEX );
|
||||
}
|
||||
|
||||
|
||||
void R_DecomposeLitSort( uint32_t sort, int* entityNum, const shader_t** shader )
|
||||
{
|
||||
*entityNum = ( sort >> LITSORT_ENTITY_INDEX ) & MAX_REFENTITIES;
|
||||
*shader = tr.sortedShaders[ ( sort >> LITSORT_SHADER_INDEX ) & (MAX_SHADERS-1) ];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -35,6 +35,10 @@ SURFACE SHADERS
|
|||
shaderCommands_t tess;
|
||||
|
||||
|
||||
// @TODO: remove all this...
|
||||
#if 0
|
||||
|
||||
|
||||
// we must set some things up before beginning any tesselation
|
||||
// because a surface may be forced to perform a RB_End due to overflow
|
||||
|
||||
|
@ -251,3 +255,6 @@ void RB_EndSurface()
|
|||
// clear shader so we can tell we don't have any unclosed surfaces
|
||||
tess.numIndexes = 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1809,8 +1809,8 @@ static void SortNewShader()
|
|||
const int numLitSurfs = tr.refdef.numLitSurfs;
|
||||
litSurf_t* litSurfs = tr.refdef.litSurfs;
|
||||
for ( i = 0; i < numLitSurfs; ++i, ++litSurfs ) {
|
||||
R_DecomposeSort( litSurfs->sort, &entityNum, &wrongShader );
|
||||
litSurfs->sort = R_ComposeSort( entityNum, tr.shaders[litSurfs->shaderNum], drawSurfs->staticGeoChunk );
|
||||
R_DecomposeLitSort( litSurfs->sort, &entityNum, &wrongShader );
|
||||
litSurfs->sort = R_ComposeLitSort( entityNum, tr.shaders[litSurfs->shaderNum], drawSurfs->staticGeoChunk );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -350,6 +350,10 @@ static void R_AddLitSurface( msurface_t* surf, const dlight_t* light )
|
|||
if ( surf->shader->sort < SS_OPAQUE )
|
||||
return;
|
||||
|
||||
// lighting a fog box' surface looks absolutely terrible
|
||||
if ( (surf->shader->contentFlags & CONTENTS_FOG) != 0 )
|
||||
return;
|
||||
|
||||
if ( surf->lightCount == tr.lightCount )
|
||||
return; // already in the lit list (or already culled) for this light
|
||||
|
||||
|
@ -374,7 +378,7 @@ static void R_AddLitSurface( msurface_t* surf, const dlight_t* light )
|
|||
return;
|
||||
}
|
||||
|
||||
R_AddLitSurf( surf->data, surf->shader, surf->fogIndex );
|
||||
R_AddLitSurf( surf->data, surf->shader, surf->fogIndex, surf->staticGeoChunk );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -49,7 +49,9 @@ void CompileShader(const ShaderArgs& args, int extraCount = 0, const char** extr
|
|||
{
|
||||
static char temp[4096];
|
||||
|
||||
strcpy(temp, va("dxc.exe -Fh %s -E %s -T %s -WX",
|
||||
// -Ges: Enable strict mode
|
||||
// -Gis: Force IEEE strictness
|
||||
strcpy(temp, va("dxc.exe -Fh %s -E %s -T %s -WX -Ges -Gis",
|
||||
args.headerPath, args.entryPoint, args.targetProfile));
|
||||
|
||||
for(int i = 0; i < extraCount; ++i)
|
||||
|
@ -231,6 +233,7 @@ int main(int /*argc*/, const char** argv)
|
|||
CompileVSAndPS("imgui", "imgui.hlsl");
|
||||
CompileVSAndPS("ui", "ui.hlsl");
|
||||
CompileVSAndPS("depth_pre_pass", "depth_pre_pass.hlsl");
|
||||
CompileVSAndPS("dynamic_light", "dynamic_light.hlsl");
|
||||
CompileVS("fog_vs.h", "fog_inside.hlsl");
|
||||
CompilePS("fog_inside_ps.h", "fog_inside.hlsl");
|
||||
CompilePS("fog_outside_ps.h", "fog_outside.hlsl");
|
||||
|
|
|
@ -259,6 +259,9 @@
|
|||
<FxCompile Include="..\..\code\renderer\hlsl\depth_pre_pass.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\dynamic_light.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\fog_inside.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
|
|
|
@ -56,6 +56,9 @@
|
|||
<FxCompile Include="..\..\code\renderer\hlsl\depth_pre_pass.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\dynamic_light.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\fog_inside.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
</FxCompile>
|
||||
|
|
|
@ -263,6 +263,9 @@
|
|||
<FxCompile Include="..\..\code\renderer\hlsl\depth_pre_pass.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\dynamic_light.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\fog_inside.hlsl">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
|
|
|
@ -56,6 +56,9 @@
|
|||
<FxCompile Include="..\..\code\renderer\hlsl\depth_pre_pass.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\dynamic_light.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="..\..\code\renderer\hlsl\fog_inside.hlsl">
|
||||
<Filter>hlsl</Filter>
|
||||
</FxCompile>
|
||||
|
|
Loading…
Reference in a new issue