mirror of
https://bitbucket.org/CPMADevs/cnq3
synced 2024-11-26 22:11:51 +00:00
208 lines
5.7 KiB
C++
208 lines
5.7 KiB
C++
/*
|
|
===========================================================================
|
|
Copyright (C) 2024 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/>.
|
|
===========================================================================
|
|
*/
|
|
// Cinematic Rendering Pipeline - fog volumes
|
|
|
|
|
|
#include "crp_local.h"
|
|
namespace fog_outside
|
|
{
|
|
#include "compshaders/crp/fog_outside_vs.h"
|
|
#include "compshaders/crp/fog_outside_ps.h"
|
|
}
|
|
namespace fog_inside
|
|
{
|
|
#include "compshaders/crp/fog_inside_vs.h"
|
|
#include "compshaders/crp/fog_inside_ps.h"
|
|
}
|
|
|
|
|
|
#pragma pack(push, 4)
|
|
struct FogRC
|
|
{
|
|
float modelViewMatrix[16];
|
|
float projectionMatrix[16];
|
|
float boxMin[4];
|
|
float boxMax[4];
|
|
float color[4];
|
|
float depth;
|
|
float linearDepthA;
|
|
float linearDepthB;
|
|
uint32_t depthTextureIndex;
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
|
|
void Fog::Init()
|
|
{
|
|
{
|
|
const uint32_t indices[] =
|
|
{
|
|
0, 1, 2, 2, 1, 3,
|
|
4, 0, 6, 6, 0, 2,
|
|
7, 5, 6, 6, 5, 4,
|
|
3, 1, 7, 7, 1, 5,
|
|
4, 5, 0, 0, 5, 1,
|
|
3, 7, 2, 2, 7, 6
|
|
};
|
|
|
|
BufferDesc desc("box index", sizeof(indices), ResourceStates::IndexBufferBit);
|
|
desc.shortLifeTime = true;
|
|
boxIndexBuffer = CreateBuffer(desc);
|
|
|
|
uint8_t* mapped = BeginBufferUpload(boxIndexBuffer);
|
|
memcpy(mapped, indices, sizeof(indices));
|
|
EndBufferUpload(boxIndexBuffer);
|
|
}
|
|
{
|
|
const float vertices[] =
|
|
{
|
|
0.0f, 1.0f, 0.0f,
|
|
1.0f, 1.0f, 0.0f,
|
|
0.0f, 0.0f, 0.0f,
|
|
1.0f, 0.0f, 0.0f,
|
|
0.0f, 1.0f, 1.0f,
|
|
1.0f, 1.0f, 1.0f,
|
|
0.0f, 0.0f, 1.0f,
|
|
1.0f, 0.0f, 1.0f
|
|
};
|
|
|
|
BufferDesc desc("box vertex", sizeof(vertices), ResourceStates::VertexBufferBit);
|
|
desc.shortLifeTime = true;
|
|
boxVertexBuffer = CreateBuffer(desc);
|
|
|
|
uint8_t* mapped = BeginBufferUpload(boxVertexBuffer);
|
|
memcpy(mapped, vertices, sizeof(vertices));
|
|
EndBufferUpload(boxVertexBuffer);
|
|
}
|
|
{
|
|
GraphicsPipelineDesc desc("fog outside");
|
|
desc.shortLifeTime = true;
|
|
desc.vertexShader = ShaderByteCode(fog_outside::g_vs);
|
|
desc.pixelShader = ShaderByteCode(fog_outside::g_ps);
|
|
desc.depthStencil.DisableDepth();
|
|
desc.rasterizer.cullMode = CT_BACK_SIDED;
|
|
desc.rasterizer.polygonOffset = false;
|
|
desc.rasterizer.clampDepth = true;
|
|
desc.AddRenderTarget(GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA, crp.renderTargetFormat);
|
|
desc.vertexLayout.AddAttribute(0, ShaderSemantic::Position, DataType::Float32, 3, 0);
|
|
fogOutsidePipeline = CreateGraphicsPipeline(desc);
|
|
}
|
|
{
|
|
GraphicsPipelineDesc desc("fog inside");
|
|
desc.shortLifeTime = true;
|
|
desc.vertexShader = ShaderByteCode(fog_inside::g_vs);
|
|
desc.pixelShader = ShaderByteCode(fog_inside::g_ps);
|
|
desc.depthStencil.DisableDepth();
|
|
desc.rasterizer.cullMode = CT_FRONT_SIDED;
|
|
desc.rasterizer.polygonOffset = false;
|
|
desc.rasterizer.clampDepth = true;
|
|
desc.AddRenderTarget(GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA, crp.renderTargetFormat);
|
|
desc.vertexLayout.AddAttribute(0, ShaderSemantic::Position, DataType::Float32, 3, 0);
|
|
fogInsidePipeline = CreateGraphicsPipeline(desc);
|
|
}
|
|
}
|
|
|
|
void Fog::Draw()
|
|
{
|
|
// @NOTE: fog 0 is invalid, it must be skipped
|
|
if(tr.world == NULL ||
|
|
tr.world->numfogs <= 1 ||
|
|
(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SCOPED_RENDER_PASS("Fog", 0.25f, 0.125f, 0.0f);
|
|
|
|
srp.renderMode = RenderMode::World;
|
|
|
|
const uint32_t stride = sizeof(vec3_t);
|
|
CmdBindVertexBuffers(1, &boxVertexBuffer, &stride, NULL);
|
|
CmdBindIndexBuffer(boxIndexBuffer, IndexType::UInt32, 0);
|
|
|
|
const TextureBarrier barriers[] =
|
|
{
|
|
TextureBarrier(crp.depthTexture, ResourceStates::PixelShaderAccessBit),
|
|
TextureBarrier(crp.renderTarget, ResourceStates::RenderTargetBit)
|
|
};
|
|
CmdBarrier(ARRAY_LEN(barriers), barriers);
|
|
|
|
CmdBindRenderTargets(1, &crp.renderTarget, NULL);
|
|
|
|
int insideIndex = -1;
|
|
for(int f = 1; f < tr.world->numfogs; ++f)
|
|
{
|
|
const fog_t& fog = tr.world->fogs[f];
|
|
|
|
bool inside = true;
|
|
for(int a = 0; a < 3; ++a)
|
|
{
|
|
if(backEnd.viewParms.orient.origin[a] <= fog.bounds[0][a] ||
|
|
backEnd.viewParms.orient.origin[a] >= fog.bounds[1][a])
|
|
{
|
|
inside = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(inside)
|
|
{
|
|
insideIndex = f;
|
|
break;
|
|
}
|
|
}
|
|
|
|
FogRC rc = {};
|
|
memcpy(rc.modelViewMatrix, backEnd.viewParms.world.modelMatrix, sizeof(rc.modelViewMatrix));
|
|
memcpy(rc.projectionMatrix, backEnd.viewParms.projectionMatrix, sizeof(rc.projectionMatrix));
|
|
RB_LinearDepthConstants(&rc.linearDepthA, &rc.linearDepthB);
|
|
rc.depthTextureIndex = GetTextureIndexSRV(crp.depthTexture);
|
|
|
|
CmdBindPipeline(fogOutsidePipeline);
|
|
for(int f = 1; f < tr.world->numfogs; ++f)
|
|
{
|
|
if(f == insideIndex)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const fog_t& fog = tr.world->fogs[f];
|
|
VectorScale(fog.parms.color, tr.identityLight, rc.color);
|
|
rc.depth = fog.parms.depthForOpaque;
|
|
VectorCopy(fog.bounds[0], rc.boxMin);
|
|
VectorCopy(fog.bounds[1], rc.boxMax);
|
|
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
|
CmdDrawIndexed(36, 0, 0);
|
|
}
|
|
|
|
if(insideIndex > 0)
|
|
{
|
|
CmdBindPipeline(fogInsidePipeline);
|
|
|
|
const fog_t& fog = tr.world->fogs[insideIndex];
|
|
VectorScale(fog.parms.color, tr.identityLight, rc.color);
|
|
rc.depth = fog.parms.depthForOpaque;
|
|
VectorCopy(fog.bounds[0], rc.boxMin);
|
|
VectorCopy(fog.bounds[1], rc.boxMax);
|
|
CmdSetGraphicsRootConstants(0, sizeof(rc), &rc);
|
|
CmdDrawIndexed(36, 0, 0);
|
|
}
|
|
}
|