mirror of
https://bitbucket.org/CPMADevs/cnq3
synced 2024-12-01 16:31:54 +00:00
289 lines
7.7 KiB
C++
289 lines
7.7 KiB
C++
/*
|
|
===========================================================================
|
|
Copyright (C) 2022-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 - UI/2D rendering
|
|
|
|
|
|
#include "srp_local.h"
|
|
|
|
|
|
#pragma pack(push, 4)
|
|
struct VertexRC
|
|
{
|
|
float scale[2];
|
|
};
|
|
|
|
struct PixelRC
|
|
{
|
|
uint32_t texture;
|
|
uint32_t sampler;
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
|
|
void UI::Init(bool ddhi_, const ShaderByteCode& vs, const ShaderByteCode& ps, TextureFormat::Id rtFormat, HDescriptorTable descTable, RootSignatureDesc* rootSigDesc)
|
|
{
|
|
ddhi = ddhi_;
|
|
descriptorTable = descTable;
|
|
|
|
if(srp.firstInit)
|
|
{
|
|
if(ddhi)
|
|
{
|
|
rootSignature = RHI_MAKE_NULL_HANDLE();
|
|
}
|
|
else
|
|
{
|
|
RootSignatureDesc desc = *rootSigDesc;
|
|
desc.name = "UI";
|
|
desc.constants[ShaderStage::Vertex].byteCount = 8;
|
|
desc.constants[ShaderStage::Pixel].byteCount = 8;
|
|
rootSignature = CreateRootSignature(desc);
|
|
}
|
|
maxVertexCount = 640 << 10;
|
|
maxIndexCount = 8 * maxVertexCount;
|
|
{
|
|
BufferDesc desc("UI index", sizeof(UI::Index) * maxIndexCount * FrameCount, ResourceStates::IndexBufferBit);
|
|
desc.memoryUsage = MemoryUsage::Upload;
|
|
indexBuffer = CreateBuffer(desc);
|
|
indices = (UI::Index*)MapBuffer(indexBuffer);
|
|
}
|
|
{
|
|
BufferDesc desc("UI vertex", sizeof(UI::Vertex) * maxVertexCount * FrameCount, ResourceStates::VertexBufferBit);
|
|
desc.memoryUsage = MemoryUsage::Upload;
|
|
vertexBuffer = CreateBuffer(desc);
|
|
vertices = (UI::Vertex*)MapBuffer(vertexBuffer);
|
|
}
|
|
}
|
|
{
|
|
GraphicsPipelineDesc desc("UI", rootSignature);
|
|
desc.shortLifeTime = true;
|
|
desc.vertexShader = vs;
|
|
desc.pixelShader = ps;
|
|
desc.vertexLayout.bindingStrides[0] = sizeof(UI::Vertex);
|
|
desc.vertexLayout.AddAttribute(0, ShaderSemantic::Position,
|
|
DataType::Float32, 2, offsetof(UI::Vertex, position));
|
|
desc.vertexLayout.AddAttribute(0, ShaderSemantic::TexCoord,
|
|
DataType::Float32, 2, offsetof(UI::Vertex, texCoords));
|
|
desc.vertexLayout.AddAttribute(0, ShaderSemantic::Color,
|
|
DataType::UNorm8, 4, offsetof(UI::Vertex, color));
|
|
desc.depthStencil.depthComparison = ComparisonFunction::Always;
|
|
desc.depthStencil.depthStencilFormat = TextureFormat::Depth32_Float;
|
|
desc.depthStencil.enableDepthTest = false;
|
|
desc.depthStencil.enableDepthWrites = false;
|
|
desc.rasterizer.cullMode = CT_TWO_SIDED;
|
|
desc.AddRenderTarget(GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA, rtFormat);
|
|
pipeline = CreateGraphicsPipeline(desc);
|
|
}
|
|
}
|
|
|
|
void UI::BeginFrame()
|
|
{
|
|
// move to this frame's dedicated buffer section
|
|
const uint32_t frameIndex = GetFrameIndex();
|
|
firstIndex = frameIndex * maxIndexCount;
|
|
firstVertex = frameIndex * maxVertexCount;
|
|
renderPassIndex = UINT32_MAX;
|
|
}
|
|
|
|
void UI::Begin(HTexture renderTarget)
|
|
{
|
|
srp.renderMode = RenderMode::UI;
|
|
|
|
renderPassIndex = srp.BeginRenderPass("UI", 0.0f, 0.85f, 1.0f);
|
|
|
|
CmdBeginBarrier();
|
|
CmdTextureBarrier(renderTarget, ResourceStates::RenderTargetBit);
|
|
CmdEndBarrier();
|
|
|
|
CmdBindRenderTargets(1, &renderTarget, NULL);
|
|
|
|
// UI always uses the entire render surface
|
|
CmdSetViewportAndScissor(0, 0, glConfig.vidWidth, glConfig.vidHeight);
|
|
|
|
if(!ddhi)
|
|
{
|
|
CmdBindRootSignature(rootSignature);
|
|
}
|
|
CmdBindPipeline(pipeline);
|
|
if(!ddhi)
|
|
{
|
|
CmdBindDescriptorTable(rootSignature, descriptorTable);
|
|
}
|
|
const uint32_t stride = sizeof(UI::Vertex);
|
|
CmdBindVertexBuffers(1, &vertexBuffer, &stride, NULL);
|
|
CmdBindIndexBuffer(indexBuffer, indexType, 0);
|
|
|
|
VertexRC vertexRC = {};
|
|
vertexRC.scale[0] = 2.0f / glConfig.vidWidth;
|
|
vertexRC.scale[1] = 2.0f / glConfig.vidHeight;
|
|
if(ddhi)
|
|
{
|
|
CmdSetGraphicsRootConstants(0, sizeof(vertexRC), &vertexRC);
|
|
}
|
|
else
|
|
{
|
|
CmdSetRootConstants(rootSignature, ShaderStage::Vertex, &vertexRC);
|
|
}
|
|
}
|
|
|
|
void UI::End()
|
|
{
|
|
DrawBatch();
|
|
|
|
srp.EndRenderPass(renderPassIndex);
|
|
|
|
srp.renderMode = RenderMode::None;
|
|
}
|
|
|
|
void UI::DrawBatch()
|
|
{
|
|
if(indexCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// @TODO: support for custom shaders?
|
|
Q_assert(shader->stages[0] != NULL);
|
|
const textureBundle_t& bundle = shader->stages[0]->bundle;
|
|
const textureWrap_t wrapMode = bundle.image[0] != NULL ? bundle.image[0]->wrapClampMode : TW_REPEAT;
|
|
PixelRC pixelRC = {};
|
|
pixelRC.texture = GetBundleImage(bundle)->textureIndex;
|
|
pixelRC.sampler = GetSamplerIndex(wrapMode, TextureFilter::Linear);
|
|
if(ddhi)
|
|
{
|
|
CmdSetGraphicsRootConstants(sizeof(VertexRC), sizeof(PixelRC), &pixelRC);
|
|
}
|
|
else
|
|
{
|
|
CmdSetRootConstants(rootSignature, ShaderStage::Pixel, &pixelRC);
|
|
}
|
|
|
|
CmdDrawIndexed(indexCount, firstIndex, 0);
|
|
firstIndex += indexCount;
|
|
firstVertex += vertexCount;
|
|
indexCount = 0;
|
|
vertexCount = 0;
|
|
}
|
|
|
|
void UI::CmdSetColor(const uiSetColorCommand_t& cmd)
|
|
{
|
|
const float rgbScale = tr.identityLight * 255.0f;
|
|
byte* const colors = (byte*)&color;
|
|
colors[0] = (byte)(cmd.color[0] * rgbScale);
|
|
colors[1] = (byte)(cmd.color[1] * rgbScale);
|
|
colors[2] = (byte)(cmd.color[2] * rgbScale);
|
|
colors[3] = (byte)(cmd.color[3] * 255.0f);
|
|
}
|
|
|
|
void UI::CmdDrawQuad(const uiDrawQuadCommand_t& cmd)
|
|
{
|
|
if(vertexCount + 4 > maxVertexCount ||
|
|
indexCount + 6 > maxIndexCount)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(shader != cmd.shader)
|
|
{
|
|
DrawBatch();
|
|
}
|
|
|
|
shader = cmd.shader;
|
|
|
|
const int v = firstVertex + vertexCount;
|
|
const int i = firstIndex + indexCount;
|
|
vertexCount += 4;
|
|
indexCount += 6;
|
|
|
|
indices[i + 0] = v + 3;
|
|
indices[i + 1] = v + 0;
|
|
indices[i + 2] = v + 2;
|
|
indices[i + 3] = v + 2;
|
|
indices[i + 4] = v + 0;
|
|
indices[i + 5] = v + 1;
|
|
|
|
vertices[v + 0].position[0] = cmd.x;
|
|
vertices[v + 0].position[1] = cmd.y;
|
|
vertices[v + 0].texCoords[0] = cmd.s1;
|
|
vertices[v + 0].texCoords[1] = cmd.t1;
|
|
vertices[v + 0].color = color;
|
|
|
|
vertices[v + 1].position[0] = cmd.x + cmd.w;
|
|
vertices[v + 1].position[1] = cmd.y;
|
|
vertices[v + 1].texCoords[0] = cmd.s2;
|
|
vertices[v + 1].texCoords[1] = cmd.t1;
|
|
vertices[v + 1].color = color;
|
|
|
|
vertices[v + 2].position[0] = cmd.x + cmd.w;
|
|
vertices[v + 2].position[1] = cmd.y + cmd.h;
|
|
vertices[v + 2].texCoords[0] = cmd.s2;
|
|
vertices[v + 2].texCoords[1] = cmd.t2;
|
|
vertices[v + 2].color = color;
|
|
|
|
vertices[v + 3].position[0] = cmd.x;
|
|
vertices[v + 3].position[1] = cmd.y + cmd.h;
|
|
vertices[v + 3].texCoords[0] = cmd.s1;
|
|
vertices[v + 3].texCoords[1] = cmd.t2;
|
|
vertices[v + 3].color = color;
|
|
}
|
|
|
|
void UI::CmdDrawTriangle(const uiDrawTriangleCommand_t& cmd)
|
|
{
|
|
if(vertexCount + 3 > maxVertexCount ||
|
|
indexCount + 3 > maxIndexCount)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(shader != cmd.shader)
|
|
{
|
|
DrawBatch();
|
|
}
|
|
|
|
shader = cmd.shader;
|
|
|
|
const int v = firstVertex + vertexCount;
|
|
const int i = firstIndex + indexCount;
|
|
vertexCount += 3;
|
|
indexCount += 3;
|
|
|
|
indices[i + 0] = v + 0;
|
|
indices[i + 1] = v + 1;
|
|
indices[i + 2] = v + 2;
|
|
|
|
vertices[v + 0].position[0] = cmd.x0;
|
|
vertices[v + 0].position[1] = cmd.y0;
|
|
vertices[v + 0].texCoords[0] = cmd.s0;
|
|
vertices[v + 0].texCoords[1] = cmd.t0;
|
|
vertices[v + 0].color = color;
|
|
|
|
vertices[v + 1].position[0] = cmd.x1;
|
|
vertices[v + 1].position[1] = cmd.y1;
|
|
vertices[v + 1].texCoords[0] = cmd.s1;
|
|
vertices[v + 1].texCoords[1] = cmd.t1;
|
|
vertices[v + 1].color = color;
|
|
|
|
vertices[v + 2].position[0] = cmd.x2;
|
|
vertices[v + 2].position[1] = cmd.y2;
|
|
vertices[v + 2].texCoords[0] = cmd.s2;
|
|
vertices[v + 2].texCoords[1] = cmd.t2;
|
|
vertices[v + 2].color = color;
|
|
}
|