From e4d12713ec9bea4c1f157c22b7e49b336e93c84a Mon Sep 17 00:00:00 2001 From: James Lambert Date: Fri, 18 Aug 2023 22:11:57 -0600 Subject: [PATCH] z sort portal gun --- assets/models/portal_gun/v_portalgun.flags | 2 +- skelatool64/main.cpp | 1 + skelatool64/src/CommandLineParser.cpp | 8 +- skelatool64/src/CommandLineParser.h | 1 + skelatool64/src/DisplayListSettings.h | 2 + skelatool64/src/ZSorter.cpp | 174 ++++++++++++++++++ skelatool64/src/ZSorter.h | 8 + .../MeshDefinitionGenerator.cpp | 7 +- 8 files changed, 199 insertions(+), 4 deletions(-) create mode 100644 skelatool64/src/ZSorter.cpp create mode 100644 skelatool64/src/ZSorter.h diff --git a/assets/models/portal_gun/v_portalgun.flags b/assets/models/portal_gun/v_portalgun.flags index 86bd123..5633e56 100644 --- a/assets/models/portal_gun/v_portalgun.flags +++ b/assets/models/portal_gun/v_portalgun.flags @@ -1 +1 @@ --m assets/materials/objects.skm.yaml \ No newline at end of file +-m assets/materials/objects.skm.yaml --sort-dir 0.029977,0.118112,0.030978 \ No newline at end of file diff --git a/skelatool64/main.cpp b/skelatool64/main.cpp index 1c3be03..42de8e3 100644 --- a/skelatool64/main.cpp +++ b/skelatool64/main.cpp @@ -111,6 +111,7 @@ int main(int argc, char *argv[]) { settings.mForcePallete = args.mForcePallete; settings.mTargetCIBuffer = args.mTargetCIBuffer; settings.mTicksPerSecond = args.mFPS; + settings.mSortDirection = args.mSortDirection; bool hasError = false; diff --git a/skelatool64/src/CommandLineParser.cpp b/skelatool64/src/CommandLineParser.cpp index 95667a0..8b05054 100644 --- a/skelatool64/src/CommandLineParser.cpp +++ b/skelatool64/src/CommandLineParser.cpp @@ -1,7 +1,7 @@ #include "CommandLineParser.h" -void parseEulerAngles(const std::string& input, aiVector3D& output) { +void parseVector3(const std::string& input, aiVector3D& output) { std::size_t firstComma = input.find(','); std::size_t secondComma = input.find(',', firstComma + 1); output.x = (float)atof(input.substr(0, firstComma).c_str()); @@ -53,7 +53,9 @@ bool parseCommandLineArguments(int argc, char *argv[], struct CommandLineArgumen } else if (lastParameter == "materials") { output.mMaterialFiles.push_back(curr); } else if (lastParameter == "rotate") { - parseEulerAngles(curr, output.mEulerAngles); + parseVector3(curr, output.mEulerAngles); + } else if (lastParameter == "sort-dir") { + parseVector3(curr, output.mSortDirection); } else if (lastParameter == "default-material") { output.mDefaultMaterial = curr; } else if (lastParameter == "force-material") { @@ -91,6 +93,8 @@ bool parseCommandLineArguments(int argc, char *argv[], struct CommandLineArgumen strcmp(curr, "-r") == 0 || strcmp(curr, "--rotate") == 0) { lastParameter = "rotate"; + } else if (strcmp(curr, "--sort-dir") == 0) { + lastParameter = "sort-dir"; } else if ( strcmp(curr, "--pallete") == 0) { lastParameter = "pallete"; diff --git a/skelatool64/src/CommandLineParser.h b/skelatool64/src/CommandLineParser.h index 0a31843..3ca8fc4 100644 --- a/skelatool64/src/CommandLineParser.h +++ b/skelatool64/src/CommandLineParser.h @@ -33,6 +33,7 @@ struct CommandLineArguments { bool mTargetCIBuffer; bool mProcessAsModel; aiVector3D mEulerAngles; + aiVector3D mSortDirection; }; bool parseCommandLineArguments(int argc, char *argv[], struct CommandLineArguments& output); diff --git a/skelatool64/src/DisplayListSettings.h b/skelatool64/src/DisplayListSettings.h index faf962c..c0f20eb 100644 --- a/skelatool64/src/DisplayListSettings.h +++ b/skelatool64/src/DisplayListSettings.h @@ -33,6 +33,8 @@ struct DisplayListSettings { bool mBonesAsVertexGroups; bool mTargetCIBuffer; + aiVector3D mSortDirection; + aiMatrix4x4 CreateGlobalTransform() const; aiMatrix4x4 CreateCollisionTransform() const; diff --git a/skelatool64/src/ZSorter.cpp b/skelatool64/src/ZSorter.cpp new file mode 100644 index 0000000..502a334 --- /dev/null +++ b/skelatool64/src/ZSorter.cpp @@ -0,0 +1,174 @@ +#include "ZSorter.h" + +struct SingleFace { + aiFace* face; + std::pair bonePair; + ExtendedMesh* mesh; + Material* material; + aiNode* meshRoot; + ai_real sortKey; +}; + +struct FaceIndices { + unsigned indices[3]; +}; + +struct EditableMesh { + std::vector sourceIndex; + std::vector faces; +}; + +void renderChunksFlush(EditableMesh& target, std::vector::iterator start, std::vector::iterator end, std::map& indexMapping) { + for (auto face = start; face != end; ++face) { + FaceIndices newFace; + + for (unsigned i = 0; i < 3 && i < face->face->mNumIndices; ++i) { + auto index = indexMapping.find(face->face->mIndices[i]); + + if (index == indexMapping.end()) { + newFace.indices[i] = 0; + } else { + newFace.indices[i] = index->second; + } + } + + target.faces.push_back(newFace); + } + + indexMapping.clear(); +} + +RenderChunk renderChunksRebuildFromFaces(std::vector::iterator start, std::vector::iterator end, unsigned chunkIndex, unsigned maxBufferSize, BoneHierarchy& boneHeirarchy) { + std::map indexMapping; + + EditableMesh mesh; + + std::vector::iterator lastFlushStart = start; + + ExtendedMesh* source = lastFlushStart->mesh; + + for (auto face = start; face != end; ++face) { + unsigned neededIndices = 0; + + for (unsigned i = 0; i < face->face->mNumIndices; ++i) { + if (indexMapping.find(face->face->mIndices[i]) == indexMapping.end()) { + ++neededIndices; + } + } + + if (neededIndices + indexMapping.size() > maxBufferSize) { + renderChunksFlush(mesh, lastFlushStart, face, indexMapping); + } + + for (unsigned i = 0; i < face->face->mNumIndices; ++i) { + if (indexMapping.find(face->face->mIndices[i]) != indexMapping.end()) { + continue; + } + + unsigned index = face->face->mIndices[i]; + unsigned newIndex = mesh.sourceIndex.size(); + indexMapping[index] = newIndex; + mesh.sourceIndex.push_back(index); + } + } + + renderChunksFlush(mesh, lastFlushStart, end, indexMapping); + + aiMesh* newAiMesh = new aiMesh(); + newAiMesh->mNumVertices = mesh.sourceIndex.size(); + + newAiMesh->mVertices = new aiVector3D[newAiMesh->mNumVertices]; + + if (source->mMesh->mNormals) { + newAiMesh->mNormals = new aiVector3D[newAiMesh->mNumVertices]; + } + + for (int i = 0; i < 8; ++i) { + if (source->mMesh->mTextureCoords[i]) { + newAiMesh->mTextureCoords[i] = new aiVector3D[newAiMesh->mNumVertices]; + } + if (source->mMesh->mColors[i]) { + newAiMesh->mColors[i] = new aiColor4D[newAiMesh->mNumVertices]; + } + } + + newAiMesh->mAABB = source->mMesh->mAABB; + newAiMesh->mName = source->mMesh->mName; + newAiMesh->mMaterialIndex = source->mMesh->mMaterialIndex; + + char indexAsString[10]; + sprintf(indexAsString, "_%d", chunkIndex); + newAiMesh->mName.Append(indexAsString); + + for (unsigned newIndex = 0; newIndex < newAiMesh->mNumVertices; ++newIndex) { + unsigned sourceIndex = mesh.sourceIndex[newIndex]; + newAiMesh->mVertices[newIndex] = source->mMesh->mVertices[sourceIndex]; + if (newAiMesh->mNormals) newAiMesh->mNormals[newIndex] = source->mMesh->mNormals[sourceIndex]; + + for (int i = 0; i < 8; ++i) { + if (newAiMesh->mTextureCoords[i]) newAiMesh->mTextureCoords[i][newIndex] = source->mMesh->mTextureCoords[i][sourceIndex]; + if (newAiMesh->mColors[i]) newAiMesh->mColors[i][newIndex] = source->mMesh->mColors[i][sourceIndex]; + } + } + + newAiMesh->mNumFaces = mesh.faces.size(); + newAiMesh->mFaces = new aiFace[newAiMesh->mNumFaces]; + + for (unsigned faceIndex = 0; faceIndex < newAiMesh->mNumFaces; ++faceIndex) { + newAiMesh->mFaces[faceIndex].mNumIndices = 3; + newAiMesh->mFaces[faceIndex].mIndices = new unsigned[3]; + std::copy(mesh.faces[faceIndex].indices, mesh.faces[faceIndex].indices + 3, newAiMesh->mFaces[faceIndex].mIndices); + } + + std::shared_ptr newMesh(new ExtendedMesh(newAiMesh, boneHeirarchy)); + + return RenderChunk(start->bonePair, newMesh, start->meshRoot, start->material); +} + +std::vector renderChunksSortByZ(const std::vector& source, const aiVector3D& direction, unsigned maxBufferSize, BoneHierarchy& boneHeirarchy) { + std::vector faces; + + for (auto chunk : source) { + for (auto face : chunk.GetFaces()) { + SingleFace singleFace; + + aiVector3D faceAverage; + + for (unsigned i = 0; i < face->mNumIndices; ++i) { + faceAverage = faceAverage + chunk.mMesh->mMesh->mVertices[face->mIndices[i]]; + } + + faceAverage = (1.0f / (ai_real)face->mNumIndices) * faceAverage; + + singleFace.face = face; + singleFace.mesh = chunk.mMesh.get(); + singleFace.material = chunk.mMaterial; + singleFace.meshRoot = chunk.mMeshRoot; + singleFace.sortKey = faceAverage * direction; + + faces.push_back(singleFace); + } + } + + std::sort(faces.begin(), faces.end(), [](const SingleFace& a, const SingleFace& b) { + return a.sortKey < b.sortKey; + }); + + std::vector result; + + auto lastStart = faces.begin(); + + int chunkIndex = 0; + + for (auto it = faces.begin(); it != faces.end(); ++it) { + if (lastStart->mesh != it->mesh || lastStart->material != it->material || lastStart->meshRoot != it->meshRoot) { + result.push_back(renderChunksRebuildFromFaces(lastStart, it, chunkIndex, maxBufferSize, boneHeirarchy)); + lastStart = it; + ++chunkIndex; + } + } + + result.push_back(renderChunksRebuildFromFaces(lastStart, faces.end(), chunkIndex, maxBufferSize, boneHeirarchy)); + + return result; +} \ No newline at end of file diff --git a/skelatool64/src/ZSorter.h b/skelatool64/src/ZSorter.h new file mode 100644 index 0000000..37467f5 --- /dev/null +++ b/skelatool64/src/ZSorter.h @@ -0,0 +1,8 @@ +#ifndef __ZSORTER_H__ +#define __ZSORTER_H__ + +#include "./RenderChunk.h" + +std::vector renderChunksSortByZ(const std::vector& source, const aiVector3D& direction, unsigned maxBufferSize, BoneHierarchy& boneHeirarchy); + +#endif \ No newline at end of file diff --git a/skelatool64/src/definition_generator/MeshDefinitionGenerator.cpp b/skelatool64/src/definition_generator/MeshDefinitionGenerator.cpp index baa80e1..3d35842 100644 --- a/skelatool64/src/definition_generator/MeshDefinitionGenerator.cpp +++ b/skelatool64/src/definition_generator/MeshDefinitionGenerator.cpp @@ -6,6 +6,7 @@ #include "../StringUtils.h" #include "MaterialGenerator.h" #include "../RenderChunkOrder.h" +#include "../ZSorter.h" bool extractMaterialAutoTileParameters(Material* material, double& sTile, double& tTile) { if (!material) { @@ -156,7 +157,11 @@ MeshDefinitionResults MeshDefinitionGenerator::GenerateDefinitionsWithResults(co AppendRenderChunks(scene, *node, fileDefinition, mSettings, renderChunks); } - orderRenderChunks(renderChunks, mSettings); + if (mSettings.mSortDirection.SquareLength() > 0.0) { + renderChunks = renderChunksSortByZ(renderChunks, mSettings.mSortDirection, mSettings.mVertexCacheSize, fileDefinition.GetBoneHierarchy()); + } else { + orderRenderChunks(renderChunks, mSettings); + } MeshDefinitionResults result;