diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index c4ebf1dbe74e..982a9c524600 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -238,106 +238,106 @@ bool DrawEngineCommon::GetCurrentSimpleVertices(int count, std::vectorDecodeVerts(bufPtr, inPtr, lowerBound, upperBound); - - // OK, morphing eliminated but bones still remain to be taken care of. - // Let's do a partial software transform where we only do skinning. - - VertexReader reader(bufPtr, dec->GetDecVtxFmt(), vertType); - - SimpleVertex *sverts = (SimpleVertex *)outPtr; - - const u8 defaultColor[4] = { - (u8)gstate.getMaterialAmbientR(), - (u8)gstate.getMaterialAmbientG(), - (u8)gstate.getMaterialAmbientB(), - (u8)gstate.getMaterialAmbientA(), - }; - - // Let's have two separate loops, one for non skinning and one for skinning. - if (!g_Config.bSoftwareSkinning && (vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE) { - int numBoneWeights = vertTypeGetNumBoneWeights(vertType); - for (int i = lowerBound; i <= upperBound; i++) { - reader.Goto(i); - SimpleVertex &sv = sverts[i]; - if (vertType & GE_VTYPE_TC_MASK) { - reader.ReadUV(sv.uv); - } - - if (vertType & GE_VTYPE_COL_MASK) { - reader.ReadColor0_8888(sv.color); - } else { - memcpy(sv.color, defaultColor, 4); - } - - float nrm[3], pos[3]; - float bnrm[3], bpos[3]; - - if (vertType & GE_VTYPE_NRM_MASK) { - // Normals are generated during tesselation anyway, not sure if any need to supply - reader.ReadNrm(nrm); - } else { - nrm[0] = 0; - nrm[1] = 0; - nrm[2] = 1.0f; - } - reader.ReadPos(pos); - - // Apply skinning transform directly - float weights[8]; - reader.ReadWeights(weights); - // Skinning - Vec3Packedf psum(0, 0, 0); - Vec3Packedf nsum(0, 0, 0); - for (int w = 0; w < numBoneWeights; w++) { - if (weights[w] != 0.0f) { - Vec3ByMatrix43(bpos, pos, gstate.boneMatrix + w * 12); - Vec3Packedf tpos(bpos); - psum += tpos * weights[w]; - - Norm3ByMatrix43(bnrm, nrm, gstate.boneMatrix + w * 12); - Vec3Packedf tnorm(bnrm); - nsum += tnorm * weights[w]; - } - } - sv.pos = psum; - sv.nrm = nsum; - } - } else { - for (int i = lowerBound; i <= upperBound; i++) { - reader.Goto(i); - SimpleVertex &sv = sverts[i]; - if (vertType & GE_VTYPE_TC_MASK) { - reader.ReadUV(sv.uv); - } else { - sv.uv[0] = 0; // This will get filled in during tesselation - sv.uv[1] = 0; - } - if (vertType & GE_VTYPE_COL_MASK) { - reader.ReadColor0_8888(sv.color); - } else { - memcpy(sv.color, defaultColor, 4); - } - if (vertType & GE_VTYPE_NRM_MASK) { - // Normals are generated during tesselation anyway, not sure if any need to supply - reader.ReadNrm((float *)&sv.nrm); - } else { - sv.nrm.x = 0; - sv.nrm.y = 0; - sv.nrm.z = 1.0f; - } - reader.ReadPos((float *)&sv.pos); - } - } - - // Okay, there we are! Return the new type (but keep the index bits) - return GE_VTYPE_TC_FLOAT | GE_VTYPE_COL_8888 | GE_VTYPE_NRM_FLOAT | GE_VTYPE_POS_FLOAT | (vertType & (GE_VTYPE_IDX_MASK | GE_VTYPE_THROUGH)); -} + +// This normalizes a set of vertices in any format to SimpleVertex format, by processing away morphing AND skinning. +// The rest of the transform pipeline like lighting will go as normal, either hardware or software. +// The implementation is initially a bit inefficient but shouldn't be a big deal. +// An intermediate buffer of not-easy-to-predict size is stored at bufPtr. +u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, VertexDecoder *dec, int lowerBound, int upperBound, u32 vertType) { + // First, decode the vertices into a GPU compatible format. This step can be eliminated but will need a separate + // implementation of the vertex decoder. + dec->DecodeVerts(bufPtr, inPtr, lowerBound, upperBound); + + // OK, morphing eliminated but bones still remain to be taken care of. + // Let's do a partial software transform where we only do skinning. + + VertexReader reader(bufPtr, dec->GetDecVtxFmt(), vertType); + + SimpleVertex *sverts = (SimpleVertex *)outPtr; + + const u8 defaultColor[4] = { + (u8)gstate.getMaterialAmbientR(), + (u8)gstate.getMaterialAmbientG(), + (u8)gstate.getMaterialAmbientB(), + (u8)gstate.getMaterialAmbientA(), + }; + + // Let's have two separate loops, one for non skinning and one for skinning. + if (!g_Config.bSoftwareSkinning && (vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE) { + int numBoneWeights = vertTypeGetNumBoneWeights(vertType); + for (int i = lowerBound; i <= upperBound; i++) { + reader.Goto(i); + SimpleVertex &sv = sverts[i]; + if (vertType & GE_VTYPE_TC_MASK) { + reader.ReadUV(sv.uv); + } + + if (vertType & GE_VTYPE_COL_MASK) { + reader.ReadColor0_8888(sv.color); + } else { + memcpy(sv.color, defaultColor, 4); + } + + float nrm[3], pos[3]; + float bnrm[3], bpos[3]; + + if (vertType & GE_VTYPE_NRM_MASK) { + // Normals are generated during tesselation anyway, not sure if any need to supply + reader.ReadNrm(nrm); + } else { + nrm[0] = 0; + nrm[1] = 0; + nrm[2] = 1.0f; + } + reader.ReadPos(pos); + + // Apply skinning transform directly + float weights[8]; + reader.ReadWeights(weights); + // Skinning + Vec3Packedf psum(0, 0, 0); + Vec3Packedf nsum(0, 0, 0); + for (int w = 0; w < numBoneWeights; w++) { + if (weights[w] != 0.0f) { + Vec3ByMatrix43(bpos, pos, gstate.boneMatrix + w * 12); + Vec3Packedf tpos(bpos); + psum += tpos * weights[w]; + + Norm3ByMatrix43(bnrm, nrm, gstate.boneMatrix + w * 12); + Vec3Packedf tnorm(bnrm); + nsum += tnorm * weights[w]; + } + } + sv.pos = psum; + sv.nrm = nsum; + } + } else { + for (int i = lowerBound; i <= upperBound; i++) { + reader.Goto(i); + SimpleVertex &sv = sverts[i]; + if (vertType & GE_VTYPE_TC_MASK) { + reader.ReadUV(sv.uv); + } else { + sv.uv[0] = 0; // This will get filled in during tesselation + sv.uv[1] = 0; + } + if (vertType & GE_VTYPE_COL_MASK) { + reader.ReadColor0_8888(sv.color); + } else { + memcpy(sv.color, defaultColor, 4); + } + if (vertType & GE_VTYPE_NRM_MASK) { + // Normals are generated during tesselation anyway, not sure if any need to supply + reader.ReadNrm((float *)&sv.nrm); + } else { + sv.nrm.x = 0; + sv.nrm.y = 0; + sv.nrm.z = 1.0f; + } + reader.ReadPos((float *)&sv.pos); + } + } + + // Okay, there we are! Return the new type (but keep the index bits) + return GE_VTYPE_TC_FLOAT | GE_VTYPE_COL_8888 | GE_VTYPE_NRM_FLOAT | GE_VTYPE_POS_FLOAT | (vertType & (GE_VTYPE_IDX_MASK | GE_VTYPE_THROUGH)); +} diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 19ab1cc333f2..28cd21b15fdd 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -35,8 +35,8 @@ class DrawEngineCommon { virtual u32 NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, u32 vertType) = 0; bool GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices); - - static u32 NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, VertexDecoder *dec, int lowerBound, int upperBound, u32 vertType); + + static u32 NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, VertexDecoder *dec, int lowerBound, int upperBound, u32 vertType); protected: // Vertex collector buffers