mirror of
https://bitbucket.org/CPMADevs/cnq3
synced 2024-11-10 06:31:48 +00:00
373 lines
11 KiB
C++
373 lines
11 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/>.
|
|
===========================================================================
|
|
*/
|
|
// Shared Rendering Pipeline - Im3d integration
|
|
|
|
|
|
#include "srp_local.h"
|
|
#include "../im3d/im3d.h"
|
|
#include "../im3d/im3d_math.h"
|
|
#include "../client/cl_imgui.h"
|
|
|
|
|
|
#define MAX_VERTEX_COUNT 65536 // we use 16-bit indices
|
|
#define MAX_INDEX_COUNT ((MAX_VERTEX_COUNT / 4) * 6)
|
|
|
|
|
|
#pragma pack(push, 4)
|
|
|
|
struct Im3DVertexRC_CRP
|
|
{
|
|
vec2_t viewport;
|
|
uint32_t vertexBufferIndex;
|
|
uint32_t vertexOffset;
|
|
};
|
|
|
|
struct Im3DVertexRC_GRP
|
|
{
|
|
matrix4x4_t viewMatrix;
|
|
matrix4x4_t projectionMatrix;
|
|
vec2_t viewport;
|
|
uint32_t vertexOffset;
|
|
};
|
|
|
|
#pragma pack(pop)
|
|
|
|
|
|
static void SetupPipeline(
|
|
Im3DVertexRC_CRP& crp, Im3DVertexRC_GRP& grp, bool ddhi, HPipeline pipeline,
|
|
HRootSignature rootSignature, HDescriptorTable descriptorTable, uint32_t vertexOffset)
|
|
{
|
|
CmdBindPipeline(pipeline);
|
|
if(ddhi)
|
|
{
|
|
crp.vertexOffset = vertexOffset;
|
|
CmdSetGraphicsRootConstants(0, sizeof(crp), &crp);
|
|
}
|
|
else
|
|
{
|
|
grp.vertexOffset = vertexOffset;
|
|
CmdSetRootConstants(rootSignature, ShaderStage::Vertex, &grp);
|
|
}
|
|
if(!ddhi)
|
|
{
|
|
CmdBindDescriptorTable(rootSignature, descriptorTable);
|
|
}
|
|
}
|
|
|
|
|
|
void Im3D::Init(bool ddhi_, const ShaderByteCode shaders[Im3D::Shader::Count], TextureFormat::Id rtFormat)
|
|
{
|
|
ddhi = ddhi_;
|
|
|
|
if(ddhi)
|
|
{
|
|
rootSignature = RHI_MAKE_NULL_HANDLE();
|
|
}
|
|
else
|
|
{
|
|
RootSignatureDesc desc("Im3d");
|
|
desc.shortLifeTime = true;
|
|
desc.AddRange(DescriptorType::Buffer, 0, 1);
|
|
desc.constants[ShaderStage::Vertex].byteCount = sizeof(Im3DVertexRC_GRP);
|
|
rootSignature = CreateRootSignature(desc);
|
|
}
|
|
|
|
if(ddhi)
|
|
{
|
|
for(uint32_t i = 0; i < ARRAY_LEN(descriptorTables); i++)
|
|
{
|
|
descriptorTables[i] = RHI_MAKE_NULL_HANDLE();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(uint32_t i = 0; i < ARRAY_LEN(descriptorTables); i++)
|
|
{
|
|
DescriptorTableDesc desc("Im3d", rootSignature);
|
|
desc.shortLifeTime = true;
|
|
descriptorTables[i] = CreateDescriptorTable(desc);
|
|
}
|
|
}
|
|
|
|
{
|
|
GraphicsPipelineDesc desc("Im3d point", rootSignature);
|
|
desc.shortLifeTime = true;
|
|
desc.vertexShader = shaders[Shader::PointVS];
|
|
desc.pixelShader = shaders[Shader::PointPS];
|
|
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
|
desc.depthStencil.DisableDepth();
|
|
desc.AddRenderTarget(GLS_BLEND_STD_ALPHA, rtFormat);
|
|
pointPipeline = CreateGraphicsPipeline(desc);
|
|
}
|
|
|
|
{
|
|
GraphicsPipelineDesc desc("Im3d line", rootSignature);
|
|
desc.shortLifeTime = true;
|
|
desc.vertexShader = shaders[Shader::LineVS];
|
|
desc.pixelShader = shaders[Shader::LinePS];
|
|
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
|
desc.depthStencil.DisableDepth();
|
|
desc.AddRenderTarget(GLS_BLEND_STD_ALPHA, rtFormat);
|
|
linePipeline = CreateGraphicsPipeline(desc);
|
|
}
|
|
|
|
{
|
|
GraphicsPipelineDesc desc("Im3d triangle", rootSignature);
|
|
desc.shortLifeTime = true;
|
|
desc.vertexShader = shaders[Shader::TriangleVS];
|
|
desc.pixelShader = shaders[Shader::TrianglePS];
|
|
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
|
desc.depthStencil.DisableDepth();
|
|
desc.AddRenderTarget(GLS_BLEND_STD_ALPHA, rtFormat);
|
|
trianglePipeline = CreateGraphicsPipeline(desc);
|
|
}
|
|
|
|
{
|
|
uint32_t byteCount = sizeof(Im3d::VertexData) * MAX_VERTEX_COUNT;
|
|
BufferDesc desc("", byteCount, ResourceStates::VertexShaderAccessBit);
|
|
desc.shortLifeTime = true;
|
|
desc.structureByteCount = sizeof(Im3d::VertexData);
|
|
desc.memoryUsage = MemoryUsage::Upload;
|
|
desc.name = "Im3d vertex #1";
|
|
vertexBuffers[0] = CreateBuffer(desc);
|
|
desc.name = "Im3d vertex #2";
|
|
vertexBuffers[1] = CreateBuffer(desc);
|
|
}
|
|
|
|
{
|
|
uint32_t byteCount = sizeof(uint16_t) * MAX_INDEX_COUNT;
|
|
BufferDesc desc("Im3d index", byteCount, ResourceStates::IndexBufferBit);
|
|
desc.shortLifeTime = true;
|
|
indexBuffer = CreateBuffer(desc);
|
|
|
|
uint16_t* indices = (uint16_t*)BeginBufferUpload(indexBuffer);
|
|
for(uint32_t i = 0, v = 0; i < MAX_INDEX_COUNT; i += 6, v += 4)
|
|
{
|
|
indices[i + 0] = v + 0;
|
|
indices[i + 1] = v + 1;
|
|
indices[i + 2] = v + 2;
|
|
indices[i + 3] = v + 2;
|
|
indices[i + 4] = v + 3;
|
|
indices[i + 5] = v + 0;
|
|
}
|
|
EndBufferUpload(indexBuffer);
|
|
}
|
|
|
|
if(!ddhi)
|
|
{
|
|
for(uint32_t i = 0; i < ARRAY_LEN(descriptorTables); i++)
|
|
{
|
|
DescriptorTableUpdate update;
|
|
update.SetBuffers(1, &vertexBuffers[i]);
|
|
UpdateDescriptorTable(descriptorTables[i], update);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Im3D::BeginFrame()
|
|
{
|
|
const int currTime = Sys_Milliseconds();
|
|
const int timeDelta = prevTime == INT_MIN ? 0 : currTime - prevTime;
|
|
prevTime = currTime;
|
|
|
|
int x, y;
|
|
Sys_GetCursorPosition(&x, &y);
|
|
R_ComputeCursorPosition(&x, &y);
|
|
|
|
Im3d::AppData& ad = Im3d::GetAppData();
|
|
ad.m_deltaTime = (float)timeDelta / 1000.0f;
|
|
ad.m_viewportSize = Im3d::Vec2((float)glConfig.vidWidth, (float)glConfig.vidHeight);
|
|
ad.m_viewOrigin = Im3d::Vec3(tr.rtRefdef.vieworg[0], tr.rtRefdef.vieworg[1], tr.rtRefdef.vieworg[2]);
|
|
ad.m_viewDirection = Im3d::Vec3(tr.rtRefdef.viewaxis[0][0], tr.rtRefdef.viewaxis[0][1], tr.rtRefdef.viewaxis[0][2]);
|
|
ad.m_worldUp = Im3d::Vec3(0.0f, 0.0f, 1.0f);
|
|
ad.m_projScaleY = 2.0f * tanf(DEG2RAD(tr.rtRefdef.fov_y) * 0.5f);
|
|
Im3d::Mat4 camWorld = LookAt(ad.m_viewOrigin, ad.m_viewOrigin + ad.m_viewDirection, ad.m_worldUp);
|
|
Im3d::Vec2 cursorNDC;
|
|
cursorNDC.x = ((float)x / (float)glConfig.vidWidth ) * -2.0f + 1.0f;
|
|
cursorNDC.y = ((float)y / (float)glConfig.vidHeight) * -2.0f + 1.0f;
|
|
Im3d::Vec3 rayOrigin, rayDirection;
|
|
rayOrigin = ad.m_viewOrigin;
|
|
rayDirection.x = tanf(0.5f * DEG2RAD(tr.rtRefdef.fov_x)) * cursorNDC.x;
|
|
rayDirection.y = tanf(0.5f * DEG2RAD(tr.rtRefdef.fov_y)) * cursorNDC.y;
|
|
rayDirection.z = 1.0f;
|
|
rayDirection = camWorld * Im3d::Vec4(Im3d::Normalize(rayDirection), 0.0f);
|
|
ad.m_cursorRayOrigin = rayOrigin;
|
|
ad.m_cursorRayDirection = rayDirection;
|
|
if(r_debugInput->integer == 0 || ImGui::GetIO().WantCaptureMouse)
|
|
{
|
|
ad.m_cursorRayOrigin = Im3d::Vec3(0.0f, 0.0f, 0.0f);
|
|
ad.m_cursorRayDirection = Im3d::Vec3(0.0f, 0.0f, 0.0f);
|
|
}
|
|
|
|
Im3d::NewFrame();
|
|
}
|
|
|
|
void Im3D::Draw(const drawSceneViewCommand_t& cmd, HTexture colorTarget, HTexture depthTarget)
|
|
{
|
|
if(cmd.viewParms.isPortal || !IsViewportFullscreen(cmd.viewParms))
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if 0 // cpm3 test/demo code
|
|
{
|
|
static Im3d::Vec3 translation(700, 50, -50);
|
|
static Im3d::Mat3 rotation(1.0f);
|
|
static Im3d::Vec3 scale(1.0f);
|
|
Im3d::PushMatrix(Im3d::Mat4(translation, rotation, scale));
|
|
if(ShouldDrawGizmos())
|
|
{
|
|
Im3d::Gizmo("Test", translation, rotation, scale);
|
|
}
|
|
Im3d::DrawConeFilled(Im3d::Vec3(0, 0, 0), Im3d::Vec3(0, 0, 1), 32.0f, 8.0f, 16);
|
|
Im3d::PopMatrix();
|
|
|
|
Im3d::DrawPoint(Im3d::Vec3(700, 0, 0), 16.0f, Im3d::Color(1, 0, 0, 1));
|
|
Im3d::DrawPoint(Im3d::Vec3(725, 0, 0), 16.0f, Im3d::Color(0, 1, 0, 1));
|
|
Im3d::DrawPoint(Im3d::Vec3(750, 0, 0), 16.0f, Im3d::Color(0, 0, 1, 1));
|
|
Im3d::DrawLine(Im3d::Vec3(700, 0, -100), Im3d::Vec3(750, 0, -100), 4.0f, Im3d::Color(1, 0, 0, 1));
|
|
Im3d::DrawLine(Im3d::Vec3(700, 0, -110), Im3d::Vec3(750, 0, -110), 4.0f, Im3d::Color(0, 1, 0, 1));
|
|
Im3d::DrawLine(Im3d::Vec3(700, 0, -120), Im3d::Vec3(750, 0, -120), 4.0f, Im3d::Color(0, 0, 1, 1));
|
|
Im3d::SetColor(0, 1, 0, 1);
|
|
Im3d::SetSize(4.0f);
|
|
Im3d::DrawArrow(Im3d::Vec3(700, 0, -150), Im3d::Vec3(750, 0, -150), 10.0f, 10.0f);
|
|
Im3d::DrawConeFilled(Im3d::Vec3(725, 0, -200), Im3d::Vec3(0, 0, 1), 32.0f, 8.0f, 16);
|
|
}
|
|
#endif
|
|
|
|
Im3d::EndFrame();
|
|
|
|
if(!ShouldDrawShapes())
|
|
{
|
|
return;
|
|
}
|
|
|
|
const Im3d::U32 drawListCount = Im3d::GetDrawListCount();
|
|
if(drawListCount == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SCOPED_DEBUG_LABEL("Im3d", 1.0f, 1.0f, 1.0f);
|
|
|
|
CmdSetViewportAndScissor(0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
|
|
|
CmdBeginBarrier();
|
|
CmdTextureBarrier(colorTarget, ResourceStates::RenderTargetBit);
|
|
CmdEndBarrier();
|
|
|
|
CmdBindRenderTargets(1, &colorTarget, NULL);
|
|
CmdBindIndexBuffer(indexBuffer, IndexType::UInt16, 0);
|
|
|
|
const uint32_t frameIndex = GetFrameIndex();
|
|
const HBuffer vertexBuffer = vertexBuffers[frameIndex];
|
|
|
|
Im3DVertexRC_CRP vertexRC_CRP;
|
|
Im3DVertexRC_GRP vertexRC_GRP;
|
|
if(ddhi)
|
|
{
|
|
vertexRC_CRP = {};
|
|
vertexRC_CRP.vertexBufferIndex = GetBufferIndexSRV(vertexBuffer);
|
|
vertexRC_CRP.viewport[0] = (float)glConfig.vidWidth;
|
|
vertexRC_CRP.viewport[1] = (float)glConfig.vidHeight;
|
|
CmdSetGraphicsRootConstants(0, sizeof(vertexRC_CRP), &vertexRC_CRP);
|
|
}
|
|
else
|
|
{
|
|
vertexRC_GRP = {};
|
|
vertexRC_GRP.viewport[0] = (float)glConfig.vidWidth;
|
|
vertexRC_GRP.viewport[1] = (float)glConfig.vidHeight;
|
|
memcpy(vertexRC_GRP.viewMatrix, cmd.viewParms.world.modelMatrix, sizeof(vertexRC_GRP.viewMatrix));
|
|
memcpy(vertexRC_GRP.projectionMatrix, cmd.viewParms.projectionMatrix, sizeof(vertexRC_GRP.projectionMatrix));
|
|
CmdSetRootConstants(rootSignature, ShaderStage::Vertex, &vertexRC_GRP);
|
|
}
|
|
|
|
Im3d::VertexData* vertices = (Im3d::VertexData*)MapBuffer(vertexBuffer);
|
|
|
|
uint32_t vertexOffset = 0;
|
|
for(Im3d::U32 i = 0; i < drawListCount; i++)
|
|
{
|
|
const Im3d::DrawList& drawList = Im3d::GetDrawLists()[i];
|
|
switch(drawList.m_primType)
|
|
{
|
|
case Im3d::DrawPrimitive_Triangles:
|
|
{
|
|
const uint32_t pointCount = (uint32_t)drawList.m_vertexCount;
|
|
const uint32_t indexCount = pointCount;
|
|
Q_assert(pointCount % 3 == 0);
|
|
memcpy(vertices, drawList.m_vertexData, (size_t)pointCount * sizeof(Im3d::VertexData));
|
|
SetupPipeline(vertexRC_CRP, vertexRC_GRP, ddhi, trianglePipeline, rootSignature, descriptorTables[frameIndex], vertexOffset);
|
|
CmdDraw(indexCount, 0);
|
|
vertexOffset += pointCount;
|
|
vertices += pointCount;
|
|
break;
|
|
}
|
|
case Im3d::DrawPrimitive_Lines:
|
|
{
|
|
const uint32_t pointCount = (uint32_t)drawList.m_vertexCount;
|
|
const uint32_t indexCount = pointCount * 3;
|
|
Q_assert(pointCount % 2 == 0);
|
|
memcpy(vertices, drawList.m_vertexData, (size_t)pointCount * sizeof(Im3d::VertexData));
|
|
SetupPipeline(vertexRC_CRP, vertexRC_GRP, ddhi, linePipeline, rootSignature, descriptorTables[frameIndex], vertexOffset);
|
|
CmdDrawIndexed(indexCount, 0, 0);
|
|
vertexOffset += pointCount;
|
|
vertices += pointCount;
|
|
break;
|
|
}
|
|
case Im3d::DrawPrimitive_Points:
|
|
{
|
|
const uint32_t pointCount = (uint32_t)drawList.m_vertexCount;
|
|
const uint32_t indexCount = pointCount * 6;
|
|
memcpy(vertices, drawList.m_vertexData, (size_t)pointCount * sizeof(Im3d::VertexData));
|
|
SetupPipeline(vertexRC_CRP, vertexRC_GRP, ddhi, pointPipeline, rootSignature, descriptorTables[frameIndex], vertexOffset);
|
|
CmdDrawIndexed(indexCount, 0, 0);
|
|
vertexOffset += pointCount;
|
|
vertices += pointCount;
|
|
break;
|
|
}
|
|
default:
|
|
Q_assert(!"Invalid primitive type");
|
|
break;
|
|
}
|
|
}
|
|
|
|
UnmapBuffer(vertexBuffer);
|
|
}
|
|
|
|
void Im3D::DrawGUI()
|
|
{
|
|
if(ImGui::IsKeyDown(ImGuiMod_Shift) && ImGui::IsKeyPressed(ImGuiKey_G, false))
|
|
{
|
|
drawGizmos = !drawGizmos;
|
|
}
|
|
GUI_AddMainMenuItem(GUI_MainMenu::Im3D, "Enable", "", &drawIm3d);
|
|
GUI_AddMainMenuItem(GUI_MainMenu::Im3D, "Draw Gizmos", "Shift+G", &drawGizmos);
|
|
}
|
|
|
|
bool Im3D::ShouldDrawShapes()
|
|
{
|
|
return drawIm3d;
|
|
}
|
|
|
|
bool Im3D::ShouldDrawGizmos()
|
|
{
|
|
return drawIm3d && drawGizmos && r_debugInput->integer != 0;
|
|
}
|