From 695e021621074b759da6a2c96c732e841d538cff Mon Sep 17 00:00:00 2001 From: Joshua Achorn Date: Tue, 4 Apr 2023 14:27:12 -0400 Subject: [PATCH] feat(gx): add locked vertex drawing functions --- src/gx/Buffer.cpp | 232 ++++++++++++++++++++++++++++++++++++++++++++++ src/gx/Buffer.hpp | 11 +++ 2 files changed, 243 insertions(+) diff --git a/src/gx/Buffer.cpp b/src/gx/Buffer.cpp index 7642ff4..28c2496 100644 --- a/src/gx/Buffer.cpp +++ b/src/gx/Buffer.cpp @@ -179,6 +179,8 @@ int32_t Buffer::s_vertexBufOffset[GxVertexBufferFormats_Last][GxVAs_Last] = { { 0, -1, -1, 12, 24, 28, 32, 40, -1, -1, -1, -1, -1, -1 } }; +uint32_t Buffer::s_lockVertexCount = 0; + uint32_t GxVertexAttribOffset(EGxVertexBufferFormat format, EGxVertexAttrib attrib) { return Buffer::s_vertexBufOffset[format][attrib]; } @@ -204,6 +206,16 @@ void GxPrimIndexPtr(CGxBuf* buf) { g_theGxDevicePtr->PrimIndexPtr(buf); } +void GxPrimIndexPtr(uint32_t indexCount, const uint16_t* indices) { + auto buf = g_theGxDevicePtr->BufStream(GxPoolTarget_Index, 2, indexCount); + + g_theGxDevicePtr->BufData(buf, indices, buf->m_itemCount * buf->m_itemSize, 0); + + buf->unk1C = 1; + + g_theGxDevicePtr->PrimIndexPtr(buf); +} + void GxPrimVertexPtr(CGxBuf* buf, EGxVertexBufferFormat format) { auto desc = &Buffer::s_vertexBufDesc[format]; @@ -211,3 +223,223 @@ void GxPrimVertexPtr(CGxBuf* buf, EGxVertexBufferFormat format) { g_theGxDevicePtr->PrimVertexMask(desc->mask); g_theGxDevicePtr->PrimVertexPtr(buf, format); } + +void GxPrimVertexPtr(uint32_t vertexCount, const C3Vector* pos, uint32_t posStride, const C3Vector* normal, uint32_t normalStride, const CImVector* color, uint32_t colorStride, const C2Vector* tex0, uint32_t tex0Stride, const C2Vector* tex1, uint32_t tex1Stride) { + // Select vertex buffer format based on given parameters + EGxVertexBufferFormat bufFmt = GxVBF_P; + + if (pos != nullptr) { + if (normal != nullptr) { + if (color != nullptr) { + if (tex0 != nullptr) { + if (tex1 != nullptr) { + bufFmt = GxVBF_PNCT2; + } else { + bufFmt = GxVBF_PNCT; + } + } else { + if (tex1 == nullptr) { + bufFmt = GxVBF_PNC; + } + } + } else { + if (tex0 != nullptr) { + if (tex1 != nullptr) { + bufFmt = GxVBF_PNT2; + } else { + bufFmt = GxVBF_PNT; + } + } else { + if (tex1 == nullptr) { + bufFmt = GxVBF_PN; + } + } + } + } else { + if (color != nullptr) { + if (tex0 != nullptr) { + if (tex1 != nullptr) { + bufFmt = GxVBF_PCT2; + } else { + bufFmt = GxVBF_PCT; + } + } else { + if (tex1 == nullptr) { + bufFmt = GxVBF_PC; + } + } + } else { + if (tex0 != nullptr) { + if (tex1 != nullptr) { + bufFmt = GxVBF_PT2; + } else { + bufFmt = GxVBF_PT; + } + } + } + } + } + + auto vertexSize = Buffer::s_vertexBufDesc[bufFmt].size; + + auto buf = g_theGxDevicePtr->BufStream(GxPoolTarget_Vertex, vertexSize, vertexCount); + auto bufData = g_theGxDevicePtr->BufLock(buf); + + C3Vector genericNormal = {}; + CImVector genericColor = {}; + C2Vector genericTexCoord0 = {}; + C2Vector genericTexCoord1 = {}; + + C3Vector* writeNormal; + CImVector* writeColor; + C2Vector* writeTexCoord0; + C2Vector* writeTexCoord1; + + uintptr_t writeNormalStride = normal != nullptr ? vertexSize : 0; + if (normal == nullptr) { + writeNormal = &genericNormal; + } else { + writeNormal = reinterpret_cast( + uintptr_t(bufData) + uintptr_t(GxVertexAttribOffset(bufFmt, GxVA_Normal)) + ); + } + + uintptr_t writeColorStride = color != nullptr ? vertexSize : 0; + if (color == nullptr) { + writeColor = &genericColor; + } else { + writeColor = reinterpret_cast( + uintptr_t(bufData) + uintptr_t(GxVertexAttribOffset(bufFmt, GxVA_Color0)) + ); + } + + uintptr_t writeTexCoord0Stride = tex0 != nullptr ? vertexSize : 0; + if (tex0 == nullptr) { + writeTexCoord0 = &genericTexCoord0; + } else { + writeTexCoord0 = reinterpret_cast( + uintptr_t(bufData) + uintptr_t(GxVertexAttribOffset(bufFmt, GxVA_TexCoord0)) + ); + } + + uintptr_t writeTexCoord1Stride = tex1 != nullptr ? vertexSize : 0; + if (tex1 == nullptr) { + writeTexCoord1 = &genericTexCoord1; + } else { + writeTexCoord1 = reinterpret_cast( + uintptr_t(bufData) + uintptr_t(GxVertexAttribOffset(bufFmt, GxVA_TexCoord1)) + ); + } + + if (normal == nullptr) { + normal = &genericNormal; + normalStride = 0; + } + + if (color == nullptr) { + color = &genericColor; + colorStride = 0; + } + + if (tex0 == nullptr) { + tex0 = &genericTexCoord0; + tex0Stride = 0; + } + + if (tex1 == nullptr) { + tex1 = &genericTexCoord1; + tex1Stride = 0; + } + + if (vertexCount != 0) { + auto useRgba = GxCaps().m_colorFormat == GxCF_rgba; + + C3Vector* writePos = reinterpret_cast( + uintptr_t(bufData) + uintptr_t(GxVertexAttribOffset(bufFmt, GxVA_Position)) + ); + + for (uint32_t v = 0; v < vertexCount; v++) { + *writePos = *pos; + pos = reinterpret_cast( + uintptr_t(pos) + uintptr_t(posStride) + ); + writePos = reinterpret_cast( + uintptr_t(writePos) + uintptr_t(vertexSize) + ); + + *writeNormal = *normal; + normal = reinterpret_cast( + uintptr_t(normal) + uintptr_t(normalStride) + ); + writeNormal = reinterpret_cast( + uintptr_t(writeNormal) + writeNormalStride + ); + + if (useRgba) { + uint8_t rgba[4]; + rgba[0] = color->r; + rgba[1] = color->g; + rgba[2] = color->b; + rgba[3] = color->a; + memcpy(writeColor, rgba, 4); + } else { + *writeColor = *color; + } + color = reinterpret_cast( + uintptr_t(color) + colorStride + ); + writeColor = reinterpret_cast( + uintptr_t(writeColor) + writeColorStride + ); + + *writeTexCoord0 = *tex0; + tex0 = reinterpret_cast( + uintptr_t(tex0) + tex0Stride + ); + writeTexCoord0 = reinterpret_cast( + uintptr_t(writeTexCoord0) + writeTexCoord0Stride + ); + + *writeTexCoord1 = *tex1; + tex1 = reinterpret_cast( + uintptr_t(tex1) + tex1Stride + ); + writeTexCoord1 = reinterpret_cast( + uintptr_t(writeTexCoord1) + writeTexCoord1Stride + ); + } + } + + GxBufUnlock(buf, vertexSize * vertexCount); + GxPrimVertexPtr(buf, bufFmt); +} + +void GxPrimLockVertexPtrs(uint32_t vertexCount, const C3Vector* pos, uint32_t posStride, const C3Vector* normal, uint32_t normalStride, const CImVector* color, uint32_t colorStride, const unsigned char* bone, uint32_t boneStride, const C2Vector* tex0, uint32_t tex0Stride, const C2Vector* tex1, uint32_t tex1Stride) { + BLIZZARD_ASSERT(Buffer::s_lockVertexCount == 0); + Buffer::s_lockVertexCount = vertexCount; + + GxPrimVertexPtr(vertexCount, pos, posStride, normal, normalStride, color, colorStride, tex0, tex0Stride, tex1, tex1Stride); +} + +void GxDrawLockedElements(EGxPrim primType, uint32_t indexCount, const uint16_t* indices) { + if (Buffer::s_lockVertexCount == 0) { + return; + } + + GxPrimIndexPtr(indexCount, indices); + + CGxBatch batch; + batch.m_primType = primType; + batch.m_minIndex = 0; + batch.m_maxIndex = Buffer::s_lockVertexCount - 1; + batch.m_start = 0; + batch.m_count = indexCount; + + BLIZZARD_ASSERT(batch.m_count > 0); + + g_theGxDevicePtr->Draw(&batch, 1); +} + +void GxPrimUnlockVertexPtrs() { + Buffer::s_lockVertexCount = 0; +} diff --git a/src/gx/Buffer.hpp b/src/gx/Buffer.hpp index 9b77a77..09b8ac5 100644 --- a/src/gx/Buffer.hpp +++ b/src/gx/Buffer.hpp @@ -19,6 +19,7 @@ struct VertexBufDesc { namespace Buffer { extern VertexBufDesc s_vertexBufDesc[GxVertexBufferFormats_Last]; extern int32_t s_vertexBufOffset[GxVertexBufferFormats_Last][GxVAs_Last]; + extern uint32_t s_lockVertexCount; } uint32_t GxVertexAttribOffset(EGxVertexBufferFormat, EGxVertexAttrib); @@ -33,6 +34,16 @@ CGxPool* GxPoolCreate(EGxPoolTarget, EGxPoolUsage, uint32_t, EGxPoolHintBits, ch void GxPrimIndexPtr(CGxBuf*); +void GxPrimIndexPtr(uint32_t indexCount, const uint16_t* indices); + void GxPrimVertexPtr(CGxBuf*, EGxVertexBufferFormat); +void GxPrimVertexPtr(uint32_t vertexCount, const C3Vector* pos, uint32_t posStride, const C3Vector* normal, uint32_t normalStride, const CImVector* color, uint32_t colorStride, const C2Vector* tex0, uint32_t tex0Stride, const C2Vector* tex1, uint32_t tex1Stride); + +void GxPrimLockVertexPtrs(uint32_t vertexCount, const C3Vector* pos, uint32_t posStride, const C3Vector* normal, uint32_t normalStride, const CImVector* color, uint32_t colorStride, const unsigned char* bone, uint32_t boneStride, const C2Vector* tex0, uint32_t tex0Stride, const C2Vector* tex1, uint32_t tex1Stride); + +void GxDrawLockedElements(EGxPrim primType, uint32_t indexCount, const uint16_t* indices); + +void GxPrimUnlockVertexPtrs(); + #endif