diff --git a/src/gx/Buffer.cpp b/src/gx/Buffer.cpp index 5d95f80..29a76fe 100644 --- a/src/gx/Buffer.cpp +++ b/src/gx/Buffer.cpp @@ -1,5 +1,8 @@ #include "gx/Buffer.hpp" #include "gx/Device.hpp" +#include "gx/Gx.hpp" +#include "gx/CGxBatch.hpp" +#include CGxVertexAttrib vertexAttribsP[] = { { GxVA_Position, 4, GxVertexAttribOffset(GxVBF_P, GxVA_Position), 12 } @@ -179,6 +182,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]; } @@ -213,6 +218,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]; @@ -220,3 +235,123 @@ 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 + auto format = GxVBF_P; + + if (pos && normal && color) { + format = GxVBF_PNC; + if (tex0 && tex1) { + format = GxVBF_PNCT2; + } else if (tex0) { + format = GxVBF_PNCT; + } + } else if (pos && normal) { + format = GxVBF_PN; + if (tex0 && tex1) { + format = GxVBF_PNT2; + } else if (tex0) { + format = GxVBF_PNT; + } + } else if (pos && color) { + format = GxVBF_PC; + if (tex0 && tex1) { + format = GxVBF_PCT2; + } else if (tex0) { + format = GxVBF_PCT; + } + } else if (pos) { + if (tex0 && tex1) { + format = GxVBF_PT2; + } else if (tex0) { + format = GxVBF_PT; + } + } + + auto vertexSize = Buffer::s_vertexBufDesc[format].size; + + auto buf = g_theGxDevicePtr->BufStream(GxPoolTarget_Vertex, vertexSize, vertexCount); + auto bufData = g_theGxDevicePtr->BufLock(buf); + + C3Vector emptyNormal = { 0.0f, 0.0f, 0.0f }; + CImVector emptyColor = { 0x00, 0x00, 0x00, 0x00 }; + C2Vector emptyTex0 = { 0.0f, 0.0f }; + C2Vector emptyTex1 = { 0.0f, 0.0f }; + + auto bufPos = reinterpret_cast(bufData + GxVertexAttribOffset(format, GxVA_Position)); + auto bufPosStride = vertexSize; + auto bufNormal = reinterpret_cast(bufData + GxVertexAttribOffset(format, GxVA_Normal)); + auto bufNormalStride = vertexSize; + if (!normal) { + normal = &emptyNormal; + normalStride = 0; + bufNormal = &emptyNormal; + bufNormalStride = 0; + } + auto bufColor = reinterpret_cast(bufData + GxVertexAttribOffset(format, GxVA_Color0)); + auto bufColorStride = vertexSize; + if (!color) { + color = &emptyColor; + colorStride = 0; + bufColor = &emptyColor; + bufColorStride = 0; + } + auto bufTex0 = reinterpret_cast(bufData + GxVertexAttribOffset(format, GxVA_TexCoord0)); + auto bufTex0Stride = vertexSize; + if (!tex0) { + tex0 = &emptyTex0; + tex0Stride = 0; + bufTex0 = &emptyTex0; + bufTex0Stride = 0; + } + auto bufTex1 = reinterpret_cast(bufData + GxVertexAttribOffset(format, GxVA_TexCoord1)); + auto bufTex1Stride = vertexSize; + if (!tex1) { + tex1 = &emptyTex1; + tex1Stride = 0; + bufTex1 = &emptyTex1; + bufTex1Stride = 0; + } + + if (vertexCount != 0) { + C3Vector* bufPos = reinterpret_cast(reinterpret_cast(bufData) + uintptr_t(GxVertexAttribOffset(format, GxVA_Position))); + + for (uint32_t i = 0; i < vertexCount; i++) { + *bufPos = *pos; + pos = reinterpret_cast(reinterpret_cast(pos) + posStride); + bufPos = reinterpret_cast(reinterpret_cast(bufPos) + bufPosStride); + + *bufNormal = *normal; + normal = reinterpret_cast(reinterpret_cast(normal) + normalStride); + bufNormal = reinterpret_cast(reinterpret_cast(bufNormal) + bufNormalStride); + *bufColor = *color; + + GxFormatColor(*bufColor); + color = reinterpret_cast(reinterpret_cast(color) + colorStride); + bufColor = reinterpret_cast(reinterpret_cast(bufColor) + bufColorStride); + + *bufTex0 = *tex0; + tex0 = reinterpret_cast(reinterpret_cast(tex0) + tex0Stride); + bufTex0 = reinterpret_cast(reinterpret_cast(bufTex0) + bufTex0Stride); + + *bufTex1 = *tex1; + tex1 = reinterpret_cast(reinterpret_cast(tex1) + tex1Stride); + bufTex1 = reinterpret_cast(reinterpret_cast(bufTex1) + bufTex1Stride); + } + } + + GxBufUnlock(buf, vertexSize * vertexCount); + GxPrimVertexPtr(buf, format); +} + +void GxPrimLockVertexPtrs(uint32_t vertexCount, const C3Vector* pos, uint32_t posStride, const C3Vector* normal, uint32_t normalStride, const CImVector* color, uint32_t colorStride, const uint8_t* 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 GxPrimUnlockVertexPtrs() { + Buffer::s_lockVertexCount = 0; +} diff --git a/src/gx/Buffer.hpp b/src/gx/Buffer.hpp index c673e0a..529dfcd 100644 --- a/src/gx/Buffer.hpp +++ b/src/gx/Buffer.hpp @@ -4,6 +4,7 @@ #include "gx/buffer/CGxBuf.hpp" #include "gx/buffer/CGxPool.hpp" #include "gx/buffer/Types.hpp" +#include "gx/Types.hpp" #include class CGxBuf; @@ -19,6 +20,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); @@ -35,6 +37,14 @@ 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 uint8_t* bone, uint32_t boneStride, const C2Vector* tex0, uint32_t tex0Stride, const C2Vector* tex1, uint32_t tex1Stride); + +void GxPrimUnlockVertexPtrs(); + #endif diff --git a/src/gx/Draw.cpp b/src/gx/Draw.cpp index 54d8954..4d3ea68 100644 --- a/src/gx/Draw.cpp +++ b/src/gx/Draw.cpp @@ -1,10 +1,31 @@ +#include "gx/Buffer.hpp" #include "gx/Draw.hpp" #include "gx/Device.hpp" +#include void GxDraw(CGxBatch* batch, int32_t indexed) { g_theGxDevicePtr->Draw(batch, indexed); } +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 GxSceneClear(uint32_t mask, CImVector color) { g_theGxDevicePtr->SceneClear(mask, color); } diff --git a/src/gx/Draw.hpp b/src/gx/Draw.hpp index e3dd0c5..0d1e698 100644 --- a/src/gx/Draw.hpp +++ b/src/gx/Draw.hpp @@ -10,6 +10,8 @@ class CImVector; void GxDraw(CGxBatch* batch, int32_t indexed); +void GxDrawLockedElements(EGxPrim primType, uint32_t indexCount, const uint16_t* indices); + void GxSceneClear(uint32_t, CImVector); void GxScenePresent(uint32_t a2);