From eb3e3b8b08f8989c22cce7bef433142d7a14c263 Mon Sep 17 00:00:00 2001 From: ragnarok-clanker Date: Tue, 27 Oct 2026 16:31:29 +0000 Subject: [PATCH] Decompile 11 functions in Source/Contents/Models/ModelLighting.cpp, Source/Contents/Models/ModelNode.cpp, ... Batch #1082 by ragnarok-clanker: 0 byte-identical, 11 confirmed by peer review. - fn_02007 ModelMesh::ModelMesh: logic confirmed by peer review - fn_02009 ModelMesh::~ModelMesh: logic confirmed by peer review - fn_02011 ModelMesh::CalculateNormals: logic confirmed by peer review - fn_07958 C3dAnimModelRes::Load: logic confirmed by peer review - fn_07997 AnimatedModelRecord::~AnimatedModelRecord: logic confirmed by peer review - fn_08023 C3dAnimModelRes::Unload: logic confirmed by peer review - fn_17482 C3dNodeV1::Initialize: logic confirmed by peer review - fn_17484 C3dNodeV2::Initialize: logic confirmed by peer review - fn_17514 C3dNode::AccumulateBounds: logic confirmed by peer review - fn_17515 C3dNode::SampleGroundColors: logic confirmed by peer review - fn_17521 C3dNode::Prepare: logic confirmed by peer review Reviewed-by: ragnarok-clanker --- Source/Contents/Models/ModelLighting.cpp | 12 ++-- Source/Contents/Models/ModelNode.cpp | 8 +-- Source/Contents/Models/ModelNode.h | 51 +++++++------ Source/Contents/Models/ModelNodeBounds.cpp | 3 +- Source/Contents/Models/ModelRendering.cpp | 10 +-- .../Resource/Models/AnimatedModelResource.cpp | 72 +++++++++++++------ .../Resource/Models/AnimatedModelResource.h | 62 +++++++++++----- Source/Resource/Models/ModelMesh.cpp | 49 +++++++++---- Source/Resource/Models/ModelMesh.h | 51 +++++++++---- Source/Resource/Models/ModelResource.cpp | 37 ++++++---- Source/Resource/Models/ModelResourceV2.cpp | 24 +++---- 11 files changed, 248 insertions(+), 131 deletions(-) diff --git a/Source/Contents/Models/ModelLighting.cpp b/Source/Contents/Models/ModelLighting.cpp index 0629c62..c2c2f25 100644 --- a/Source/Contents/Models/ModelLighting.cpp +++ b/Source/Contents/Models/ModelLighting.cpp @@ -78,7 +78,7 @@ void C3dNode::OverrideColors() { // OFFSET: 0x00ABB450 // FUNCTION: fn_17515 void C3dNode::SampleGroundColors(const float* matrix, const float* position, const GroundGeometry& ground) { - for (unsigned index = 0; index < this->mesh->faces.size(); ++index) { + for (int index = 0; index < this->mesh->faceCount; ++index) { const ModelFace& face = this->mesh->faces[index]; for (unsigned corner = 0; corner < 3; ++corner) { @@ -107,7 +107,7 @@ void C3dNode::Prepare(const float* matrix, ModelLightingContext& context) { AffineMatrix combined; combined.Compose(this->transform, parentMatrix); - for (unsigned index = 0; index < this->mesh->faces.size(); ++index) { + for (int index = 0; index < this->mesh->faceCount; ++index) { const ModelFace& face = this->mesh->faces[index]; float light[3]; @@ -131,9 +131,9 @@ void C3dNode::Prepare(const float* matrix, ModelLightingContext& context) { } } - unsigned index = 0; + int index = 0; - while (index < this->mesh->faces.size()) { + while (index < this->mesh->faceCount) { const unsigned texture = this->mesh->faces[index].texture; CTexture* image = this->textures[texture % this->textures.size()]; @@ -149,7 +149,7 @@ void C3dNode::Prepare(const float* matrix, ModelLightingContext& context) { } for (unsigned corner = 0; corner < 3; ++corner) { - if (this->mesh->textureVertices.empty()) { + if (this->mesh->textureVertexCount == 0) { state.uv[corner][0] = u; state.uv[corner][1] = v; } else { @@ -160,7 +160,7 @@ void C3dNode::Prepare(const float* matrix, ModelLightingContext& context) { } ++index; - } while (index < this->mesh->faces.size() && this->mesh->faces[index].texture == texture); + } while (index < this->mesh->faceCount && this->mesh->faces[index].texture == texture); } this->SampleGroundColors(combined.values, context.position, context.ground); diff --git a/Source/Contents/Models/ModelNode.cpp b/Source/Contents/Models/ModelNode.cpp index 77c572d..d353505 100644 --- a/Source/Contents/Models/ModelNode.cpp +++ b/Source/Contents/Models/ModelNode.cpp @@ -75,8 +75,8 @@ void C3dNodeV1::Initialize(const ModelNode& base) { child->Initialize(*resourceChild); } - this->faceState.resize(this->mesh->faces.size()); - this->faceValues.resize(this->mesh->faces.size() * 9u); + this->faceState.resize(this->mesh->faceCount); + this->faceValues.resize(this->mesh->faceCount * 9u); } // OFFSET: 0x00AB73F0 @@ -113,8 +113,8 @@ void C3dNodeV2::Initialize(const ModelNode& base) { this->alpha = static_cast(resource.alpha) * 0.00390625f; this->textures.insert(this->textures.end(), resource.textures.begin(), resource.textures.end()); this->alpha = static_cast(resource.alpha) / 255.0f; - this->faceState.resize(this->mesh->faces.size()); - this->faceValues.resize(this->mesh->faces.size() * 9u); + this->faceState.resize(this->mesh->faceCount); + this->faceValues.resize(this->mesh->faceCount * 9u); } // OFFSET: 0x00AB9120 diff --git a/Source/Contents/Models/ModelNode.h b/Source/Contents/Models/ModelNode.h index 08c7070..1abaaf3 100644 --- a/Source/Contents/Models/ModelNode.h +++ b/Source/Contents/Models/ModelNode.h @@ -9,7 +9,7 @@ class C3dActor; struct ModelTextureTransform { - float values[5] = {0, 0, 1, 1, 0}; + /* 0000 */ float values[5] = {0, 0, 1, 1, 0}; }; void SampleModelTexture(const ModelTextureChannels& channels, float frame, ModelTextureTransform& output); @@ -30,17 +30,17 @@ public: void SampleGroundColors(const float* matrix, const float* position, const class GroundGeometry& ground); void AccumulateBounds(float* bounds, const float* matrix); - std::string name; - C3dActor* model; - C3dNode* parent; - std::list children; - ModelMesh* mesh; - AffineMatrix transform; - std::vector textures; - float alpha; - std::vector faceState; - std::vector faceValues; - unsigned char unknown_0088; + /* 0004 */ std::string name; + /* 001C */ C3dActor* model; + /* 0020 */ C3dNode* parent; + /* 0024 */ std::list children; + /* 002C */ ModelMesh* mesh; + /* 0030 */ AffineMatrix transform; + /* 0060 */ std::vector textures; + /* 006C */ float alpha; + /* 0070 */ std::vector faceState; + /* 007C */ std::vector faceValues; + /* 0088 */ unsigned char unknown_0088; }; class C3dNodeV1 : public C3dNode { @@ -51,9 +51,9 @@ public: void Animate(double frame) override; void Draw(const float* matrix, unsigned char reversed, bool clip, unsigned char commandMode, ModelRenderContext& context) override; - std::vector scaleKeys; - std::vector rotationKeys; - std::vector positionKeys; + /* 008C */ std::vector scaleKeys; + /* 0098 */ std::vector rotationKeys; + /* 00A4 */ std::vector positionKeys; }; class C3dNodeV2 : public C3dNode { @@ -64,19 +64,26 @@ public: void Animate(double frame) override; void Draw(const float* matrix, unsigned char reversed, bool clip, unsigned char commandMode, ModelRenderContext& context) override; - AffineMatrix resourceTransform; - AffineMatrix localTransform; - std::vector scaleKeys; - std::vector rotationKeys; - std::vector positionKeys; - std::map textureKeys; - std::map textureTransforms; + /* 008C */ AffineMatrix resourceTransform; + /* 00BC */ AffineMatrix localTransform; + /* 00EC */ std::vector scaleKeys; + /* 00F8 */ std::vector rotationKeys; + /* 0104 */ std::vector positionKeys; + /* 0110 */ std::map textureKeys; + /* 0118 */ std::map textureTransforms; }; #if defined(_WIN32) && !defined(_WIN64) static_assert(sizeof(C3dNode) == 140); static_assert(sizeof(C3dNodeV1) == 176); static_assert(sizeof(C3dNodeV2) == 288); +static_assert(sizeof(ModelTextureTransform) == 20); +static_assert(offsetof(C3dNode, mesh) == 0x2C); +static_assert(offsetof(C3dNode, transform) == 0x30); +static_assert(offsetof(C3dNode, faceState) == 0x70); +static_assert(offsetof(C3dNodeV1, scaleKeys) == 0x8C); +static_assert(offsetof(C3dNodeV2, resourceTransform) == 0x8C); +static_assert(offsetof(C3dNodeV2, textureTransforms) == 0x118); #endif #endif diff --git a/Source/Contents/Models/ModelNodeBounds.cpp b/Source/Contents/Models/ModelNodeBounds.cpp index 84007f0..935cc60 100644 --- a/Source/Contents/Models/ModelNodeBounds.cpp +++ b/Source/Contents/Models/ModelNodeBounds.cpp @@ -10,7 +10,8 @@ void C3dNode::AccumulateBounds(float* bounds, const float* matrix) { AffineMatrix combined; combined.Compose(this->transform, parentMatrix); - for (const auto& vertex : this->mesh->vertices) { + for (int index = 0; index < this->mesh->vertexCount; ++index) { + const auto& vertex = this->mesh->vertices[index]; const float x = ((vertex[0] * combined.values[0] + vertex[1] * combined.values[3]) + vertex[2] * combined.values[6]) + combined.values[9]; const float y = ((vertex[1] * combined.values[4] + vertex[0] * combined.values[1]) + vertex[2] * combined.values[7]) + combined.values[10]; const float z = ((vertex[0] * combined.values[2] + vertex[1] * combined.values[5]) + vertex[2] * combined.values[8]) + combined.values[11]; diff --git a/Source/Contents/Models/ModelRendering.cpp b/Source/Contents/Models/ModelRendering.cpp index b27d854..1799c32 100644 --- a/Source/Contents/Models/ModelRendering.cpp +++ b/Source/Contents/Models/ModelRendering.cpp @@ -107,14 +107,14 @@ void DrawModelNode(C3dNode& node, const float* matrix, unsigned char reversed, b const unsigned char alpha = node.model->alpha; auto& projected = modern ? context.modernProjected : context.legacyProjected; - for (unsigned index = 0; index < node.mesh->vertices.size(); ++index) { + for (int index = 0; index < node.mesh->vertexCount; ++index) { context.projection.Project(node.mesh->vertices[index].data(), combined.values, projected[index]); } - RenderVertex* output = context.vertices.Acquire(static_cast(node.mesh->faces.size()) * 3u); - unsigned index = 0; + RenderVertex* output = context.vertices.Acquire(static_cast(node.mesh->faceCount) * 3u); + int index = 0; - while (index < node.mesh->faces.size()) { + while (index < node.mesh->faceCount) { const unsigned texture = node.mesh->faces[index].texture; RenderVertex* first = output; @@ -174,7 +174,7 @@ void DrawModelNode(C3dNode& node, const float* matrix, unsigned char reversed, b } ++index; - } while (index < node.mesh->faces.size() && node.mesh->faces[index].texture == texture); + } while (index < node.mesh->faceCount && node.mesh->faces[index].texture == texture); if (output != first) { RenderCommand* command = context.commands.Acquire(); diff --git a/Source/Resource/Models/AnimatedModelResource.cpp b/Source/Resource/Models/AnimatedModelResource.cpp index 73b0b1d..ae1274c 100644 --- a/Source/Resource/Models/AnimatedModelResource.cpp +++ b/Source/Resource/Models/AnimatedModelResource.cpp @@ -5,27 +5,47 @@ #include "Resource/Bitmap/BitmapResource.h" #include "Resource/ResourceByteReader.h" +// INLINED +AnimatedModelFrame::AnimatedModelFrame() : vertices(nullptr), textureVertices(nullptr) { +} + +// OFFSET: 0x00756680 +// FUNCTION: fn_07994 +AnimatedModelFrame::~AnimatedModelFrame() { + delete[] this->vertices; + delete[] this->textureVertices; +} + // INLINED AnimatedModelNode::AnimatedModelNode(TextureCache& textures) - : model(nullptr), parent(nullptr), unknown_0040(0), vertexCount(0), textureVertexCount(0), faceCount(0), sharedTextureVertices(0), m_textures(textures) { + : model(nullptr), parent(nullptr), vertexCount(0), faceCount(0), faceNormals(nullptr), frames(nullptr), faces(nullptr), textures(nullptr), + m_textures(textures) { } // INLINED AnimatedModelNode::~AnimatedModelNode() { - for (CTexture* texture : this->textures) { - texture->Release(); - this->m_textures.Remove(texture); + delete[] this->frames; + delete[] this->faces; + delete[] this->faceNormals; + + if (this->textures) { + for (int index = 0; index < this->textureCount; ++index) { + this->textures[index]->Release(); + this->m_textures.Remove(this->textures[index]); + } + + delete[] this->textures; } } // OFFSET: 0x007550E0 // FUNCTION: fn_07979 C3dAnimModelRes::C3dAnimModelRes(ModelResourceContext& context) - : unknown_0110(0), unknown_0114(0), shade(2), frameCount(0), animationLength(0), speed(1.0f), unknown_0150(0), unknown_0154(0.0f), unknown_0158(0.0f), + : unknown_0110(0), unknown_0114(nullptr), shade(2), frameCount(0), animationLength(0), speed(1.0f), unknown_0150(0), unknown_0154(0.0f), unknown_0158(0.0f), unknown_015C(0.0f), alpha(255), m_context(&context) { } -// OFFSET: 0x00753510 +// OFFSET: 0x00756480 // FUNCTION: fn_07993 C3dAnimModelRes::~C3dAnimModelRes() { this->Unload(); @@ -41,6 +61,12 @@ C3dAnimModelRes* C3dAnimModelRes::Create() { // OFFSET: 0x0075C710 // FUNCTION: fn_08023 void C3dAnimModelRes::Unload() { + if (this->unknown_0114) { + delete[] this->unknown_0114; + this->unknown_0114 = nullptr; + this->unknown_0110 = 0; + } + for (AnimatedModelNode* node : this->nodes) { delete node; } @@ -99,7 +125,7 @@ bool C3dAnimModelRes::Load(const char* name) { for (int index = 0; index < nodeCount; ++index) { auto node = std::make_unique(this->m_context->textures); node->model = this; - node->frames.resize(static_cast(this->frameCount)); + node->frames = new AnimatedModelFrame[this->frameCount]; std::uint32_t marker; input.Read(&marker, 4); @@ -113,41 +139,43 @@ bool C3dAnimModelRes::Load(const char* name) { node->name = field; input.Read(field, sizeof(field)); node->parentName = field; - int count; - input.Read(&count, 4); + input.Read(&node->textureCount, 4); + node->textures = new CTexture*[node->textureCount]; - for (int texture = 0; texture < count; ++texture) { + for (int texture = 0; texture < node->textureCount; ++texture) { int id; input.Read(&id, 4); CTexture* value = this->m_context->textures.Load(names[id].c_str(), 0, false, true, false); value->Retain(); - node->textures.push_back(value); + node->textures[texture] = value; } input.Read(&node->vertexCount, 4); - for (AnimatedModelFrame& frame : node->frames) { - frame.vertices.resize(static_cast(node->vertexCount)); - input.Read(frame.vertices.data(), static_cast(node->vertexCount) * 12u); + for (int frameIndex = 0; frameIndex < this->frameCount; ++frameIndex) { + AnimatedModelFrame& frame = node->frames[frameIndex]; + frame.vertices = new std::array[node->vertexCount]{}; + input.Read(frame.vertices, static_cast(node->vertexCount) * 12u); } input.Read(&node->textureVertexCount, 4); input.Read(&node->sharedTextureVertices, 4); if (node->sharedTextureVertices) { - node->frames[0].textureVertices.resize(static_cast(node->textureVertexCount)); - input.Read(node->frames[0].textureVertices.data(), static_cast(node->textureVertexCount) * 12u); + node->frames[0].textureVertices = new ModelTextureVertex[node->textureVertexCount]; + input.Read(node->frames[0].textureVertices, static_cast(node->textureVertexCount) * 12u); } else { - for (AnimatedModelFrame& frame : node->frames) { - frame.textureVertices.resize(static_cast(node->textureVertexCount)); - input.Read(frame.textureVertices.data(), static_cast(node->textureVertexCount) * 12u); + for (int frameIndex = 0; frameIndex < this->frameCount; ++frameIndex) { + AnimatedModelFrame& frame = node->frames[frameIndex]; + frame.textureVertices = new ModelTextureVertex[node->textureVertexCount]; + input.Read(frame.textureVertices, static_cast(node->textureVertexCount) * 12u); } } input.Read(&node->faceCount, 4); - node->faceNormals.resize(static_cast(node->faceCount)); - node->faces.resize(static_cast(node->faceCount)); - input.Read(node->faces.data(), static_cast(node->faceCount) * 24u); + node->faceNormals = new std::array[node->faceCount]; + node->faces = new AnimatedModelFace[node->faceCount]; + input.Read(node->faces, static_cast(node->faceCount) * 24u); this->nodes.push_back(node.release()); input.Read(&marker, 4); diff --git a/Source/Resource/Models/AnimatedModelResource.h b/Source/Resource/Models/AnimatedModelResource.h index 1b04df8..8106c32 100644 --- a/Source/Resource/Models/AnimatedModelResource.h +++ b/Source/Resource/Models/AnimatedModelResource.h @@ -4,12 +4,24 @@ #include "Resource/Models/ModelResource.h" struct AnimatedModelFace { - std::uint32_t values[6]; + /* 0000 */ std::uint32_t values[6]; }; struct AnimatedModelFrame { - std::vector> vertices; - std::vector textureVertices; + AnimatedModelFrame(); + ~AnimatedModelFrame(); + AnimatedModelFrame(const AnimatedModelFrame&) = delete; + AnimatedModelFrame& operator=(const AnimatedModelFrame&) = delete; + + /* 0000 */ std::array* vertices; + /* 0004 */ ModelTextureVertex* textureVertices; +}; + +struct AnimatedModelRecord { + ~AnimatedModelRecord(); + + /* 0000 */ unsigned char unknown_0000[0x84]; + /* 0084 */ std::string* unknown_0084; }; class C3dAnimModelRes; @@ -20,20 +32,20 @@ struct AnimatedModelNode { AnimatedModelNode(const AnimatedModelNode&) = delete; AnimatedModelNode& operator=(const AnimatedModelNode&) = delete; - std::string name; - std::string parentName; - C3dAnimModelRes* model; - AnimatedModelNode* parent; - std::list children; - std::uint32_t unknown_0040; - int vertexCount; - int textureVertexCount; - int faceCount; - std::vector faces; - std::vector> faceNormals; - std::vector frames; - std::vector textures; - int sharedTextureVertices; + /* 0000 */ std::string name; + /* 0018 */ std::string parentName; + /* 0030 */ C3dAnimModelRes* model; + /* 0034 */ AnimatedModelNode* parent; + /* 0038 */ std::list children; + /* 0040 */ int vertexCount; + /* 0044 */ int textureVertexCount; + /* 0048 */ int faceCount; + /* 004C */ int textureCount; + /* 0050 */ std::array* faceNormals; + /* 0054 */ AnimatedModelFrame* frames; + /* 0058 */ AnimatedModelFace* faces; + /* 005C */ CTexture** textures; + /* 0060 */ int sharedTextureVertices; private: TextureCache& m_textures; @@ -47,8 +59,8 @@ public: bool Load(const char* name) override; void Unload() override; - /* 0110 */ std::uint32_t unknown_0110; - /* 0114 */ std::uint32_t unknown_0114; + /* 0110 */ int unknown_0110; + /* 0114 */ AnimatedModelRecord* unknown_0114; /* 0118 */ std::list nodes; /* 0120 */ std::list rootNames; /* 0128 */ std::string sourceName; @@ -68,4 +80,16 @@ private: static_assert(sizeof(AnimatedModelFace) == 24); +#if defined(_WIN32) && !defined(_WIN64) +static_assert(sizeof(AnimatedModelFrame) == 8); +static_assert(offsetof(AnimatedModelFrame, textureVertices) == 0x04); +static_assert(offsetof(AnimatedModelNode, vertexCount) == 0x40); +static_assert(offsetof(AnimatedModelNode, textureCount) == 0x4C); +static_assert(offsetof(AnimatedModelNode, faceNormals) == 0x50); +static_assert(offsetof(AnimatedModelNode, frames) == 0x54); +static_assert(offsetof(AnimatedModelNode, faces) == 0x58); +static_assert(offsetof(AnimatedModelNode, textures) == 0x5C); +static_assert(offsetof(AnimatedModelNode, sharedTextureVertices) == 0x60); +#endif + #endif diff --git a/Source/Resource/Models/ModelMesh.cpp b/Source/Resource/Models/ModelMesh.cpp index 61351f0..b1604aa 100644 --- a/Source/Resource/Models/ModelMesh.cpp +++ b/Source/Resource/Models/ModelMesh.cpp @@ -20,14 +20,39 @@ namespace { // FUNCTION: fn_07988 ModelFace::ModelFace() = default; +// OFFSET: 0x00551BA0 +// FUNCTION: fn_02007 +ModelMesh::ModelMesh() + : vertexCount(0), vertices(nullptr), faceCount(0), faces(nullptr), textureVertexCount(0), textureVertices(nullptr), faceNormals(nullptr), + vertexNormals(nullptr) { +} + +// OFFSET: 0x00551E80 +// FUNCTION: fn_02009 +ModelMesh::~ModelMesh() { + delete[] this->vertices; + this->vertices = nullptr; + this->vertexCount = 0; + delete[] this->faces; + this->faces = nullptr; + this->faceCount = 0; + delete[] this->textureVertices; + this->textureVertices = nullptr; + this->textureVertexCount = 0; + delete[] this->faceNormals; + this->faceNormals = nullptr; + delete[] this->vertexNormals; + this->vertexNormals = nullptr; +} + // OFFSET: 0x00551FD0 // FUNCTION: fn_02011 void ModelMesh::CalculateNormals() { - if (this->faceNormals.empty()) { - this->faceNormals.resize(this->faces.size()); + if (!this->faceNormals) { + this->faceNormals = new std::array[this->faceCount]{}; } - for (unsigned index = 0; index < this->faces.size(); ++index) { + for (int index = 0; index < this->faceCount; ++index) { const ModelFace& face = this->faces[index]; const auto& first = this->vertices[face.vertices[0]]; const auto& second = this->vertices[face.vertices[1]]; @@ -46,25 +71,25 @@ void ModelMesh::CalculateNormals() { Normalize(normal.data()); } - std::map> adjacent; + std::map> adjacent; - for (unsigned face = 0; face < this->faces.size(); ++face) { - for (unsigned corner = 0; corner < 3; ++corner) { + for (int face = 0; face < this->faceCount; ++face) { + for (int corner = 0; corner < 3; ++corner) { adjacent[this->faces[face].vertices[corner]].push_back(face); } } - if (this->vertexNormals.empty()) { - this->vertexNormals.resize(this->faces.size() * 3); + if (!this->vertexNormals) { + this->vertexNormals = new std::array[this->faceCount * 3]{}; } - for (unsigned index = 0; index < this->faces.size(); ++index) { + for (int index = 0; index < this->faceCount; ++index) { const ModelFace& face = this->faces[index]; - for (unsigned corner = 0; corner < 3; ++corner) { + for (int corner = 0; corner < 3; ++corner) { auto& normal = this->vertexNormals[index * 3 + corner]; - for (unsigned neighbor : adjacent[face.vertices[corner]]) { + for (int neighbor : adjacent[face.vertices[corner]]) { const ModelFace& other = this->faces[neighbor]; for (std::uint32_t group : face.smoothing) { @@ -87,7 +112,7 @@ void ModelMesh::CalculateNormals() { } } - for (unsigned index = 0; index < this->faces.size() * 3; ++index) { + for (int index = 0; index < this->faceCount * 3; ++index) { Normalize(this->vertexNormals[index].data()); } } diff --git a/Source/Resource/Models/ModelMesh.h b/Source/Resource/Models/ModelMesh.h index 4929584..a35d206 100644 --- a/Source/Resource/Models/ModelMesh.h +++ b/Source/Resource/Models/ModelMesh.h @@ -2,18 +2,19 @@ #define RAGNAROK_SOURCE_RESOURCE_MODELS_MODELMESH_H #include +#include #include #include struct ModelFace { ModelFace(); - std::uint16_t vertices[3]; - std::uint16_t textureVertices[3]; - std::uint16_t texture; - std::uint16_t unknown_000E; - std::uint32_t twoSided; - std::vector smoothing; + /* 0000 */ std::uint16_t vertices[3]; + /* 0006 */ std::uint16_t textureVertices[3]; + /* 000C */ std::uint16_t texture; + /* 000E */ std::uint16_t unknown_000E; + /* 0010 */ std::uint32_t twoSided; + /* 0014 */ std::vector smoothing; }; struct ModelTextureVertex { @@ -25,18 +26,44 @@ struct ModelTextureVertex { static_assert(sizeof(ModelTextureVertex) == 12); struct ModelMesh { - std::vector> vertices; - std::vector textureVertices; - std::vector faces; - std::vector> faceNormals; - std::vector> vertexNormals; - std::array, 32> indices; + ModelMesh(); + ~ModelMesh(); + ModelMesh(const ModelMesh&) = delete; + ModelMesh& operator=(const ModelMesh&) = delete; + + /* 0000 */ int vertexCount; + /* 0004 */ std::array* vertices; + /* 0008 */ int faceCount; + /* 000C */ ModelFace* faces; + /* 0010 */ int textureVertexCount; + /* 0014 */ ModelTextureVertex* textureVertices; + /* 0018 */ std::array* faceNormals; + /* 001C */ std::array* vertexNormals; + /* 0020 */ unsigned char unknown_0020[4]; + /* 0024 */ std::array, 32> indices; + /* 01A4 */ unsigned char unknown_01A4[48]; void CalculateNormals(); }; #if defined(_WIN32) && !defined(_WIN64) static_assert(sizeof(ModelFace) == 32); +static_assert(offsetof(ModelFace, vertices) == 0x00); +static_assert(offsetof(ModelFace, textureVertices) == 0x06); +static_assert(offsetof(ModelFace, texture) == 0x0C); +static_assert(offsetof(ModelFace, unknown_000E) == 0x0E); +static_assert(offsetof(ModelFace, twoSided) == 0x10); +static_assert(offsetof(ModelFace, smoothing) == 0x14); +static_assert(sizeof(ModelMesh) == 0x1D4); +static_assert(offsetof(ModelMesh, vertices) == 0x04); +static_assert(offsetof(ModelMesh, faceCount) == 0x08); +static_assert(offsetof(ModelMesh, faces) == 0x0C); +static_assert(offsetof(ModelMesh, textureVertexCount) == 0x10); +static_assert(offsetof(ModelMesh, textureVertices) == 0x14); +static_assert(offsetof(ModelMesh, faceNormals) == 0x18); +static_assert(offsetof(ModelMesh, vertexNormals) == 0x1C); +static_assert(offsetof(ModelMesh, indices) == 0x24); +static_assert(offsetof(ModelMesh, unknown_01A4) == 0x1A4); #endif #endif diff --git a/Source/Resource/Models/ModelResource.cpp b/Source/Resource/Models/ModelResource.cpp index a0a9d77..1199ebf 100644 --- a/Source/Resource/Models/ModelResource.cpp +++ b/Source/Resource/Models/ModelResource.cpp @@ -2,12 +2,19 @@ #include "Render/Textures/Texture.h" #include "Render/Textures/TextureCache.h" #include "Resource/Bitmap/BitmapResource.h" +#include "Resource/Models/AnimatedModelResource.h" #include "Resource/Models/ModelResource.h" #include "Resource/ResourceByteReader.h" #include #include +// OFFSET: 0x00756D60 +// FUNCTION: fn_07997 +AnimatedModelRecord::~AnimatedModelRecord() { + delete[] this->unknown_0084; +} + // OFFSET: 0x00755630 // FUNCTION: fn_07985 ModelNode::ModelNode() : model(nullptr), parent(nullptr), alpha(255) { @@ -126,12 +133,12 @@ inline void C3dModelResV1::ReadNode(ResourceByteReader& input, unsigned minor, c input.Read(node->scale, sizeof(node->scale)); node->mesh = std::make_unique(); ModelMesh& mesh = *node->mesh; - int vertexCount = 0; - input.Read(&vertexCount, 4); - mesh.vertices.resize(static_cast(vertexCount)); - input.Read(mesh.vertices.data(), static_cast(vertexCount) * 12u); + input.Read(&mesh.vertexCount, 4); + mesh.vertices = new std::array[mesh.vertexCount]{}; + input.Read(mesh.vertices, static_cast(mesh.vertexCount) * 12u); - for (auto& vertex : mesh.vertices) { + for (int index = 0; index < mesh.vertexCount; ++index) { + auto& vertex = mesh.vertices[index]; const float y = ((vertex[0] * matrix[1] + vertex[1] * matrix[4]) + matrix[7] * vertex[2]) + matrix[10]; const float z = ((vertex[0] * matrix[2] + vertex[1] * matrix[5]) + matrix[8] * vertex[2]) + matrix[11]; vertex[0] = ((vertex[0] * matrix[0] + vertex[1] * matrix[3]) + vertex[2] * matrix[6]) + matrix[9]; @@ -139,27 +146,27 @@ inline void C3dModelResV1::ReadNode(ResourceByteReader& input, unsigned minor, c vertex[2] = z; } - int textureVertexCount = 0; - input.Read(&textureVertexCount, 4); - mesh.textureVertices.resize(static_cast(textureVertexCount)); + input.Read(&mesh.textureVertexCount, 4); + mesh.textureVertices = new ModelTextureVertex[mesh.textureVertexCount]; if (minor == 1) { float uv[2]; - for (auto& vertex : mesh.textureVertices) { + for (int index = 0; index < mesh.textureVertexCount; ++index) { + auto& vertex = mesh.textureVertices[index]; input.Read(uv, sizeof(uv)); vertex = {0xFFFFFFFFu, uv[0], uv[1]}; } } else { - input.Read(mesh.textureVertices.data(), static_cast(textureVertexCount) * 12u); + input.Read(mesh.textureVertices, static_cast(mesh.textureVertexCount) * 12u); } - std::uint32_t faceCount = 0; - input.Read(&faceCount, 4); - mesh.faces.resize(faceCount); + input.Read(&mesh.faceCount, 4); + mesh.faces = new ModelFace[mesh.faceCount]; unsigned char record[24]; - for (ModelFace& face : mesh.faces) { + for (int index = 0; index < mesh.faceCount; ++index) { + ModelFace& face = mesh.faces[index]; input.Read(record, minor == 1 ? 20 : 24); std::memcpy(face.vertices, record, sizeof(face.vertices)); std::memcpy(face.textureVertices, record + 6, sizeof(face.textureVertices)); @@ -175,7 +182,7 @@ inline void C3dModelResV1::ReadNode(ResourceByteReader& input, unsigned minor, c } // INLINED - std::sort(mesh.faces.begin(), mesh.faces.end(), [](const ModelFace& a, const ModelFace& b) { return a.texture < b.texture; }); + std::sort(mesh.faces, mesh.faces + mesh.faceCount, [](const ModelFace& a, const ModelFace& b) { return a.texture < b.texture; }); mesh.CalculateNormals(); int rotationCount; input.Read(&rotationCount, 4); diff --git a/Source/Resource/Models/ModelResourceV2.cpp b/Source/Resource/Models/ModelResourceV2.cpp index 0d06794..bbb28ee 100644 --- a/Source/Resource/Models/ModelResourceV2.cpp +++ b/Source/Resource/Models/ModelResourceV2.cpp @@ -121,19 +121,17 @@ inline void C3dModelResV2::ReadNode(ResourceByteReader& input, unsigned minor, c input.Read(node->transform, sizeof(node->transform)); ModelMesh& mesh = *node->mesh; - unsigned vertexCount = 0; - input.Read(&vertexCount, 4); - mesh.vertices.resize(vertexCount); - input.Read(mesh.vertices.data(), vertexCount * 12u); - unsigned textureVertexCount = 0; - input.Read(&textureVertexCount, 4); - mesh.textureVertices.resize(textureVertexCount); - input.Read(mesh.textureVertices.data(), textureVertexCount * 12u); - int faceCount = 0; - input.Read(&faceCount, 4); - mesh.faces.resize(static_cast(faceCount)); + input.Read(&mesh.vertexCount, 4); + mesh.vertices = new std::array[mesh.vertexCount]{}; + input.Read(mesh.vertices, static_cast(mesh.vertexCount) * 12u); + input.Read(&mesh.textureVertexCount, 4); + mesh.textureVertices = new ModelTextureVertex[mesh.textureVertexCount]; + input.Read(mesh.textureVertices, static_cast(mesh.textureVertexCount) * 12u); + input.Read(&mesh.faceCount, 4); + mesh.faces = new ModelFace[mesh.faceCount]; - for (ModelFace& face : mesh.faces) { + for (int index = 0; index < mesh.faceCount; ++index) { + ModelFace& face = mesh.faces[index]; std::vector bytes; unsigned char fixed[24]; const unsigned char* record; @@ -161,7 +159,7 @@ inline void C3dModelResV2::ReadNode(ResourceByteReader& input, unsigned minor, c } // INLINED - std::sort(mesh.faces.begin(), mesh.faces.end(), [](const ModelFace& a, const ModelFace& b) { return a.texture < b.texture; }); + std::sort(mesh.faces, mesh.faces + mesh.faceCount, [](const ModelFace& a, const ModelFace& b) { return a.texture < b.texture; }); mesh.CalculateNormals(); ReadKeys(input, node->scaleKeys, false); ReadKeys(input, node->rotationKeys, true);