cnq3/code/renderer/crp_geometry.cpp

226 lines
7.9 KiB
C++

/*
===========================================================================
Copyright (C) 2023-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 - vertex and index buffer management
#include "crp_local.h"
void GeoBuffers::Create(const char* name, uint32_t vertexCount, uint32_t indexCount)
{
baseVertexBuffers[BaseBufferId::Position].CreateVertexBuffer(
va("%s position", name), MemoryUsage::Upload, vertexCount, sizeof(vec3_t));
baseVertexBuffers[BaseBufferId::Normal].CreateVertexBuffer(
va("%s normal", name), MemoryUsage::Upload, vertexCount, sizeof(vec3_t));
stageVertexBuffers[StageBufferId::TexCoords].CreateVertexBuffer(
va("%s tc", name), MemoryUsage::Upload, vertexCount * MAX_SHADER_STAGES, sizeof(vec2_t));
stageVertexBuffers[StageBufferId::Color].CreateVertexBuffer(
va("%s color", name), MemoryUsage::Upload, vertexCount * MAX_SHADER_STAGES, sizeof(color4ub_t));
indexBuffer.Create(name, MemoryUsage::Upload, indexCount);
vertexBuffers[0] = baseVertexBuffers[BaseBufferId::Position].buffer;
vertexBuffers[1] = baseVertexBuffers[BaseBufferId::Normal].buffer;
vertexBuffers[2] = stageVertexBuffers[StageBufferId::TexCoords].buffer;
vertexBuffers[3] = stageVertexBuffers[StageBufferId::Color].buffer;
vertexBufferStrides[0] = sizeof(vec3_t);
vertexBufferStrides[1] = sizeof(vec3_t);
vertexBufferStrides[2] = sizeof(vec2_t);
vertexBufferStrides[3] = sizeof(color4ub_t);
}
void GeoBuffers::Rewind()
{
for(uint32_t b = 0; b < ARRAY_LEN(baseVertexBuffers); ++b)
{
baseVertexBuffers[b].Rewind();
}
for(uint32_t b = 0; b < ARRAY_LEN(stageVertexBuffers); ++b)
{
stageVertexBuffers[b].Rewind();
}
indexBuffer.Rewind();
}
void GeoBuffers::BeginUpload()
{
for(uint32_t b = 0; b < ARRAY_LEN(baseVertexBuffers); ++b)
{
baseVertexBuffers[b].BeginUpload();
}
for(uint32_t b = 0; b < ARRAY_LEN(stageVertexBuffers); ++b)
{
stageVertexBuffers[b].BeginUpload();
}
indexBuffer.BeginUpload();
}
void GeoBuffers::EndUpload()
{
for(uint32_t b = 0; b < ARRAY_LEN(baseVertexBuffers); ++b)
{
baseVertexBuffers[b].EndUpload();
}
for(uint32_t b = 0; b < ARRAY_LEN(stageVertexBuffers); ++b)
{
stageVertexBuffers[b].EndUpload();
}
indexBuffer.EndUpload();
}
void GeoBuffers::UploadBase()
{
indexBuffer.Upload();
const uint32_t batchOffset = baseVertexBuffers[0].batchFirst + baseVertexBuffers[0].batchCount;
float* pos = (float*)baseVertexBuffers[BaseBufferId::Position].mapped + 3 * batchOffset;
for(int v = 0; v < tess.numVertexes; ++v)
{
pos[0] = tess.xyz[v][0];
pos[1] = tess.xyz[v][1];
pos[2] = tess.xyz[v][2];
pos += 3;
}
float* nor = (float*)baseVertexBuffers[BaseBufferId::Normal].mapped + 3 * batchOffset;
for(int v = 0; v < tess.numVertexes; ++v)
{
nor[0] = tess.normal[v][0];
nor[1] = tess.normal[v][1];
nor[2] = tess.normal[v][2];
nor += 3;
}
}
void GeoBuffers::UploadStage(uint32_t svarsIndex)
{
const uint32_t batchOffset = stageVertexBuffers[0].batchFirst + stageVertexBuffers[0].batchCount;
const stageVars_t& sv = tess.svars[svarsIndex];
uint8_t* const tcBuffer = stageVertexBuffers[StageBufferId::TexCoords].mapped;
float* tc = (float*)tcBuffer + 2 * batchOffset;
memcpy(tc, &sv.texcoords[0], tess.numVertexes * sizeof(vec2_t));
uint8_t* const colBuffer = stageVertexBuffers[StageBufferId::Color].mapped;
uint32_t* col = (uint32_t*)colBuffer + batchOffset;
memcpy(col, &sv.colors[0], tess.numVertexes * sizeof(color4ub_t));
}
void GeoBuffers::EndBaseBatch(uint32_t vertexCount)
{
baseVertexBuffers[BaseBufferId::Position].EndBatch(vertexCount);
baseVertexBuffers[BaseBufferId::Normal].EndBatch(vertexCount);
indexBuffer.EndBatch(tess.numIndexes);
}
bool GeoBuffers::CanAdd(uint32_t vertexCount, uint32_t indexCount, uint32_t stageCount)
{
return
baseVertexBuffers[0].CanAdd(vertexCount) &&
stageVertexBuffers[0].CanAdd(vertexCount * stageCount) &&
indexBuffer.CanAdd(indexCount);
}
void GeoBuffers::DrawStage(uint32_t vertexCount, uint32_t indexCount)
{
const uint32_t vertexOffset = stageVertexBuffers[0].batchFirst - baseVertexBuffers[0].batchFirst;
uint32_t byteOffsets[BaseBufferId::Count + StageBufferId::Count] = {};
byteOffsets[BaseBufferId::Count + StageBufferId::TexCoords] = vertexOffset * sizeof(vec2_t);
byteOffsets[BaseBufferId::Count + StageBufferId::Color] = vertexOffset * sizeof(color4ub_t);
CmdBindVertexBuffers(ARRAY_LEN(vertexBuffers), vertexBuffers, vertexBufferStrides, byteOffsets);
CmdDrawIndexed(indexCount, indexBuffer.batchFirst, baseVertexBuffers[0].batchFirst);
// @NOTE: must happen after the final vertex buffer byte offsets have been computed
stageVertexBuffers[StageBufferId::TexCoords].EndBatch(vertexCount);
stageVertexBuffers[StageBufferId::Color].EndBatch(vertexCount);
}
void GeoBuffers::DrawPositionOnly(uint32_t vertexCount, uint32_t indexCount)
{
const HBuffer buffer = vertexBuffers[BaseBufferId::Position];
const uint32_t stride = vertexBufferStrides[BaseBufferId::Position];
const uint32_t byteOffset = 0;
CmdBindVertexBuffers(1, &buffer, &stride, &byteOffset);
CmdDrawIndexed(indexCount, indexBuffer.batchFirst, baseVertexBuffers[0].batchFirst);
}
void GeoBuffers::UploadAndDrawDebugNormals()
{
if(!baseVertexBuffers[0].CanAdd(tess.numVertexes * 2) ||
!indexBuffer.CanAdd(tess.numVertexes * 3))
{
return;
}
const uint32_t posBatchOffset = baseVertexBuffers[BaseBufferId::Position].batchFirst + baseVertexBuffers[BaseBufferId::Position].batchCount;
float* positions = (float*)baseVertexBuffers[BaseBufferId::Position].mapped + 3 * posBatchOffset;
for(uint32_t v = 0; v < tess.numVertexes; v++)
{
vec3_t newPoint;
VectorMA(tess.xyz[v], 4.0f, tess.normal[v], newPoint);
*positions++ = tess.xyz[v][0];
*positions++ = tess.xyz[v][1];
*positions++ = tess.xyz[v][2];
*positions++ = newPoint[0];
*positions++ = newPoint[1];
*positions++ = newPoint[2];
}
const uint32_t colBatchOffset = stageVertexBuffers[StageBufferId::Color].batchFirst + stageVertexBuffers[StageBufferId::Color].batchCount;
uint8_t* const colBuffer = stageVertexBuffers[StageBufferId::Color].mapped;
uint32_t* col = (uint32_t*)colBuffer + colBatchOffset;
for(uint32_t v = 0; v < tess.numVertexes; v++)
{
*col++ = 0xFF0000FF;
*col++ = 0xFFFF7F00;
}
uint32_t* indices = indexBuffer.GetCurrentAddress();
for(uint32_t i = 0; i < tess.numVertexes; i++)
{
*indices++ = i * 2 + 0;
*indices++ = i * 2 + 0;
*indices++ = i * 2 + 1;
}
const uint32_t vertexOffset = stageVertexBuffers[0].batchFirst - baseVertexBuffers[0].batchFirst;
const uint32_t byteOffsets[2] = { 0, vertexOffset * sizeof(color4ub_t) };
HBuffer vb[2];
vb[0] = vertexBuffers[BaseBufferId::Position];
vb[1] = vertexBuffers[BaseBufferId::Count + StageBufferId::Color];
uint32_t strides[2];
strides[0] = vertexBufferStrides[BaseBufferId::Position];
strides[1] = vertexBufferStrides[BaseBufferId::Count + StageBufferId::Color];
CmdBindVertexBuffers(ARRAY_LEN(vb), vb, strides, byteOffsets);
CmdDrawIndexed(tess.numVertexes * 3, indexBuffer.batchFirst, baseVertexBuffers[0].batchFirst);
for(int b = 0; b < ARRAY_LEN(baseVertexBuffers); b++)
{
baseVertexBuffers[b].EndBatch(tess.numVertexes * 2);
}
for(int b = 0; b < ARRAY_LEN(stageVertexBuffers); b++)
{
stageVertexBuffers[b].EndBatch(tess.numVertexes * 2);
}
indexBuffer.EndBatch(tess.numVertexes * 3);
}