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/mesh.h
src/render/meshes.h
src/render/model/aabbnode.h
src/render/model/animation.h
src/render/model/emitter.h
src/render/model/mdlreader.h
@ -215,6 +216,7 @@ set(RENDER_SOURCES
src/render/materials.cpp
src/render/mesh.cpp
src/render/meshes.cpp
src/render/model/aabbnode.cpp
src/render/model/animation.cpp
src/render/model/mdlreader.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/resources.h"
#include "../model/models.h"
#include "../textures.h"
#include "models.h"
using namespace std;
using namespace reone::resource;
@ -591,9 +592,6 @@ unique_ptr<ModelNode> MdlReader::readNode(uint32_t offset, ModelNode *parent) {
if (header.flags & NodeFlags::skin) {
node->_skin = make_shared<ModelNode::Skin>();
}
if (header.flags & NodeFlags::aabb) {
node->_aabb = true;
}
if (header.flags & NodeFlags::saber) {
node->_saber = true;
}
@ -610,15 +608,18 @@ unique_ptr<ModelNode> MdlReader::readNode(uint32_t offset, ModelNode *parent) {
if (header.flags & NodeFlags::reference) {
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)) {
readMesh(*node);
}
if (header.flags & NodeFlags::skin) {
readSkin(*node);
}
if (header.flags & NodeFlags::dangly) {
readDanglymesh(*node);
}
if (header.flags & NodeFlags::aabb) {
// TODO: read AABB tree
readAABB(*node);
}
if (header.flags & NodeFlags::saber) {
readSaber(*node);
@ -777,6 +778,38 @@ void MdlReader::readMesh(ModelNode &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) {
SkinHeader header(readStruct<SkinHeader>());
@ -871,36 +904,37 @@ void MdlReader::readSaber(ModelNode &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) {
auto mesh = make_unique<Mesh>(numVertices, vertices, indices, offsets);
mesh->computeAABB();
void MdlReader::readDanglymesh(ModelNode &node) {
DanglymeshHeader header(readStruct<DanglymeshHeader>());
// TODO: fill ModelNode
}
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));
void MdlReader::readAABB(ModelNode &node) {
uint32_t offTree = readUint32();
size_t pos = tell();
string tex1ResRef(getStringLower(header.texture1, 32));
string tex2ResRef(getStringLower(header.texture2, 32));
string tex3ResRef(getStringLower(header.texture3, 12));
string tex4ResRef(getStringLower(header.texture4, 12));
node._aabb = readAABBNode(offTree);
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;
seek(pos);
}
shared_ptr<AABBNode> MdlReader::readAABBNode(uint32_t offset) {
auto node = make_shared<AABBNode>();
seek(kMdlDataOffset + offset);
AABBNodeHeader header(readStruct<AABBNodeHeader>());
node->faceIndex = header.faceIndex;
node->mostSignificantPlane = static_cast<AABBNode::Plane>(header.mostSignificantPlane);
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) {
@ -940,12 +974,15 @@ unique_ptr<Animation> MdlReader::readAnimation(uint32_t offset) {
shared_ptr<Model> MdlModelLoader::loadModel(GameID gameId, const string &resRef) {
shared_ptr<ByteArray> mdlData(Resources::instance().get(resRef, ResourceType::Mdl));
shared_ptr<ByteArray> mdxData(Resources::instance().get(resRef, ResourceType::Mdx));
shared_ptr<Model> model;
if (mdlData && mdxData) {
MdlReader mdl(gameId);
mdl.load(wrap(mdlData), wrap(mdxData));
return mdl.model();
model = mdl.model();
}
return nullptr;
return move(model);
}
} // namespace render

View file

@ -20,8 +20,9 @@
#include "../../resource/format/binreader.h"
#include "../../resource/types.h"
#include "../model/model.h"
#include "../model/modelloader.h"
#include "aabbnode.h"
#include "model.h"
#include "modelloader.h"
namespace reone {
@ -211,6 +212,23 @@ private:
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 {
uint32_t offVertices { 0 };
uint32_t offTexCoords { 0 };
@ -243,8 +261,12 @@ private:
void readReference(render::ModelNode &node);
void readMesh(render::ModelNode &node);
void readSkin(render::ModelNode &node);
void readDanglymesh(render::ModelNode &node);
void readAABB(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);
std::shared_ptr<AABBNode> readAABBNode(uint32_t offset);
};
class MdlModelLoader : public IModelLoader {

View file

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