From b90c1d9f4acd91f8a0f32f5f37c45f881eff6a62 Mon Sep 17 00:00:00 2001 From: Vsevolod Kremianskii Date: Sun, 7 Feb 2021 20:45:10 +0700 Subject: [PATCH] refactor: Move TOR support code into a separate library --- CMakeLists.txt | 21 ++- src/game/object/creaturemodelbuilder.cpp | 18 +- src/render/mesh/aabb.cpp | 6 +- src/render/mesh/billboard.cpp | 6 +- src/render/mesh/cube.cpp | 6 +- src/render/mesh/mesh.h | 5 +- src/render/mesh/modelmesh.cpp | 38 +++- src/render/mesh/modelmesh.h | 20 ++- src/render/mesh/quad.cpp | 6 +- src/render/model/mdlfile.cpp | 47 +++-- src/render/model/model.cpp | 13 +- src/render/model/model.h | 6 +- src/render/model/modelnode.cpp | 6 +- src/render/model/modelnode.h | 35 ++-- src/render/models.cpp | 28 +-- src/render/models.h | 8 +- src/render/shaders.cpp | 4 +- src/render/shaders.h | 2 +- src/scene/node/modelnodescenenode.cpp | 2 +- src/scene/node/modelscenenode.cpp | 4 +- src/{render/model => tor}/gr2file.cpp | 214 +++-------------------- src/{render/model => tor}/gr2file.h | 27 +-- src/{render/model => tor}/jbafile.cpp | 185 ++++++++------------ src/{render/model => tor}/jbafile.h | 35 ++-- 24 files changed, 261 insertions(+), 481 deletions(-) rename src/{render/model => tor}/gr2file.cpp (63%) rename src/{render/model => tor}/gr2file.h (80%) rename src/{render/model => tor}/jbafile.cpp (58%) rename src/{render/model => tor}/jbafile.h (70%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0787ddc2..b1d97f76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,8 +163,6 @@ set(RENDER_HEADERS src/render/mesh/mesh.h src/render/mesh/modelmesh.h src/render/model/animation.h - src/render/model/gr2file.h - src/render/model/jbafile.h src/render/model/mdlfile.h src/render/model/model.h src/render/model/modelnode.h @@ -200,8 +198,6 @@ set(RENDER_SOURCES src/render/mesh/mesh.cpp src/render/mesh/modelmesh.cpp src/render/model/animation.cpp - src/render/model/gr2file.cpp - src/render/model/jbafile.cpp src/render/model/mdlfile.cpp src/render/model/model.cpp src/render/model/modelnode.cpp @@ -221,6 +217,21 @@ set_target_properties(librender PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINA ## END librender static library +## libtor static library + +set(TOR_HEADERS + src/tor/gr2file.h + src/tor/jbafile.h) + +set(TOR_SOURCES + src/tor/gr2file.cpp + src/tor/jbafile.cpp) + +add_library(libtor STATIC ${TOR_HEADERS} ${TOR_SOURCES}) +set_target_properties(libtor PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + +## END libtor static library + ## libaudio static library set(AUDIO_HEADERS @@ -665,7 +676,7 @@ add_executable(reone ${REONE_HEADERS} ${REONE_SOURCES}) set_target_properties(reone PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) target_link_libraries(reone PRIVATE - libmp libnet libgame libscript libgui libscene libvideo librender libaudio libresource libcommon + libmp libnet libgame libscript libgui libscene libvideo libaudio libtor librender libresource libcommon libs3tc ${Boost_FILESYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_SYSTEM_LIBRARY} GLEW::GLEW diff --git a/src/game/object/creaturemodelbuilder.cpp b/src/game/object/creaturemodelbuilder.cpp index 914a9758..8d056c79 100644 --- a/src/game/object/creaturemodelbuilder.cpp +++ b/src/game/object/creaturemodelbuilder.cpp @@ -23,8 +23,6 @@ #include #include "../../common/streamutil.h" -#include "../../render/model/gr2file.h" -#include "../../render/model/jbafile.h" #include "../../render/models.h" #include "../../render/textures.h" #include "../../resource/resources.h" @@ -42,11 +40,6 @@ namespace reone { namespace game { -// This is a hook to replace vanilla models with SWTOR models -static const unordered_map g_modelOverrides { - // { "p_bastilabb", "bfn_satele_a02" } -}; - static const string g_headHookNode("headhook"); static const string g_maskHookNode("gogglehook"); @@ -60,21 +53,12 @@ shared_ptr CreatureModelBuilder::build() { string modelName(getBodyModelName()); if (modelName.empty()) return nullptr; - bool gr2Model = false; - auto maybeOverride = g_modelOverrides.find(modelName); - if (maybeOverride != g_modelOverrides.end()) { - modelName = maybeOverride->second; - gr2Model = true; - } - - shared_ptr model(Models::instance().get(modelName, gr2Model)); + shared_ptr model(Models::instance().get(modelName)); if (!model) return nullptr; auto modelSceneNode = make_unique(&_creature->sceneGraph(), model); modelSceneNode->setLightingEnabled(true); - if (gr2Model) return move(modelSceneNode); - // Body texture string bodyTextureName(getBodyTextureName()); diff --git a/src/render/mesh/aabb.cpp b/src/render/mesh/aabb.cpp index 80cb8124..3bdeeb1e 100644 --- a/src/render/mesh/aabb.cpp +++ b/src/render/mesh/aabb.cpp @@ -56,11 +56,7 @@ AABBMesh &AABBMesh::instance() { return mesh; } -AABBMesh::AABBMesh() { - _vertexCount = 8; - _vertices = g_vertices; - _indices = g_indices; - _offsets = g_offsets; +AABBMesh::AABBMesh() : Mesh(8, move(g_vertices), move(g_indices), move(g_offsets)) { } void AABBMesh::render(const AABB &aabb, const glm::mat4 &transform) const { diff --git a/src/render/mesh/billboard.cpp b/src/render/mesh/billboard.cpp index 804c46e6..c4eaefaa 100644 --- a/src/render/mesh/billboard.cpp +++ b/src/render/mesh/billboard.cpp @@ -41,11 +41,7 @@ BillboardMesh &BillboardMesh::instance() { return mesh; } -BillboardMesh::BillboardMesh() { - _vertexCount = 4; - _vertices = move(g_vertices); - _indices = move(g_indices); - _offsets = move(g_offsets); +BillboardMesh::BillboardMesh() : Mesh(4, move(g_vertices), move(g_indices), move(g_offsets)) { } } // namespace render diff --git a/src/render/mesh/cube.cpp b/src/render/mesh/cube.cpp index 4268bb31..db643ca7 100644 --- a/src/render/mesh/cube.cpp +++ b/src/render/mesh/cube.cpp @@ -54,11 +54,7 @@ CubeMesh &CubeMesh::instance() { return mesh; } -CubeMesh::CubeMesh() { - _vertexCount = 8; - _vertices = move(g_vertices); - _indices = move(g_indices); - _offsets = move(g_offsets); +CubeMesh::CubeMesh() : Mesh(8, move(g_vertices), move(g_indices), move(g_offsets)) { } void CubeMesh::render(const glm::mat4 &transform) const { diff --git a/src/render/mesh/mesh.h b/src/render/mesh/mesh.h index a331b0ba..8ac430ae 100644 --- a/src/render/mesh/mesh.h +++ b/src/render/mesh/mesh.h @@ -53,6 +53,8 @@ public: void initGL(); void deinitGL(); + void computeAABB(); + void renderLines() const; void renderTriangles() const; @@ -67,9 +69,6 @@ protected: uint32_t _indexBufferId { 0 }; uint32_t _vertexArrayId { 0 }; - Mesh() = default; - - void computeAABB(); void render(uint32_t mode, int count, int offset) const; private: diff --git a/src/render/mesh/modelmesh.cpp b/src/render/mesh/modelmesh.cpp index 9be3bc9b..1b7d9de3 100644 --- a/src/render/mesh/modelmesh.cpp +++ b/src/render/mesh/modelmesh.cpp @@ -17,6 +17,8 @@ #include "modelmesh.h" +#include + #include "GL/glew.h" #include "SDL2/SDL_opengl.h" @@ -29,10 +31,23 @@ namespace reone { namespace render { -ModelMesh::ModelMesh(bool render, int transparency, bool shadow) : +ModelMesh::ModelMesh(const shared_ptr &mesh, bool render, int transparency, bool shadow) : + _mesh(mesh), _render(render), _transparency(transparency), _shadow(shadow) { + + if (!mesh) { + throw invalid_argument("mesh must not be null"); + } +} + +void ModelMesh::initGL() { + _mesh->initGL(); +} + +void ModelMesh::deinitGL() { + _mesh->deinitGL(); } void ModelMesh::render(const shared_ptr &diffuseOverride) const { @@ -62,9 +77,9 @@ void ModelMesh::render(const shared_ptr &diffuseOverride) const { } if (additive) { - withAdditiveBlending([this]() { Mesh::renderTriangles(); }); + withAdditiveBlending([this]() { _mesh->renderTriangles(); }); } else { - Mesh::renderTriangles(); + _mesh->renderTriangles(); } } @@ -82,6 +97,23 @@ bool ModelMesh::isTransparent() const { return true; } +void ModelMesh::setDiffuseTexture(const shared_ptr &texture) { + _diffuse = texture; +} + +void ModelMesh::setBumpmapTexture(const shared_ptr &texture, bool swizzled) { + _bumpmap = texture; + _bumpmapSwizzled = swizzled; +} + +void ModelMesh::setDiffuseColor(glm::vec3 color) { + _diffuseColor = move(color); +} + +void ModelMesh::setAmbientColor(glm::vec3 color) { + _ambientColor = move(color); +} + } // namespace render } // namespace reone diff --git a/src/render/mesh/modelmesh.h b/src/render/mesh/modelmesh.h index af08f092..c908dab5 100644 --- a/src/render/mesh/modelmesh.h +++ b/src/render/mesh/modelmesh.h @@ -27,7 +27,6 @@ namespace reone { namespace render { -class Gr2File; class MdlFile; /** @@ -36,7 +35,7 @@ class MdlFile; * @see reone::render::ModelNode * @see reone::render::Texture */ -class ModelMesh : public Mesh { +class ModelMesh { public: struct UVAnimation { bool animated { false }; @@ -46,7 +45,10 @@ public: float jitterSpeed { 0.0f }; }; - ModelMesh(bool render, int transparency, bool shadow); + ModelMesh(const std::shared_ptr &mesh, bool render, int transparency, bool shadow); + + void initGL(); + void deinitGL(); void render(const std::shared_ptr &diffuseOverride = nullptr) const; @@ -55,7 +57,7 @@ public: bool isTransparent() const; bool isBackgroundGeometry() const { return _backgroundGeometry; } - bool isBumpmapFromTOR() const { return _bumpmapFromTOR; } + bool isBumpmapSwizzled() const { return _bumpmapSwizzled; } bool hasDiffuseTexture() const { return static_cast(_diffuse); } bool hasEnvmapTexture() const { return static_cast(_envmap); } @@ -63,6 +65,7 @@ public: bool hasBumpyShinyTexture() const { return static_cast(_bumpyShiny); } bool hasBumpmapTexture() const { return static_cast(_bumpmap); } + std::shared_ptr mesh() const { return _mesh; } int transparency() const { return _transparency; } const glm::vec3 &diffuseColor() const { return _diffuseColor; } const glm::vec3 &ambientColor() const { return _ambientColor; } @@ -71,7 +74,13 @@ public: const std::shared_ptr &diffuseTexture() const { return _diffuse; } const std::shared_ptr &bumpmapTexture() const { return _bumpmap; } + void setDiffuseTexture(const std::shared_ptr &texture); + void setBumpmapTexture(const std::shared_ptr &texture, bool swizzled = false); + void setDiffuseColor(glm::vec3 color); + void setAmbientColor(glm::vec3 color); + private: + std::shared_ptr _mesh; bool _render; int _transparency; bool _shadow; @@ -80,7 +89,7 @@ private: glm::vec3 _diffuseColor { 1.0f }; glm::vec3 _ambientColor { 0.0f }; UVAnimation _uvAnimation; - bool _bumpmapFromTOR { false }; /**< SWTOR normal maps require special handling by the shader */ + bool _bumpmapSwizzled { false }; // Textures @@ -93,7 +102,6 @@ private: // END Textures friend class MdlFile; - friend class Gr2File; }; } // namespace render diff --git a/src/render/mesh/quad.cpp b/src/render/mesh/quad.cpp index 2dd2cee7..1695de51 100644 --- a/src/render/mesh/quad.cpp +++ b/src/render/mesh/quad.cpp @@ -76,11 +76,7 @@ Quad &Quad::getXYFlipped() { return quad; } -Quad::Quad(vector &&vertices) { - _vertexCount = 4; - _vertices = move(vertices); - _indices = g_indices; - _offsets = g_offsets; +Quad::Quad(vector &&vertices) : Mesh(4, move(vertices), g_indices, g_offsets) { } } // namespace render diff --git a/src/render/model/mdlfile.cpp b/src/render/model/mdlfile.cpp index 9c09864d..83801552 100644 --- a/src/render/model/mdlfile.cpp +++ b/src/render/model/mdlfile.cpp @@ -148,8 +148,7 @@ void MdlFile::doLoad() { superModel = Models::instance().get(superModelName); } - _model = make_unique(_name, move(rootNode), anims, superModel); - _model->setClassification(getClassification(classification)); + _model = make_unique(_name, getClassification(classification), move(rootNode), anims, superModel); _model->setAnimationScale(scale); } @@ -793,43 +792,41 @@ unique_ptr MdlFile::readMesh(const string &nodeName, int nodeFlags) { seek(endPos); - auto mesh = make_unique(render, transparency, shadow); - mesh->_vertexCount = vertexCount; - mesh->_vertices = move(vertices); - mesh->_offsets = move(offsets); - mesh->_indices = move(indices); - mesh->_backgroundGeometry = backgroundGeometry != 0; - mesh->_diffuseColor = glm::make_vec3(&diffuseColor[0]); - mesh->_ambientColor = glm::make_vec3(&ambientColor[0]); + auto mesh = make_unique(vertexCount, move(vertices), move(indices), move(offsets)); mesh->computeAABB(); + auto modelMesh = make_unique(move(mesh), render, transparency, shadow); + modelMesh->_backgroundGeometry = backgroundGeometry != 0; + modelMesh->_diffuseColor = glm::make_vec3(&diffuseColor[0]); + modelMesh->_ambientColor = glm::make_vec3(&ambientColor[0]); + if (!diffuse.empty() && diffuse != "null") { - mesh->_diffuse = Textures::instance().get(diffuse, TextureType::Diffuse); - if (mesh->_diffuse) { - const TextureFeatures &features = mesh->_diffuse->features(); + modelMesh->_diffuse = Textures::instance().get(diffuse, TextureType::Diffuse); + if (modelMesh->_diffuse) { + const TextureFeatures &features = modelMesh->_diffuse->features(); if (!features.envMapTexture.empty()) { - mesh->_envmap = Textures::instance().get(features.envMapTexture, TextureType::EnvironmentMap); + modelMesh->_envmap = Textures::instance().get(features.envMapTexture, TextureType::EnvironmentMap); } if (!features.bumpyShinyTexture.empty()) { - mesh->_bumpyShiny = Textures::instance().get(features.bumpyShinyTexture, TextureType::EnvironmentMap); + modelMesh->_bumpyShiny = Textures::instance().get(features.bumpyShinyTexture, TextureType::EnvironmentMap); } if (!features.bumpMapTexture.empty()) { - mesh->_bumpmap = Textures::instance().get(features.bumpMapTexture, TextureType::Bumpmap); + modelMesh->_bumpmap = Textures::instance().get(features.bumpMapTexture, TextureType::Bumpmap); } } } if (!lightmap.empty()) { - mesh->_lightmap = Textures::instance().get(lightmap, TextureType::Lightmap); + modelMesh->_lightmap = Textures::instance().get(lightmap, TextureType::Lightmap); } if (animateUv) { - mesh->_uvAnimation.animated = true; - mesh->_uvAnimation.directionX = uvDirectionX; - mesh->_uvAnimation.directionY = uvDirectionY; - mesh->_uvAnimation.jitter = uvJitter; - mesh->_uvAnimation.jitterSpeed = uvJitterSpeed; + modelMesh->_uvAnimation.animated = true; + modelMesh->_uvAnimation.directionX = uvDirectionX; + modelMesh->_uvAnimation.directionY = uvDirectionY; + modelMesh->_uvAnimation.jitter = uvJitter; + modelMesh->_uvAnimation.jitterSpeed = uvJitterSpeed; } - return move(mesh); + return move(modelMesh); } void MdlFile::readSkin(ModelNode &node) { @@ -840,8 +837,8 @@ void MdlFile::readSkin(ModelNode &node) { uint32_t bonesOffset = readUint32(); uint32_t boneCount = readUint32(); - node._mesh->_offsets.boneWeights = boneWeightsOffset; - node._mesh->_offsets.boneIndices = boneIndicesOffset; + node._mesh->_mesh->_offsets.boneWeights = boneWeightsOffset; + node._mesh->_mesh->_offsets.boneIndices = boneIndicesOffset; unordered_map nodeIdxByBoneIdx; seek(kMdlDataOffset + bonesOffset); diff --git a/src/render/model/model.cpp b/src/render/model/model.cpp index 67280691..3a519009 100644 --- a/src/render/model/model.cpp +++ b/src/render/model/model.cpp @@ -17,6 +17,8 @@ #include "model.h" +#include + #include "../../common/log.h" using namespace std; @@ -27,14 +29,19 @@ namespace render { Model::Model( const string &name, + Classification classification, const shared_ptr &rootNode, vector> &anims, const shared_ptr &superModel ) : _name(name), + _classification(classification), _rootNode(rootNode), _superModel(superModel) { + if (!rootNode) { + throw invalid_argument("rootNode must not be null"); + } for (auto &anim : anims) { _animations.insert(make_pair(anim->name(), move(anim))); } @@ -49,7 +56,7 @@ void Model::init(const shared_ptr &node) { shared_ptr mesh(node->mesh()); if (mesh) { - _aabb.expand(mesh->aabb() * node->absoluteTransform()); + _aabb.expand(mesh->mesh()->aabb() * node->absoluteTransform()); } for (auto &child : node->children()) { @@ -100,10 +107,6 @@ shared_ptr Model::findNodeByName(const string &name) const { return it != _nodeByName.end() ? it->second : nullptr; } -void Model::setClassification(Classification classification) { - _classification = classification; -} - void Model::setAnimationScale(float scale) { _animationScale = scale; } diff --git a/src/render/model/model.h b/src/render/model/model.h index 9896564f..b4deaceb 100644 --- a/src/render/model/model.h +++ b/src/render/model/model.h @@ -51,6 +51,7 @@ public: Model( const std::string &name, + Classification classification, const std::shared_ptr &rootNode, std::vector> &anims, const std::shared_ptr &superModel = nullptr); @@ -69,15 +70,15 @@ public: std::shared_ptr superModel() const { return _superModel; } const AABB &aabb() const { return _aabb; } - void setClassification(Classification classification); void setAnimationScale(float scale); private: - Classification _classification { Classification::Other }; std::string _name; + Classification _classification; std::shared_ptr _rootNode; std::unordered_map> _animations; std::shared_ptr _superModel; + std::unordered_map> _nodeByNumber; std::unordered_map> _nodeByName; AABB _aabb; @@ -90,7 +91,6 @@ private: void init(const std::shared_ptr &node); friend class MdlFile; - friend class Gr2File; }; } // namespace render diff --git a/src/render/model/modelnode.cpp b/src/render/model/modelnode.cpp index cb2acbf0..719c7c33 100644 --- a/src/render/model/modelnode.cpp +++ b/src/render/model/modelnode.cpp @@ -150,7 +150,11 @@ bool ModelNode::getScale(float time, float &scale) const { } const glm::vec3 &ModelNode::getCenterOfAABB() const { - return _mesh->aabb().center(); + return _mesh->mesh()->aabb().center(); +} + +void ModelNode::setName(string name) { + _name = move(name); } } // namespace render diff --git a/src/render/model/modelnode.h b/src/render/model/modelnode.h index ae1d7c3b..17ef364b 100644 --- a/src/render/model/modelnode.h +++ b/src/render/model/modelnode.h @@ -28,7 +28,6 @@ namespace reone { namespace render { -class JbaFile; class Model; /** @@ -41,6 +40,21 @@ class Model; */ class ModelNode { public: + struct PositionKeyframe { + float time { 0.0f }; + glm::vec3 position { 0.0f }; + }; + + struct OrientationKeyframe { + float time { 0.0f }; + glm::quat orientation { 1.0f, 0.0f, 0.0f, 0.0f }; + }; + + struct ScaleKeyframe { + float time { 0.0f }; + float scale { 0.0f }; + }; + struct Light { int priority { 1 }; bool ambientOnly { false }; @@ -97,22 +111,9 @@ public: std::shared_ptr emitter() const { return _emitter; } const std::vector> &children() const { return _children; } + void setName(std::string name); + private: - struct PositionKeyframe { - float time { 0.0f }; - glm::vec3 position { 0.0f }; - }; - - struct OrientationKeyframe { - float time { 0.0f }; - glm::quat orientation { 1.0f, 0.0f, 0.0f, 0.0f }; - }; - - struct ScaleKeyframe { - float time { 0.0f }; - float scale { 0.0f }; - }; - int _index { 0 }; const ModelNode *_parent { nullptr }; uint16_t _flags { 0 }; @@ -142,8 +143,6 @@ private: ModelNode &operator=(const ModelNode &) = delete; friend class MdlFile; - friend class Gr2File; - friend class JbaFile; }; } // namespace render diff --git a/src/render/models.cpp b/src/render/models.cpp index 01fcc10e..269d0f4a 100644 --- a/src/render/models.cpp +++ b/src/render/models.cpp @@ -20,7 +20,6 @@ #include "../common/streamutil.h" #include "../resource/resources.h" -#include "model/gr2file.h" #include "model/mdlfile.h" using namespace std; @@ -44,34 +43,25 @@ void Models::invalidateCache() { _cache.clear(); } -shared_ptr Models::get(const string &resRef, bool gr2) { +shared_ptr Models::get(const string &resRef) { auto maybeModel = _cache.find(resRef); if (maybeModel != _cache.end()) { return maybeModel->second; } - auto inserted = _cache.insert(make_pair(resRef, doGet(resRef, gr2))); + auto inserted = _cache.insert(make_pair(resRef, doGet(resRef))); return inserted.first->second; } -shared_ptr Models::doGet(const string &resRef, bool gr2) { +shared_ptr Models::doGet(const string &resRef) { + shared_ptr mdlData(Resources::instance().get(resRef, ResourceType::Mdl)); + shared_ptr mdxData(Resources::instance().get(resRef, ResourceType::Mdx)); shared_ptr model; - if (gr2) { - shared_ptr gr2Data(Resources::instance().get(resRef, ResourceType::Gr2)); - if (gr2Data) { - Gr2File gr2(resRef); - gr2.load(wrap(gr2Data)); - model = gr2.model(); - } - } else { - shared_ptr mdlData(Resources::instance().get(resRef, ResourceType::Mdl)); - shared_ptr mdxData(Resources::instance().get(resRef, ResourceType::Mdx)); - if (mdlData && mdxData) { - MdlFile mdl(_gameId); - mdl.load(wrap(mdlData), wrap(mdxData)); - model = mdl.model(); - } + if (mdlData && mdxData) { + MdlFile mdl(_gameId); + mdl.load(wrap(mdlData), wrap(mdxData)); + model = mdl.model(); } if (model) { model->initGL(); diff --git a/src/render/models.h b/src/render/models.h index 505af3ed..46285c66 100644 --- a/src/render/models.h +++ b/src/render/models.h @@ -38,11 +38,7 @@ public: void init(resource::GameID gameId); void invalidateCache(); - /** - * @param resRef ResRef of the model - * @param gr2 true if model is from SWTOR, false otherwise - */ - std::shared_ptr get(const std::string &resRef, bool gr2 = false); + std::shared_ptr get(const std::string &resRef); private: resource::GameID _gameId { resource::GameID::KotOR }; @@ -52,7 +48,7 @@ private: Models(const Models &) = delete; Models &operator=(const Models &) = delete; - std::shared_ptr doGet(const std::string &resRef, bool gr2); + std::shared_ptr doGet(const std::string &resRef); }; } // namespace render diff --git a/src/render/shaders.cpp b/src/render/shaders.cpp index b7d302ea..4b77e8ec 100644 --- a/src/render/shaders.cpp +++ b/src/render/shaders.cpp @@ -108,7 +108,7 @@ layout(std140) uniform Bumpmap { uniform float uBumpmapScaling; uniform vec2 uBumpmapGridSize; uniform int uBumpmapFrame; - uniform bool uBumpmapFromTOR; + uniform bool uBumpmapSwizzled; }; )END"; @@ -371,7 +371,7 @@ void applyBumpmapToNormal(inout vec3 normal, vec2 uv) { } else { vec4 bumpmapSample = texture(uBumpmap, uv); - if (uBumpmapFromTOR) { + if (uBumpmapSwizzled) { normal = vec3(bumpmapSample.a, bumpmapSample.g, 1.0); } else { normal = vec3(bumpmapSample.r, bumpmapSample.g, bumpmapSample.b); diff --git a/src/render/shaders.h b/src/render/shaders.h index ebc0b5ff..566be73a 100644 --- a/src/render/shaders.h +++ b/src/render/shaders.h @@ -130,7 +130,7 @@ struct BumpmapUniforms { float scaling { 0.0f }; glm::vec2 gridSize { 1.0f }; int frame { 0 }; - int fromTOR { 0 }; + int swizzled { 0 }; char padding[8]; }; diff --git a/src/scene/node/modelnodescenenode.cpp b/src/scene/node/modelnodescenenode.cpp index 4f69f62a..4948c679 100644 --- a/src/scene/node/modelnodescenenode.cpp +++ b/src/scene/node/modelnodescenenode.cpp @@ -129,7 +129,7 @@ void ModelNodeSceneNode::renderSingle(bool shadowPass) const { locals.bumpmap.scaling = bumpmapTexture->features().bumpMapScaling; locals.bumpmap.gridSize = glm::vec2(bumpmapTexture->features().numX, bumpmapTexture->features().numY); locals.bumpmap.frame = _bumpmapFrame; - locals.bumpmap.fromTOR = mesh->isBumpmapFromTOR(); + locals.bumpmap.swizzled = mesh->isBumpmapSwizzled(); } bool receivesShadows = diff --git a/src/scene/node/modelscenenode.cpp b/src/scene/node/modelscenenode.cpp index 6894ce67..a31121b3 100644 --- a/src/scene/node/modelscenenode.cpp +++ b/src/scene/node/modelscenenode.cpp @@ -348,9 +348,9 @@ void ModelSceneNode::refreshAABB() { auto modelNodeSceneNode = dynamic_cast(node); if (modelNodeSceneNode) { - shared_ptr mesh(modelNodeSceneNode->modelNode()->mesh()); + shared_ptr mesh(modelNodeSceneNode->modelNode()->mesh()); if (mesh) { - _aabb.expand(mesh->aabb() * node->localTransform()); + _aabb.expand(mesh->mesh()->aabb() * node->localTransform()); } } diff --git a/src/render/model/gr2file.cpp b/src/tor/gr2file.cpp similarity index 63% rename from src/render/model/gr2file.cpp rename to src/tor/gr2file.cpp index 36cf1fdc..7d04bbfc 100644 --- a/src/render/model/gr2file.cpp +++ b/src/tor/gr2file.cpp @@ -24,27 +24,28 @@ #include "glm/gtc/type_ptr.hpp" -#include "../../common/log.h" -#include "../../common/streamutil.h" -#include "../../render/model/jbafile.h" -#include "../../render/models.h" -#include "../../render/textures.h" -#include "../../resource/resources.h" +#include "../common/log.h" +#include "../common/streamutil.h" +#include "../render/models.h" +#include "../render/textures.h" +#include "../resource/resources.h" + +#include "jbafile.h" using namespace std; +using namespace reone::render; using namespace reone::resource; namespace pt = boost::property_tree; namespace reone { -namespace render { +namespace tor { -Gr2File::Gr2File(string resRef, shared_ptr skeleton) : +Gr2File::Gr2File(string resRef) : BinaryFile(4, "GAWB"), - _resRef(move(resRef)), - _skeleton(move(skeleton)) { + _resRef(move(resRef)) { } void Gr2File::doLoad() { @@ -75,12 +76,6 @@ void Gr2File::doLoad() { loadMeshes(); loadSkeletonBones(); loadAttachments(); - - if (_fileType == FileType::Skeleton) { - loadSkeletonModel(); - } else { - loadGeometryModel(); - } } void Gr2File::loadMeshes() { @@ -258,14 +253,12 @@ unique_ptr Gr2File::readModelMesh(const Gr2Mesh &mesh) { indices.insert(indices.end(), pieceIndices.begin(), pieceIndices.end()); } - auto modelMesh = make_unique(true, 0, true); - modelMesh->_vertexCount = mesh.header.numVertices; - modelMesh->_vertices = move(vertices); - modelMesh->_offsets = move(offsets); - modelMesh->_indices = move(indices); - modelMesh->_diffuseColor = glm::vec3(0.8f); - modelMesh->_ambientColor = glm::vec3(0.2f); - modelMesh->computeAABB(); + auto simpleMesh = make_unique(mesh.header.numVertices, move(vertices), move(indices), move(offsets)); + simpleMesh->computeAABB(); + + auto modelMesh = make_unique(move(simpleMesh), true, 0, true); + modelMesh->setDiffuseColor(glm::vec3(0.8f)); + modelMesh->setAmbientColor(glm::vec3(0.2f)); // Fill mesh textures from materials if (!_materials.empty()) { @@ -293,10 +286,9 @@ unique_ptr Gr2File::readModelMesh(const Gr2Mesh &mesh) { value = value.substr(lastSlashIdx + 1ll); } if (semantic == "DiffuseMap") { - modelMesh->_diffuse = Textures::instance().get(value, TextureType::Diffuse); + modelMesh->setDiffuseTexture(Textures::instance().get(value, TextureType::Diffuse)); } else if (semantic == "RotationMap1") { - modelMesh->_bumpmap = Textures::instance().get(value, TextureType::Bumpmap); - modelMesh->_bumpmapFromTOR = true; + modelMesh->setBumpmapTexture(Textures::instance().get(value, TextureType::Bumpmap), true); } } } @@ -376,172 +368,6 @@ unique_ptr Gr2File::readAttachment() { return move(attachment); } -void Gr2File::loadSkeletonModel() { - vector vertices { - -0.001f, -0.001f, -0.001f, - -0.001f, -0.001f, 0.001f, - -0.001f, 0.001f, 0.001f, - -0.001f, 0.001f, -0.001f, - 0.001f, 0.001f, 0.001f, - 0.001f, 0.001f, -0.001f, - 0.001f, -0.001f, -0.001f, - 0.001f, -0.001f, 0.001f - }; - vector indices { - 0, 1, 2, 2, 3, 0, - 2, 4, 5, 5, 3, 2, - 1, 7, 4, 4, 2, 1, - 0, 6, 7, 7, 1, 0, - 7, 6, 5, 5, 4, 7, - 6, 0, 3, 3, 5, 6 - }; - Mesh::VertexOffsets offsets { 0, -1, -1, -1, -1, -1, -1, -1, 3 * sizeof(float) }; - - auto mesh = make_shared(true, 0, false); - mesh->_vertexCount = 8; - mesh->_vertices = move(vertices); - mesh->_offsets = move(offsets); - mesh->_indices = move(indices); - mesh->_diffuse = Textures::instance().get("redfill", TextureType::GUI); - mesh->_diffuseColor = glm::vec3(0.0f); - mesh->_ambientColor = glm::vec3(1.0f); - mesh->computeAABB(); - - glm::mat4 transform(1.0f); - transform *= glm::mat4_cast(glm::angleAxis(glm::radians(180.0f), glm::vec3(0.0f, 0.0f, 1.0f))); - transform *= glm::mat4_cast(glm::angleAxis(glm::half_pi(), glm::vec3(1.0f, 0.0, 0.0f))); - transform = glm::scale(transform, glm::vec3(10.0f)); - - int index = 0; - auto rootNode = make_shared(index++); - rootNode->_absTransform = transform; - rootNode->_absTransformInv = glm::inverse(rootNode->_absTransform); - - vector> nodes; - - // Convert bones into model nodes - for (uint16_t i = 0; i < _numBones; ++i) { - auto node = make_shared(index); - node->_nodeNumber = index; - node->_name = _bones[i]->name; - node->_mesh = mesh; - node->_absTransform = rootNode->_absTransform * glm::inverse(_bones[i]->rootToBone); - node->_absTransformInv = glm::inverse(node->_absTransform); - nodes.push_back(move(node)); - - ++index; - } - - // Reparent model nodes - for (uint16_t i = 0; i < _numBones; ++i) { - int parentIdx = _bones[i]->parentIndex; - if (parentIdx == 0xffffffff) { - nodes[i]->_parent = rootNode.get(); - rootNode->_children.push_back(nodes[i]); - } else { - nodes[i]->_parent = nodes[parentIdx].get(); - nodes[parentIdx]->_children.push_back(nodes[i]); - } - } - - rootNode->computeLocalTransforms(); - - vector> anims; - _model = make_shared("", rootNode, anims); - _model->_classification = Model::Classification::Character; - _model->initGL(); -} - -static string getSkeletonResRef(const string &modelResRef) { - return boost::starts_with(modelResRef, "bfn_") ? "bfnnew_skeleton" : ""; -} - -static vector getSkeletonAnimations(const string &skeletonResRef) { - vector result; - if (skeletonResRef == "bfnnew_skeleton") { - result.push_back("mv_run_forward"); - } - return move(result); -} - -void Gr2File::loadGeometryModel() { - if (_meshes.empty()) return; - - // In SWTOR, geometry, skeletons and animations are all separate files - shared_ptr skeletonModel; - string skeletonResRef(getSkeletonResRef(_resRef)); - if (!skeletonResRef.empty()) { - skeletonModel = Models::instance().get(skeletonResRef, true); - } - - shared_ptr rootNode; - int index = 0; - - if (skeletonModel) { - rootNode = skeletonModel->_rootNode; - index = skeletonModel->_maxNodeIndex + 1; - - } else { - // Create our own root node, if skeleton model is not found - - glm::mat4 transform(1.0f); - transform *= glm::mat4_cast(glm::angleAxis(glm::radians(180.0f), glm::vec3(0.0f, 0.0f, 1.0f))); - transform *= glm::mat4_cast(glm::angleAxis(glm::radians(90.0f), glm::vec3(1.0f, 0.0, 0.0f))); - transform = glm::scale(transform, glm::vec3(10.0f)); - - rootNode = make_shared(index++); - rootNode->_localTransform = transform; - rootNode->_absTransform = rootNode->_localTransform; - rootNode->_absTransformInv = glm::inverse(rootNode->_absTransform); - } - - for (uint16_t i = 0; i < _numMeshes; ++i) { - if (boost::contains(_meshes[i]->header.name, "collision")) continue; // do not add collision meshes to the model - - auto node = make_shared(index); - node->_nodeNumber = index; - node->_name = _meshes[i]->header.name; - node->_mesh = _meshes[i]->mesh; - node->_absTransform = rootNode->_absTransform; - node->_absTransformInv = glm::inverse(node->_absTransform); - - if (skeletonModel) { - node->_skin = make_shared(); - for (uint16_t j = 0; j < _meshes[i]->header.numUsedBones; ++j) { - shared_ptr boneNode(skeletonModel->findNodeByName(_meshes[i]->bones[j]->name)); - if (boneNode) { - node->_skin->nodeIdxByBoneIdx.insert(make_pair(j, boneNode->index())); - } - } - } - - rootNode->_children.push_back(move(node)); - - ++index; - } - - vector> anims; - if (skeletonModel) { - vector animResRefs(getSkeletonAnimations(skeletonResRef)); - for (auto &resRef : animResRefs) { - shared_ptr animation; - shared_ptr jbaData(Resources::instance().get(resRef, ResourceType::Jba)); - if (jbaData) { - JbaFile jbaFile(resRef, skeletonModel); - jbaFile.load(wrap(jbaData)); - animation = jbaFile.animation(); - } - if (animation) { - anims.push_back(move(animation)); - } - } - } - - _model = make_shared("", rootNode, anims); - _model->_classification = Model::Classification::Character; // this prevents self-shadowing - _model->initGL(); -} - -} // namespace render +} // namespace tor } // namespace reone diff --git a/src/render/model/gr2file.h b/src/tor/gr2file.h similarity index 80% rename from src/render/model/gr2file.h rename to src/tor/gr2file.h index 3a040908..18261d4d 100644 --- a/src/render/model/gr2file.h +++ b/src/tor/gr2file.h @@ -17,16 +17,15 @@ #pragma once -#include "../../render/model/model.h" -#include "../../resource/format/binfile.h" +#include "../render/model/model.h" +#include "../resource/format/binfile.h" namespace reone { -namespace render { +namespace tor { /** - * Encapsulates reading GR2 model files, used by Star Wars: The Old Republic. - * This is highly experimental. + * Encapsulates loading GR2 model files, used by Star Wars: The Old Republic. */ class Gr2File : public resource::BinaryFile { public: @@ -36,13 +35,7 @@ public: Skeleton = 2 }; - /** - * @param resRef ResRef of the model - * @param skeleton skeleton file to use when constructing this model (optional) - */ - Gr2File(std::string resRef, std::shared_ptr skeleton = nullptr); - - std::shared_ptr model() const { return _model; } + Gr2File(std::string resRef); private: struct MeshHeader { @@ -74,7 +67,7 @@ private: struct Gr2Mesh { MeshHeader header; std::vector> pieces; - std::shared_ptr mesh; + std::shared_ptr mesh; std::vector> bones; }; @@ -91,7 +84,6 @@ private: }; std::string _resRef; - std::shared_ptr _skeleton; FileType _fileType { FileType::Geometry }; uint16_t _numMeshes { 0 }; @@ -107,7 +99,6 @@ private: std::vector> _bones; std::vector _materials; std::vector> _attachments; - std::shared_ptr _model; void doLoad() override; @@ -115,17 +106,15 @@ private: void loadMaterials(); void loadSkeletonBones(); void loadAttachments(); - void loadSkeletonModel(); - void loadGeometryModel(); std::unique_ptr readMesh(); std::unique_ptr readMeshPiece(); - std::unique_ptr readModelMesh(const Gr2Mesh &mesh); + std::unique_ptr readModelMesh(const Gr2Mesh &mesh); std::unique_ptr readMeshBone(); std::unique_ptr readSkeletonBone(); std::unique_ptr readAttachment(); }; -} // namespace render +} // namespace tor } // namespace reone diff --git a/src/render/model/jbafile.cpp b/src/tor/jbafile.cpp similarity index 58% rename from src/render/model/jbafile.cpp rename to src/tor/jbafile.cpp index 6f365f81..4806dcc7 100644 --- a/src/render/model/jbafile.cpp +++ b/src/tor/jbafile.cpp @@ -22,21 +22,23 @@ #include "glm/gtc/type_ptr.hpp" -#include "../../common/log.h" -#include "../../render/model/model.h" +#include "../common/log.h" +#include "../render/model/model.h" using namespace std; +using namespace reone::render; using namespace reone::resource; namespace reone { -namespace render { +namespace tor { -JbaFile::JbaFile(const string &resRef, const shared_ptr &skeleton) : +static const glm::vec3 g_translationModifier { -0.001f, 0.001f, -0.001f }; + +JbaFile::JbaFile(const string &resRef) : BinaryFile(4, "\0\0\0\0"), - _resRef(resRef), - _skeleton(skeleton) { + _resRef(resRef) { } void JbaFile::doLoad() { @@ -48,7 +50,6 @@ void JbaFile::doLoad() { loadPartData(); loadKeyframes(); loadBones(); - loadAnimation(); } void JbaFile::loadHeader() { @@ -69,8 +70,8 @@ void JbaFile::loadPartHeaders() { for (uint32_t i = 0; i < _numParts; ++i) { JbaPart part; part.keyframeIdx = readUint32(); - part.dataSize = readUint32(); - debug(boost::format("JBA: part %d header: %u %u") % i % part.keyframeIdx % part.dataSize); + part.keyframesSize = readUint32(); + debug(boost::format("JBA: part %d header: %u %u") % i % part.keyframeIdx % part.keyframesSize); _parts.push_back(move(part)); } ignore(4 * _numParts); @@ -88,6 +89,15 @@ static string describeVector(const glm::vec3 &vec) { return str(boost::format("(%.06f, %.06f, %.06f)") % vec.x % vec.y % vec.z); } +static string describeQuaternion(const glm::quat &q) { + return str(boost::format("(%.06f, %.06f, %.06f, %.06f)") % q.x % q.y % q.z % q.w); +} + +static glm::quat getUnitQuaternion(const glm::vec3 &axis) { + float w = glm::sqrt(1.0f - glm::dot(axis, axis)); + return glm::normalize(glm::quat(w, axis)); +} + void JbaFile::loadBoneData() { seek(alignAt80(tell())); vector data(readArray(48ll * _numBones)); @@ -95,15 +105,15 @@ void JbaFile::loadBoneData() { for (uint32_t i = 0; i < _numBones; ++i) { JbaBone bone; - bone.minTranslation = glm::make_vec3(dataPtr + 0); - bone.maxTranslation = glm::make_vec3(dataPtr + 3); - bone.minOrientation = glm::make_vec3(dataPtr + 6); - bone.maxOrientation = glm::make_vec3(dataPtr + 9); + bone.minTranslation = glm::make_vec3(dataPtr + 0) * g_translationModifier; + bone.maxTranslation = glm::make_vec3(dataPtr + 3) * g_translationModifier; + bone.minOrientation = getUnitQuaternion(glm::make_vec3(dataPtr + 6)); + bone.maxOrientation = getUnitQuaternion(glm::make_vec3(dataPtr + 9)); debug(boost::format("JBA: bone %d data: %s, %s, %s, %s") % i % describeVector(bone.minTranslation) % describeVector(bone.maxTranslation) - % describeVector(bone.minOrientation) % describeVector(bone.maxOrientation), 2); + % describeQuaternion(bone.minOrientation) % describeQuaternion(bone.maxOrientation), 2); _bones.push_back(move(bone)); @@ -116,34 +126,52 @@ void JbaFile::loadPartData() { uint32_t start = alignAt80(tell()); seek(start); - _parts[i].data = readPartData(); + _parts[i].keyframes = readPartKeyframes(); - seek(start + _parts[i].dataSize); + seek(start + _parts[i].keyframesSize); } } static glm::vec3 decompressPosition(uint32_t value, const glm::vec3 &min, const glm::vec3 &max) { - float nx = (value & 0x3ff) / 1023.0f; - float ny = ((value >> 10) & 0x7ff) / 2047.0f; - float nz = ((value >> 21) & 0x7ff) / 2047.0f; - return min + max * glm::vec3(nx, ny, nz); + uint32_t z = (value & 0x3ff); + uint32_t y = ((value >> 10) & 0x7ff); + uint32_t x = ((value >> 21) & 0x7ff); + + float nx = (x & 0x1ff) / 511.0f; + float ny = (y & 0x3ff) / 1023.0f; + float nz = (z & 0x3ff) / 1023.0f; + + bool sx = (x & !0x3ff) != 0; + bool sy = (y & !0x3ff) != 0; + bool sz = (z & !0x1ff) != 0; + + glm::vec3 result(min); + result.x += (sx ? -1.0f : 1.0f) * nx * max.x; + result.y += (sy ? -1.0f : 1.0f) * ny * max.y; + result.z += (sz ? -1.0f : 1.0f) * nz * max.z; + + return move(result); } -static glm::quat decompressOrientation(const uint16_t *values, const glm::vec3 &min, const glm::vec3 &max) { +static glm::quat decompressOrientation(const uint16_t *values, const glm::quat &min, const glm::quat &max) { float nx = (values[0] & 0x7fff) / 32767.0f; - float ny = (values[1] & 0xffff) / 65535.0f; - float nz = (values[2] & 0xffff) / 65535.0f; - glm::vec3 v(min + max * glm::vec3(nx, ny, nz)); - float w = glm::sqrt(1.0f - glm::dot(v, v)); - return glm::quat(w, v); + float ny = (values[1] & 0x7fff) / 32767.0f; + float nz = (values[2] & 0x7fff) / 32767.0f; + + bool sx = (values[0] & 0x8000) != 0; + bool sy = (values[1] & 0x8000) != 0; + bool sz = (values[2] & 0x8000) != 0; + + glm::vec3 axis(min.x, min.y, min.z); + axis.x += (sx ? -1.0f : 1.0f) * nx * max.x; + axis.y += (sy ? -1.0f : 1.0f) * ny * max.y; + axis.z += (sz ? -1.0f : 1.0f) * nz * max.z; + + return getUnitQuaternion(axis); } -static string describeQuaternion(const glm::quat &q) { - return str(boost::format("(%.06f, %.06f, %.06f, %.06f)") % q.x % q.y % q.z % q.w); -} - -unique_ptr JbaFile::readPartData() { - auto partData = make_unique(); +vector> JbaFile::readPartKeyframes() { + vector> keyframes; ignore(8); // number of bones again @@ -160,28 +188,28 @@ unique_ptr JbaFile::readPartData() { const uint32_t *keyframeLayoutPtr = &keyframeLayout[0]; for (uint32_t i = 0; i < _numBones; ++i) { - vector keyframes; - keyframes.resize(keyframeLayoutPtr[0]); + vector boneKeyframes; + boneKeyframes.resize(keyframeLayoutPtr[0]); // Decompress 48-bit orientation poses for (uint32_t j = 0; j < keyframeLayoutPtr[0]; ++j) { vector values(readArray(3)); - keyframes[j].orientation = decompressOrientation(&values[0], _bones[i].minOrientation, _bones[i].maxOrientation); - debug(boost::format("JBA: bone %u: keyframe %u: orientation: %04X %04X %04X -> %s") % i % j % values[0] % values[1] % values[2] % describeQuaternion(keyframes[j].orientation), 2); + boneKeyframes[j].orientation = decompressOrientation(&values[0], _bones[i].minOrientation, _bones[i].maxOrientation); + debug(boost::format("JBA: bone %u: keyframe %u: orientation: %04X %04X %04X -> %s") % i % j % values[0] % values[1] % values[2] % describeQuaternion(boneKeyframes[j].orientation), 2); } // Decompress 32-bit translation poses, if any for (uint32_t j = 0; j < keyframeLayoutPtr[2]; ++j) { uint32_t value = readUint32(); - keyframes[j].translation = decompressPosition(value, _bones[i].minTranslation, _bones[i].maxTranslation); - debug(boost::format("JBA: bone %u: keyframe %u: translation: %08X -> %s") % i % j % value % describeVector(keyframes[j].translation), 2); + boneKeyframes[j].translation = decompressPosition(value, _bones[i].minTranslation, _bones[i].maxTranslation); + debug(boost::format("JBA: bone %u: keyframe %u: translation: %08X -> %s") % i % j % value % describeVector(boneKeyframes[j].translation), 2); } - partData->keyframes.push_back(move(keyframes)); + keyframes.push_back(move(boneKeyframes)); keyframeLayoutPtr += 4; } - return move(partData); + return move(keyframes); } void JbaFile::loadKeyframes() { @@ -191,16 +219,17 @@ void JbaFile::loadKeyframes() { ignore(8); vector valuesAt08(readArray(12)); - _maxTranslation = glm::make_vec3(&valuesAt08[0]); - _minTranslation = glm::make_vec3(&valuesAt08[3]); - _maxOrientation = glm::make_vec3(&valuesAt08[6]); - _minOrientation = glm::make_vec3(&valuesAt08[9]); + _maxTranslation = glm::make_vec3(&valuesAt08[0]) * g_translationModifier; + _minTranslation = glm::make_vec3(&valuesAt08[3]) * g_translationModifier; + _maxOrientation = getUnitQuaternion(glm::make_vec3(&valuesAt08[6])); + _minOrientation = getUnitQuaternion(glm::make_vec3(&valuesAt08[9])); debug(boost::format("JBA: maxTranslation=%s minTranslation=%s maxOrientation=%s minOrientation=%s") % describeVector(_maxTranslation) % describeVector(_minTranslation) % - describeVector(_maxOrientation) % describeVector(_minOrientation)); + describeQuaternion(_maxOrientation) % describeQuaternion(_minOrientation)); _numKeyframes = readUint32(); debug("JBA: numKeyframes=" + to_string(_numKeyframes)); + _keyframes.resize(_numKeyframes); ignore(3 * sizeof(uint32_t)); @@ -212,6 +241,7 @@ void JbaFile::loadKeyframes() { valuesAt48Ptr[0] % valuesAt48Ptr[1] % valuesAt48Ptr[2] % describeQuaternion(orientation), 2); + _keyframes[i].orientation = move(orientation); valuesAt48Ptr += 3; } if (_numKeyframes % 2 != 0) { @@ -222,6 +252,7 @@ void JbaFile::loadKeyframes() { for (uint32_t i = 0; i < _numKeyframes; ++i) { glm::vec3 translation(decompressPosition(keyframeValues[i], _minTranslation, _maxTranslation)); debug(boost::format("JBA: keyframe %d translation: %08X -> %s") % i % keyframeValues[i] % describeVector(translation), 2); + _keyframes[i].translation = move(translation); } } @@ -241,68 +272,6 @@ void JbaFile::loadBones() { } } -void JbaFile::loadAnimation() { - if (_numParts == 0) return; - - int index = 0; - auto rootNode = make_shared(index++); - - stack modelNodes; - modelNodes.push(&_skeleton->rootNode()); - - while (!modelNodes.empty()) { - ModelNode *modelNode = modelNodes.top(); - modelNodes.pop(); - - // Match a skeleton model node to a bone - auto maybeBone = find_if(_bones.begin(), _bones.end(), [this, &modelNode](auto &bone) { - return bone.name == modelNode->_name; - }); - if (maybeBone != _bones.end()) { - // Convert a skeleton model node to an animation model node - auto animNode = make_shared(index++); - animNode->_name = modelNode->_name; - - uint32_t boneIdx = maybeBone->index; - - for (size_t i = 0; i < _numKeyframes; ++i) { - int partIdx = getPartByKeyframe(i); - if (partIdx == -1) break; - - const vector &keyframes = _parts[partIdx].data->keyframes[boneIdx]; - const JbaKeyframe &keyframe = keyframes[i - _parts[partIdx].keyframeIdx]; - float step = _length / static_cast(keyframes.size() - 1); - float time = i * step; - - ModelNode::PositionKeyframe pos; - pos.time = time; - pos.position = keyframe.translation; - animNode->_positionFrames.push_back(move(pos)); - - //ModelNode::OrientationKeyframe orient; - //orient.time = time; - //orient.orientation = modelNode->_orientation * keyframe.orientation; - //animNode->_orientationFrames.push_back(move(orient)); - } - - rootNode->_children.push_back(move(animNode)); - } - - for (auto &child : modelNode->_children) { - modelNodes.push(child.get()); - } - } - - _animation = make_shared("pause1" /* _resRef */, _length, 0.5f * _length, vector(), rootNode); -} - -int JbaFile::getPartByKeyframe(int keyframeIdx) const { - for (uint32_t i = 0; i < _numParts; ++i) { - if (keyframeIdx >= _parts[i].keyframeIdx) return i; - } - return -1; -} - -} // namespace render +} // namespace tor } // namespace reone diff --git a/src/render/model/jbafile.h b/src/tor/jbafile.h similarity index 70% rename from src/render/model/jbafile.h rename to src/tor/jbafile.h index 7afc88e1..56e1b72d 100644 --- a/src/render/model/jbafile.h +++ b/src/tor/jbafile.h @@ -20,18 +20,15 @@ #include "glm/gtc/quaternion.hpp" #include "glm/vec3.hpp" -#include "../../render/model/animation.h" -#include "../../resource/format/binfile.h" +#include "../resource/format/binfile.h" namespace reone { -namespace render { +namespace tor { class JbaFile : public resource::BinaryFile { public: - JbaFile(const std::string &resRef, const std::shared_ptr &skeleton); - - std::shared_ptr animation() const { return _animation; } + JbaFile(const std::string &resRef); private: struct JbaKeyframe { @@ -39,27 +36,22 @@ private: glm::quat orientation { 1.0f, 0.0f, 0.0, 0.0f }; }; - struct PartData { - std::vector> keyframes; - }; - struct JbaPart { uint32_t keyframeIdx { 0 }; - uint32_t dataSize; - std::unique_ptr data; + uint32_t keyframesSize; + std::vector> keyframes; }; struct JbaBone { glm::vec3 minTranslation { 0.0f }; glm::vec3 maxTranslation { 0.0f }; - glm::vec3 minOrientation { 0.0f }; - glm::vec3 maxOrientation { 0.0f }; + glm::quat minOrientation { 1.0f, 0.0f, 0.0f, 0.0f }; + glm::quat maxOrientation { 1.0f, 0.0f, 0.0f, 0.0f }; uint32_t index { 0 }; std::string name; }; std::string _resRef; - std::shared_ptr _skeleton; float _length { 0.0f }; float _fps { 0 }; @@ -69,14 +61,12 @@ private: glm::vec3 _maxTranslation { 0.0f }; glm::vec3 _minTranslation { 0.0f }; - glm::vec3 _maxOrientation { 0.0f }; - glm::vec3 _minOrientation { 0.0f }; + glm::quat _maxOrientation { 1.0f, 0.0f, 0.0f, 0.0f }; + glm::quat _minOrientation { 1.0f, 0.0f, 0.0f, 0.0f }; std::vector _parts; - std::vector _orientationFrames; - std::vector _positionFrames; + std::vector _keyframes; std::vector _bones; - std::shared_ptr _animation; void doLoad(); @@ -86,13 +76,12 @@ private: void loadPartData(); void loadKeyframes(); void loadBones(); - void loadAnimation(); - std::unique_ptr readPartData(); + std::vector> readPartKeyframes(); int getPartByKeyframe(int keyframeIdx) const; }; -} // namespace render +} // namespace tor } // namespace reone