Read Danglymesh header and AABB tree from MDL

This commit is contained in:
Vsevolod Kremianskii 2021-03-22 19:11:44 +07:00
parent 100f318c81
commit ac55ac6a8d
6 changed files with 150 additions and 42 deletions

View file

@ -175,6 +175,7 @@ set(RENDER_HEADERS
src/render/materials.h src/render/materials.h
src/render/mesh.h src/render/mesh.h
src/render/meshes.h src/render/meshes.h
src/render/model/aabbnode.h
src/render/model/animation.h src/render/model/animation.h
src/render/model/emitter.h src/render/model/emitter.h
src/render/model/mdlreader.h src/render/model/mdlreader.h
@ -215,6 +216,7 @@ set(RENDER_SOURCES
src/render/materials.cpp src/render/materials.cpp
src/render/mesh.cpp src/render/mesh.cpp
src/render/meshes.cpp src/render/meshes.cpp
src/render/model/aabbnode.cpp
src/render/model/animation.cpp src/render/model/animation.cpp
src/render/model/mdlreader.cpp src/render/model/mdlreader.cpp
src/render/model/model.cpp src/render/model/model.cpp

View file

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2020-2021 The reone project contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <memory>
#include "../aabb.h"
namespace reone {
namespace render {
struct AABBNode {
enum class Plane {
None = 0,
PositiveX = 1,
PositiveY = 2,
PositiveZ = 4
};
int faceIndex { 0 };
Plane mostSignificantPlane { Plane::None };
AABB aabb;
std::shared_ptr<AABBNode> leftChild;
std::shared_ptr<AABBNode> rightChild;
};
} // namespace render
} // namespace reone

View file

@ -30,9 +30,10 @@
#include "../../resource/gameidutil.h" #include "../../resource/gameidutil.h"
#include "../../resource/resources.h" #include "../../resource/resources.h"
#include "../model/models.h"
#include "../textures.h" #include "../textures.h"
#include "models.h"
using namespace std; using namespace std;
using namespace reone::resource; using namespace reone::resource;
@ -591,9 +592,6 @@ unique_ptr<ModelNode> MdlReader::readNode(uint32_t offset, ModelNode *parent) {
if (header.flags & NodeFlags::skin) { if (header.flags & NodeFlags::skin) {
node->_skin = make_shared<ModelNode::Skin>(); node->_skin = make_shared<ModelNode::Skin>();
} }
if (header.flags & NodeFlags::aabb) {
node->_aabb = true;
}
if (header.flags & NodeFlags::saber) { if (header.flags & NodeFlags::saber) {
node->_saber = true; node->_saber = true;
} }
@ -610,15 +608,18 @@ unique_ptr<ModelNode> MdlReader::readNode(uint32_t offset, ModelNode *parent) {
if (header.flags & NodeFlags::reference) { if (header.flags & NodeFlags::reference) {
readReference(*node); readReference(*node);
} }
// Mesh will be loaded by either readMesh here, or readSaber // Mesh will be loaded by either readMesh here, or readSaber below
if ((header.flags & NodeFlags::mesh) && !(header.flags & NodeFlags::saber)) { if ((header.flags & NodeFlags::mesh) && !(header.flags & NodeFlags::saber)) {
readMesh(*node); readMesh(*node);
} }
if (header.flags & NodeFlags::skin) { if (header.flags & NodeFlags::skin) {
readSkin(*node); readSkin(*node);
} }
if (header.flags & NodeFlags::dangly) {
readDanglymesh(*node);
}
if (header.flags & NodeFlags::aabb) { if (header.flags & NodeFlags::aabb) {
// TODO: read AABB tree readAABB(*node);
} }
if (header.flags & NodeFlags::saber) { if (header.flags & NodeFlags::saber) {
readSaber(*node); readSaber(*node);
@ -777,6 +778,38 @@ void MdlReader::readMesh(ModelNode &node) {
loadMesh(header, header.numVertices, move(vertices), move(indices), move(offsets), node); loadMesh(header, header.numVertices, move(vertices), move(indices), move(offsets), node);
} }
void MdlReader::loadMesh(const MeshHeader &header, int numVertices, vector<float> &&vertices, vector<uint16_t> &&indices, Mesh::VertexOffsets &&offsets, ModelNode &node) {
auto mesh = make_unique<Mesh>(numVertices, vertices, indices, offsets);
mesh->computeAABB();
node._mesh = make_unique<ModelMesh>(move(mesh));
node._mesh->setRender(static_cast<bool>(header.render));
node._mesh->setTransparency(static_cast<int>(header.transparencyHint));
node._mesh->setShadow(static_cast<bool>(header.shadow));
node._mesh->setBackgroundGeometry(static_cast<bool>(header.backgroundGeometry) != 0);
node._mesh->setDiffuseColor(glm::make_vec3(header.diffuse));
node._mesh->setAmbientColor(glm::make_vec3(header.ambient));
string tex1ResRef(getStringLower(header.texture1, 32));
string tex2ResRef(getStringLower(header.texture2, 32));
string tex3ResRef(getStringLower(header.texture3, 12));
string tex4ResRef(getStringLower(header.texture4, 12));
if (!tex1ResRef.empty() && tex1ResRef != "null") {
node._mesh->_diffuse = Textures::instance().get(tex1ResRef, TextureUsage::Diffuse);
}
if (!tex2ResRef.empty()) {
node._mesh->_lightmap = Textures::instance().get(tex2ResRef, TextureUsage::Lightmap);
}
if (header.animateUV) {
node._mesh->_uvAnimation.animated = true;
node._mesh->_uvAnimation.directionX = header.uvDirectionX;
node._mesh->_uvAnimation.directionY = header.uvDirectionY;
node._mesh->_uvAnimation.jitter = header.uvJitter;
node._mesh->_uvAnimation.jitterSpeed = header.uvJitterSpeed;
}
}
void MdlReader::readSkin(ModelNode &node) { void MdlReader::readSkin(ModelNode &node) {
SkinHeader header(readStruct<SkinHeader>()); SkinHeader header(readStruct<SkinHeader>());
@ -871,36 +904,37 @@ void MdlReader::readSaber(ModelNode &node) {
loadMesh(meshHeader, numVertices, move(vertices), move(indices), move(offsets), node); loadMesh(meshHeader, numVertices, move(vertices), move(indices), move(offsets), node);
} }
void MdlReader::loadMesh(const MeshHeader &header, int numVertices, vector<float> &&vertices, vector<uint16_t> &&indices, Mesh::VertexOffsets &&offsets, ModelNode &node) { void MdlReader::readDanglymesh(ModelNode &node) {
auto mesh = make_unique<Mesh>(numVertices, vertices, indices, offsets); DanglymeshHeader header(readStruct<DanglymeshHeader>());
mesh->computeAABB(); // TODO: fill ModelNode
}
node._mesh = make_unique<ModelMesh>(move(mesh)); void MdlReader::readAABB(ModelNode &node) {
node._mesh->setRender(static_cast<bool>(header.render)); uint32_t offTree = readUint32();
node._mesh->setTransparency(static_cast<int>(header.transparencyHint)); size_t pos = tell();
node._mesh->setShadow(static_cast<bool>(header.shadow));
node._mesh->setBackgroundGeometry(static_cast<bool>(header.backgroundGeometry) != 0);
node._mesh->setDiffuseColor(glm::make_vec3(header.diffuse));
node._mesh->setAmbientColor(glm::make_vec3(header.ambient));
string tex1ResRef(getStringLower(header.texture1, 32)); node._aabb = readAABBNode(offTree);
string tex2ResRef(getStringLower(header.texture2, 32));
string tex3ResRef(getStringLower(header.texture3, 12));
string tex4ResRef(getStringLower(header.texture4, 12));
if (!tex1ResRef.empty() && tex1ResRef != "null") { seek(pos);
node._mesh->_diffuse = Textures::instance().get(tex1ResRef, TextureUsage::Diffuse); }
}
if (!tex2ResRef.empty()) { shared_ptr<AABBNode> MdlReader::readAABBNode(uint32_t offset) {
node._mesh->_lightmap = Textures::instance().get(tex2ResRef, TextureUsage::Lightmap); auto node = make_shared<AABBNode>();
}
if (header.animateUV) { seek(kMdlDataOffset + offset);
node._mesh->_uvAnimation.animated = true; AABBNodeHeader header(readStruct<AABBNodeHeader>());
node._mesh->_uvAnimation.directionX = header.uvDirectionX;
node._mesh->_uvAnimation.directionY = header.uvDirectionY; node->faceIndex = header.faceIndex;
node._mesh->_uvAnimation.jitter = header.uvJitter; node->mostSignificantPlane = static_cast<AABBNode::Plane>(header.mostSignificantPlane);
node._mesh->_uvAnimation.jitterSpeed = header.uvJitterSpeed; node->aabb.expand(glm::make_vec3(header.bbMin));
node->aabb.expand(glm::make_vec3(header.bbMax));
if (header.faceIndex == -1) {
node->leftChild = readAABBNode(header.offChildLeft);
node->rightChild = readAABBNode(header.offChildRight);
} }
return move(node);
} }
vector<shared_ptr<Animation>> MdlReader::readAnimations(const vector<uint32_t> &offsets) { vector<shared_ptr<Animation>> MdlReader::readAnimations(const vector<uint32_t> &offsets) {
@ -940,12 +974,15 @@ unique_ptr<Animation> MdlReader::readAnimation(uint32_t offset) {
shared_ptr<Model> MdlModelLoader::loadModel(GameID gameId, const string &resRef) { shared_ptr<Model> MdlModelLoader::loadModel(GameID gameId, const string &resRef) {
shared_ptr<ByteArray> mdlData(Resources::instance().get(resRef, ResourceType::Mdl)); shared_ptr<ByteArray> mdlData(Resources::instance().get(resRef, ResourceType::Mdl));
shared_ptr<ByteArray> mdxData(Resources::instance().get(resRef, ResourceType::Mdx)); shared_ptr<ByteArray> mdxData(Resources::instance().get(resRef, ResourceType::Mdx));
shared_ptr<Model> model;
if (mdlData && mdxData) { if (mdlData && mdxData) {
MdlReader mdl(gameId); MdlReader mdl(gameId);
mdl.load(wrap(mdlData), wrap(mdxData)); mdl.load(wrap(mdlData), wrap(mdxData));
return mdl.model(); model = mdl.model();
} }
return nullptr;
return move(model);
} }
} // namespace render } // namespace render

View file

@ -20,8 +20,9 @@
#include "../../resource/format/binreader.h" #include "../../resource/format/binreader.h"
#include "../../resource/types.h" #include "../../resource/types.h"
#include "../model/model.h" #include "aabbnode.h"
#include "../model/modelloader.h" #include "model.h"
#include "modelloader.h"
namespace reone { namespace reone {
@ -211,6 +212,23 @@ private:
uint8_t unknown[72]; // QBones, TBones, etc. uint8_t unknown[72]; // QBones, TBones, etc.
}; };
struct DanglymeshHeader {
ArrayHeader constraints;
float displacement { 0.0f };
float tightness { 0.0f };
float period { 0.0f };
uint32_t unknown1 { 0 };
};
struct AABBNodeHeader {
float bbMin[3];
float bbMax[3];
uint32_t offChildLeft { 0 };
uint32_t offChildRight { 0 };
int faceIndex { 0 };
uint32_t mostSignificantPlane { 0 };
};
struct SaberHeader { struct SaberHeader {
uint32_t offVertices { 0 }; uint32_t offVertices { 0 };
uint32_t offTexCoords { 0 }; uint32_t offTexCoords { 0 };
@ -243,8 +261,12 @@ private:
void readReference(render::ModelNode &node); void readReference(render::ModelNode &node);
void readMesh(render::ModelNode &node); void readMesh(render::ModelNode &node);
void readSkin(render::ModelNode &node); void readSkin(render::ModelNode &node);
void readDanglymesh(render::ModelNode &node);
void readAABB(render::ModelNode &node);
void readSaber(render::ModelNode &node); void readSaber(render::ModelNode &node);
void loadMesh(const MeshHeader &header, int numVertices, std::vector<float> &&vertices, std::vector<uint16_t> &&indices, Mesh::VertexOffsets &&offsets, render::ModelNode &node); void loadMesh(const MeshHeader &header, int numVertices, std::vector<float> &&vertices, std::vector<uint16_t> &&indices, Mesh::VertexOffsets &&offsets, render::ModelNode &node);
std::shared_ptr<AABBNode> readAABBNode(uint32_t offset);
}; };
class MdlModelLoader : public IModelLoader { class MdlModelLoader : public IModelLoader {

View file

@ -24,6 +24,7 @@
#include "glm/gtx/quaternion.hpp" #include "glm/gtx/quaternion.hpp"
#include "aabbnode.h"
#include "emitter.h" #include "emitter.h"
#include "modelmesh.h" #include "modelmesh.h"
@ -110,7 +111,7 @@ public:
void addAlphaKeyframe(Keyframe keyframe); void addAlphaKeyframe(Keyframe keyframe);
void addSelfIllumColorKeyframe(Keyframe keyframe); void addSelfIllumColorKeyframe(Keyframe keyframe);
bool isAABB() const { return _aabb; } bool isAABB() const { return static_cast<bool>(_aabb); }
bool isSaber() const { return _saber; } bool isSaber() const { return _saber; }
bool getTranslation(float time, glm::vec3 &translation, float scale = 1.0f) const; bool getTranslation(float time, glm::vec3 &translation, float scale = 1.0f) const;
@ -151,10 +152,11 @@ public:
// Components // Components
std::shared_ptr<Light> light() const { return _light; } std::shared_ptr<Light> light() const { return _light; }
std::shared_ptr<ModelMesh> mesh() const { return _mesh; }
std::shared_ptr<Skin> skin() const { return _skin; }
std::shared_ptr<Emitter> emitter() const { return _emitter; } std::shared_ptr<Emitter> emitter() const { return _emitter; }
std::shared_ptr<Reference> reference() const { return _reference; } std::shared_ptr<Reference> reference() const { return _reference; }
std::shared_ptr<ModelMesh> mesh() const { return _mesh; }
std::shared_ptr<Skin> skin() const { return _skin; }
std::shared_ptr<AABBNode> aabb() const { return _aabb; }
// END Components // END Components
@ -167,7 +169,6 @@ private:
glm::vec3 _color { 0.0f }; glm::vec3 _color { 0.0f };
glm::vec3 _selfIllumColor { 0.0f }; glm::vec3 _selfIllumColor { 0.0f };
float _alpha { 1.0f }; float _alpha { 1.0f };
bool _aabb { false };
bool _saber { false }; bool _saber { false };
std::vector<std::shared_ptr<ModelNode>> _children; std::vector<std::shared_ptr<ModelNode>> _children;
@ -184,11 +185,12 @@ private:
// Components // Components
std::shared_ptr<ModelMesh> _mesh;
std::shared_ptr<Skin> _skin;
std::shared_ptr<Light> _light; std::shared_ptr<Light> _light;
std::shared_ptr<Emitter> _emitter; std::shared_ptr<Emitter> _emitter;
std::shared_ptr<Reference> _reference; std::shared_ptr<Reference> _reference;
std::shared_ptr<ModelMesh> _mesh;
std::shared_ptr<Skin> _skin;
std::shared_ptr<AABBNode> _aabb;
// END Components // END Components