From 8e4d73fca9ea2b34f231525fd30174bba329c6a8 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Tue, 3 Jan 2017 14:18:06 +0000 Subject: [PATCH 01/19] Rename Model -> Clump --- rwengine/src/ai/CharacterController.cpp | 2 +- rwengine/src/data/ModelData.hpp | 14 ++++---- rwengine/src/data/Skeleton.cpp | 2 +- rwengine/src/engine/Animator.cpp | 4 +-- rwengine/src/engine/Animator.hpp | 6 ++-- rwengine/src/engine/GameData.cpp | 4 +-- rwengine/src/engine/GameData.hpp | 2 +- rwengine/src/engine/GameWorld.cpp | 2 +- rwengine/src/objects/CutsceneObject.cpp | 2 +- rwengine/src/objects/CutsceneObject.hpp | 2 +- rwengine/src/objects/GameObject.hpp | 8 ++--- rwengine/src/objects/VehicleObject.cpp | 2 +- rwengine/src/render/DebugDraw.hpp | 4 +-- rwengine/src/render/GameRenderer.cpp | 12 +++---- rwengine/src/render/GameRenderer.hpp | 16 ++++----- rwengine/src/render/ObjectRenderer.cpp | 14 ++++---- rwengine/src/render/ObjectRenderer.hpp | 4 +-- rwgame/states/IngameState.cpp | 2 +- rwlib/CMakeLists.txt | 4 +-- rwlib/source/data/{Model.cpp => Clump.cpp} | 10 +++--- rwlib/source/data/{Model.hpp => Clump.hpp} | 7 ++-- rwlib/source/loaders/LoaderDFF.cpp | 40 +++++++++++----------- rwlib/source/loaders/LoaderDFF.hpp | 22 ++++++------ rwviewer/ViewerWidget.cpp | 8 ++--- rwviewer/ViewerWidget.hpp | 14 ++++---- rwviewer/models/DFFFramesTreeModel.cpp | 4 +-- rwviewer/models/DFFFramesTreeModel.hpp | 6 ++-- rwviewer/views/ModelViewer.cpp | 2 +- rwviewer/views/ModelViewer.hpp | 6 ++-- rwviewer/views/ObjectViewer.hpp | 4 +-- rwviewer/widgets/ModelFramesWidget.cpp | 10 +++--- rwviewer/widgets/ModelFramesWidget.hpp | 6 ++-- tests/test_animation.cpp | 2 +- tests/test_loaderdff.cpp | 6 ++-- tests/test_vehicle.cpp | 2 +- 35 files changed, 127 insertions(+), 128 deletions(-) rename rwlib/source/data/{Model.cpp => Clump.cpp} (86%) rename rwlib/source/data/{Model.hpp => Clump.hpp} (96%) diff --git a/rwengine/src/ai/CharacterController.cpp b/rwengine/src/ai/CharacterController.cpp index f395bdce..49f5a4a2 100644 --- a/rwengine/src/ai/CharacterController.cpp +++ b/rwengine/src/ai/CharacterController.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include diff --git a/rwengine/src/data/ModelData.hpp b/rwengine/src/data/ModelData.hpp index 488ec005..512ef8be 100644 --- a/rwengine/src/data/ModelData.hpp +++ b/rwengine/src/data/ModelData.hpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include #ifdef RW_WINDOWS @@ -133,13 +133,13 @@ public: } /// @todo change with librw - void setAtomic(Model* model, int n, ModelFrame* atomic) { + void setAtomic(Clump* model, int n, ModelFrame* atomic) { model_ = model; atomics_[n] = atomic; } /// @todo remove this - Model* getModel() const { + Clump* getModel() const { return model_; } @@ -204,7 +204,7 @@ public: }; private: - Model* model_ = nullptr; + Clump* model_ = nullptr; ModelFrame* atomics_[3] = {}; float loddistances_[3] = {}; uint8_t numatomics_ = 0; @@ -231,11 +231,11 @@ public: ClumpModelInfo(ModelDataType type) : BaseModelInfo(type) { } - void setModel(Model* model) { + void setModel(Clump* model) { model_ = model; } - Model* getModel() const { + Clump* getModel() const { return model_; } @@ -249,7 +249,7 @@ public: } private: - Model* model_ = nullptr; + Clump* model_ = nullptr; }; /** diff --git a/rwengine/src/data/Skeleton.cpp b/rwengine/src/data/Skeleton.cpp index 1548d60e..2665344a 100644 --- a/rwengine/src/data/Skeleton.cpp +++ b/rwengine/src/data/Skeleton.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/rwengine/src/engine/Animator.cpp b/rwengine/src/engine/Animator.cpp index fe7355b8..6dcf727d 100644 --- a/rwengine/src/engine/Animator.cpp +++ b/rwengine/src/engine/Animator.cpp @@ -1,10 +1,10 @@ -#include +#include #include #include #include #include -Animator::Animator(Model* model, Skeleton* skeleton) +Animator::Animator(Clump* model, Skeleton* skeleton) : model(model), skeleton(skeleton) { } diff --git a/rwengine/src/engine/Animator.hpp b/rwengine/src/engine/Animator.hpp index d9441426..50323589 100644 --- a/rwengine/src/engine/Animator.hpp +++ b/rwengine/src/engine/Animator.hpp @@ -8,7 +8,7 @@ #include #include -class Model; +class Clump; class ModelFrame; class Skeleton; @@ -49,7 +49,7 @@ class Animator { /** * @brief model The model being animated. */ - Model* model; + Clump* model; /** * @brief Skeleton instance. @@ -62,7 +62,7 @@ class Animator { std::vector animations; public: - Animator(Model* model, Skeleton* skeleton); + Animator(Clump* model, Skeleton* skeleton); Animation* getAnimation(unsigned int slot) { if (slot < animations.size()) { diff --git a/rwengine/src/engine/GameData.cpp b/rwengine/src/engine/GameData.cpp index 02c38d90..19b91396 100644 --- a/rwengine/src/engine/GameData.cpp +++ b/rwengine/src/engine/GameData.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -363,7 +363,7 @@ void GameData::getNameAndLod(std::string& name, int& lod) { } } -Model* GameData::loadClump(const std::string& name) { +Clump* GameData::loadClump(const std::string& name) { auto file = index.openFile(name); if (!file) { logger->error("Data", "Failed to load model " + name); diff --git a/rwengine/src/engine/GameData.hpp b/rwengine/src/engine/GameData.hpp index f6a2df36..5b729841 100644 --- a/rwengine/src/engine/GameData.hpp +++ b/rwengine/src/engine/GameData.hpp @@ -133,7 +133,7 @@ public: /** * Loads an archived model and returns it directly */ - Model* loadClump(const std::string& name); + Clump* loadClump(const std::string& name); /** * Loads a DFF and associates its atomics with models. diff --git a/rwengine/src/engine/GameWorld.cpp b/rwengine/src/engine/GameWorld.cpp index 97167379..d19f0db1 100644 --- a/rwengine/src/engine/GameWorld.cpp +++ b/rwengine/src/engine/GameWorld.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/rwengine/src/objects/CutsceneObject.cpp b/rwengine/src/objects/CutsceneObject.cpp index 6d1b55b3..5cad5df4 100644 --- a/rwengine/src/objects/CutsceneObject.cpp +++ b/rwengine/src/objects/CutsceneObject.cpp @@ -3,7 +3,7 @@ #include CutsceneObject::CutsceneObject(GameWorld *engine, const glm::vec3 &pos, - const glm::quat &rot, Model *model, + const glm::quat &rot, Clump *model, BaseModelInfo *modelinfo) : GameObject(engine, pos, rot, modelinfo) , _parent(nullptr) diff --git a/rwengine/src/objects/CutsceneObject.hpp b/rwengine/src/objects/CutsceneObject.hpp index 280db419..566d638f 100644 --- a/rwengine/src/objects/CutsceneObject.hpp +++ b/rwengine/src/objects/CutsceneObject.hpp @@ -12,7 +12,7 @@ class CutsceneObject : public GameObject { public: CutsceneObject(GameWorld* engine, const glm::vec3& pos, - const glm::quat& rot, Model* model, + const glm::quat& rot, Clump* model, BaseModelInfo* modelinfo); ~CutsceneObject(); diff --git a/rwengine/src/objects/GameObject.hpp b/rwengine/src/objects/GameObject.hpp index 917b21f3..c4a2fc90 100644 --- a/rwengine/src/objects/GameObject.hpp +++ b/rwengine/src/objects/GameObject.hpp @@ -2,7 +2,7 @@ #ifndef _GAMEOBJECT_HPP_ #define _GAMEOBJECT_HPP_ -#include +#include #include #include #include @@ -33,7 +33,7 @@ class GameObject { /** * Model used for rendering */ - Model* model_; + Clump* model_; protected: void changeModelInfo(BaseModelInfo* next) { @@ -106,14 +106,14 @@ public: /** * @return The model used in rendering */ - Model* getModel() const { + Clump* getModel() const { return model_; } /** * Changes the current model, used for re-dressing chars */ - void setModel(Model* model) { + void setModel(Clump* model) { model_ = model; } diff --git a/rwengine/src/objects/VehicleObject.cpp b/rwengine/src/objects/VehicleObject.cpp index 964acf9d..2afcebca 100644 --- a/rwengine/src/objects/VehicleObject.cpp +++ b/rwengine/src/objects/VehicleObject.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include diff --git a/rwengine/src/render/DebugDraw.hpp b/rwengine/src/render/DebugDraw.hpp index 833dc12c..d4e2b386 100644 --- a/rwengine/src/render/DebugDraw.hpp +++ b/rwengine/src/render/DebugDraw.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include class DebugDraw : public btIDebugDraw { @@ -28,7 +28,7 @@ public: protected: int debugMode; - std::vector lines; + std::vector lines; size_t maxlines; GeometryBuffer *lineBuff; DrawBuffer *dbuff; diff --git a/rwengine/src/render/GameRenderer.cpp b/rwengine/src/render/GameRenderer.cpp index a345c622..d9a860bb 100644 --- a/rwengine/src/render/GameRenderer.cpp +++ b/rwengine/src/render/GameRenderer.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -475,11 +475,11 @@ void GameRenderer::renderPostProcess() { renderer->drawArrays(glm::mat4(), &ssRectDraw, wdp); } -void GameRenderer::renderGeometry(Model* model, size_t g, +void GameRenderer::renderGeometry(Clump* model, size_t g, const glm::mat4& modelMatrix, float opacity, GameObject* object) { for (size_t sg = 0; sg < model->geometries[g]->subgeom.size(); ++sg) { - Model::SubGeometry& subgeom = model->geometries[g]->subgeom[sg]; + Clump::SubGeometry& subgeom = model->geometries[g]->subgeom[sg]; Renderer::DrawParameters dp; @@ -489,7 +489,7 @@ void GameRenderer::renderGeometry(Model* model, size_t g, dp.textures = {0}; if (model->geometries[g]->materials.size() > subgeom.material) { - Model::Material& mat = + Clump::Material& mat = model->geometries[g]->materials[subgeom.material]; if (mat.textures.size() > 0) { @@ -656,7 +656,7 @@ void GameRenderer::drawColour(const glm::vec4& colour, glm::vec4 extents) { renderer->invalidate(); } -bool GameRenderer::renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix, +bool GameRenderer::renderFrame(Clump* m, ModelFrame* f, const glm::mat4& matrix, GameObject* object, float opacity, bool queueTransparent) { auto localmatrix = matrix; @@ -693,7 +693,7 @@ bool GameRenderer::renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix, return true; } -void GameRenderer::renderModel(Model* model, const glm::mat4& modelMatrix, +void GameRenderer::renderModel(Clump* model, const glm::mat4& modelMatrix, GameObject* object) { renderFrame(model, model->frames[model->rootFrameIdx], modelMatrix, object, 1.f); diff --git a/rwengine/src/render/GameRenderer.hpp b/rwengine/src/render/GameRenderer.hpp index 91daf69f..6377cb87 100644 --- a/rwengine/src/render/GameRenderer.hpp +++ b/rwengine/src/render/GameRenderer.hpp @@ -16,7 +16,7 @@ class Logger; #include "TextRenderer.hpp" #include "WaterRenderer.hpp" -class Model; +class Clump; class ModelFrame; class GameWorld; class GameObject; @@ -53,7 +53,7 @@ class GameRenderer { /** Stores data for deferring transparent objects */ struct RQueueEntry { - Model* model; + Clump* model; size_t g; size_t sg; glm::mat4 matrix; @@ -71,7 +71,7 @@ class GameRenderer { * materials * @return True if the frame was drawn, false if it should be queued */ - bool renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix, + bool renderFrame(Clump* m, ModelFrame* f, const glm::mat4& matrix, GameObject* object, float opacity, bool queueTransparent = true); @@ -158,10 +158,10 @@ public: /** * Renders a model (who'd have thought) */ - void renderModel(Model*, const glm::mat4& modelMatrix, + void renderModel(Clump*, const glm::mat4& modelMatrix, GameObject* = nullptr); - void renderGeometry(Model*, size_t geom, const glm::mat4& modelMatrix, + void renderGeometry(Clump*, size_t geom, const glm::mat4& modelMatrix, float opacity, GameObject* = nullptr); /** method for rendering AI debug information */ @@ -207,15 +207,15 @@ public: * * GameRenderer will take ownership of the Model* pointer */ - void setSpecialModel(SpecialModel usage, Model* model) { + void setSpecialModel(SpecialModel usage, Clump* model) { specialmodels_[usage].reset(model); } private: /// Hard-coded models to use for each of the special models - std::unique_ptr + std::unique_ptr specialmodels_[SpecialModel::SpecialModelCount]; - Model* getSpecialModel(SpecialModel usage) const { + Clump* getSpecialModel(SpecialModel usage) const { return specialmodels_[usage].get(); } }; diff --git a/rwengine/src/render/ObjectRenderer.cpp b/rwengine/src/render/ObjectRenderer.cpp index 9477c19c..7e3027d4 100644 --- a/rwengine/src/render/ObjectRenderer.cpp +++ b/rwengine/src/render/ObjectRenderer.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include @@ -33,11 +33,11 @@ RenderKey createKey(bool transparent, float normalizedDepth, uint8_t(0xFF & (textures.size() > 0 ? textures[0] : 0)) << 0; } -void ObjectRenderer::renderGeometry(Model* model, size_t g, +void ObjectRenderer::renderGeometry(Clump* model, size_t g, const glm::mat4& modelMatrix, float opacity, GameObject* object, RenderList& outList) { for (size_t sg = 0; sg < model->geometries[g]->subgeom.size(); ++sg) { - Model::SubGeometry& subgeom = model->geometries[g]->subgeom[sg]; + Clump::SubGeometry& subgeom = model->geometries[g]->subgeom[sg]; bool isTransparent = false; @@ -56,7 +56,7 @@ void ObjectRenderer::renderGeometry(Model* model, size_t g, } if (model->geometries[g]->materials.size() > subgeom.material) { - Model::Material& mat = + Clump::Material& mat = model->geometries[g]->materials[subgeom.material]; if (mat.textures.size() > 0) { @@ -107,7 +107,7 @@ void ObjectRenderer::renderGeometry(Model* model, size_t g, &model->geometries[g]->dbuff, dp); } } -bool ObjectRenderer::renderFrame(Model* m, ModelFrame* f, +bool ObjectRenderer::renderFrame(Clump* m, ModelFrame* f, const glm::mat4& matrix, GameObject* object, float opacity, RenderList& outList) { auto localmatrix = matrix; @@ -175,12 +175,12 @@ void ObjectRenderer::renderInstance(InstanceObject* instance, instance->getModel()->getBoundingRadius(); mindist *= 1.f / kDrawDistanceFactor; - Model* model = nullptr; + Clump* model = nullptr; ModelFrame* frame = nullptr; // These are used to gracefully fade out things that are just out of view // distance. - Model* fadingModel = nullptr; + Clump* fadingModel = nullptr; ModelFrame* fadingFrame = nullptr; auto fadingMatrix = matrixModel; float opacity = 0.f; diff --git a/rwengine/src/render/ObjectRenderer.hpp b/rwengine/src/render/ObjectRenderer.hpp index e8e9fb86..e06041ce 100644 --- a/rwengine/src/render/ObjectRenderer.hpp +++ b/rwengine/src/render/ObjectRenderer.hpp @@ -37,10 +37,10 @@ public: size_t culled; void buildRenderList(GameObject* object, RenderList& outList); - bool renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix, + bool renderFrame(Clump* m, ModelFrame* f, const glm::mat4& matrix, GameObject* object, float opacity, RenderList& outList); - void renderGeometry(Model* model, size_t g, const glm::mat4& modelMatrix, + void renderGeometry(Clump* model, size_t g, const glm::mat4& modelMatrix, float opacity, GameObject* object, RenderList& outList); private: diff --git a/rwgame/states/IngameState.cpp b/rwgame/states/IngameState.cpp index 15d26abd..747bd1ba 100644 --- a/rwgame/states/IngameState.cpp +++ b/rwgame/states/IngameState.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include #include diff --git a/rwlib/CMakeLists.txt b/rwlib/CMakeLists.txt index 02469696..d978b715 100644 --- a/rwlib/CMakeLists.txt +++ b/rwlib/CMakeLists.txt @@ -23,8 +23,8 @@ SET(RWLIB_SOURCES "source/platform/FileIndex.hpp" "source/platform/FileIndex.cpp" - "source/data/Model.hpp" - "source/data/Model.cpp" + "source/data/Clump.hpp" + "source/data/Clump.cpp" "source/loaders/LoaderIMG.hpp" "source/loaders/LoaderIMG.cpp" diff --git a/rwlib/source/data/Model.cpp b/rwlib/source/data/Clump.cpp similarity index 86% rename from rwlib/source/data/Model.cpp rename to rwlib/source/data/Clump.cpp index 3a7985ab..dc77fd1e 100644 --- a/rwlib/source/data/Model.cpp +++ b/rwlib/source/data/Clump.cpp @@ -1,12 +1,12 @@ -#include "data/Model.hpp" +#include "data/Clump.hpp" #include #include -Model::Geometry::Geometry() : flags(0) { +Clump::Geometry::Geometry() : flags(0) { } -Model::Geometry::~Geometry() { +Clump::Geometry::~Geometry() { } ModelFrame::ModelFrame(unsigned int index, ModelFrame* parent, glm::mat3 dR, @@ -30,13 +30,13 @@ void ModelFrame::addGeometry(size_t idx) { geometries.push_back(idx); } -Model::~Model() { +Clump::~Clump() { for (auto mf : frames) { delete mf; } } -void Model::recalculateMetrics() { +void Clump::recalculateMetrics() { boundingRadius = std::numeric_limits::min(); for (size_t g = 0; g < geometries.size(); g++) { RW::BSGeometryBounds& bounds = geometries[g]->geometryBounds; diff --git a/rwlib/source/data/Model.hpp b/rwlib/source/data/Clump.hpp similarity index 96% rename from rwlib/source/data/Model.hpp rename to rwlib/source/data/Clump.hpp index d2043a9d..221e8811 100644 --- a/rwlib/source/data/Model.hpp +++ b/rwlib/source/data/Clump.hpp @@ -76,10 +76,9 @@ public: }; /** - * Model stores all the data contained within a DFF, as well as data required - * to render them. + * A clump is a collection of Frames and Atomics */ -class Model { +class Clump { public: enum FaceType { Triangles = 0, TriangleStrip = 1 }; @@ -167,7 +166,7 @@ public: return fit != frames.end() ? *fit : nullptr; } - ~Model(); + ~Clump(); void recalculateMetrics(); diff --git a/rwlib/source/loaders/LoaderDFF.cpp b/rwlib/source/loaders/LoaderDFF.cpp index 1425d4f1..2000b80a 100644 --- a/rwlib/source/loaders/LoaderDFF.cpp +++ b/rwlib/source/loaders/LoaderDFF.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -40,7 +40,7 @@ struct RWBSFrame { uint32_t matrixflags; // Not used }; -void LoaderDFF::readFrameList(Model *model, const RWBStream &stream) { +void LoaderDFF::readFrameList(Clump *model, const RWBStream &stream) { auto listStream = stream.getInnerStream(); auto listStructID = listStream.getNextChunk(); @@ -102,7 +102,7 @@ void LoaderDFF::readFrameList(Model *model, const RWBStream &stream) { } } -void LoaderDFF::readGeometryList(Model *model, const RWBStream &stream) { +void LoaderDFF::readGeometryList(Clump *model, const RWBStream &stream) { auto listStream = stream.getInnerStream(); auto listStructID = listStream.getNextChunk(); @@ -129,7 +129,7 @@ void LoaderDFF::readGeometryList(Model *model, const RWBStream &stream) { } } -void LoaderDFF::readGeometry(Model *model, const RWBStream &stream) { +void LoaderDFF::readGeometry(Clump *model, const RWBStream &stream) { auto geomStream = stream.getInnerStream(); auto geomStructID = geomStream.getNextChunk(); @@ -137,7 +137,7 @@ void LoaderDFF::readGeometry(Model *model, const RWBStream &stream) { throw DFFLoaderException("Geometry missing struct chunk"); } - std::shared_ptr geom(new Model::Geometry); + std::shared_ptr geom(new Clump::Geometry); char *headerPtr = geomStream.getCursor(); @@ -156,7 +156,7 @@ void LoaderDFF::readGeometry(Model *model, const RWBStream &stream) { /*unsigned int numFrames = *(std::uint32_t*)headerPtr;*/ headerPtr += sizeof(std::uint32_t); - std::vector verts; + std::vector verts; verts.resize(numVerts); if (geomStream.getChunkVersion() < 0x1003FFFF) { @@ -235,7 +235,7 @@ void LoaderDFF::readGeometry(Model *model, const RWBStream &stream) { } geom->dbuff.setFaceType( - geom->facetype == Model::Triangles ? GL_TRIANGLES : GL_TRIANGLE_STRIP); + geom->facetype == Clump::Triangles ? GL_TRIANGLES : GL_TRIANGLE_STRIP); geom->gbuff.uploadVertices(verts); geom->dbuff.addGeometry(&geom->gbuff); @@ -244,7 +244,7 @@ void LoaderDFF::readGeometry(Model *model, const RWBStream &stream) { size_t icount = std::accumulate( geom->subgeom.begin(), geom->subgeom.end(), 0u, - [](size_t a, const Model::SubGeometry &b) { return a + b.numIndices; }); + [](size_t a, const Clump::SubGeometry &b) { return a + b.numIndices; }); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * icount, 0, GL_STATIC_DRAW); for (auto &sg : geom->subgeom) { @@ -253,7 +253,7 @@ void LoaderDFF::readGeometry(Model *model, const RWBStream &stream) { } } -void LoaderDFF::readMaterialList(Model *model, const RWBStream &stream) { +void LoaderDFF::readMaterialList(Clump *model, const RWBStream &stream) { auto listStream = stream.getInnerStream(); auto listStructID = listStream.getNextChunk(); @@ -277,7 +277,7 @@ void LoaderDFF::readMaterialList(Model *model, const RWBStream &stream) { } } -void LoaderDFF::readMaterial(Model *model, const RWBStream &stream) { +void LoaderDFF::readMaterial(Clump *model, const RWBStream &stream) { auto materialStream = stream.getInnerStream(); auto matStructID = materialStream.getNextChunk(); @@ -287,7 +287,7 @@ void LoaderDFF::readMaterial(Model *model, const RWBStream &stream) { char *matData = materialStream.getCursor(); - Model::Material material; + Clump::Material material; // Unkown matData += sizeof(std::uint32_t); @@ -320,7 +320,7 @@ void LoaderDFF::readMaterial(Model *model, const RWBStream &stream) { } } -void LoaderDFF::readTexture(Model *model, const RWBStream &stream) { +void LoaderDFF::readTexture(Clump *model, const RWBStream &stream) { auto texStream = stream.getInnerStream(); auto texStructID = texStream.getNextChunk(); @@ -347,7 +347,7 @@ void LoaderDFF::readTexture(Model *model, const RWBStream &stream) { {name, alpha, textureinst}); } -void LoaderDFF::readGeometryExtension(Model *model, const RWBStream &stream) { +void LoaderDFF::readGeometryExtension(Clump *model, const RWBStream &stream) { auto extStream = stream.getInnerStream(); RWBStream::ChunkID chunkID; @@ -362,11 +362,11 @@ void LoaderDFF::readGeometryExtension(Model *model, const RWBStream &stream) { } } -void LoaderDFF::readBinMeshPLG(Model *model, const RWBStream &stream) { +void LoaderDFF::readBinMeshPLG(Clump *model, const RWBStream &stream) { auto data = stream.getCursor(); model->geometries.back()->facetype = - static_cast(*(std::uint32_t *)data); + static_cast(*(std::uint32_t *)data); data += sizeof(std::uint32_t); unsigned int numSplits = *(std::uint32_t *)data; @@ -380,7 +380,7 @@ void LoaderDFF::readBinMeshPLG(Model *model, const RWBStream &stream) { size_t start = 0; for (size_t s = 0; s < numSplits; ++s) { - Model::SubGeometry sg; + Clump::SubGeometry sg; sg.numIndices = *(std::uint32_t *)data; data += sizeof(std::uint32_t); sg.material = *(std::uint32_t *)data; @@ -397,7 +397,7 @@ void LoaderDFF::readBinMeshPLG(Model *model, const RWBStream &stream) { } } -void LoaderDFF::readAtomic(Model *model, const RWBStream &stream) { +void LoaderDFF::readAtomic(Clump *model, const RWBStream &stream) { auto atomicStream = stream.getInnerStream(); auto atomicStructID = atomicStream.getNextChunk(); @@ -405,7 +405,7 @@ void LoaderDFF::readAtomic(Model *model, const RWBStream &stream) { throw DFFLoaderException("Atomic missing struct chunk"); } - Model::Atomic atom; + Clump::Atomic atom; auto data = atomicStream.getCursor(); atom.frame = *(std::uint32_t *)data; data += sizeof(std::uint32_t); @@ -416,8 +416,8 @@ void LoaderDFF::readAtomic(Model *model, const RWBStream &stream) { /// @todo are any atomic extensions important? } -Model *LoaderDFF::loadFromMemory(FileHandle file) { - auto model = new Model; +Clump *LoaderDFF::loadFromMemory(FileHandle file) { + auto model = new Clump; RWBStream rootStream(file->data, file->length); diff --git a/rwlib/source/loaders/LoaderDFF.hpp b/rwlib/source/loaders/LoaderDFF.hpp index 828b927f..573d82ef 100644 --- a/rwlib/source/loaders/LoaderDFF.hpp +++ b/rwlib/source/loaders/LoaderDFF.hpp @@ -9,7 +9,7 @@ #include #include -class Model; +class Clump; class DFFLoaderException { std::string _message; @@ -29,29 +29,29 @@ class LoaderDFF { * @param model * @param stream */ - void readFrameList(Model* model, const RWBStream& stream); + void readFrameList(Clump* model, const RWBStream& stream); - void readGeometryList(Model* model, const RWBStream& stream); + void readGeometryList(Clump* model, const RWBStream& stream); - void readGeometry(Model* model, const RWBStream& stream); + void readGeometry(Clump* model, const RWBStream& stream); - void readMaterialList(Model* model, const RWBStream& stream); + void readMaterialList(Clump* model, const RWBStream& stream); - void readMaterial(Model* model, const RWBStream& stream); + void readMaterial(Clump* model, const RWBStream& stream); - void readTexture(Model* model, const RWBStream& stream); + void readTexture(Clump* model, const RWBStream& stream); - void readGeometryExtension(Model* model, const RWBStream& stream); + void readGeometryExtension(Clump* model, const RWBStream& stream); - void readBinMeshPLG(Model* model, const RWBStream& stream); + void readBinMeshPLG(Clump* model, const RWBStream& stream); - void readAtomic(Model* model, const RWBStream& stream); + void readAtomic(Clump* model, const RWBStream& stream); public: using TextureLookupCallback = std::function; - Model* loadFromMemory(FileHandle file); + Clump* loadFromMemory(FileHandle file); void setTextureLookupCallback(TextureLookupCallback tlc) { texturelookup = tlc; diff --git a/rwviewer/ViewerWidget.cpp b/rwviewer/ViewerWidget.cpp index fcd863a0..3bfd6080 100644 --- a/rwviewer/ViewerWidget.cpp +++ b/rwviewer/ViewerWidget.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include @@ -103,7 +103,7 @@ void ViewerWidget::paintGL() { vc.frustum.fov = viewFov; vc.frustum.aspectRatio = width() / (height() * 1.f); - Model* model = activeModel; + Clump* model = activeModel; if (model != _lastModel) { _lastModel = model; emit modelChanged(_lastModel); @@ -197,7 +197,7 @@ void ViewerWidget::showObject(qint16 item) { } } -void ViewerWidget::showModel(Model* model) { +void ViewerWidget::showModel(Clump* model) { if (dummyObject) gworld->destroyObject(dummyObject); dummyObject = nullptr; activeModel = model; @@ -259,7 +259,7 @@ void ViewerWidget::keyReleaseEvent(QKeyEvent* e) { if (e->key() == Qt::Key_Shift) moveFast = false; } -Model* ViewerWidget::currentModel() const { +Clump* ViewerWidget::currentModel() const { return activeModel; } diff --git a/rwviewer/ViewerWidget.hpp b/rwviewer/ViewerWidget.hpp index 6911c7d1..ba216814 100644 --- a/rwviewer/ViewerWidget.hpp +++ b/rwviewer/ViewerWidget.hpp @@ -2,7 +2,7 @@ #ifndef _VIEWERWIDGET_HPP_ #define _VIEWERWIDGET_HPP_ #include -#include +#include #include #include #include @@ -16,7 +16,7 @@ #include class GameRenderer; -class Model; +class Clump; class ViewerWidget : public QGLWidget { Q_OBJECT @@ -27,12 +27,12 @@ class ViewerWidget : public QGLWidget { QTimer timer; GameWorld* gworld; - Model* activeModel; + Clump* activeModel; ModelFrame* selectedFrame; GameObject* dummyObject; quint16 currentObjectID; - Model* _lastModel; + Clump* _lastModel; Animation* canimation; float viewDistance; @@ -60,7 +60,7 @@ public: virtual void paintGL(); - Model* currentModel() const; + Clump* currentModel() const; GameObject* currentObject() const; GameWorld* world(); @@ -68,7 +68,7 @@ public: public slots: void showObject(qint16 item); - void showModel(Model* model); + void showModel(Clump* model); void selectFrame(ModelFrame* frame); void exportModel(); @@ -81,7 +81,7 @@ signals: void fileOpened(const QString& file); - void modelChanged(Model* model); + void modelChanged(Clump* model); protected: void keyPressEvent(QKeyEvent*) override; diff --git a/rwviewer/models/DFFFramesTreeModel.cpp b/rwviewer/models/DFFFramesTreeModel.cpp index bb202cc3..3769bc94 100644 --- a/rwviewer/models/DFFFramesTreeModel.cpp +++ b/rwviewer/models/DFFFramesTreeModel.cpp @@ -1,8 +1,8 @@ #include "DFFFramesTreeModel.hpp" -#include +#include #include -DFFFramesTreeModel::DFFFramesTreeModel(Model* m, Skeleton* skel, +DFFFramesTreeModel::DFFFramesTreeModel(Clump* m, Skeleton* skel, QObject* parent) : QAbstractItemModel(parent), model(m), skeleton(skel) { } diff --git a/rwviewer/models/DFFFramesTreeModel.hpp b/rwviewer/models/DFFFramesTreeModel.hpp index d839dfbe..236578c7 100644 --- a/rwviewer/models/DFFFramesTreeModel.hpp +++ b/rwviewer/models/DFFFramesTreeModel.hpp @@ -4,15 +4,15 @@ #include #include -class Model; +class Clump; class Skeleton; class DFFFramesTreeModel : public QAbstractItemModel { - Model* model; + Clump* model; Skeleton* skeleton; public: - explicit DFFFramesTreeModel(Model* m, Skeleton* skel, QObject* parent = 0); + explicit DFFFramesTreeModel(Clump* m, Skeleton* skel, QObject* parent = 0); virtual int columnCount(const QModelIndex& parent = QModelIndex()) const; diff --git a/rwviewer/views/ModelViewer.cpp b/rwviewer/views/ModelViewer.cpp index 4ba8df6f..2baecf28 100644 --- a/rwviewer/views/ModelViewer.cpp +++ b/rwviewer/views/ModelViewer.cpp @@ -40,7 +40,7 @@ void ModelViewer::setViewerWidget(ViewerWidget* widget) { showModel(viewing); } -void ModelViewer::showModel(Model* model) { +void ModelViewer::showModel(Clump* model) { viewing = model; if (skeleton) { delete skeleton; diff --git a/rwviewer/views/ModelViewer.hpp b/rwviewer/views/ModelViewer.hpp index 1b08ba79..7154d248 100644 --- a/rwviewer/views/ModelViewer.hpp +++ b/rwviewer/views/ModelViewer.hpp @@ -14,7 +14,7 @@ #include class ViewerWidget; -class Model; +class Clump; class Skeleton; class ModelFramesWidget; class Animation; @@ -22,7 +22,7 @@ class Animation; class ModelViewer : public ViewerInterface { Q_OBJECT - Model* viewing; + Clump* viewing; Skeleton* skeleton; QSplitter* mainSplit; @@ -45,7 +45,7 @@ public slots: /** * Display a raw model */ - void showModel(Model* model); + void showModel(Clump* model); /** * Display a game object's model diff --git a/rwviewer/views/ObjectViewer.hpp b/rwviewer/views/ObjectViewer.hpp index b5d5773f..f7418cf4 100644 --- a/rwviewer/views/ObjectViewer.hpp +++ b/rwviewer/views/ObjectViewer.hpp @@ -12,7 +12,7 @@ #include class ViewerWidget; -class Model; +class Clump; class ObjectViewer : public ViewerInterface { Q_OBJECT @@ -40,7 +40,7 @@ protected: signals: - void modelChanged(Model* model); + void modelChanged(Clump* model); void showObjectModel(uint16_t object); diff --git a/rwviewer/widgets/ModelFramesWidget.cpp b/rwviewer/widgets/ModelFramesWidget.cpp index 98c8e437..72c5c30c 100644 --- a/rwviewer/widgets/ModelFramesWidget.cpp +++ b/rwviewer/widgets/ModelFramesWidget.cpp @@ -1,8 +1,8 @@ #include "ModelFramesWidget.hpp" -#include +#include #include -void ModelFramesWidget::updateInfoBox(Model* model, ModelFrame* f) { +void ModelFramesWidget::updateInfoBox(Clump* model, ModelFrame* f) { if (f == nullptr) { _frameLabel->setText(""); } else { @@ -14,8 +14,8 @@ void ModelFramesWidget::updateInfoBox(Model* model, ModelFrame* f) { for (size_t gi : f->getGeometries()) { auto& g = model->geometries[gi]; // for(Model::SubGeometry& sg : g->subgeom) - for (Model::Material& m : g->materials) { - for (Model::Texture& t : m.textures) { + for (Clump::Material& m : g->materials) { + for (Clump::Texture& t : m.textures) { geomString += QString("\n %1 (%2)") .arg(t.name.c_str()) .arg(t.alphaName.c_str()); @@ -46,7 +46,7 @@ ModelFramesWidget::ModelFramesWidget(QWidget* parent, Qt::WindowFlags flags) setLayout(_layout); } -void ModelFramesWidget::setModel(Model* model, Skeleton* skeleton) { +void ModelFramesWidget::setModel(Clump* model, Skeleton* skeleton) { if (framemodel) { delete framemodel; framemodel = nullptr; diff --git a/rwviewer/widgets/ModelFramesWidget.hpp b/rwviewer/widgets/ModelFramesWidget.hpp index 1bf17861..cdc96907 100644 --- a/rwviewer/widgets/ModelFramesWidget.hpp +++ b/rwviewer/widgets/ModelFramesWidget.hpp @@ -13,7 +13,7 @@ class ModelFrame; class ModelFramesWidget : public QWidget { Q_OBJECT - Model* gmodel; + Clump* gmodel; DFFFramesTreeModel* framemodel; QTreeView* tree; QVBoxLayout* _layout; @@ -21,7 +21,7 @@ class ModelFramesWidget : public QWidget { private slots: - void updateInfoBox(Model* model, ModelFrame* f); + void updateInfoBox(Clump* model, ModelFrame* f); void selectedModelChanged(const QModelIndex&, const QModelIndex&); @@ -30,7 +30,7 @@ public: public slots: - void setModel(Model* model, Skeleton* skeleton); + void setModel(Clump* model, Skeleton* skeleton); signals: diff --git a/tests/test_animation.cpp b/tests/test_animation.cpp index b4d2654d..a4308c4d 100644 --- a/tests/test_animation.cpp +++ b/tests/test_animation.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include diff --git a/tests/test_loaderdff.cpp b/tests/test_loaderdff.cpp index ff8f2317..ea7773c0 100644 --- a/tests/test_loaderdff.cpp +++ b/tests/test_loaderdff.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "test_globals.hpp" BOOST_AUTO_TEST_SUITE(LoaderDFFTests) @@ -11,7 +11,7 @@ BOOST_AUTO_TEST_CASE(test_load_dff) { LoaderDFF loader; - Model* m = loader.loadFromMemory(d); + Clump* m = loader.loadFromMemory(d); BOOST_REQUIRE(m != nullptr); @@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(test_load_dff) { BOOST_REQUIRE(m->atomics.size() > 0); - for (Model::Atomic& a : m->atomics) { + for (Clump::Atomic& a : m->atomics) { BOOST_CHECK(a.frame < m->frames.size()); BOOST_CHECK(a.geometry < m->geometries.size()); } diff --git a/tests/test_vehicle.cpp b/tests/test_vehicle.cpp index 1fb1a9ad..69d79c8e 100644 --- a/tests/test_vehicle.cpp +++ b/tests/test_vehicle.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include "test_globals.hpp" From a0eaf5b8b02d304eee2c158669528418839446c9 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Tue, 3 Jan 2017 16:21:21 +0000 Subject: [PATCH 02/19] Move Atomic and Geometry out of Clump class --- rwengine/src/render/DebugDraw.hpp | 2 +- rwengine/src/render/GameRenderer.cpp | 4 +- rwengine/src/render/ObjectRenderer.cpp | 4 +- rwlib/source/data/Clump.cpp | 4 +- rwlib/source/data/Clump.hpp | 102 ++++++++++++++----------- rwlib/source/loaders/LoaderDFF.cpp | 16 ++-- rwviewer/widgets/ModelFramesWidget.cpp | 4 +- tests/test_loaderdff.cpp | 2 +- 8 files changed, 74 insertions(+), 64 deletions(-) diff --git a/rwengine/src/render/DebugDraw.hpp b/rwengine/src/render/DebugDraw.hpp index d4e2b386..3c2ad88e 100644 --- a/rwengine/src/render/DebugDraw.hpp +++ b/rwengine/src/render/DebugDraw.hpp @@ -28,7 +28,7 @@ public: protected: int debugMode; - std::vector lines; + std::vector lines; size_t maxlines; GeometryBuffer *lineBuff; DrawBuffer *dbuff; diff --git a/rwengine/src/render/GameRenderer.cpp b/rwengine/src/render/GameRenderer.cpp index d9a860bb..4ce4dc93 100644 --- a/rwengine/src/render/GameRenderer.cpp +++ b/rwengine/src/render/GameRenderer.cpp @@ -479,7 +479,7 @@ void GameRenderer::renderGeometry(Clump* model, size_t g, const glm::mat4& modelMatrix, float opacity, GameObject* object) { for (size_t sg = 0; sg < model->geometries[g]->subgeom.size(); ++sg) { - Clump::SubGeometry& subgeom = model->geometries[g]->subgeom[sg]; + SubGeometry& subgeom = model->geometries[g]->subgeom[sg]; Renderer::DrawParameters dp; @@ -489,7 +489,7 @@ void GameRenderer::renderGeometry(Clump* model, size_t g, dp.textures = {0}; if (model->geometries[g]->materials.size() > subgeom.material) { - Clump::Material& mat = + Geometry::Material& mat = model->geometries[g]->materials[subgeom.material]; if (mat.textures.size() > 0) { diff --git a/rwengine/src/render/ObjectRenderer.cpp b/rwengine/src/render/ObjectRenderer.cpp index 7e3027d4..2e9dbd73 100644 --- a/rwengine/src/render/ObjectRenderer.cpp +++ b/rwengine/src/render/ObjectRenderer.cpp @@ -37,7 +37,7 @@ void ObjectRenderer::renderGeometry(Clump* model, size_t g, const glm::mat4& modelMatrix, float opacity, GameObject* object, RenderList& outList) { for (size_t sg = 0; sg < model->geometries[g]->subgeom.size(); ++sg) { - Clump::SubGeometry& subgeom = model->geometries[g]->subgeom[sg]; + SubGeometry& subgeom = model->geometries[g]->subgeom[sg]; bool isTransparent = false; @@ -56,7 +56,7 @@ void ObjectRenderer::renderGeometry(Clump* model, size_t g, } if (model->geometries[g]->materials.size() > subgeom.material) { - Clump::Material& mat = + Geometry::Material& mat = model->geometries[g]->materials[subgeom.material]; if (mat.textures.size() > 0) { diff --git a/rwlib/source/data/Clump.cpp b/rwlib/source/data/Clump.cpp index dc77fd1e..c112633c 100644 --- a/rwlib/source/data/Clump.cpp +++ b/rwlib/source/data/Clump.cpp @@ -3,10 +3,10 @@ #include -Clump::Geometry::Geometry() : flags(0) { +Geometry::Geometry() : flags(0) { } -Clump::Geometry::~Geometry() { +Geometry::~Geometry() { } ModelFrame::ModelFrame(unsigned int index, ModelFrame* parent, glm::mat3 dR, diff --git a/rwlib/source/data/Clump.hpp b/rwlib/source/data/Clump.hpp index 221e8811..0117efdb 100644 --- a/rwlib/source/data/Clump.hpp +++ b/rwlib/source/data/Clump.hpp @@ -76,13 +76,37 @@ public: }; /** - * A clump is a collection of Frames and Atomics + * Subgeometry */ -class Clump { -public: - enum FaceType { Triangles = 0, TriangleStrip = 1 }; - std::uint32_t numAtomics; +struct SubGeometry { + GLuint start = 0; + size_t material = 0; + std::vector indices; + size_t numIndices = 0; +}; + +struct GeometryVertex { + glm::vec3 position; /* 0 */ + glm::vec3 normal; /* 24 */ + glm::vec2 texcoord; /* 48 */ + glm::u8vec4 colour; /* 64 */ + + /** @see GeometryBuffer */ + static const AttributeList vertex_attributes() { + return {{ATRS_Position, 3, sizeof(GeometryVertex), 0ul}, + {ATRS_Normal, 3, sizeof(GeometryVertex), sizeof(float) * 3}, + {ATRS_TexCoord, 2, sizeof(GeometryVertex), sizeof(float) * 6}, + {ATRS_Colour, 4, sizeof(GeometryVertex), sizeof(float) * 8, + GL_UNSIGNED_BYTE}}; + } +}; + +/** + * Geometry + */ +struct Geometry { + enum FaceType { Triangles = 0, TriangleStrip = 1 }; struct Texture { std::string name; @@ -102,58 +126,44 @@ public: float ambientIntensity; }; - struct SubGeometry { - GLuint start = 0; - size_t material; - std::vector indices; - size_t numIndices; - }; + DrawBuffer dbuff; + GeometryBuffer gbuff; - struct GeometryVertex { - glm::vec3 position; /* 0 */ - glm::vec3 normal; /* 24 */ - glm::vec2 texcoord; /* 48 */ - glm::u8vec4 colour; /* 64 */ + GLuint EBO; - /** @see GeometryBuffer */ - static const AttributeList vertex_attributes() { - return { - {ATRS_Position, 3, sizeof(GeometryVertex), 0ul}, - {ATRS_Normal, 3, sizeof(GeometryVertex), sizeof(float) * 3}, - {ATRS_TexCoord, 2, sizeof(GeometryVertex), sizeof(float) * 6}, - {ATRS_Colour, 4, sizeof(GeometryVertex), sizeof(float) * 8, - GL_UNSIGNED_BYTE}}; - } - }; + RW::BSGeometryBounds geometryBounds; - struct Geometry { - DrawBuffer dbuff; - GeometryBuffer gbuff; + uint32_t clumpNum; - GLuint EBO; + FaceType facetype; - RW::BSGeometryBounds geometryBounds; + uint32_t flags; - uint32_t clumpNum; + std::vector materials; + std::vector subgeom; - FaceType facetype; + Geometry(); + ~Geometry(); +}; - uint32_t flags; +/** + * @brief The Atomic struct + */ +struct Atomic { + uint32_t frame; + uint32_t geometry; +}; - std::vector materials; - std::vector subgeom; - - Geometry(); - ~Geometry(); - }; - - struct Atomic { - uint32_t frame; - uint32_t geometry; - }; +/** + * A clump is a collection of Frames and Atomics + */ +class Clump { +public: + std::uint32_t numAtomics; + // This should be gone std::vector frames; - /** @TODO clean up this mess a little */ + // This should be gone std::vector> geometries; std::vector atomics; diff --git a/rwlib/source/loaders/LoaderDFF.cpp b/rwlib/source/loaders/LoaderDFF.cpp index 2000b80a..94be9f54 100644 --- a/rwlib/source/loaders/LoaderDFF.cpp +++ b/rwlib/source/loaders/LoaderDFF.cpp @@ -137,7 +137,7 @@ void LoaderDFF::readGeometry(Clump *model, const RWBStream &stream) { throw DFFLoaderException("Geometry missing struct chunk"); } - std::shared_ptr geom(new Clump::Geometry); + std::shared_ptr geom(new Geometry); char *headerPtr = geomStream.getCursor(); @@ -156,7 +156,7 @@ void LoaderDFF::readGeometry(Clump *model, const RWBStream &stream) { /*unsigned int numFrames = *(std::uint32_t*)headerPtr;*/ headerPtr += sizeof(std::uint32_t); - std::vector verts; + std::vector verts; verts.resize(numVerts); if (geomStream.getChunkVersion() < 0x1003FFFF) { @@ -235,7 +235,7 @@ void LoaderDFF::readGeometry(Clump *model, const RWBStream &stream) { } geom->dbuff.setFaceType( - geom->facetype == Clump::Triangles ? GL_TRIANGLES : GL_TRIANGLE_STRIP); + geom->facetype == Geometry::Triangles ? GL_TRIANGLES : GL_TRIANGLE_STRIP); geom->gbuff.uploadVertices(verts); geom->dbuff.addGeometry(&geom->gbuff); @@ -244,7 +244,7 @@ void LoaderDFF::readGeometry(Clump *model, const RWBStream &stream) { size_t icount = std::accumulate( geom->subgeom.begin(), geom->subgeom.end(), 0u, - [](size_t a, const Clump::SubGeometry &b) { return a + b.numIndices; }); + [](size_t a, const SubGeometry &b) { return a + b.numIndices; }); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * icount, 0, GL_STATIC_DRAW); for (auto &sg : geom->subgeom) { @@ -287,7 +287,7 @@ void LoaderDFF::readMaterial(Clump *model, const RWBStream &stream) { char *matData = materialStream.getCursor(); - Clump::Material material; + Geometry::Material material; // Unkown matData += sizeof(std::uint32_t); @@ -366,7 +366,7 @@ void LoaderDFF::readBinMeshPLG(Clump *model, const RWBStream &stream) { auto data = stream.getCursor(); model->geometries.back()->facetype = - static_cast(*(std::uint32_t *)data); + static_cast(*(std::uint32_t *)data); data += sizeof(std::uint32_t); unsigned int numSplits = *(std::uint32_t *)data; @@ -380,7 +380,7 @@ void LoaderDFF::readBinMeshPLG(Clump *model, const RWBStream &stream) { size_t start = 0; for (size_t s = 0; s < numSplits; ++s) { - Clump::SubGeometry sg; + SubGeometry sg; sg.numIndices = *(std::uint32_t *)data; data += sizeof(std::uint32_t); sg.material = *(std::uint32_t *)data; @@ -405,7 +405,7 @@ void LoaderDFF::readAtomic(Clump *model, const RWBStream &stream) { throw DFFLoaderException("Atomic missing struct chunk"); } - Clump::Atomic atom; + Atomic atom; auto data = atomicStream.getCursor(); atom.frame = *(std::uint32_t *)data; data += sizeof(std::uint32_t); diff --git a/rwviewer/widgets/ModelFramesWidget.cpp b/rwviewer/widgets/ModelFramesWidget.cpp index 72c5c30c..480348ea 100644 --- a/rwviewer/widgets/ModelFramesWidget.cpp +++ b/rwviewer/widgets/ModelFramesWidget.cpp @@ -14,8 +14,8 @@ void ModelFramesWidget::updateInfoBox(Clump* model, ModelFrame* f) { for (size_t gi : f->getGeometries()) { auto& g = model->geometries[gi]; // for(Model::SubGeometry& sg : g->subgeom) - for (Clump::Material& m : g->materials) { - for (Clump::Texture& t : m.textures) { + for (Geometry::Material& m : g->materials) { + for (Geometry::Texture& t : m.textures) { geomString += QString("\n %1 (%2)") .arg(t.name.c_str()) .arg(t.alphaName.c_str()); diff --git a/tests/test_loaderdff.cpp b/tests/test_loaderdff.cpp index ea7773c0..caaf2a4a 100644 --- a/tests/test_loaderdff.cpp +++ b/tests/test_loaderdff.cpp @@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(test_load_dff) { BOOST_REQUIRE(m->atomics.size() > 0); - for (Clump::Atomic& a : m->atomics) { + for (auto& a : m->atomics) { BOOST_CHECK(a.frame < m->frames.size()); BOOST_CHECK(a.geometry < m->geometries.size()); } From 34c70b0be2c88c4e6541c7c4de466dcc12b64cab Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Wed, 4 Jan 2017 21:08:21 +0000 Subject: [PATCH 03/19] Allow ModelFrame, Atomic, Geometry to exist outside of a Clump This changes the Clump data structure to simplify it and move some of the concerns into the Atomic and Frame types. --- rwlib/source/data/Clump.cpp | 67 +++++++++++--- rwlib/source/data/Clump.hpp | 135 +++++++++++++++++++-------- rwlib/source/loaders/LoaderDFF.cpp | 144 ++++++++++++++++++----------- rwlib/source/loaders/LoaderDFF.hpp | 48 +++++----- tests/test_loaderdff.cpp | 19 +--- 5 files changed, 269 insertions(+), 144 deletions(-) diff --git a/rwlib/source/data/Clump.cpp b/rwlib/source/data/Clump.cpp index c112633c..c12eb471 100644 --- a/rwlib/source/data/Clump.cpp +++ b/rwlib/source/data/Clump.cpp @@ -9,37 +9,78 @@ Geometry::Geometry() : flags(0) { Geometry::~Geometry() { } -ModelFrame::ModelFrame(unsigned int index, ModelFrame* parent, glm::mat3 dR, - glm::vec3 dT) +ModelFrame::ModelFrame(unsigned int index, glm::mat3 dR, glm::vec3 dT) : index(index) , defaultRotation(dR) , defaultTranslation(dT) - , parentFrame(parent) { - if (parent != nullptr) { - parent->childs.push_back(this); - } + , parent_(nullptr) { reset(); } void ModelFrame::reset() { matrix = glm::translate(glm::mat4(), defaultTranslation) * glm::mat4(defaultRotation); + updateHierarchyTransform(); } -void ModelFrame::addGeometry(size_t idx) { - geometries.push_back(idx); +void ModelFrame::updateHierarchyTransform() { + // Update our own transformation + if (parent_) { + worldtransform_ = parent_->getWorldTransform() * matrix; + } else { + worldtransform_ = matrix; + } + for (const auto& child : children_) { + child->updateHierarchyTransform(); + } +} + +void ModelFrame::addChild(ModelFramePtr& child) { + // Make sure the child is an orphan + if (child->getParent()) { + auto& other_children = child->getParent()->children_; + other_children.erase( + std::remove(other_children.begin(), other_children.end(), child), + other_children.end()); + } + child->parent_ = this; + children_.push_back(child); +} + +ModelFrame* ModelFrame::findDescendant(const std::string& name) const { + for (const auto& frame : children_) { + if (frame->getName() == name) { + return frame.get(); + } + + auto result = frame->findDescendant(name); + if (result) { + return result; + } + } + + return nullptr; +} + +ModelFrame* Clump::findFrame(const std::string& name) const { + if (rootframe_->getName() == name) { + return rootframe_.get(); + } + + return rootframe_->findDescendant(name); } Clump::~Clump() { - for (auto mf : frames) { - delete mf; - } } void Clump::recalculateMetrics() { boundingRadius = std::numeric_limits::min(); - for (size_t g = 0; g < geometries.size(); g++) { - RW::BSGeometryBounds& bounds = geometries[g]->geometryBounds; + for (const auto& atomic : atomics_) { + const auto& geometry = atomic->getGeometry(); + if (!geometry) { + continue; + } + const auto& bounds = geometry->geometryBounds; boundingRadius = std::max(boundingRadius, glm::length(bounds.center) + bounds.radius); } diff --git a/rwlib/source/data/Clump.hpp b/rwlib/source/data/Clump.hpp index 0117efdb..d01658d3 100644 --- a/rwlib/source/data/Clump.hpp +++ b/rwlib/source/data/Clump.hpp @@ -12,26 +12,43 @@ #include #include +// Forward Declerations +class ModelFrame; +struct Geometry; +class Atomic; +class Clump; + +// Pointer types +using ModelFramePtr = std::shared_ptr; +using GeometryPtr = std::shared_ptr; +using AtomicPtr = std::shared_ptr; +using AtomicList = std::vector; +using ClumpPtr = std::shared_ptr; + /** - * ModelFrame stores the hierarchy of a model's geometry as well as default - * transformations. + * ModelFrame stores transformation hierarchy */ class ModelFrame { unsigned int index; glm::mat3 defaultRotation; glm::vec3 defaultTranslation; glm::mat4 matrix; - ModelFrame* parentFrame; + glm::mat4 worldtransform_; + ModelFrame* parent_; std::string name; - std::vector geometries; - std::vector childs; + std::vector children_; public: - ModelFrame(unsigned int index, ModelFrame* parent, glm::mat3 dR, - glm::vec3 dT); + ModelFrame(unsigned int index = 0, glm::mat3 dR = glm::mat3(), + glm::vec3 dT = glm::vec3()); void reset(); - void setTransform(const glm::mat4& m); + + void setTransform(const glm::mat4& m) { + matrix = m; + updateHierarchyTransform(); + } + const glm::mat4& getTransform() const { return matrix; } @@ -40,8 +57,6 @@ public: name = fname; } - void addGeometry(size_t idx); - unsigned int getIndex() const { return index; } @@ -54,25 +69,45 @@ public: return defaultRotation; } - glm::mat4 getMatrix() const { - return (parentFrame ? parentFrame->getMatrix() : glm::mat4()) * matrix; + void setTranslation(const glm::vec3& t) { + matrix[3] = glm::vec4(t, matrix[3][3]); + updateHierarchyTransform(); + } + + void setRotation(const glm::mat3& r) { + for (unsigned int i = 0; i < 3; i++) { + matrix[i] = glm::vec4(r[i], matrix[i][3]); + } + updateHierarchyTransform(); + } + + /** + * Updates the cached matrix + */ + void updateHierarchyTransform(); + + /** + * @return the cached world transformation for this Frame + */ + const glm::mat4& getWorldTransform() const { + return worldtransform_; } ModelFrame* getParent() const { - return parentFrame; + return parent_; } - const std::vector& getChildren() const { - return childs; + void addChild(ModelFramePtr& child); + + const std::vector& getChildren() const { + return children_; } const std::string& getName() const { return name; } - const std::vector& getGeometries() const { - return geometries; - } + ModelFrame* findDescendant(const std::string& name) const; }; /** @@ -149,9 +184,27 @@ struct Geometry { /** * @brief The Atomic struct */ -struct Atomic { - uint32_t frame; - uint32_t geometry; +class Atomic { + ModelFramePtr frame_; + GeometryPtr geometry_; + +public: + + void setFrame(ModelFramePtr& frame) { + frame_ = frame; + } + + const ModelFramePtr& getFrame() const { + return frame_; + } + + void setGeometry(GeometryPtr& geom) { + geometry_ = geom; + } + + const GeometryPtr& getGeometry() const { + return geometry_; + } }; /** @@ -159,22 +212,12 @@ struct Atomic { */ class Clump { public: - std::uint32_t numAtomics; - - // This should be gone - std::vector frames; - // This should be gone - std::vector> geometries; - std::vector atomics; - - int32_t rootFrameIdx; - - ModelFrame* findFrame(const std::string& name) const { - auto fit = - std::find_if(frames.begin(), frames.end(), - [&](ModelFrame* f) { return f->getName() == name; }); - return fit != frames.end() ? *fit : nullptr; - } + /** + * @brief findFrame Locates frame with name anywhere in the hierarchy + * @param name + * @return + */ + ModelFrame* findFrame(const std::string& name) const; ~Clump(); @@ -184,8 +227,26 @@ public: return boundingRadius; } + void addAtomic(AtomicPtr& atomic) { + atomics_.push_back(atomic); + } + + const AtomicList& getAtomics() const { + return atomics_; + } + + void setFrame(ModelFramePtr& root) { + rootframe_ = root; + } + + const ModelFramePtr& getFrame() const { + return rootframe_; + } + private: float boundingRadius; + AtomicList atomics_; + ModelFramePtr rootframe_; }; #endif diff --git a/rwlib/source/loaders/LoaderDFF.cpp b/rwlib/source/loaders/LoaderDFF.cpp index 94be9f54..72f7a4b9 100644 --- a/rwlib/source/loaders/LoaderDFF.cpp +++ b/rwlib/source/loaders/LoaderDFF.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -40,7 +41,7 @@ struct RWBSFrame { uint32_t matrixflags; // Not used }; -void LoaderDFF::readFrameList(Clump *model, const RWBStream &stream) { +LoaderDFF::FrameList LoaderDFF::readFrameList(const RWBStream &stream) { auto listStream = stream.getInnerStream(); auto listStructID = listStream.getNextChunk(); @@ -53,21 +54,22 @@ void LoaderDFF::readFrameList(Clump *model, const RWBStream &stream) { unsigned int numFrames = *(std::uint32_t *)headerPtr; headerPtr += sizeof(std::uint32_t); - model->frames.reserve(numFrames); + FrameList framelist; + framelist.reserve(numFrames); for (size_t f = 0; f < numFrames; ++f) { auto data = (RWBSFrame *)headerPtr; headerPtr += sizeof(RWBSFrame); + auto frame = + std::make_shared(f, data->rotation, data->position); - ModelFrame *parent = nullptr; - if (data->index != -1) { - parent = model->frames[data->index]; - } else { - model->rootFrameIdx = f; + RW_CHECK(data->index < int(framelist.size()), + "Frame parent out of bounds"); + if (data->index != -1 && data->index < int(framelist.size())) { + framelist[data->index]->addChild(frame); } - auto frame = new ModelFrame(f, parent, data->rotation, data->position); - model->frames.push_back(frame); + framelist.push_back(frame); } size_t namedFrames = 0; @@ -87,8 +89,8 @@ void LoaderDFF::readFrameList(Clump *model, const RWBStream &stream) { std::transform(fname.begin(), fname.end(), fname.begin(), ::tolower); - if (namedFrames < model->frames.size()) { - model->frames[namedFrames++]->setName(fname); + if (namedFrames < framelist.size()) { + framelist[namedFrames++]->setName(fname); } } break; default: @@ -100,9 +102,11 @@ void LoaderDFF::readFrameList(Clump *model, const RWBStream &stream) { break; } } + + return framelist; } -void LoaderDFF::readGeometryList(Clump *model, const RWBStream &stream) { +LoaderDFF::GeometryList LoaderDFF::readGeometryList(const RWBStream &stream) { auto listStream = stream.getInnerStream(); auto listStructID = listStream.getNextChunk(); @@ -115,21 +119,24 @@ void LoaderDFF::readGeometryList(Clump *model, const RWBStream &stream) { unsigned int numGeometries = *(std::uint32_t *)headerPtr; headerPtr += sizeof(std::uint32_t); - model->geometries.reserve(numGeometries); + std::vector geometrylist; + geometrylist.reserve(numGeometries); for (auto chunkID = listStream.getNextChunk(); chunkID != 0; chunkID = listStream.getNextChunk()) { switch (chunkID) { - case CHUNK_GEOMETRY: - readGeometry(model, listStream); - break; + case CHUNK_GEOMETRY: { + geometrylist.push_back(readGeometry(listStream)); + } break; default: break; } } + + return geometrylist; } -void LoaderDFF::readGeometry(Clump *model, const RWBStream &stream) { +GeometryPtr LoaderDFF::readGeometry(const RWBStream &stream) { auto geomStream = stream.getInnerStream(); auto geomStructID = geomStream.getNextChunk(); @@ -137,7 +144,7 @@ void LoaderDFF::readGeometry(Clump *model, const RWBStream &stream) { throw DFFLoaderException("Geometry missing struct chunk"); } - std::shared_ptr geom(new Geometry); + auto geom = std::make_shared(); char *headerPtr = geomStream.getCursor(); @@ -216,26 +223,24 @@ void LoaderDFF::readGeometry(Clump *model, const RWBStream &stream) { } } - // Add the geometry to the model now so that it can be accessed. - model->geometries.push_back(geom); - // Process the geometry child sections for (auto chunkID = geomStream.getNextChunk(); chunkID != 0; chunkID = geomStream.getNextChunk()) { switch (chunkID) { case CHUNK_MATERIALLIST: - readMaterialList(model, geomStream); + readMaterialList(geom, geomStream); break; case CHUNK_EXTENSION: - readGeometryExtension(model, geomStream); + readGeometryExtension(geom, geomStream); break; default: break; } } - geom->dbuff.setFaceType( - geom->facetype == Geometry::Triangles ? GL_TRIANGLES : GL_TRIANGLE_STRIP); + geom->dbuff.setFaceType(geom->facetype == Geometry::Triangles + ? GL_TRIANGLES + : GL_TRIANGLE_STRIP); geom->gbuff.uploadVertices(verts); geom->dbuff.addGeometry(&geom->gbuff); @@ -251,9 +256,11 @@ void LoaderDFF::readGeometry(Clump *model, const RWBStream &stream) { glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, sg.start * sizeof(uint32_t), sizeof(uint32_t) * sg.numIndices, sg.indices.data()); } + + return geom; } -void LoaderDFF::readMaterialList(Clump *model, const RWBStream &stream) { +void LoaderDFF::readMaterialList(GeometryPtr &geom, const RWBStream &stream) { auto listStream = stream.getInnerStream(); auto listStructID = listStream.getNextChunk(); @@ -263,13 +270,13 @@ void LoaderDFF::readMaterialList(Clump *model, const RWBStream &stream) { unsigned int numMaterials = *(std::uint32_t *)listStream.getCursor(); - model->geometries.back()->materials.reserve(numMaterials); + geom->materials.reserve(numMaterials); RWBStream::ChunkID chunkID; while ((chunkID = listStream.getNextChunk())) { switch (chunkID) { case CHUNK_MATERIAL: - readMaterial(model, listStream); + readMaterial(geom, listStream); break; default: break; @@ -277,7 +284,7 @@ void LoaderDFF::readMaterialList(Clump *model, const RWBStream &stream) { } } -void LoaderDFF::readMaterial(Clump *model, const RWBStream &stream) { +void LoaderDFF::readMaterial(GeometryPtr &geom, const RWBStream &stream) { auto materialStream = stream.getInnerStream(); auto matStructID = materialStream.getNextChunk(); @@ -306,21 +313,22 @@ void LoaderDFF::readMaterial(Clump *model, const RWBStream &stream) { matData += sizeof(float); material.flags = 0; - model->geometries.back()->materials.push_back(material); - RWBStream::ChunkID chunkID; while ((chunkID = materialStream.getNextChunk())) { switch (chunkID) { case CHUNK_TEXTURE: - readTexture(model, materialStream); + readTexture(material, materialStream); break; default: break; } } + + geom->materials.push_back(material); } -void LoaderDFF::readTexture(Clump *model, const RWBStream &stream) { +void LoaderDFF::readTexture(Geometry::Material &material, + const RWBStream &stream) { auto texStream = stream.getInnerStream(); auto texStructID = texStream.getNextChunk(); @@ -343,18 +351,18 @@ void LoaderDFF::readTexture(Clump *model, const RWBStream &stream) { TextureData::Handle textureinst = texturelookup ? texturelookup(name, alpha) : nullptr; - model->geometries.back()->materials.back().textures.push_back( - {name, alpha, textureinst}); + material.textures.push_back({name, alpha, textureinst}); } -void LoaderDFF::readGeometryExtension(Clump *model, const RWBStream &stream) { +void LoaderDFF::readGeometryExtension(GeometryPtr &geom, + const RWBStream &stream) { auto extStream = stream.getInnerStream(); RWBStream::ChunkID chunkID; while ((chunkID = extStream.getNextChunk())) { switch (chunkID) { case CHUNK_BINMESHPLG: - readBinMeshPLG(model, extStream); + readBinMeshPLG(geom, extStream); break; default: break; @@ -362,11 +370,10 @@ void LoaderDFF::readGeometryExtension(Clump *model, const RWBStream &stream) { } } -void LoaderDFF::readBinMeshPLG(Clump *model, const RWBStream &stream) { +void LoaderDFF::readBinMeshPLG(GeometryPtr &geom, const RWBStream &stream) { auto data = stream.getCursor(); - model->geometries.back()->facetype = - static_cast(*(std::uint32_t *)data); + geom->facetype = static_cast(*(std::uint32_t *)data); data += sizeof(std::uint32_t); unsigned int numSplits = *(std::uint32_t *)data; @@ -375,7 +382,7 @@ void LoaderDFF::readBinMeshPLG(Clump *model, const RWBStream &stream) { // Number of triangles. data += sizeof(std::uint32_t); - model->geometries.back()->subgeom.reserve(numSplits); + geom->subgeom.reserve(numSplits); size_t start = 0; @@ -393,11 +400,13 @@ void LoaderDFF::readBinMeshPLG(Clump *model, const RWBStream &stream) { sizeof(std::uint32_t) * sg.numIndices); data += sizeof(std::uint32_t) * sg.numIndices; - model->geometries.back()->subgeom.push_back(sg); + geom->subgeom.push_back(sg); } } -void LoaderDFF::readAtomic(Clump *model, const RWBStream &stream) { +AtomicPtr LoaderDFF::readAtomic(FrameList &framelist, + GeometryList &geometrylist, + const RWBStream &stream) { auto atomicStream = stream.getInnerStream(); auto atomicStructID = atomicStream.getNextChunk(); @@ -405,15 +414,26 @@ void LoaderDFF::readAtomic(Clump *model, const RWBStream &stream) { throw DFFLoaderException("Atomic missing struct chunk"); } - Atomic atom; auto data = atomicStream.getCursor(); - atom.frame = *(std::uint32_t *)data; + auto frame = *(std::uint32_t *)data; data += sizeof(std::uint32_t); - atom.geometry = *(std::uint32_t *)data; - model->frames[atom.frame]->addGeometry(atom.geometry); - model->atomics.push_back(atom); + auto geometry = *(std::uint32_t *)data; - /// @todo are any atomic extensions important? + // Verify the atomic's particulars + RW_CHECK(frame < framelist.size(), "atomic frame " << frame + << " out of bounds"); + RW_CHECK(geometry < geometrylist.size(), + "atomic geometry " << geometry << " out of bounds"); + + auto atomic = std::make_shared(); + if (geometry < geometrylist.size()) { + atomic->setGeometry(geometrylist[geometry]); + } + if (frame < framelist.size()) { + atomic->setFrame(framelist[frame]); + } + + return atomic; } Clump *LoaderDFF::loadFromMemory(FileHandle file) { @@ -434,26 +454,40 @@ Clump *LoaderDFF::loadFromMemory(FileHandle file) { } // There is only one value in the struct section. - model->numAtomics = *(std::uint32_t *)rootStream.getCursor(); + auto numAtomics = *(std::uint32_t *)rootStream.getCursor(); + RW_UNUSED(numAtomics); + + GeometryList geometrylist; + FrameList framelist; // Process everything inside the clump stream. RWBStream::ChunkID chunkID; while ((chunkID = modelStream.getNextChunk())) { switch (chunkID) { case CHUNK_FRAMELIST: - readFrameList(model, modelStream); + framelist = readFrameList(modelStream); break; case CHUNK_GEOMETRYLIST: - readGeometryList(model, modelStream); - break; - case CHUNK_ATOMIC: - readAtomic(model, modelStream); + geometrylist = readGeometryList(modelStream); break; + case CHUNK_ATOMIC: { + auto atomic = readAtomic(framelist, geometrylist, modelStream); + RW_CHECK(atomic, "Failed to read atomic"); + if (!atomic) { + // Abort reading the rest of the clump + return nullptr; + } + model->addAtomic(atomic); + } break; default: break; } } + if (!framelist.empty()) { + model->setFrame(framelist[0]); + } + // Ensure the model has cached metrics model->recalculateMetrics(); diff --git a/rwlib/source/loaders/LoaderDFF.hpp b/rwlib/source/loaders/LoaderDFF.hpp index 573d82ef..a36e0dbc 100644 --- a/rwlib/source/loaders/LoaderDFF.hpp +++ b/rwlib/source/loaders/LoaderDFF.hpp @@ -2,6 +2,7 @@ #ifndef _LOADERDFF_HPP_ #define _LOADERDFF_HPP_ +#include #include #include #include @@ -9,8 +10,6 @@ #include #include -class Clump; - class DFFLoaderException { std::string _message; @@ -24,40 +23,39 @@ public: }; class LoaderDFF { - /** - * @brief loads a Frame List chunk from stream into model. - * @param model - * @param stream - */ - void readFrameList(Clump* model, const RWBStream& stream); - - void readGeometryList(Clump* model, const RWBStream& stream); - - void readGeometry(Clump* model, const RWBStream& stream); - - void readMaterialList(Clump* model, const RWBStream& stream); - - void readMaterial(Clump* model, const RWBStream& stream); - - void readTexture(Clump* model, const RWBStream& stream); - - void readGeometryExtension(Clump* model, const RWBStream& stream); - - void readBinMeshPLG(Clump* model, const RWBStream& stream); - - void readAtomic(Clump* model, const RWBStream& stream); - public: using TextureLookupCallback = std::function; + using GeometryList = std::vector; + using FrameList = std::vector; Clump* loadFromMemory(FileHandle file); void setTextureLookupCallback(TextureLookupCallback tlc) { texturelookup = tlc; } + private: TextureLookupCallback texturelookup; + + FrameList readFrameList(const RWBStream& stream); + + GeometryList readGeometryList(const RWBStream& stream); + + GeometryPtr readGeometry(const RWBStream& stream); + + void readMaterialList(GeometryPtr& geom, const RWBStream& stream); + + void readMaterial(GeometryPtr& geom, const RWBStream& stream); + + void readTexture(Geometry::Material& material, const RWBStream& stream); + + void readGeometryExtension(GeometryPtr& geom, const RWBStream& stream); + + void readBinMeshPLG(GeometryPtr& geom, const RWBStream& stream); + + AtomicPtr readAtomic(FrameList& framelist, GeometryList& geometrylist, + const RWBStream& stream); }; #endif diff --git a/tests/test_loaderdff.cpp b/tests/test_loaderdff.cpp index caaf2a4a..41138fcf 100644 --- a/tests/test_loaderdff.cpp +++ b/tests/test_loaderdff.cpp @@ -15,22 +15,13 @@ BOOST_AUTO_TEST_CASE(test_load_dff) { BOOST_REQUIRE(m != nullptr); - BOOST_REQUIRE_EQUAL(m->frames.size(), 40); + BOOST_REQUIRE(m->getFrame()); - BOOST_REQUIRE_EQUAL(m->geometries.size(), 16); + BOOST_REQUIRE(!m->getAtomics().empty()); + const auto& atomic = m->getAtomics()[0]; - BOOST_REQUIRE_EQUAL(m->geometries[0]->subgeom.size(), 5); - - for (auto& g : m->geometries) { - BOOST_CHECK_GT(g->geometryBounds.radius, 0.f); - } - - BOOST_REQUIRE(m->atomics.size() > 0); - - for (auto& a : m->atomics) { - BOOST_CHECK(a.frame < m->frames.size()); - BOOST_CHECK(a.geometry < m->geometries.size()); - } + BOOST_REQUIRE(atomic->getGeometry()); + BOOST_REQUIRE(atomic->getFrame()); delete m; } From d798509f93c734c194c9101414f292a648ff4a38 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Wed, 4 Jan 2017 21:24:35 +0000 Subject: [PATCH 04/19] Use Atomic instead of ModelFrame in ObjectRenderer --- rwengine/src/data/ModelData.hpp | 9 +- rwengine/src/engine/GameData.cpp | 16 ++- rwengine/src/render/GameRenderer.cpp | 6 +- rwengine/src/render/ObjectRenderer.cpp | 166 ++++++++++--------------- rwengine/src/render/ObjectRenderer.hpp | 22 +++- rwlib/source/data/Clump.hpp | 24 +++- rwlib/source/loaders/LoaderDFF.cpp | 3 + 7 files changed, 124 insertions(+), 122 deletions(-) diff --git a/rwengine/src/data/ModelData.hpp b/rwengine/src/data/ModelData.hpp index 512ef8be..334fe330 100644 --- a/rwengine/src/data/ModelData.hpp +++ b/rwengine/src/data/ModelData.hpp @@ -133,8 +133,9 @@ public: } /// @todo change with librw - void setAtomic(Clump* model, int n, ModelFrame* atomic) { + void setAtomic(Clump* model, int n, AtomicPtr atomic) { model_ = model; + /// @todo disassociated the Atomic from Clump atomics_[n] = atomic; } @@ -143,8 +144,8 @@ public: return model_; } - ModelFrame* getAtomic(int n) const { - return atomics_[n]; + Atomic* getAtomic(int n) const { + return atomics_[n].get(); } void setLodDistance(int n, float d) { @@ -205,7 +206,7 @@ public: private: Clump* model_ = nullptr; - ModelFrame* atomics_[3] = {}; + std::array atomics_; float loddistances_[3] = {}; uint8_t numatomics_ = 0; uint8_t alpha_ = 0; /// @todo ask aap why diff --git a/rwengine/src/engine/GameData.cpp b/rwengine/src/engine/GameData.cpp index 19b91396..45bf8e93 100644 --- a/rwengine/src/engine/GameData.cpp +++ b/rwengine/src/engine/GameData.cpp @@ -390,9 +390,9 @@ void GameData::loadModelFile(const std::string& name) { } // Associate the frames with models. - for (auto& frame : m->frames) { + for (const auto& atomic : m->getAtomics()) { /// @todo this is useful elsewhere, please move elsewhere - std::string name = frame->getName(); + std::string name = atomic->getFrame()->getName(); int lod = 0; getNameAndLod(name, lod); for (auto& model : modelinfo) { @@ -402,7 +402,9 @@ void GameData::loadModelFile(const std::string& name) { } if (boost::iequals(info->name, name)) { auto simple = static_cast(info); - simple->setAtomic(m, lod, frame); + simple->setAtomic(m, lod, atomic); + auto identity = std::make_shared(); + atomic->setFrame(identity); } } } @@ -458,11 +460,13 @@ void GameData::loadModel(ModelID model) { if (isSimple) { auto simple = static_cast(info); // Associate atomics - for (auto& frame : m->frames) { - auto name = frame->getName(); + for (auto& atomic : m->getAtomics()) { + auto name = atomic->getFrame()->getName(); int lod = 0; getNameAndLod(name, lod); - simple->setAtomic(m, lod, frame); + simple->setAtomic(m, lod, atomic); + auto identity = std::make_shared(); + atomic->setFrame(identity); } } else { // Associate clumps diff --git a/rwengine/src/render/GameRenderer.cpp b/rwengine/src/render/GameRenderer.cpp index 4ce4dc93..53e70271 100644 --- a/rwengine/src/render/GameRenderer.cpp +++ b/rwengine/src/render/GameRenderer.cpp @@ -318,8 +318,7 @@ void GameRenderer::renderWorld(GameWorld* world, const ViewCamera& camera, m, glm::vec3(i.radius + 0.15f * glm::sin(_renderWorld->getGameTime() * 5.f))); - objectRenderer.renderFrame(sphereModel, sphereModel->frames[0], m, - nullptr, 1.f, renderList); + objectRenderer.renderClump(sphereModel, m, nullptr, renderList); } // Render arrows above anything that isn't radar only (or hidden) @@ -346,8 +345,7 @@ void GameRenderer::renderWorld(GameWorld* world, const ViewCamera& camera, glm::vec3(0.f, 0.f, 2.5f + glm::sin(a) * 0.5f)); model = glm::rotate(model, a, glm::vec3(0.f, 0.f, 1.f)); model = glm::scale(model, glm::vec3(1.5f, 1.5f, 1.5f)); - objectRenderer.renderFrame(arrowModel, arrowModel->frames[0], model, - nullptr, 1.f, renderList); + objectRenderer.renderClump(arrowModel, model, nullptr, renderList); } RW_PROFILE_END(); diff --git a/rwengine/src/render/ObjectRenderer.cpp b/rwengine/src/render/ObjectRenderer.cpp index 2e9dbd73..6890bea2 100644 --- a/rwengine/src/render/ObjectRenderer.cpp +++ b/rwengine/src/render/ObjectRenderer.cpp @@ -1,5 +1,5 @@ -#include #include +#include #include #include #include @@ -33,12 +33,10 @@ RenderKey createKey(bool transparent, float normalizedDepth, uint8_t(0xFF & (textures.size() > 0 ? textures[0] : 0)) << 0; } -void ObjectRenderer::renderGeometry(Clump* model, size_t g, - const glm::mat4& modelMatrix, float opacity, +void ObjectRenderer::renderGeometry(Geometry* geom, + const glm::mat4& modelMatrix, GameObject* object, RenderList& outList) { - for (size_t sg = 0; sg < model->geometries[g]->subgeom.size(); ++sg) { - SubGeometry& subgeom = model->geometries[g]->subgeom[sg]; - + for (SubGeometry& subgeom : geom->subgeom) { bool isTransparent = false; Renderer::DrawParameters dp; @@ -55,9 +53,8 @@ void ObjectRenderer::renderGeometry(Clump* model, size_t g, !(modelinfo->flags & SimpleModelInfo::NO_ZBUFFER_WRITE); } - if (model->geometries[g]->materials.size() > subgeom.material) { - Geometry::Material& mat = - model->geometries[g]->materials[subgeom.material]; + if (geom->materials.size() > subgeom.material) { + Geometry::Material& mat = geom->materials[subgeom.material]; if (mat.textures.size() > 0) { auto tex = mat.textures[0].texture; @@ -69,8 +66,7 @@ void ObjectRenderer::renderGeometry(Clump* model, size_t g, } } - if ((model->geometries[g]->flags & - RW::BSGeometry::ModuleMaterialColor) == + if ((geom->flags & RW::BSGeometry::ModuleMaterialColor) == RW::BSGeometry::ModuleMaterialColor) { dp.colour = mat.colour; @@ -86,7 +82,7 @@ void ObjectRenderer::renderGeometry(Clump* model, size_t g, } } - dp.visibility = opacity; + dp.visibility = 1.f; if (dp.colour.a < 255) { isTransparent = true; @@ -104,44 +100,40 @@ void ObjectRenderer::renderGeometry(Clump* model, size_t g, (m_camera.frustum.far - m_camera.frustum.near); outList.emplace_back( createKey(isTransparent, depth * depth, dp.textures), modelMatrix, - &model->geometries[g]->dbuff, dp); + &geom->dbuff, dp); } } -bool ObjectRenderer::renderFrame(Clump* m, ModelFrame* f, - const glm::mat4& matrix, GameObject* object, - float opacity, RenderList& outList) { - auto localmatrix = matrix; - bool vis = true; - if (object && object->skeleton) { - // Skeleton is loaded with the correct matrix via Animator. - localmatrix *= object->skeleton->getMatrix(f); +void ObjectRenderer::renderAtomic(Atomic* atomic, + const glm::mat4& worldtransform, + GameObject* object, RenderList& render) { + RW_CHECK(atomic->getGeometry(), "Can't render an atomic without geometry"); + RW_CHECK(atomic->getFrame(), "Can't render an atomic without a frame"); - vis = object->skeleton->getData(f->getIndex()).enabled; - } else { - localmatrix *= f->getTransform(); + const auto& geometry = atomic->getGeometry(); + const auto& frame = atomic->getFrame(); + + RW::BSGeometryBounds& bounds = geometry->geometryBounds; + + glm::vec3 boundpos = bounds.center + glm::vec3(worldtransform[3]); + if (!m_camera.frustum.intersects(boundpos, bounds.radius)) { + culled++; + return; } - if (vis) { - for (size_t g : f->getGeometries()) { - if (!object || !object->animator) { - RW::BSGeometryBounds& bounds = m->geometries[g]->geometryBounds; + renderGeometry(geometry.get(), worldtransform, object, render); +} - glm::vec3 boundpos = bounds.center + glm::vec3(localmatrix[3]); - if (!m_camera.frustum.intersects(boundpos, bounds.radius)) { - culled++; - continue; - } - } - - renderGeometry(m, g, localmatrix, opacity, object, outList); +void ObjectRenderer::renderClump(Clump* model, const glm::mat4& worldtransform, + GameObject* object, RenderList& render) { + for (const auto& atomic : model->getAtomics()) { + const auto flags = atomic->getFlags(); + if ((flags & Atomic::ATOMIC_RENDER) == 0) { + continue; } - } - for (ModelFrame* c : f->getChildren()) { - renderFrame(m, c, localmatrix, object, opacity, outList); + renderAtomic(atomic.get(), worldtransform, object, render); } - return true; } void ObjectRenderer::renderInstance(InstanceObject* instance, @@ -175,13 +167,12 @@ void ObjectRenderer::renderInstance(InstanceObject* instance, instance->getModel()->getBoundingRadius(); mindist *= 1.f / kDrawDistanceFactor; - Clump* model = nullptr; - ModelFrame* frame = nullptr; + Atomic* atomic = nullptr; - // These are used to gracefully fade out things that are just out of view + // These are used to gracefully fade out things that are just out of + // view // distance. - Clump* fadingModel = nullptr; - ModelFrame* fadingFrame = nullptr; + Atomic* fadingAtomic = nullptr; auto fadingMatrix = matrixModel; float opacity = 0.f; constexpr float fadeRange = 50.f; @@ -203,32 +194,27 @@ void ObjectRenderer::renderInstance(InstanceObject* instance, matrixModel = instance->LODinstance->getTimeAdjustedTransform( m_renderAlpha); + atomic = lodmodelinfo->getAtomic(0); // If the object is only just out of range, keep // rendering it and screen-door the LOD. if (overlap < fadeRange) { - model = instance->LODinstance->getModel(); - fadingModel = instance->getModel(); + fadingAtomic = modelinfo->getAtomic(0); opacity = 1.f - (overlap / fadeRange); - } else { - model = instance->LODinstance->getModel(); } } } // We don't have a LOD object, so fade out gracefully. else if (overlap < fadeRange) { - fadingModel = instance->getModel(); + fadingAtomic = modelinfo->getAtomic(0); opacity = 1.f - (overlap / fadeRange); } } // Otherwise, if we aren't marked as a LOD model, we can render else if (!modelinfo->LOD) { - model = instance->getModel(); + atomic = modelinfo->getAtomic(0); } } else { - auto root = instance->getModel()->frames[0]; - auto objectModel = instance->getModel(); - fadingFrame = nullptr; - fadingModel = nullptr; + auto root = instance->getModel()->getFrame(); matrixModel *= root->getTransform(); @@ -236,30 +222,20 @@ void ObjectRenderer::renderInstance(InstanceObject* instance, auto ind = (modelinfo->getNumAtomics() - 1) - i; float lodDistance = modelinfo->getLodDistance(i); if (mindist > lodDistance) { - fadingFrame = root->getChildren()[ind]; - fadingModel = objectModel; + fadingAtomic = modelinfo->getAtomic(ind); opacity = 1.f - ((mindist - lodDistance) / fadeRange); } else { - model = objectModel; - frame = root->getChildren()[ind]; + fadingAtomic = modelinfo->getAtomic(ind); } } } - if (model) { - frame = frame ? frame : model->frames[0]; - renderFrame(model, frame, - matrixModel * glm::inverse(frame->getTransform()), instance, - 1.f, outList); + if (atomic) { + renderAtomic(atomic, matrixModel, instance, outList); } - if (fadingModel) { - if (opacity >= 0.01f) { - fadingFrame = fadingFrame ? fadingFrame : fadingModel->frames[0]; - renderFrame( - fadingModel, fadingFrame, - fadingMatrix * glm::inverse(fadingFrame->getTransform()), - instance, opacity, outList); - } + if (fadingAtomic && opacity >= 0.01f) { + // @todo pass opacity + renderAtomic(fadingAtomic, fadingMatrix, instance, outList); } } @@ -286,10 +262,7 @@ void ObjectRenderer::renderCharacter(CharacterObject* pedestrian, if (!pedestrian->getModel()) return; - auto root = pedestrian->getModel()->frames[0]; - - renderFrame(pedestrian->getModel(), root->getChildren()[0], matrixModel, - pedestrian, 1.f, outList); + renderClump(pedestrian->getModel(), matrixModel, nullptr, outList); auto item = pedestrian->getActiveItem(); const auto& weapon = pedestrian->engine->data->weaponData[item]; @@ -312,9 +285,8 @@ void ObjectRenderer::renderCharacter(CharacterObject* pedestrian, // Assume items are all simple auto simple = m_world->data->findModelInfo(weapon->modelID); - auto geometry = simple->getAtomic(0)->getGeometries().at(0); - renderGeometry(simple->getModel(), geometry, matrixModel * localMatrix, 1.f, - nullptr, outList); + auto itematomic = simple->getAtomic(0); + renderAtomic(itematomic, matrixModel * localMatrix, nullptr, outList); } void ObjectRenderer::renderVehicle(VehicleObject* vehicle, @@ -327,8 +299,7 @@ void ObjectRenderer::renderVehicle(VehicleObject* vehicle, glm::mat4 matrixModel = vehicle->getTimeAdjustedTransform(m_renderAlpha); - renderFrame(vehicle->getModel(), vehicle->getModel()->frames[0], - matrixModel, vehicle, 1.f, outList); + renderClump(vehicle->getModel(), matrixModel, vehicle, outList); auto modelinfo = vehicle->getVehicle(); @@ -338,7 +309,8 @@ void ObjectRenderer::renderVehicle(VehicleObject* vehicle, if (!woi || !woi->isLoaded()) { return; } - auto wheelgeom = woi->getAtomic(0)->getGeometries().at(0); + + auto wheelatomic = woi->getAtomic(0); for (size_t w = 0; w < vehicle->info->wheels.size(); ++w) { auto& wi = vehicle->physVehicle->getWheelInfo(w); // Construct our own matrix so we can use the local transform @@ -371,8 +343,7 @@ void ObjectRenderer::renderVehicle(VehicleObject* vehicle, wheelM = glm::scale(wheelM, glm::vec3(-1.f, 1.f, 1.f)); } - renderGeometry(woi->getModel(), wheelgeom, wheelM, 1.f, nullptr, - outList); + renderAtomic(wheelatomic, wheelM, nullptr, outList); } } @@ -385,16 +356,9 @@ void ObjectRenderer::renderPickup(PickupObject* pickup, RenderList& outList) { auto odata = pickup->getModelInfo(); - auto model = odata->getModel(); - auto itemModel = odata->getAtomic(0); - auto geom = 0; - if (!itemModel->getGeometries().empty()) { - geom = itemModel->getGeometries()[0]; - } else if (!itemModel->getChildren().empty()) { - geom = itemModel->getChildren()[0]->getGeometries()[0]; - } + auto atomic = odata->getAtomic(0); - renderGeometry(model, geom, modelMatrix, 1.f, pickup, outList); + renderAtomic(atomic, modelMatrix, nullptr, outList); } void ObjectRenderer::renderCutsceneObject(CutsceneObject* cutscene, @@ -413,7 +377,8 @@ void ObjectRenderer::renderCutsceneObject(CutsceneObject* cutscene, matrixModel = glm::translate(matrixModel, cutsceneOffset); // matrixModel = // cutscene->getParentActor()->getTimeAdjustedTransform(_renderAlpha); - // matrixModel = glm::translate(matrixModel, glm::vec3(0.f, 0.f, 1.f)); + // matrixModel = glm::translate(matrixModel, glm::vec3(0.f, 0.f, + // 1.f)); glm::mat4 localMatrix; auto boneframe = cutscene->getParentFrame(); while (boneframe) { @@ -432,11 +397,9 @@ void ObjectRenderer::renderCutsceneObject(CutsceneObject* cutscene, glm::mat4 align; /// @todo figure out where this 90 degree offset is coming from. align = glm::rotate(align, glm::half_pi(), {0.f, 1.f, 0.f}); - renderFrame(model, model->frames[0], matrixModel * align, cutscene, 1.f, - outList); + renderClump(model, matrixModel * align, nullptr, outList); } else { - renderFrame(model, model->frames[0], matrixModel, cutscene, 1.f, - outList); + renderClump(model, matrixModel, nullptr, outList); } } @@ -447,11 +410,8 @@ void ObjectRenderer::renderProjectile(ProjectileObject* projectile, auto odata = m_world->data->findModelInfo( projectile->getProjectileInfo().weapon->modelID); - auto model = odata->getModel(); - auto modelframe = odata->getAtomic(0); - auto geom = modelframe->getGeometries().at(0); - - renderGeometry(model, geom, modelMatrix, 1.f, projectile, outList); + auto atomic = odata->getAtomic(0); + renderAtomic(atomic, modelMatrix, nullptr, outList); } void ObjectRenderer::buildRenderList(GameObject* object, RenderList& outList) { diff --git a/rwengine/src/render/ObjectRenderer.hpp b/rwengine/src/render/ObjectRenderer.hpp index e06041ce..6b483994 100644 --- a/rwengine/src/render/ObjectRenderer.hpp +++ b/rwengine/src/render/ObjectRenderer.hpp @@ -37,11 +37,25 @@ public: size_t culled; void buildRenderList(GameObject* object, RenderList& outList); - bool renderFrame(Clump* m, ModelFrame* f, const glm::mat4& matrix, - GameObject* object, float opacity, RenderList& outList); + void renderGeometry(Geometry* geom, const glm::mat4& modelMatrix, + GameObject* object, RenderList& outList); - void renderGeometry(Clump* model, size_t g, const glm::mat4& modelMatrix, - float opacity, GameObject* object, RenderList& outList); + /** + * @brief renderAtomic renders an atomic with the given worldtransform + * @param model + * @param atomic + * @param worldtransform + * @param object + */ + void renderAtomic(Atomic* atomic, const glm::mat4& worldtransform, GameObject* object, RenderList& render); + + /** + * @brief renderClump Renders all visible atomics in the clump + * @param model + * @param worldtransform + * @param render + */ + void renderClump(Clump* model, const glm::mat4& worldtransform, GameObject* object, RenderList& render); private: GameWorld* m_world; diff --git a/rwlib/source/data/Clump.hpp b/rwlib/source/data/Clump.hpp index d01658d3..2c6a303a 100644 --- a/rwlib/source/data/Clump.hpp +++ b/rwlib/source/data/Clump.hpp @@ -187,10 +187,15 @@ struct Geometry { class Atomic { ModelFramePtr frame_; GeometryPtr geometry_; + uint32_t flags_; public: + enum { + // If this is set, the atomic will be rendered + ATOMIC_RENDER = 0x04 + }; - void setFrame(ModelFramePtr& frame) { + void setFrame(ModelFramePtr frame) { frame_ = frame; } @@ -205,6 +210,23 @@ public: const GeometryPtr& getGeometry() const { return geometry_; } + + void setFlags(uint32_t flags) { + flags_ = flags; + } + + uint32_t getFlags() const { + return flags_; + } + + void setFlag(uint32_t flag, bool set) { + if (set) { + flags_ |= flag; + } + else { + flags_ &= ~flag; + } + } }; /** diff --git a/rwlib/source/loaders/LoaderDFF.cpp b/rwlib/source/loaders/LoaderDFF.cpp index 72f7a4b9..b90ba8c5 100644 --- a/rwlib/source/loaders/LoaderDFF.cpp +++ b/rwlib/source/loaders/LoaderDFF.cpp @@ -418,6 +418,8 @@ AtomicPtr LoaderDFF::readAtomic(FrameList &framelist, auto frame = *(std::uint32_t *)data; data += sizeof(std::uint32_t); auto geometry = *(std::uint32_t *)data; + data += sizeof(std::uint32_t); + auto flags = *(std::uint32_t *) data; // Verify the atomic's particulars RW_CHECK(frame < framelist.size(), "atomic frame " << frame @@ -432,6 +434,7 @@ AtomicPtr LoaderDFF::readAtomic(FrameList &framelist, if (frame < framelist.size()) { atomic->setFrame(framelist[frame]); } + atomic->setFlags(flags); return atomic; } From 0a0be3c52a7f0d689b2818dcead1b16c83db4b59 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sun, 8 Jan 2017 20:43:18 +0000 Subject: [PATCH 05/19] Use new Clump structures in rwviewer + remove old renderer --- rwengine/src/render/GameRenderer.cpp | 94 -------------------------- rwengine/src/render/GameRenderer.hpp | 33 --------- rwviewer/ViewerWidget.cpp | 58 +++++++++------- rwviewer/models/DFFFramesTreeModel.cpp | 6 +- rwviewer/widgets/ModelFramesWidget.cpp | 15 +--- 5 files changed, 36 insertions(+), 170 deletions(-) diff --git a/rwengine/src/render/GameRenderer.cpp b/rwengine/src/render/GameRenderer.cpp index 53e70271..d6596528 100644 --- a/rwengine/src/render/GameRenderer.cpp +++ b/rwengine/src/render/GameRenderer.cpp @@ -473,57 +473,6 @@ void GameRenderer::renderPostProcess() { renderer->drawArrays(glm::mat4(), &ssRectDraw, wdp); } -void GameRenderer::renderGeometry(Clump* model, size_t g, - const glm::mat4& modelMatrix, float opacity, - GameObject* object) { - for (size_t sg = 0; sg < model->geometries[g]->subgeom.size(); ++sg) { - SubGeometry& subgeom = model->geometries[g]->subgeom[sg]; - - Renderer::DrawParameters dp; - - dp.colour = {255, 255, 255, 255}; - dp.count = subgeom.numIndices; - dp.start = subgeom.start; - dp.textures = {0}; - - if (model->geometries[g]->materials.size() > subgeom.material) { - Geometry::Material& mat = - model->geometries[g]->materials[subgeom.material]; - - if (mat.textures.size() > 0) { - auto tex = mat.textures[0].texture; - if (tex) { - dp.textures = {tex->getName()}; - } - } - - if ((model->geometries[g]->flags & - RW::BSGeometry::ModuleMaterialColor) == - RW::BSGeometry::ModuleMaterialColor) { - dp.colour = mat.colour; - - if (object && object->type() == GameObject::Vehicle) { - auto vehicle = static_cast(object); - if (dp.colour.r == 60 && dp.colour.g == 255 && - dp.colour.b == 0) { - dp.colour = glm::u8vec4(vehicle->colourPrimary, 255); - } else if (dp.colour.r == 255 && dp.colour.g == 0 && - dp.colour.b == 175) { - dp.colour = glm::u8vec4(vehicle->colourSecondary, 255); - } - } - } - - dp.colour.a *= opacity; - - dp.diffuse = mat.diffuseIntensity; - dp.ambient = mat.ambientIntensity; - } - - renderer->draw(modelMatrix, &model->geometries[g]->dbuff, dp); - } -} - void GameRenderer::renderEffects(GameWorld* world) { renderer->useProgram(particleProg); @@ -654,49 +603,6 @@ void GameRenderer::drawColour(const glm::vec4& colour, glm::vec4 extents) { renderer->invalidate(); } -bool GameRenderer::renderFrame(Clump* m, ModelFrame* f, const glm::mat4& matrix, - GameObject* object, float opacity, - bool queueTransparent) { - auto localmatrix = matrix; - bool vis = true; - - if (object && object->skeleton) { - // Skeleton is loaded with the correct matrix via Animator. - localmatrix *= object->skeleton->getMatrix(f); - - vis = object->skeleton->getData(f->getIndex()).enabled; - } else { - localmatrix *= f->getTransform(); - } - - if (vis) { - for (size_t g : f->getGeometries()) { - if (!object || !object->animator) { - RW::BSGeometryBounds& bounds = m->geometries[g]->geometryBounds; - - glm::vec3 boundpos = bounds.center + glm::vec3(localmatrix[3]); - if (!_camera.frustum.intersects(boundpos, bounds.radius)) { - culled++; - continue; - } - } - - renderGeometry(m, g, localmatrix, opacity, object); - } - } - - for (ModelFrame* c : f->getChildren()) { - renderFrame(m, c, localmatrix, object, queueTransparent); - } - return true; -} - -void GameRenderer::renderModel(Clump* model, const glm::mat4& modelMatrix, - GameObject* object) { - renderFrame(model, model->frames[model->rootFrameIdx], modelMatrix, object, - 1.f); -} - void GameRenderer::renderPaths() { /*glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, debugTex); diff --git a/rwengine/src/render/GameRenderer.hpp b/rwengine/src/render/GameRenderer.hpp index 6377cb87..8a4fb4ef 100644 --- a/rwengine/src/render/GameRenderer.hpp +++ b/rwengine/src/render/GameRenderer.hpp @@ -51,30 +51,6 @@ class GameRenderer { /** The low-level drawing interface to use */ Renderer* renderer; - /** Stores data for deferring transparent objects */ - struct RQueueEntry { - Clump* model; - size_t g; - size_t sg; - glm::mat4 matrix; - Renderer::DrawParameters dp; - GameObject* object; - }; - - /** - * @brief renders a model's frame. - * @param m - * @param f - * @param matrix - * @param object - * @param queueTransparent abort the draw if the frame contains transparent - * materials - * @return True if the frame was drawn, false if it should be queued - */ - bool renderFrame(Clump* m, ModelFrame* f, const glm::mat4& matrix, - GameObject* object, float opacity, - bool queueTransparent = true); - // Temporary variables used during rendering float _renderAlpha; GameWorld* _renderWorld; @@ -155,15 +131,6 @@ public: void drawTexture(TextureData* texture, glm::vec4 extents); void drawColour(const glm::vec4& colour, glm::vec4 extents); - /** - * Renders a model (who'd have thought) - */ - void renderModel(Clump*, const glm::mat4& modelMatrix, - GameObject* = nullptr); - - void renderGeometry(Clump*, size_t geom, const glm::mat4& modelMatrix, - float opacity, GameObject* = nullptr); - /** method for rendering AI debug information */ void renderPaths(); diff --git a/rwviewer/ViewerWidget.cpp b/rwviewer/ViewerWidget.cpp index 3bfd6080..1f563bc7 100644 --- a/rwviewer/ViewerWidget.cpp +++ b/rwviewer/ViewerWidget.cpp @@ -6,13 +6,13 @@ #include #include #include -#include -#include -#include - #include +#include #include #include +#include +#include +#include ViewerWidget::ViewerWidget(QGLFormat g, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f) @@ -113,10 +113,15 @@ void ViewerWidget::paintGL() { cos(viewAngles.x) * cos(viewAngles.y), sin(viewAngles.y)); if (model) { + model->getFrame()->updateHierarchyTransform(); + + // Ensure camera is still accurate + vc.position = eye * viewDistance; glm::mat4 proj = vc.frustum.projection(); - glm::mat4 view = - glm::lookAt(eye * viewDistance, glm::vec3(0.f, 0.f, 0.f), - glm::vec3(0.f, 0.f, 1.f)); + glm::mat4 view = glm::lookAt(vc.position, glm::vec3(0.f, 0.f, 0.f), + glm::vec3(0.f, 0.f, 1.f)); + vc.rotation = -glm::quat_cast(view); + vc.frustum.update(proj * view); r.getRenderer()->setSceneParameters( {proj, view, glm::vec4(0.15f), glm::vec4(0.7f), glm::vec4(1.f), @@ -126,9 +131,12 @@ void ViewerWidget::paintGL() { r.setupRender(); - r.renderModel(model, m, dummyObject); + ObjectRenderer renderer(world(), vc, 1.f, 0); + RenderList renders; + renderer.renderClump(model, glm::mat4(), nullptr, renders); + r.getRenderer()->drawBatched(renders); - drawFrameWidget(model->frames[model->rootFrameIdx]); + drawFrameWidget(model->getFrame().get()); r.renderPostProcess(); } else if (world()->allObjects.size() > 0) { vc.frustum.fov = glm::radians(90.f); @@ -143,26 +151,24 @@ void ViewerWidget::paintGL() { void ViewerWidget::drawFrameWidget(ModelFrame* f, const glm::mat4& m) { auto thisM = m * f->getTransform(); - if (f->getGeometries().size() == 0) { - Renderer::DrawParameters dp; - dp.count = _frameWidgetGeom->getCount(); - dp.start = 0; - dp.ambient = 1.f; - dp.diffuse = 1.f; - if (f == selectedFrame) { - dp.colour = {255, 255, 0, 255}; - // Sorry! - glLineWidth(10.f); - } else { - dp.colour = {255, 255, 255, 255}; - glLineWidth(1.f); - } - dp.textures = {whiteTex}; - renderer->getRenderer()->drawArrays(thisM, _frameWidgetDraw, dp); + Renderer::DrawParameters dp; + dp.count = _frameWidgetGeom->getCount(); + dp.start = 0; + dp.ambient = 1.f; + dp.diffuse = 1.f; + if (f == selectedFrame) { + dp.colour = {255, 255, 0, 255}; + // Sorry! + glLineWidth(10.f); + } else { + dp.colour = {255, 255, 255, 255}; + glLineWidth(1.f); } + dp.textures = {whiteTex}; + renderer->getRenderer()->drawArrays(thisM, _frameWidgetDraw, dp); for (auto c : f->getChildren()) { - drawFrameWidget(c, thisM); + drawFrameWidget(c.get(), thisM); } } diff --git a/rwviewer/models/DFFFramesTreeModel.cpp b/rwviewer/models/DFFFramesTreeModel.cpp index 3769bc94..10840ce9 100644 --- a/rwviewer/models/DFFFramesTreeModel.cpp +++ b/rwviewer/models/DFFFramesTreeModel.cpp @@ -27,10 +27,10 @@ int DFFFramesTreeModel::rowCount(const QModelIndex& parent) const { QModelIndex DFFFramesTreeModel::index(int row, int column, const QModelIndex& parent) const { if (parent.row() == -1 && parent.column() == -1) { - return createIndex(row, column, model->frames[model->rootFrameIdx]); + return createIndex(row, column, model->getFrame().get()); } ModelFrame* f = static_cast(parent.internalPointer()); - ModelFrame* p = f->getChildren()[row]; + ModelFrame* p = f->getChildren()[row].get(); return createIndex(row, column, p); } @@ -40,7 +40,7 @@ QModelIndex DFFFramesTreeModel::parent(const QModelIndex& child) const { auto cp = c->getParent(); if (cp->getParent()) { for (size_t i = 0; i < cp->getParent()->getChildren().size(); ++i) { - if (cp->getParent()->getChildren()[i] == c->getParent()) { + if (cp->getParent()->getChildren()[i].get() == c->getParent()) { return createIndex(i, 0, c->getParent()); } } diff --git a/rwviewer/widgets/ModelFramesWidget.cpp b/rwviewer/widgets/ModelFramesWidget.cpp index 480348ea..4fa3bb15 100644 --- a/rwviewer/widgets/ModelFramesWidget.cpp +++ b/rwviewer/widgets/ModelFramesWidget.cpp @@ -6,23 +6,10 @@ void ModelFramesWidget::updateInfoBox(Clump* model, ModelFrame* f) { if (f == nullptr) { _frameLabel->setText(""); } else { - auto labText = QString("Name: %1\nTranslation: %2\nTextures:%3") + auto labText = QString("Name: %1\nTranslation: %2") .arg(QString::fromStdString(f->getName())) .arg(QString::fromStdString( glm::to_string(f->getDefaultTranslation()))); - QString geomString; - for (size_t gi : f->getGeometries()) { - auto& g = model->geometries[gi]; - // for(Model::SubGeometry& sg : g->subgeom) - for (Geometry::Material& m : g->materials) { - for (Geometry::Texture& t : m.textures) { - geomString += QString("\n %1 (%2)") - .arg(t.name.c_str()) - .arg(t.alphaName.c_str()); - } - } - } - labText = labText.arg(geomString); _frameLabel->setText(labText); } } From ac8d6733cb2a4f7b3864f7adead5014749234c29 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Thu, 5 Jan 2017 01:26:37 +0000 Subject: [PATCH 06/19] Add clone methods to Clump, Atomic and ModelFrame to permit copying --- rwlib/source/data/Clump.cpp | 60 ++++++++++++++++++++++++++++++++++++- rwlib/source/data/Clump.hpp | 13 ++++++-- tests/test_loaderdff.cpp | 40 +++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 3 deletions(-) diff --git a/rwlib/source/data/Clump.cpp b/rwlib/source/data/Clump.cpp index c12eb471..58951cb8 100644 --- a/rwlib/source/data/Clump.cpp +++ b/rwlib/source/data/Clump.cpp @@ -1,5 +1,6 @@ #include "data/Clump.hpp" #include +#include #include @@ -35,7 +36,7 @@ void ModelFrame::updateHierarchyTransform() { } } -void ModelFrame::addChild(ModelFramePtr& child) { +void ModelFrame::addChild(ModelFramePtr child) { // Make sure the child is an orphan if (child->getParent()) { auto& other_children = child->getParent()->children_; @@ -62,6 +63,26 @@ ModelFrame* ModelFrame::findDescendant(const std::string& name) const { return nullptr; } +ModelFramePtr ModelFrame::cloneHierarchy() const { + auto self = std::make_shared(getIndex(), getDefaultRotation(), + getDefaultTranslation()); + self->setName(getName()); + for (const auto& child : getChildren()) { + auto childclone = child->cloneHierarchy(); + self->addChild(childclone); + } + + return self; +} + +AtomicPtr Atomic::clone() const { + auto newatomic = std::make_shared(); + newatomic->setGeometry(getGeometry()); + newatomic->setFrame(getFrame()); + newatomic->setFlags(getFlags()); + return newatomic; +} + ModelFrame* Clump::findFrame(const std::string& name) const { if (rootframe_->getName() == name) { return rootframe_.get(); @@ -85,3 +106,40 @@ void Clump::recalculateMetrics() { glm::length(bounds.center) + bounds.radius); } } + +Clump* Clump::clone() const { + // Clone frame hierarchy + auto newroot = rootframe_->cloneHierarchy(); + auto clump = new Clump; + clump->setFrame(newroot); + + // This isn't the most optimal implementation, but this code is likely + // to be replaced soon. + auto find_new_frame = [&](const ModelFramePtr& old) -> ModelFramePtr { + std::queue open; + open.push(newroot); + while (!open.empty()) { + auto frame = open.front(); + open.pop(); + if (frame->getIndex() == old->getIndex()) { + return frame; + } + for (const auto& child : frame->getChildren()) { + open.push(child); + } + } + return nullptr; + }; + + // Generate new atomics + for (const auto& atomic : getAtomics()) { + auto newatomic = atomic->clone(); + // Replace the original frame with the cloned frame + if (atomic->getFrame()) { + newatomic->setFrame(find_new_frame(atomic->getFrame())); + } + clump->addAtomic(newatomic); + } + + return clump; +} diff --git a/rwlib/source/data/Clump.hpp b/rwlib/source/data/Clump.hpp index 2c6a303a..ee14b3ce 100644 --- a/rwlib/source/data/Clump.hpp +++ b/rwlib/source/data/Clump.hpp @@ -97,7 +97,7 @@ public: return parent_; } - void addChild(ModelFramePtr& child); + void addChild(ModelFramePtr child); const std::vector& getChildren() const { return children_; @@ -108,6 +108,8 @@ public: } ModelFrame* findDescendant(const std::string& name) const; + + ModelFramePtr cloneHierarchy() const; }; /** @@ -203,7 +205,7 @@ public: return frame_; } - void setGeometry(GeometryPtr& geom) { + void setGeometry(GeometryPtr geom) { geometry_ = geom; } @@ -227,6 +229,8 @@ public: flags_ &= ~flag; } } + + AtomicPtr clone() const; }; /** @@ -265,6 +269,11 @@ public: return rootframe_; } + /** + * @return A Copy of the frames and atomics in this clump + */ + Clump* clone() const; + private: float boundingRadius; AtomicList atomics_; diff --git a/tests/test_loaderdff.cpp b/tests/test_loaderdff.cpp index 41138fcf..2875f16c 100644 --- a/tests/test_loaderdff.cpp +++ b/tests/test_loaderdff.cpp @@ -29,4 +29,44 @@ BOOST_AUTO_TEST_CASE(test_load_dff) { #endif +BOOST_AUTO_TEST_CASE(test_clump_clone) { + { + auto frame1 = std::make_shared(0); + frame1->setName("Frame1"); + auto frame2 = std::make_shared(1); + frame2->setName("Frame2"); + + frame1->addChild(frame2); + + auto geometry = std::make_shared(); + + auto atomic = std::make_shared(); + atomic->setFrame(frame2); + atomic->setGeometry(geometry); + + auto clump = std::make_shared(); + clump->addAtomic(atomic); + clump->setFrame(frame1); + + // Now clone and verify that: + // The hierarchy has the same data but different objects + // The atomics have the same data but different objects + // Suspected correct behaviour: + // The geometry is the same for each atomic + + auto newclump = std::shared_ptr(clump->clone()); + BOOST_REQUIRE(newclump); + + BOOST_CHECK_NE(newclump, clump); + + BOOST_REQUIRE(newclump->getFrame()); + BOOST_CHECK_NE(newclump->getFrame(), clump->getFrame()); + BOOST_CHECK_EQUAL(newclump->getFrame()->getChildren().size(), 1); + + BOOST_CHECK_EQUAL(newclump->getAtomics().size(), 1); + + BOOST_CHECK_EQUAL(frame1->getName(), newclump->getFrame()->getName()); + } +} + BOOST_AUTO_TEST_SUITE_END() From 729085d08c28db686491628affa15b56fb01fb5e Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Wed, 4 Jan 2017 23:32:31 +0000 Subject: [PATCH 07/19] Re-implement vehicle parts for changed frame interfaces --- rwengine/src/engine/GameWorld.cpp | 31 ++++++++------ rwengine/src/objects/VehicleObject.cpp | 56 ++++++++------------------ 2 files changed, 35 insertions(+), 52 deletions(-) diff --git a/rwengine/src/engine/GameWorld.cpp b/rwengine/src/engine/GameWorld.cpp index d19f0db1..88fd4c46 100644 --- a/rwengine/src/engine/GameWorld.cpp +++ b/rwengine/src/engine/GameWorld.cpp @@ -280,18 +280,23 @@ VehicleObject* GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos, auto model = vti->getModel(); auto info = data->vehicleInfo.find(vti->handling_); - if (model && info != data->vehicleInfo.end()) { - if (info->second->wheels.size() == 0 && - info->second->seats.size() == 0) { - for (const ModelFrame* f : model->frames) { - const std::string& name = f->getName(); + if (model && info != data->vehicleInfo.end() && + info->second->wheels.size() == 0 && info->second->seats.size() == 0) { + auto root = model->getFrame(); + for (const auto& frame : root->getChildren()) { + const std::string& name = frame->getName(); - if (name.size() > 5 && name.substr(0, 5) == "wheel") { - auto frameTrans = f->getMatrix(); - info->second->wheels.push_back({glm::vec3(frameTrans[3])}); - } - if (name == "ped_frontseat") { - auto p = f->getDefaultTranslation(); + if (name.size() > 5 && name.substr(0, 5) == "wheel") { + auto frameTrans = frame->getMatrix(); + info->second->wheels.push_back({glm::vec3(frameTrans[3])}); + } + + if (name == "chassis_dummy") { + // These are nested within chassis_dummy + auto frontseat = frame->findDescendant("ped_frontseat"); + auto backseat = frame->findDescendant("ped_backseat"); + if (frontseat) { + auto p = frontseat->getDefaultTranslation(); // Left seat p.x = -p.x; info->second->seats.front.push_back({p}); @@ -299,10 +304,10 @@ VehicleObject* GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos, p.x = -p.x; info->second->seats.front.push_back({p}); } - if (name == "ped_backseat") { + if (backseat) { // @todo how does this work for the barracks, ambulance // or coach? - auto p = f->getDefaultTranslation(); + auto p = backseat->getDefaultTranslation(); // Left seat p.x = -p.x; info->second->seats.back.push_back({p}); diff --git a/rwengine/src/objects/VehicleObject.cpp b/rwengine/src/objects/VehicleObject.cpp index 2afcebca..d75be0fe 100644 --- a/rwengine/src/objects/VehicleObject.cpp +++ b/rwengine/src/objects/VehicleObject.cpp @@ -1,6 +1,6 @@ #include -#include #include +#include #include #include #include @@ -153,18 +153,13 @@ VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, setModel(getVehicle()->getModel()); - for (ModelFrame* frame : getModel()->frames) { + // Create meta-data for dummy parts + auto chassisframe = getModel()->findFrame("chassis_dummy"); + for (auto& frame : chassisframe->getChildren()) { auto& name = frame->getName(); - bool isDam = name.find("_dam") != name.npos; - bool isLod = name.find("lo") != name.npos; bool isDum = name.find("_dummy") != name.npos; - /*bool isOk = name.find("_ok") != name.npos;*/ - if (isDam || isLod || isDum) { - skeleton->setEnabled(frame, false); - } - if (isDum) { - registerPart(frame); + registerPart(frame.get()); } } } @@ -551,13 +546,11 @@ bool VehicleObject::takeDamage(const GameObject::DamageInfo& dmg) { if (p->normal == nullptr) continue; if (skeleton->getData(p->normal->getIndex()).enabled) { - auto& geom = - getModel()->geometries[p->normal->getGeometries()[0]]; - auto pp = - p->normal->getMatrix() * glm::vec4(0.f, 0.f, 0.f, 1.f); - float td = glm::distance( - glm::vec3(pp) + geom->geometryBounds.center, dpoint); - if (td < geom->geometryBounds.radius * 1.2f) { + /// @todo correct logic + float damageradius = 0.1f; + auto center = glm::vec3(p->normal->getMatrix()[3]); + float td = glm::distance(center, dpoint); + if (td < damageradius * 1.2f) { setPartState(p, DAM); } /// @todo determine when doors etc. should un-latch @@ -638,20 +631,13 @@ VehicleObject::Part* VehicleObject::getPart(const std::string& name) { return nullptr; } -ModelFrame* findStateFrame(ModelFrame* f, const std::string& state) { - auto it = std::find_if( - f->getChildren().begin(), f->getChildren().end(), [&](ModelFrame* c) { - return c->getName().find(state) != std::string::npos; - }); - if (it != f->getChildren().end()) { - return *it; - } - return nullptr; -} - void VehicleObject::registerPart(ModelFrame* mf) { - auto normal = findStateFrame(mf, "_ok"); - auto damage = findStateFrame(mf, "_dam"); + auto dummynameend = mf->getName().find("_dummy"); + RW_CHECK(dummynameend != std::string::npos, + "Can't create part from non-dummy"); + auto dummyname = mf->getName().substr(0, dummynameend); + auto normal = mf->findDescendant(dummyname + "_hi_ok"); + auto damage = mf->findDescendant(dummyname + "_hi_dam"); if (normal == nullptr && damage == nullptr) { // Not actually a useful part, just a dummy. @@ -672,20 +658,12 @@ void VehicleObject::createObjectHinge(Part* part) { auto& fn = part->dummy->getName(); - ModelFrame* okframe = part->normal; - - if (okframe->getGeometries().size() == 0) return; - - auto& geom = getModel()->geometries[okframe->getGeometries()[0]]; - auto gbounds = geom->geometryBounds; - if (fn.find("door") != fn.npos) { hingeAxis = {0.f, 0.f, 1.f}; // hingePosition = {0.f, 0.2f, 0.f}; boxSize = {0.15f, 0.5f, 0.6f}; // boxOffset = {0.f,-0.2f, gbounds.center.z/2.f}; - auto tf = gbounds.center; - boxOffset = btVector3(tf.x, tf.y, tf.z); + boxOffset = btVector3(0.f, -0.25f, 0.f); hingePosition = -boxOffset; if (sign < 0.f) { From 80c9b73ac5e926d1d3f25b90f5b5f30e0d9357dd Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sat, 7 Jan 2017 23:51:30 +0000 Subject: [PATCH 08/19] Initial Instance Object Rendering via atomics --- rwengine/src/objects/GameObject.hpp | 2 +- rwengine/src/objects/InstanceObject.cpp | 35 +++++++++ rwengine/src/objects/InstanceObject.hpp | 12 ++++ rwengine/src/render/ObjectRenderer.cpp | 95 +++++++------------------ 4 files changed, 72 insertions(+), 72 deletions(-) diff --git a/rwengine/src/objects/GameObject.hpp b/rwengine/src/objects/GameObject.hpp index c4a2fc90..424bafbc 100644 --- a/rwengine/src/objects/GameObject.hpp +++ b/rwengine/src/objects/GameObject.hpp @@ -235,7 +235,7 @@ public: return lifetime; } - void updateTransform(const glm::vec3& pos, const glm::quat& rot) { + virtual void updateTransform(const glm::vec3& pos, const glm::quat& rot) { _lastPosition = position; _lastRotation = rotation; position = pos; diff --git a/rwengine/src/objects/InstanceObject.cpp b/rwengine/src/objects/InstanceObject.cpp index 1b40898c..82572cc7 100644 --- a/rwengine/src/objects/InstanceObject.cpp +++ b/rwengine/src/objects/InstanceObject.cpp @@ -18,6 +18,8 @@ InstanceObject::InstanceObject(GameWorld* engine, const glm::vec3& pos, , _enablePhysics(false) { if (modelinfo) { changeModel(modelinfo); + setPosition(pos); + setRotation(rot); /// @todo store path information properly if (modelinfo->type() == ModelDataType::SimpleInfo) { @@ -133,6 +135,17 @@ void InstanceObject::changeModel(BaseModelInfo* incoming) { setModel(getModelInfo()->getModel()); auto collision = getModelInfo()->getCollision(); + auto modelatomic = getModelInfo()->getAtomic(0); + if (modelatomic) { + auto previousatomic = atomic_; + atomic_ = modelatomic->clone(); + if (previousatomic) { + atomic_->setFrame(previousatomic->getFrame()); + } else { + atomic_->setFrame(std::make_shared()); + } + } + if (collision) { body.reset(new CollisionInstance); body->createPhysicsBody(this, collision, dynamics.get()); @@ -141,11 +154,25 @@ void InstanceObject::changeModel(BaseModelInfo* incoming) { } } +void InstanceObject::setPosition(const glm::vec3& pos) { + if (body) { + auto& wtr = body->getBulletBody()->getWorldTransform(); + wtr.setOrigin(btVector3(pos.x, pos.y, pos.z)); + } + if (atomic_) { + atomic_->getFrame()->setTranslation(pos); + } + GameObject::setPosition(pos); +} + void InstanceObject::setRotation(const glm::quat& r) { if (body) { auto& wtr = body->getBulletBody()->getWorldTransform(); wtr.setRotation(btQuaternion(r.x, r.y, r.z, r.w)); } + if (atomic_) { + atomic_->getFrame()->setRotation(glm::mat3_cast(r)); + } GameObject::setRotation(r); } @@ -181,3 +208,11 @@ void InstanceObject::setSolid(bool solid) { } body->getBulletBody()->setCollisionFlags(flags); } + +void InstanceObject::updateTransform(const glm::vec3& pos, + const glm::quat& rot) { + position = pos; + rotation = rot; + getAtomic()->getFrame()->setRotation(glm::mat3_cast(rot)); + getAtomic()->getFrame()->setTranslation(pos); +} diff --git a/rwengine/src/objects/InstanceObject.hpp b/rwengine/src/objects/InstanceObject.hpp index b669da22..4ca7f1ef 100644 --- a/rwengine/src/objects/InstanceObject.hpp +++ b/rwengine/src/objects/InstanceObject.hpp @@ -14,6 +14,11 @@ class InstanceObject : public GameObject { float health; bool visible = true; + /** + * The Atomic instance for this object + */ + AtomicPtr atomic_; + public: glm::vec3 scale; std::unique_ptr body; @@ -31,10 +36,15 @@ public: return Instance; } + const AtomicPtr& getAtomic() const { + return atomic_; + } + void tick(float dt); void changeModel(BaseModelInfo* incoming); + virtual void setPosition(const glm::vec3 &pos); virtual void setRotation(const glm::quat& r); virtual bool takeDamage(const DamageInfo& damage); @@ -51,6 +61,8 @@ public: float getHealth() const { return health; } + + void updateTransform(const glm::vec3& pos, const glm::quat& rot) override; }; #endif diff --git a/rwengine/src/render/ObjectRenderer.cpp b/rwengine/src/render/ObjectRenderer.cpp index 6890bea2..b2af23bd 100644 --- a/rwengine/src/render/ObjectRenderer.cpp +++ b/rwengine/src/render/ObjectRenderer.cpp @@ -23,6 +23,7 @@ constexpr float kWorldDrawDistanceFactor = kDrawDistanceFactor; constexpr float kVehicleDrawDistanceFactor = kDrawDistanceFactor; constexpr float kPedestrianDrawDistanceFactor = kDrawDistanceFactor; #endif +constexpr float kMagicLODDistance = 330.f; RenderKey createKey(bool transparent, float normalizedDepth, Renderer::Textures& textures) { @@ -132,13 +133,15 @@ void ObjectRenderer::renderClump(Clump* model, const glm::mat4& worldtransform, continue; } - renderAtomic(atomic.get(), worldtransform, object, render); + const auto& framematrix = atomic->getFrame()->getMatrix(); + renderAtomic(atomic.get(), worldtransform * framematrix, object, render); } } void ObjectRenderer::renderInstance(InstanceObject* instance, RenderList& outList) { - if (!instance->getModel()) { + const auto& atomic = instance->getAtomic(); + if (!atomic) { return; } @@ -161,82 +164,32 @@ void ObjectRenderer::renderInstance(InstanceObject* instance, return; } - auto matrixModel = instance->getTimeAdjustedTransform(m_renderAlpha); + float mindist = glm::length(instance->getPosition() - m_camera.position); - float mindist = glm::length(instance->getPosition() - m_camera.position) - - instance->getModel()->getBoundingRadius(); - mindist *= 1.f / kDrawDistanceFactor; + if (mindist < kMagicLODDistance && modelinfo->LOD) { + // @todo this should check if it might be best to render anyway + return; + } - Atomic* atomic = nullptr; - - // These are used to gracefully fade out things that are just out of - // view - // distance. - Atomic* fadingAtomic = nullptr; - auto fadingMatrix = matrixModel; - float opacity = 0.f; - constexpr float fadeRange = 50.f; - - /// @todo replace this block with the correct logic - if (modelinfo->getNumAtomics() == 1) { - // Is closest point greater than the *object* draw distance - float objectRange = modelinfo->getLodDistance(0); - float overlap = (mindist - objectRange); - if (mindist > objectRange) { - // Check for LOD instances - if (instance->LODinstance) { - // Is the closest point greater than the *LOD* draw distance - auto lodmodelinfo = - instance->LODinstance->getModelInfo(); - float LODrange = lodmodelinfo->getLodDistance(0); - if (mindist <= LODrange && instance->LODinstance->getModel()) { - // The model matrix needs to be for the LOD instead - matrixModel = - instance->LODinstance->getTimeAdjustedTransform( - m_renderAlpha); - atomic = lodmodelinfo->getAtomic(0); - // If the object is only just out of range, keep - // rendering it and screen-door the LOD. - if (overlap < fadeRange) { - fadingAtomic = modelinfo->getAtomic(0); - opacity = 1.f - (overlap / fadeRange); - } - } - } - // We don't have a LOD object, so fade out gracefully. - else if (overlap < fadeRange) { - fadingAtomic = modelinfo->getAtomic(0); - opacity = 1.f - (overlap / fadeRange); - } - } - // Otherwise, if we aren't marked as a LOD model, we can render - else if (!modelinfo->LOD) { - atomic = modelinfo->getAtomic(0); - } - } else { - auto root = instance->getModel()->getFrame(); - - matrixModel *= root->getTransform(); - - for (int i = 0; i < modelinfo->getNumAtomics() - 1; ++i) { - auto ind = (modelinfo->getNumAtomics() - 1) - i; - float lodDistance = modelinfo->getLodDistance(i); - if (mindist > lodDistance) { - fadingAtomic = modelinfo->getAtomic(ind); - opacity = 1.f - ((mindist - lodDistance) / fadeRange); - } else { - fadingAtomic = modelinfo->getAtomic(ind); - } + Atomic* distanceatomic = nullptr; + for (int i = 0; i < modelinfo->getNumAtomics(); i++) { + auto atomicdistance = modelinfo->getLodDistance(i); + if (mindist < atomicdistance * kDrawDistanceFactor) { + distanceatomic = modelinfo->getAtomic(i); } } - if (atomic) { - renderAtomic(atomic, matrixModel, instance, outList); + if (! distanceatomic) { + return; } - if (fadingAtomic && opacity >= 0.01f) { - // @todo pass opacity - renderAtomic(fadingAtomic, fadingMatrix, instance, outList); + + if (atomic->getGeometry() != distanceatomic->getGeometry()) { + atomic->setGeometry(distanceatomic->getGeometry()); } + + const auto& frame = atomic->getFrame()->getTransform(); + // Render the atomic the instance thinks it should be + renderAtomic(atomic.get(), frame, instance, outList); } void ObjectRenderer::renderCharacter(CharacterObject* pedestrian, From f64104600e77f9ab0004c496419727f37c44f689 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Tue, 10 Jan 2017 01:24:35 +0000 Subject: [PATCH 09/19] Add a clump instance for each VehicleObject --- rwengine/src/engine/GameWorld.cpp | 2 +- rwengine/src/objects/GameObject.hpp | 15 +++++++++++++- rwengine/src/objects/VehicleObject.cpp | 28 ++++++++++++++++++++++++-- rwengine/src/objects/VehicleObject.hpp | 4 +++- rwengine/src/render/ObjectRenderer.cpp | 23 ++++++++++----------- 5 files changed, 55 insertions(+), 17 deletions(-) diff --git a/rwengine/src/engine/GameWorld.cpp b/rwengine/src/engine/GameWorld.cpp index 88fd4c46..6e25b06f 100644 --- a/rwengine/src/engine/GameWorld.cpp +++ b/rwengine/src/engine/GameWorld.cpp @@ -287,7 +287,7 @@ VehicleObject* GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos, const std::string& name = frame->getName(); if (name.size() > 5 && name.substr(0, 5) == "wheel") { - auto frameTrans = frame->getMatrix(); + const auto& frameTrans = frame->getWorldTransform(); info->second->wheels.push_back({glm::vec3(frameTrans[3])}); } diff --git a/rwengine/src/objects/GameObject.hpp b/rwengine/src/objects/GameObject.hpp index 424bafbc..bbce6e20 100644 --- a/rwengine/src/objects/GameObject.hpp +++ b/rwengine/src/objects/GameObject.hpp @@ -13,7 +13,6 @@ class Skeleton; class CharacterController; -class ModelFrame; class Animator; class GameWorld; @@ -246,4 +245,18 @@ private: ObjectLifetime lifetime; }; +class ClumpObject { + ClumpPtr clump_; + +protected: + void setClump(ClumpPtr ptr) { + clump_ = ptr; + } + +public: + const ClumpPtr& getClump() const { + return clump_; + } +}; + #endif // __GAMEOBJECTS_HPP__ diff --git a/rwengine/src/objects/VehicleObject.cpp b/rwengine/src/objects/VehicleObject.cpp index d75be0fe..f26110cf 100644 --- a/rwengine/src/objects/VehicleObject.cpp +++ b/rwengine/src/objects/VehicleObject.cpp @@ -152,9 +152,11 @@ VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, skeleton = new Skeleton; setModel(getVehicle()->getModel()); + setClump(ClumpPtr(getModelInfo()->getModel()->clone())); // Create meta-data for dummy parts - auto chassisframe = getModel()->findFrame("chassis_dummy"); + auto chassisframe = getClump()->findFrame("chassis_dummy"); + RW_CHECK(chassisframe, "Vehicle has no chassis_dummy"); for (auto& frame : chassisframe->getChildren()) { auto& name = frame->getName(); bool isDum = name.find("_dummy") != name.npos; @@ -179,6 +181,7 @@ VehicleObject::~VehicleObject() { void VehicleObject::setPosition(const glm::vec3& pos) { GameObject::setPosition(pos); + getClump()->getFrame()->setTranslation(pos); if (collision->getBulletBody()) { auto bodyOrigin = btVector3(position.x, position.y, position.z); for (auto& part : dynamicParts) { @@ -196,6 +199,7 @@ void VehicleObject::setPosition(const glm::vec3& pos) { } void VehicleObject::setRotation(const glm::quat& orientation) { + getClump()->getFrame()->setRotation(glm::mat3_cast(orientation)); if (collision->getBulletBody()) { auto t = collision->getBulletBody()->getWorldTransform(); t.setRotation(btQuaternion(orientation.x, orientation.y, orientation.z, @@ -205,6 +209,14 @@ void VehicleObject::setRotation(const glm::quat& orientation) { GameObject::setRotation(orientation); } +void VehicleObject::updateTransform(const glm::vec3& pos, + const glm::quat& rot) { + position = pos; + rotation = rot; + getClump()->getFrame()->setRotation(glm::mat3_cast(rot)); + getClump()->getFrame()->setTranslation(pos); +} + #include void VehicleObject::tick(float dt) { @@ -548,7 +560,7 @@ bool VehicleObject::takeDamage(const GameObject::DamageInfo& dmg) { if (skeleton->getData(p->normal->getIndex()).enabled) { /// @todo correct logic float damageradius = 0.1f; - auto center = glm::vec3(p->normal->getMatrix()[3]); + auto center = glm::vec3(p->normal->getWorldTransform()[3]); float td = glm::distance(center, dpoint); if (td < damageradius * 1.2f) { setPartState(p, DAM); @@ -644,6 +656,18 @@ void VehicleObject::registerPart(ModelFrame* mf) { return; } + // Find the Atomics for the part + Atomic *normal = nullptr, *damage = nullptr; + for (const auto& atomic : getClump()->getAtomics()) { + if (atomic->getFrame().get() == normalframe) { + normal = atomic.get(); + } + if (atomic->getFrame().get() == damageframe) { + damage = atomic.get(); + damage->setFlag(Atomic::ATOMIC_RENDER, false); + } + } + dynamicParts.insert( {mf->getName(), {mf, normal, damage, nullptr, nullptr, false, 0.f, 0.f, 0.f}}); diff --git a/rwengine/src/objects/VehicleObject.hpp b/rwengine/src/objects/VehicleObject.hpp index 870b59ca..e9e42253 100644 --- a/rwengine/src/objects/VehicleObject.hpp +++ b/rwengine/src/objects/VehicleObject.hpp @@ -16,7 +16,7 @@ class btTransform; * @class VehicleObject * Implements Vehicle behaviours. */ -class VehicleObject : public GameObject { +class VehicleObject : public GameObject, public ClumpObject { private: float steerAngle; float throttle; @@ -58,6 +58,8 @@ public: void setRotation(const glm::quat& orientation); + void updateTransform(const glm::vec3& pos, const glm::quat& rot) override; + VehicleModelInfo* getVehicle() const { return getModelInfo(); } diff --git a/rwengine/src/render/ObjectRenderer.cpp b/rwengine/src/render/ObjectRenderer.cpp index b2af23bd..7666735c 100644 --- a/rwengine/src/render/ObjectRenderer.cpp +++ b/rwengine/src/render/ObjectRenderer.cpp @@ -116,13 +116,14 @@ void ObjectRenderer::renderAtomic(Atomic* atomic, RW::BSGeometryBounds& bounds = geometry->geometryBounds; - glm::vec3 boundpos = bounds.center + glm::vec3(worldtransform[3]); + glm::vec3 boundpos = + bounds.center + glm::vec3(frame->getWorldTransform()[3]); if (!m_camera.frustum.intersects(boundpos, bounds.radius)) { culled++; return; } - renderGeometry(geometry.get(), worldtransform, object, render); + renderGeometry(geometry.get(), frame->getWorldTransform(), object, render); } void ObjectRenderer::renderClump(Clump* model, const glm::mat4& worldtransform, @@ -133,8 +134,7 @@ void ObjectRenderer::renderClump(Clump* model, const glm::mat4& worldtransform, continue; } - const auto& framematrix = atomic->getFrame()->getMatrix(); - renderAtomic(atomic.get(), worldtransform * framematrix, object, render); + renderAtomic(atomic.get(), worldtransform, object, render); } } @@ -179,7 +179,7 @@ void ObjectRenderer::renderInstance(InstanceObject* instance, } } - if (! distanceatomic) { + if (!distanceatomic) { return; } @@ -244,15 +244,14 @@ void ObjectRenderer::renderCharacter(CharacterObject* pedestrian, void ObjectRenderer::renderVehicle(VehicleObject* vehicle, RenderList& outList) { - RW_CHECK(vehicle->getModel(), "Vehicle model is null"); - - if (!vehicle->getModel()) { + RW_CHECK(vehicle->getClump(), "Vehicle clump is null"); + if (!vehicle->getClump()) { return; } - glm::mat4 matrixModel = vehicle->getTimeAdjustedTransform(m_renderAlpha); + const auto& clump = vehicle->getClump(); - renderClump(vehicle->getModel(), matrixModel, vehicle, outList); + renderClump(clump.get(), glm::mat4(), vehicle, outList); auto modelinfo = vehicle->getVehicle(); @@ -271,7 +270,7 @@ void ObjectRenderer::renderVehicle(VehicleObject* vehicle, /// @todo migrate this into Vehicle physics tick so we can /// interpolate old -> new - glm::mat4 wheelM(matrixModel); + glm::mat4 wheelM; auto up = -wi.m_wheelDirectionCS; auto right = wi.m_wheelAxleCS; @@ -289,7 +288,7 @@ void ObjectRenderer::renderVehicle(VehicleObject* vehicle, wi.m_raycastInfo.m_suspensionLength); t.getOpenGLMatrix(glm::value_ptr(wheelM)); - wheelM = matrixModel * wheelM; + wheelM = clump->getFrame()->getWorldTransform() * wheelM; wheelM = glm::scale(wheelM, glm::vec3(modelinfo->wheelscale_)); if (wi.m_chassisConnectionPointCS.x() < 0.f) { From 1514bd2cc52759b9269b590d7797cfb1d7f3a1cb Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sun, 8 Jan 2017 01:36:08 +0000 Subject: [PATCH 10/19] Implement Vehicle dynamics with Frames instead of Skeleton --- rwengine/src/objects/VehicleObject.cpp | 44 ++++++++++---------------- rwengine/src/objects/VehicleObject.hpp | 4 +-- tests/test_vehicle.cpp | 16 ++++++---- 3 files changed, 27 insertions(+), 37 deletions(-) diff --git a/rwengine/src/objects/VehicleObject.cpp b/rwengine/src/objects/VehicleObject.cpp index f26110cf..30b76773 100644 --- a/rwengine/src/objects/VehicleObject.cpp +++ b/rwengine/src/objects/VehicleObject.cpp @@ -70,11 +70,7 @@ public: const auto& rot = tform.getRotation(); auto r2 = inv * glm::quat(rot.w(), rot.x(), rot.y(), rot.z()); - auto skeleton = m_object->skeleton; - auto& prev = skeleton->getData(m_part->dummy->getIndex()).a; - auto next = prev; - next.rotation = r2; - skeleton->setData(m_part->dummy->getIndex(), {next, prev, true}); + m_part->dummy->setRotation(glm::mat3_cast(r2)); } private: @@ -148,9 +144,6 @@ VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, : 1.f - info->handling.tractionBias); } - // Hide all LOD and damage frames. - skeleton = new Skeleton; - setModel(getVehicle()->getModel()); setClump(ClumpPtr(getModelInfo()->getModel()->clone())); @@ -557,16 +550,14 @@ bool VehicleObject::takeDamage(const GameObject::DamageInfo& dmg) { if (p->normal == nullptr) continue; - if (skeleton->getData(p->normal->getIndex()).enabled) { - /// @todo correct logic - float damageradius = 0.1f; - auto center = glm::vec3(p->normal->getWorldTransform()[3]); - float td = glm::distance(center, dpoint); - if (td < damageradius * 1.2f) { - setPartState(p, DAM); - } - /// @todo determine when doors etc. should un-latch + /// @todo correct logic + float damageradius = 0.1f; + auto center = glm::vec3(p->dummy->getWorldTransform()[3]); + float td = glm::distance(center, dpoint); + if (td < damageradius * 1.2f) { + setPartState(p, DAM); } + /// @todo determine when doors etc. should un-latch } } @@ -576,11 +567,11 @@ bool VehicleObject::takeDamage(const GameObject::DamageInfo& dmg) { void VehicleObject::setPartState(VehicleObject::Part* part, VehicleObject::FrameState state) { if (state == VehicleObject::OK) { - if (part->normal) skeleton->setEnabled(part->normal, true); - if (part->damaged) skeleton->setEnabled(part->damaged, false); + if (part->normal) part->normal->setFlag(Atomic::ATOMIC_RENDER, true); + if (part->damaged) part->damaged->setFlag(Atomic::ATOMIC_RENDER, false); } else if (state == VehicleObject::DAM) { - if (part->normal) skeleton->setEnabled(part->normal, false); - if (part->damaged) skeleton->setEnabled(part->damaged, true); + if (part->normal) part->normal->setFlag(Atomic::ATOMIC_RENDER, false); + if (part->damaged) part->damaged->setFlag(Atomic::ATOMIC_RENDER, true); } } @@ -611,10 +602,7 @@ void VehicleObject::setPartLocked(VehicleObject::Part* part, bool locked) { destroyObjectHinge(part); // Restore default bone transform - auto dt = part->dummy->getDefaultTranslation(); - auto dr = glm::quat_cast(part->dummy->getDefaultRotation()); - Skeleton::FrameTransform tf{dt, dr}; - skeleton->setData(part->dummy->getIndex(), {tf, tf, true}); + part->dummy->reset(); } } @@ -648,10 +636,10 @@ void VehicleObject::registerPart(ModelFrame* mf) { RW_CHECK(dummynameend != std::string::npos, "Can't create part from non-dummy"); auto dummyname = mf->getName().substr(0, dummynameend); - auto normal = mf->findDescendant(dummyname + "_hi_ok"); - auto damage = mf->findDescendant(dummyname + "_hi_dam"); + auto normalframe = mf->findDescendant(dummyname + "_hi_ok"); + auto damageframe = mf->findDescendant(dummyname + "_hi_dam"); - if (normal == nullptr && damage == nullptr) { + if (normalframe == nullptr && damageframe == nullptr) { // Not actually a useful part, just a dummy. return; } diff --git a/rwengine/src/objects/VehicleObject.hpp b/rwengine/src/objects/VehicleObject.hpp index e9e42253..180497cc 100644 --- a/rwengine/src/objects/VehicleObject.hpp +++ b/rwengine/src/objects/VehicleObject.hpp @@ -36,8 +36,8 @@ public: struct Part { ModelFrame* dummy; - ModelFrame* normal; - ModelFrame* damaged; + Atomic* normal; + Atomic* damaged; btRigidBody* body; btHingeConstraint* constraint; bool moveToAngle; diff --git a/tests/test_vehicle.cpp b/tests/test_vehicle.cpp index 69d79c8e..d5082d8d 100644 --- a/tests/test_vehicle.cpp +++ b/tests/test_vehicle.cpp @@ -41,8 +41,11 @@ BOOST_AUTO_TEST_CASE(vehicle_parts) { BOOST_REQUIRE(part->normal != nullptr); BOOST_REQUIRE(part->damaged != nullptr); - BOOST_CHECK_EQUAL(part->normal->getName(), "bonnet_hi_ok"); - BOOST_CHECK_EQUAL(part->damaged->getName(), "bonnet_hi_dam"); + BOOST_REQUIRE(part->normal->getFrame()); + BOOST_REQUIRE(part->damaged->getFrame()); + + BOOST_CHECK_EQUAL(part->normal->getFrame()->getName(), "bonnet_hi_ok"); + BOOST_CHECK_EQUAL(part->damaged->getFrame()->getName(), "bonnet_hi_dam"); Global::get().e->destroyObject(vehicle); } @@ -55,17 +58,16 @@ BOOST_AUTO_TEST_CASE(vehicle_part_vis) { BOOST_REQUIRE(vehicle->getModel() != nullptr); VehicleObject::Part* bonnetpart = vehicle->getPart("bonnet_dummy"); - auto skel = vehicle->skeleton; vehicle->setPartState(bonnetpart, VehicleObject::DAM); - BOOST_CHECK(!skel->getData(bonnetpart->normal->getIndex()).enabled); - BOOST_CHECK(skel->getData(bonnetpart->damaged->getIndex()).enabled); + BOOST_CHECK((bonnetpart->normal->getFlags() & Atomic::ATOMIC_RENDER) == 0); + BOOST_CHECK((bonnetpart->damaged->getFlags() & Atomic::ATOMIC_RENDER) != 0); vehicle->setPartState(bonnetpart, VehicleObject::OK); - BOOST_CHECK(skel->getData(bonnetpart->normal->getIndex()).enabled); - BOOST_CHECK(!skel->getData(bonnetpart->damaged->getIndex()).enabled); + BOOST_CHECK((bonnetpart->normal->getFlags() & Atomic::ATOMIC_RENDER) != 0); + BOOST_CHECK((bonnetpart->damaged->getFlags() & Atomic::ATOMIC_RENDER) == 0); Global::get().e->destroyObject(vehicle); } From 3163a5dd5736cf925821754fd29a4aa2c6667224 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sun, 8 Jan 2017 02:52:04 +0000 Subject: [PATCH 11/19] Initial CharacterObject Clump implementation --- rwengine/src/items/Weapon.cpp | 14 +---- rwengine/src/objects/CharacterObject.cpp | 72 ++++++++++++------------ rwengine/src/objects/CharacterObject.hpp | 2 +- rwengine/src/render/ObjectRenderer.cpp | 36 ++++-------- 4 files changed, 51 insertions(+), 73 deletions(-) diff --git a/rwengine/src/items/Weapon.cpp b/rwengine/src/items/Weapon.cpp index 5f3d1a48..b45bd993 100644 --- a/rwengine/src/items/Weapon.cpp +++ b/rwengine/src/items/Weapon.cpp @@ -4,20 +4,12 @@ #include void Weapon::fireHitscan(WeaponData* weapon, CharacterObject* owner) { - auto handFrame = owner->getModel()->findFrame("srhand"); - glm::mat4 handMatrix; - if (handFrame) { - while (handFrame->getParent()) { - handMatrix = - owner->skeleton->getMatrix(handFrame->getIndex()) * handMatrix; - handFrame = handFrame->getParent(); - } - } + auto handFrame = owner->getClump()->findFrame("srhand"); + glm::mat4 handMatrix = handFrame->getWorldTransform(); const auto& raydirection = owner->getLookDirection(); const auto rayend = owner->getPosition() + raydirection * weapon->hitRange; - auto handPos = glm::vec3(handMatrix[3]); - auto fireOrigin = owner->getPosition() + owner->getRotation() * handPos; + auto fireOrigin = glm::vec3(handMatrix[3]); float dmg = weapon->damage; owner->engine->doWeaponScan({dmg, fireOrigin, rayend, weapon}); diff --git a/rwengine/src/objects/CharacterObject.cpp b/rwengine/src/objects/CharacterObject.cpp index 5983fcd3..c92a489d 100644 --- a/rwengine/src/objects/CharacterObject.cpp +++ b/rwengine/src/objects/CharacterObject.cpp @@ -71,6 +71,7 @@ CharacterObject::CharacterObject(GameWorld* engine, const glm::vec3& pos, animations.ko_shot_front = engine->data->animations["ko_shot_front"]; auto info = getModelInfo(); + setClump(ClumpPtr(info->getModel()->clone())); if (info->getModel()) { setModel(info->getModel()); skeleton = new Skeleton; @@ -108,9 +109,8 @@ void CharacterObject::createActor(const glm::vec2& size) { physCharacter = new btKinematicCharacterController(physObject, physShape, 0.30f, 2); #else - physCharacter = - new btKinematicCharacterController(physObject, physShape, 0.30f, - btVector3(0.f, 0.f, 1.f)); + physCharacter = new btKinematicCharacterController( + physObject, physShape, 0.30f, btVector3(0.f, 0.f, 1.f)); #endif physCharacter->setFallSpeed(20.f); physCharacter->setUseGhostSweepTest(true); @@ -220,42 +220,41 @@ glm::vec3 CharacterObject::updateMovementAnimation(float dt) { } // If we have to, interrogate the movement animation - if (movementAnimation != animations.idle) { - if (!getModel()->frames[0]->getChildren().empty()) { - ModelFrame* root = getModel()->frames[0]->getChildren()[0]; - auto it = movementAnimation->bones.find(root->getName()); - if (it != movementAnimation->bones.end()) { - AnimationBone* rootBone = it->second; - float step = dt; - const float duration = - animator->getAnimation(AnimIndexMovement)->duration; - float animTime = fmod( - animator->getAnimationTime(AnimIndexMovement), duration); - - // Handle any remaining transformation before the end of the - // keyframes - if ((animTime + step) > duration) { - glm::vec3 a = - rootBone->getInterpolatedKeyframe(animTime).position; - glm::vec3 b = - rootBone->getInterpolatedKeyframe(duration).position; - glm::vec3 d = (b - a); - animTranslate.y += d.y; - step -= (duration - animTime); - animTime = 0.f; - } + const auto& modelroot = getModel()->getFrame(); + if (movementAnimation != animations.idle && + !modelroot->getChildren().empty()) { + const auto& root = modelroot->getChildren()[0]; + auto it = movementAnimation->bones.find(root->getName()); + if (it != movementAnimation->bones.end()) { + AnimationBone* rootBone = it->second; + float step = dt; + const float duration = + animator->getAnimation(AnimIndexMovement)->duration; + float animTime = + fmod(animator->getAnimationTime(AnimIndexMovement), duration); + // Handle any remaining transformation before the end of the + // keyframes + if ((animTime + step) > duration) { glm::vec3 a = rootBone->getInterpolatedKeyframe(animTime).position; glm::vec3 b = - rootBone->getInterpolatedKeyframe(animTime + step).position; + rootBone->getInterpolatedKeyframe(duration).position; glm::vec3 d = (b - a); animTranslate.y += d.y; - - Skeleton::FrameData fd = skeleton->getData(root->getIndex()); - fd.a.translation.y = 0.f; - skeleton->setData(root->getIndex(), fd); + step -= (duration - animTime); + animTime = 0.f; } + + glm::vec3 a = rootBone->getInterpolatedKeyframe(animTime).position; + glm::vec3 b = + rootBone->getInterpolatedKeyframe(animTime + step).position; + glm::vec3 d = (b - a); + animTranslate.y += d.y; + + Skeleton::FrameData fd = skeleton->getData(root->getIndex()); + fd.a.translation.y = 0.f; + skeleton->setData(root->getIndex(), fd); } } @@ -276,8 +275,7 @@ void CharacterObject::tick(float dt) { } } -void CharacterObject::setRotation(const glm::quat &orientation) -{ +void CharacterObject::setRotation(const glm::quat& orientation) { m_look.x = glm::roll(orientation); rotation = orientation; } @@ -332,6 +330,7 @@ void CharacterObject::updateCharacter(float dt) { yaw += std::atan2(movement.z, movement.x); } rotation = glm::quat(glm::vec3(0.f, 0.f, yaw)); + getClump()->getFrame()->setRotation(glm::mat3_cast(rotation)); } walkDir = rotation * walkDir; @@ -352,6 +351,7 @@ void CharacterObject::updateCharacter(float dt) { auto Pos = physCharacter->getGhostObject()->getWorldTransform().getOrigin(); position = glm::vec3(Pos.x(), Pos.y(), Pos.z()); + getClump()->getFrame()->setTranslation(position); // Handle above waist height water. auto wi = engine->data->getWaterIndexAt(getPosition()); @@ -407,6 +407,7 @@ void CharacterObject::setPosition(const glm::vec3& pos) { physCharacter->warp(bpos); } position = pos; + getClump()->getFrame()->setTranslation(pos); } bool CharacterObject::isAlive() const { @@ -611,8 +612,7 @@ void CharacterObject::useItem(bool active, bool primary) { if (!currentState.primaryActive && active) { // If we've just started, activate controller->setNextActivity(new Activities::UseItem(item)); - } - else if (currentState.primaryActive && !active) { + } else if (currentState.primaryActive && !active) { // UseItem will cancel itself upon !primaryActive } currentState.primaryActive = active; diff --git a/rwengine/src/objects/CharacterObject.hpp b/rwengine/src/objects/CharacterObject.hpp index f95c28cd..4ffed1c3 100644 --- a/rwengine/src/objects/CharacterObject.hpp +++ b/rwengine/src/objects/CharacterObject.hpp @@ -98,7 +98,7 @@ struct AnimationGroup { * @brief The CharacterObject struct * Implements Character object behaviours. */ -class CharacterObject : public GameObject { +class CharacterObject : public GameObject, public ClumpObject { private: CharacterState currentState; diff --git a/rwengine/src/render/ObjectRenderer.cpp b/rwengine/src/render/ObjectRenderer.cpp index 7666735c..c5346093 100644 --- a/rwengine/src/render/ObjectRenderer.cpp +++ b/rwengine/src/render/ObjectRenderer.cpp @@ -194,28 +194,27 @@ void ObjectRenderer::renderInstance(InstanceObject* instance, void ObjectRenderer::renderCharacter(CharacterObject* pedestrian, RenderList& outList) { - glm::mat4 matrixModel; + const auto& clump = pedestrian->getClump(); if (pedestrian->getCurrentVehicle()) { auto vehicle = pedestrian->getCurrentVehicle(); + const auto& vehicleclump = vehicle->getClump(); auto seat = pedestrian->getCurrentSeat(); - matrixModel = vehicle->getTimeAdjustedTransform(m_renderAlpha); + auto matrixModel = vehicleclump->getFrame()->getWorldTransform(); if (pedestrian->isEnteringOrExitingVehicle()) { matrixModel = glm::translate(matrixModel, vehicle->getSeatEntryPosition(seat)); + clump->getFrame()->setTransform(matrixModel); } else { if (seat < vehicle->info->seats.size()) { matrixModel = glm::translate(matrixModel, vehicle->info->seats[seat].offset); + clump->getFrame()->setTransform(matrixModel); } } - } else { - matrixModel = pedestrian->getTimeAdjustedTransform(m_renderAlpha); } - if (!pedestrian->getModel()) return; - - renderClump(pedestrian->getModel(), matrixModel, nullptr, outList); + renderClump(pedestrian->getClump().get(), glm::mat4(), nullptr, outList); auto item = pedestrian->getActiveItem(); const auto& weapon = pedestrian->engine->data->weaponData[item]; @@ -224,22 +223,13 @@ void ObjectRenderer::renderCharacter(CharacterObject* pedestrian, return; // No model for this item } - auto handFrame = pedestrian->getModel()->findFrame("srhand"); - glm::mat4 localMatrix; + auto handFrame = pedestrian->getClump()->findFrame("srhand"); if (handFrame) { - while (handFrame->getParent()) { - localMatrix = - pedestrian->skeleton->getMatrix(handFrame->getIndex()) * - localMatrix; - handFrame = handFrame->getParent(); - } - } - - // Assume items are all simple - auto simple = + auto simple = m_world->data->findModelInfo(weapon->modelID); - auto itematomic = simple->getAtomic(0); - renderAtomic(itematomic, matrixModel * localMatrix, nullptr, outList); + auto itematomic = simple->getAtomic(0); + renderAtomic(itematomic, handFrame->getWorldTransform(), nullptr, outList); + } } void ObjectRenderer::renderVehicle(VehicleObject* vehicle, @@ -367,10 +357,6 @@ void ObjectRenderer::renderProjectile(ProjectileObject* projectile, } void ObjectRenderer::buildRenderList(GameObject* object, RenderList& outList) { - if (object->skeleton) { - object->skeleton->interpolate(m_renderAlpha); - } - // Right now specialized on each object type switch (object->type()) { case GameObject::Instance: From ec5f1d7b553fa8496cec58c13863e91e557df25d Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sun, 8 Jan 2017 03:28:33 +0000 Subject: [PATCH 12/19] Change Animator to animate Frames directly instead of Skeleton --- rwengine/src/engine/Animator.cpp | 41 +++++++++++------------- rwengine/src/engine/Animator.hpp | 18 ++--------- rwengine/src/objects/CharacterObject.cpp | 14 +++----- rwengine/src/objects/CutsceneObject.cpp | 3 +- tests/test_animation.cpp | 12 +++---- 5 files changed, 31 insertions(+), 57 deletions(-) diff --git a/rwengine/src/engine/Animator.cpp b/rwengine/src/engine/Animator.cpp index 6dcf727d..68dabbd6 100644 --- a/rwengine/src/engine/Animator.cpp +++ b/rwengine/src/engine/Animator.cpp @@ -3,9 +3,9 @@ #include #include #include +#include -Animator::Animator(Clump* model, Skeleton* skeleton) - : model(model), skeleton(skeleton) { +Animator::Animator(Clump* model) : model(model) { } void Animator::tick(float dt) { @@ -18,21 +18,21 @@ void Animator::tick(float dt) { glm::quat rotation; }; +#if 0 // Blend all active animations together - std::map blendFrames; + std::map blendFrames; +#endif for (AnimationState& state : animations) { - RW_CHECK(state.animation != nullptr, - "AnimationState with no animation"); if (state.animation == nullptr) continue; - if (state.boneInstances.size() == 0) { - for (unsigned int f = 0; f < model->frames.size(); ++f) { - auto bit = - state.animation->bones.find(model->frames[f]->getName()); - if (bit != state.animation->bones.end()) { - state.boneInstances.insert({bit->second, {f}}); + if (state.boneInstances.empty()) { + for (const auto& bone : state.animation->bones) { + auto frame = model->findFrame(bone.first); + if (!frame) { + continue; } + state.boneInstances.insert({bone.second, frame}); } } @@ -72,23 +72,20 @@ void Animator::tick(float dt) { blendFrames[b.second.frameIndex] = xform; } #else - blendFrames[b.second.frameIndex] = xform; + b.second->setTranslation(b.second->getDefaultTranslation() + + xform.translation); + b.second->setRotation(glm::mat3_cast(xform.rotation)); #endif } } +#if 0 for (auto& p : blendFrames) { - auto& data = skeleton->getData(p.first); - Skeleton::FrameData fd; - fd.b = data.a; - fd.enabled = data.enabled; - - fd.a.translation = model->frames[p.first]->getDefaultTranslation() + - p.second.translation; - fd.a.rotation = p.second.rotation; - - skeleton->setData(p.first, fd); + p.first->setTranslation(p.first->getDefaultTranslation() + + p.second.translation); + p.first->setRotation(glm::mat3_cast(p.second.rotation)); } +#endif } bool Animator::isCompleted(unsigned int slot) const { diff --git a/rwengine/src/engine/Animator.hpp b/rwengine/src/engine/Animator.hpp index 50323589..dc1cd894 100644 --- a/rwengine/src/engine/Animator.hpp +++ b/rwengine/src/engine/Animator.hpp @@ -11,8 +11,6 @@ class Clump; class ModelFrame; -class Skeleton; - /** * @brief calculates animation frame matrices, as well as procedural frame * animation. @@ -24,13 +22,6 @@ class Skeleton; * The Animator will blend all active animations together. */ class Animator { - /** - * @brief Stores data required to animate a model frame - */ - struct BoneInstanceData { - unsigned int frameIndex; - }; - /** * @brief The AnimationState struct stores information about playing * animations @@ -43,7 +34,7 @@ class Animator { float speed; /// Automatically restart bool repeat; - std::map boneInstances; + std::map boneInstances; }; /** @@ -51,18 +42,13 @@ class Animator { */ Clump* model; - /** - * @brief Skeleton instance. - */ - Skeleton* skeleton; - /** * @brief Currently playing animations */ std::vector animations; public: - Animator(Clump* model, Skeleton* skeleton); + Animator(Clump* model); Animation* getAnimation(unsigned int slot) { if (slot < animations.size()) { diff --git a/rwengine/src/objects/CharacterObject.cpp b/rwengine/src/objects/CharacterObject.cpp index c92a489d..103b23dd 100644 --- a/rwengine/src/objects/CharacterObject.cpp +++ b/rwengine/src/objects/CharacterObject.cpp @@ -74,8 +74,7 @@ CharacterObject::CharacterObject(GameWorld* engine, const glm::vec3& pos, setClump(ClumpPtr(info->getModel()->clone())); if (info->getModel()) { setModel(info->getModel()); - skeleton = new Skeleton; - animator = new Animator(getModel(), skeleton); + animator = new Animator(getClump().get()); createActor(); } @@ -251,10 +250,6 @@ glm::vec3 CharacterObject::updateMovementAnimation(float dt) { rootBone->getInterpolatedKeyframe(animTime + step).position; glm::vec3 d = (b - a); animTranslate.y += d.y; - - Skeleton::FrameData fd = skeleton->getData(root->getIndex()); - fd.a.translation.y = 0.f; - skeleton->setData(root->getIndex(), fd); } } @@ -278,6 +273,7 @@ void CharacterObject::tick(float dt) { void CharacterObject::setRotation(const glm::quat& orientation) { m_look.x = glm::roll(orientation); rotation = orientation; + getClump()->getFrame()->setRotation(glm::mat3_cast(rotation)); } #include @@ -291,15 +287,13 @@ void CharacterObject::changeCharacterModel(const std::string& name) { engine->data->loadTXD(modelName + ".txd"); auto newmodel = engine->data->loadClump(modelName + ".dff"); - if (skeleton) { + if (animator) { delete animator; - delete skeleton; } setModel(newmodel); - skeleton = new Skeleton; - animator = new Animator(getModel(), skeleton); + animator = new Animator(getClump().get()); } void CharacterObject::updateCharacter(float dt) { diff --git a/rwengine/src/objects/CutsceneObject.cpp b/rwengine/src/objects/CutsceneObject.cpp index 5cad5df4..557a0498 100644 --- a/rwengine/src/objects/CutsceneObject.cpp +++ b/rwengine/src/objects/CutsceneObject.cpp @@ -14,8 +14,7 @@ CutsceneObject::CutsceneObject(GameWorld *engine, const glm::vec3 &pos, else { setModel(getModelInfo()->getModel()); } - skeleton = new Skeleton; - animator = new Animator(getModel(), skeleton); + animator = new Animator(getModel()); } CutsceneObject::~CutsceneObject() { diff --git a/tests/test_animation.cpp b/tests/test_animation.cpp index a4308c4d..77f24f96 100644 --- a/tests/test_animation.cpp +++ b/tests/test_animation.cpp @@ -17,7 +17,7 @@ BOOST_AUTO_TEST_CASE(test_matrix) { * frame #s. */ auto test_model = Global::get().d->loadClump("player.dff"); - Animator animator(test_model, &skeleton); + Animator animator(test_model); animation.duration = 1.f; animation.bones["player"] = new AnimationBone{ @@ -35,17 +35,15 @@ BOOST_AUTO_TEST_CASE(test_matrix) { animator.tick(0.0f); - BOOST_CHECK(skeleton.getData(0).a.translation == - glm::vec3(0.f, 0.f, 0.f)); - BOOST_CHECK(skeleton.getData(0).b.translation == + const auto& root = test_model->findFrame("player"); + + BOOST_CHECK(glm::vec3(root->getTransform()[3]) == glm::vec3(0.f, 0.f, 0.f)); animator.tick(1.0f); - BOOST_CHECK(skeleton.getData(0).a.translation == + BOOST_CHECK(glm::vec3(root->getTransform()[3]) == glm::vec3(0.f, 1.f, 0.f)); - BOOST_CHECK(skeleton.getData(0).b.translation == - glm::vec3(0.f, 0.f, 0.f)); } } #endif From a6396ec6e8f980bc9dbbcde1fb3bfb2b369a13af Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sun, 8 Jan 2017 17:32:09 +0000 Subject: [PATCH 13/19] Remove forward movement from Character Animation --- rwengine/src/objects/CharacterObject.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/rwengine/src/objects/CharacterObject.cpp b/rwengine/src/objects/CharacterObject.cpp index 103b23dd..5fca3a35 100644 --- a/rwengine/src/objects/CharacterObject.cpp +++ b/rwengine/src/objects/CharacterObject.cpp @@ -219,7 +219,7 @@ glm::vec3 CharacterObject::updateMovementAnimation(float dt) { } // If we have to, interrogate the movement animation - const auto& modelroot = getModel()->getFrame(); + const auto& modelroot = getClump()->getFrame(); if (movementAnimation != animations.idle && !modelroot->getChildren().empty()) { const auto& root = modelroot->getChildren()[0]; @@ -250,6 +250,11 @@ glm::vec3 CharacterObject::updateMovementAnimation(float dt) { rootBone->getInterpolatedKeyframe(animTime + step).position; glm::vec3 d = (b - a); animTranslate.y += d.y; + + // Kludge: Drop y component of root bone + auto t = glm::vec3(root->getTransform()[3]); + t.y = 0.f; + root->setTranslation(t); } } From 94456aa732dff7101e4508cc789e5a45cd6e4223 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sun, 8 Jan 2017 17:32:45 +0000 Subject: [PATCH 14/19] Convert CutsceneObject to use Frame animation --- rwengine/src/objects/CutsceneObject.cpp | 3 +- rwengine/src/objects/CutsceneObject.hpp | 2 +- rwengine/src/render/ObjectRenderer.cpp | 50 ++++++------------- .../src/script/modules/GTA3ModuleImpl.inl | 10 ++-- 4 files changed, 24 insertions(+), 41 deletions(-) diff --git a/rwengine/src/objects/CutsceneObject.cpp b/rwengine/src/objects/CutsceneObject.cpp index 557a0498..c5893929 100644 --- a/rwengine/src/objects/CutsceneObject.cpp +++ b/rwengine/src/objects/CutsceneObject.cpp @@ -14,7 +14,8 @@ CutsceneObject::CutsceneObject(GameWorld *engine, const glm::vec3 &pos, else { setModel(getModelInfo()->getModel()); } - animator = new Animator(getModel()); + setClump(ClumpPtr(getModel()->clone())); + animator = new Animator(getClump().get()); } CutsceneObject::~CutsceneObject() { diff --git a/rwengine/src/objects/CutsceneObject.hpp b/rwengine/src/objects/CutsceneObject.hpp index 566d638f..6a05f4f8 100644 --- a/rwengine/src/objects/CutsceneObject.hpp +++ b/rwengine/src/objects/CutsceneObject.hpp @@ -6,7 +6,7 @@ /** * @brief Object type used for cutscene animations. */ -class CutsceneObject : public GameObject { +class CutsceneObject : public GameObject, public ClumpObject { GameObject* _parent; ModelFrame* _bone; diff --git a/rwengine/src/render/ObjectRenderer.cpp b/rwengine/src/render/ObjectRenderer.cpp index c5346093..c0ac1d9f 100644 --- a/rwengine/src/render/ObjectRenderer.cpp +++ b/rwengine/src/render/ObjectRenderer.cpp @@ -116,14 +116,15 @@ void ObjectRenderer::renderAtomic(Atomic* atomic, RW::BSGeometryBounds& bounds = geometry->geometryBounds; - glm::vec3 boundpos = - bounds.center + glm::vec3(frame->getWorldTransform()[3]); + auto transform = worldtransform * frame->getWorldTransform(); + + glm::vec3 boundpos = bounds.center + glm::vec3(transform[3]); if (!m_camera.frustum.intersects(boundpos, bounds.radius)) { culled++; return; } - renderGeometry(geometry.get(), frame->getWorldTransform(), object, render); + renderGeometry(geometry.get(), transform, object, render); } void ObjectRenderer::renderClump(Clump* model, const glm::mat4& worldtransform, @@ -187,9 +188,8 @@ void ObjectRenderer::renderInstance(InstanceObject* instance, atomic->setGeometry(distanceatomic->getGeometry()); } - const auto& frame = atomic->getFrame()->getTransform(); // Render the atomic the instance thinks it should be - renderAtomic(atomic.get(), frame, instance, outList); + renderAtomic(atomic.get(), glm::mat4(), instance, outList); } void ObjectRenderer::renderCharacter(CharacterObject* pedestrian, @@ -226,7 +226,7 @@ void ObjectRenderer::renderCharacter(CharacterObject* pedestrian, auto handFrame = pedestrian->getClump()->findFrame("srhand"); if (handFrame) { auto simple = - m_world->data->findModelInfo(weapon->modelID); + m_world->data->findModelInfo(weapon->modelID); auto itematomic = simple->getAtomic(0); renderAtomic(itematomic, handFrame->getWorldTransform(), nullptr, outList); } @@ -306,43 +306,21 @@ void ObjectRenderer::renderPickup(PickupObject* pickup, RenderList& outList) { void ObjectRenderer::renderCutsceneObject(CutsceneObject* cutscene, RenderList& outList) { if (!m_world->state->currentCutscene) return; + const auto& clump = cutscene->getClump(); - if (!cutscene->getModel()) { - return; - } - - glm::mat4 matrixModel; auto cutsceneOffset = m_world->state->currentCutscene->meta.sceneOffset + glm::vec3(0.f, 0.f, 1.f); + glm::mat4 cutscenespace; + cutscenespace = glm::translate(cutscenespace, cutsceneOffset); if (cutscene->getParentActor()) { - matrixModel = glm::translate(matrixModel, cutsceneOffset); - // matrixModel = - // cutscene->getParentActor()->getTimeAdjustedTransform(_renderAlpha); - // matrixModel = glm::translate(matrixModel, glm::vec3(0.f, 0.f, - // 1.f)); - glm::mat4 localMatrix; - auto boneframe = cutscene->getParentFrame(); - while (boneframe) { - localMatrix = cutscene->getParentActor()->skeleton->getMatrix( - boneframe->getIndex()) * - localMatrix; - boneframe = boneframe->getParent(); - } - matrixModel = matrixModel * localMatrix; - } else { - matrixModel = glm::translate(matrixModel, cutsceneOffset); + auto parent = cutscene->getParentFrame(); + cutscenespace *= parent->getWorldTransform(); + cutscenespace = + glm::rotate(cutscenespace, glm::half_pi(), {0.f, 1.f, 0.f}); } - auto model = cutscene->getModel(); - if (cutscene->getParentActor()) { - glm::mat4 align; - /// @todo figure out where this 90 degree offset is coming from. - align = glm::rotate(align, glm::half_pi(), {0.f, 1.f, 0.f}); - renderClump(model, matrixModel * align, nullptr, outList); - } else { - renderClump(model, matrixModel, nullptr, outList); - } + renderClump(clump.get(), cutscenespace, nullptr, outList); } void ObjectRenderer::renderProjectile(ProjectileObject* projectile, diff --git a/rwengine/src/script/modules/GTA3ModuleImpl.inl b/rwengine/src/script/modules/GTA3ModuleImpl.inl index 762842df..843558f5 100644 --- a/rwengine/src/script/modules/GTA3ModuleImpl.inl +++ b/rwengine/src/script/modules/GTA3ModuleImpl.inl @@ -8455,11 +8455,15 @@ void opcode_02f4(const ScriptArguments& args, const ScriptObject object0, const RW_UNUSED(model); RW_UNUSED(object1); auto id = args[1].integer; - auto actor = args.getObject(0); + auto actor = static_cast(args.getObject(0)); CutsceneObject* object = args.getWorld()->createCutsceneObject(id, args.getWorld()->state->currentCutscene->meta.sceneOffset ); - auto headframe = actor->getModel()->findFrame("shead"); - actor->skeleton->setEnabled(headframe, false); + auto headframe = actor->getClump()->findFrame("shead"); + for (const auto& atomic : actor->getClump()->getAtomics()) { + if (atomic->getFrame().get() == headframe) { + atomic->setFlag(Atomic::ATOMIC_RENDER, false); + } + } object->setParentActor(actor, headframe); *args[2].globalInteger = object->getGameObjectID(); From d84b492412913ec79057dc364cf80c39d4114dc3 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sun, 8 Jan 2017 19:46:00 +0000 Subject: [PATCH 15/19] Remove all traces of Skeleton --- rwengine/CMakeLists.txt | 2 - rwengine/src/data/Skeleton.cpp | 100 ------------------ rwengine/src/data/Skeleton.hpp | 59 ----------- rwengine/src/engine/Animator.cpp | 1 - rwengine/src/items/Weapon.cpp | 1 - rwengine/src/objects/CharacterObject.cpp | 1 - rwengine/src/objects/CutsceneObject.cpp | 1 - rwengine/src/objects/GameObject.cpp | 4 - rwengine/src/objects/GameObject.hpp | 3 - rwengine/src/objects/VehicleObject.cpp | 1 - rwengine/src/render/GameRenderer.cpp | 1 - rwengine/src/render/ObjectRenderer.cpp | 1 - .../src/script/modules/GTA3ModuleImpl.inl | 1 - rwviewer/ViewerWidget.cpp | 4 +- rwviewer/models/DFFFramesTreeModel.cpp | 17 ++- rwviewer/models/DFFFramesTreeModel.hpp | 4 +- rwviewer/views/ModelViewer.cpp | 12 +-- rwviewer/views/ModelViewer.hpp | 2 - rwviewer/widgets/ModelFramesWidget.cpp | 4 +- rwviewer/widgets/ModelFramesWidget.hpp | 2 +- tests/CMakeLists.txt | 1 - tests/test_animation.cpp | 2 - tests/test_skeleton.cpp | 63 ----------- tests/test_vehicle.cpp | 1 - 24 files changed, 14 insertions(+), 274 deletions(-) delete mode 100644 rwengine/src/data/Skeleton.cpp delete mode 100644 rwengine/src/data/Skeleton.hpp delete mode 100644 tests/test_skeleton.cpp diff --git a/rwengine/CMakeLists.txt b/rwengine/CMakeLists.txt index 5e9b8951..534744c3 100644 --- a/rwengine/CMakeLists.txt +++ b/rwengine/CMakeLists.txt @@ -41,8 +41,6 @@ set(RWENGINE_SOURCES src/data/PathData.hpp src/data/PedData.cpp src/data/PedData.hpp - src/data/Skeleton.cpp - src/data/Skeleton.hpp src/data/WeaponData.hpp src/data/ZoneData.hpp src/dynamics/CollisionInstance.cpp diff --git a/rwengine/src/data/Skeleton.cpp b/rwengine/src/data/Skeleton.cpp deleted file mode 100644 index 2665344a..00000000 --- a/rwengine/src/data/Skeleton.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include -#include -#include - -Skeleton::FrameTransform Skeleton::IdentityTransform = {glm::vec3(0.f), - glm::quat()}; -Skeleton::FrameData Skeleton::IdentityData = { - Skeleton::IdentityTransform, Skeleton::IdentityTransform, true}; - -Skeleton::Skeleton() { -} - -void Skeleton::setAllData(const Skeleton::FramesData& data) { - framedata = data; -} - -const Skeleton::FrameData& Skeleton::getData(unsigned int frameIdx) const { - auto fdit = framedata.find(frameIdx); - if (fdit == framedata.end()) { - return Skeleton::IdentityData; - } - - return fdit->second; -} - -void Skeleton::setData(unsigned int frameIdx, const Skeleton::FrameData& data) { - framedata[frameIdx] = data; -} - -void Skeleton::setEnabled(ModelFrame* frame, bool enabled) { - auto fdit = framedata.find(frame->getIndex()); - if (fdit != framedata.end()) { - fdit->second.enabled = enabled; - } else { - FrameTransform tf{frame->getDefaultTranslation(), - glm::quat_cast(frame->getDefaultRotation())}; - framedata.insert({frame->getIndex(), {tf, tf, enabled}}); - } -} - -void Skeleton::setEnabled(unsigned int frameIdx, bool enabled) { - auto fdit = framedata.find(frameIdx); - if (fdit == framedata.end()) { - framedata.insert({frameIdx, - {Skeleton::IdentityTransform, - Skeleton::IdentityTransform, enabled}}); - } else { - fdit->second.enabled = enabled; - } -} - -const Skeleton::FrameTransform& Skeleton::getInterpolated( - unsigned int frameIdx) const { - auto itit = interpolateddata.find(frameIdx); - if (itit == interpolateddata.end()) { - return Skeleton::IdentityTransform; - } - - return itit->second; -} - -void Skeleton::interpolate(float alpha) { - interpolateddata.clear(); - - for (auto i = framedata.begin(); i != framedata.end(); ++i) { - auto& t2 = i->second.a.translation; - auto& t1 = i->second.b.translation; - - auto& r2 = i->second.a.rotation; - auto& r1 = i->second.b.rotation; - - interpolateddata.insert( - {i->first, {glm::mix(t1, t2, alpha), glm::slerp(r1, r2, alpha)}}); - } -} - -glm::mat4 Skeleton::getMatrix(unsigned int frameIdx) const { - const FrameTransform& ft = getInterpolated(frameIdx); - - glm::mat4 m; - - m = glm::translate(m, ft.translation); - m = m * glm::mat4_cast(ft.rotation); - - return m; -} - -glm::mat4 Skeleton::getMatrix(ModelFrame* frame) const { - auto itit = interpolateddata.find(frame->getIndex()); - if (itit != interpolateddata.end()) { - glm::mat4 m; - - m = glm::translate(m, itit->second.translation); - m = m * glm::mat4_cast(itit->second.rotation); - - return m; - } - - return frame->getTransform(); -} diff --git a/rwengine/src/data/Skeleton.hpp b/rwengine/src/data/Skeleton.hpp deleted file mode 100644 index 0c487989..00000000 --- a/rwengine/src/data/Skeleton.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef _SKELETON_HPP_ -#define _SKELETON_HPP_ - -#include -#include -#include -#include - -class ModelFrame; -/** - * Data class for additional frame transformation and meta data. - * - * Provides interfaces to modify and query the visibility of model frames, - * as well as their transformation. Modified by Animator to animate models. - */ -class Skeleton { -public: - struct FrameTransform { - glm::vec3 translation; - glm::quat rotation; - }; - - static FrameTransform IdentityTransform; - - struct FrameData { - FrameTransform a; - FrameTransform b; - bool enabled; - }; - - static FrameData IdentityData; - - typedef std::map FramesData; - typedef std::map TransformData; - - Skeleton(); - - void setAllData(const FramesData& data); - - const FrameData& getData(unsigned int frameIdx) const; - - void setData(unsigned int frameIdx, const FrameData& data); - void setEnabled(ModelFrame* frame, bool enabled); - - void setEnabled(unsigned int frameIdx, bool enabled); - - const FrameTransform& getInterpolated(unsigned int frameIdx) const; - - glm::mat4 getMatrix(unsigned int frameIdx) const; - glm::mat4 getMatrix(ModelFrame* frame) const; - - void interpolate(float alpha); - -private: - FramesData framedata; - TransformData interpolateddata; -}; - -#endif \ No newline at end of file diff --git a/rwengine/src/engine/Animator.cpp b/rwengine/src/engine/Animator.cpp index 68dabbd6..a03cd2c9 100644 --- a/rwengine/src/engine/Animator.cpp +++ b/rwengine/src/engine/Animator.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/rwengine/src/items/Weapon.cpp b/rwengine/src/items/Weapon.cpp index b45bd993..560161de 100644 --- a/rwengine/src/items/Weapon.cpp +++ b/rwengine/src/items/Weapon.cpp @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/rwengine/src/objects/CharacterObject.cpp b/rwengine/src/objects/CharacterObject.cpp index 5fca3a35..ba3608b9 100644 --- a/rwengine/src/objects/CharacterObject.cpp +++ b/rwengine/src/objects/CharacterObject.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/rwengine/src/objects/CutsceneObject.cpp b/rwengine/src/objects/CutsceneObject.cpp index c5893929..bc35a74e 100644 --- a/rwengine/src/objects/CutsceneObject.cpp +++ b/rwengine/src/objects/CutsceneObject.cpp @@ -1,4 +1,3 @@ -#include #include #include diff --git a/rwengine/src/objects/GameObject.cpp b/rwengine/src/objects/GameObject.cpp index 08f6741a..c80d51ed 100644 --- a/rwengine/src/objects/GameObject.cpp +++ b/rwengine/src/objects/GameObject.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -9,9 +8,6 @@ GameObject::~GameObject() { if (animator) { delete animator; } - if (skeleton) { - delete skeleton; - } if (modelinfo_) { modelinfo_->removeReference(); diff --git a/rwengine/src/objects/GameObject.hpp b/rwengine/src/objects/GameObject.hpp index bbce6e20..7a6de40a 100644 --- a/rwengine/src/objects/GameObject.hpp +++ b/rwengine/src/objects/GameObject.hpp @@ -11,7 +11,6 @@ #include #include -class Skeleton; class CharacterController; class Animator; class GameWorld; @@ -46,7 +45,6 @@ public: GameWorld* engine; Animator* animator; /// Object's animator. - Skeleton* skeleton; bool inWater; @@ -71,7 +69,6 @@ public: , rotation(rot) , engine(engine) , animator(nullptr) - , skeleton(nullptr) , inWater(false) , _lastHeight(std::numeric_limits::max()) , visible(true) diff --git a/rwengine/src/objects/VehicleObject.cpp b/rwengine/src/objects/VehicleObject.cpp index 30b76773..2792b178 100644 --- a/rwengine/src/objects/VehicleObject.cpp +++ b/rwengine/src/objects/VehicleObject.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include diff --git a/rwengine/src/render/GameRenderer.cpp b/rwengine/src/render/GameRenderer.cpp index d6596528..c0a33b5d 100644 --- a/rwengine/src/render/GameRenderer.cpp +++ b/rwengine/src/render/GameRenderer.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include diff --git a/rwengine/src/render/ObjectRenderer.cpp b/rwengine/src/render/ObjectRenderer.cpp index c0ac1d9f..bc0098f3 100644 --- a/rwengine/src/render/ObjectRenderer.cpp +++ b/rwengine/src/render/ObjectRenderer.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include diff --git a/rwengine/src/script/modules/GTA3ModuleImpl.inl b/rwengine/src/script/modules/GTA3ModuleImpl.inl index 843558f5..c2f77a26 100644 --- a/rwengine/src/script/modules/GTA3ModuleImpl.inl +++ b/rwengine/src/script/modules/GTA3ModuleImpl.inl @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/rwviewer/ViewerWidget.cpp b/rwviewer/ViewerWidget.cpp index 1f563bc7..c2a8ea50 100644 --- a/rwviewer/ViewerWidget.cpp +++ b/rwviewer/ViewerWidget.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -81,9 +80,8 @@ void ViewerWidget::paintGL() { r.setViewport(width(), height()); - if (dummyObject && dummyObject->animator && dummyObject->skeleton) { + if (dummyObject && dummyObject->animator) { dummyObject->animator->tick(1.f / 60.f); - dummyObject->skeleton->interpolate(1.f); } r.getRenderer()->invalidate(); diff --git a/rwviewer/models/DFFFramesTreeModel.cpp b/rwviewer/models/DFFFramesTreeModel.cpp index 10840ce9..3950482c 100644 --- a/rwviewer/models/DFFFramesTreeModel.cpp +++ b/rwviewer/models/DFFFramesTreeModel.cpp @@ -1,10 +1,9 @@ #include "DFFFramesTreeModel.hpp" #include -#include -DFFFramesTreeModel::DFFFramesTreeModel(Clump* m, Skeleton* skel, +DFFFramesTreeModel::DFFFramesTreeModel(Clump* m, QObject* parent) - : QAbstractItemModel(parent), model(m), skeleton(skel) { + : QAbstractItemModel(parent), model(m) { } int DFFFramesTreeModel::columnCount(const QModelIndex& parent) const { @@ -59,10 +58,7 @@ QVariant DFFFramesTreeModel::data(const QModelIndex& index, int role) const { } } else if (role == Qt::CheckStateRole) { if (index.column() == 0) { - if (skeleton) { - return skeleton->getData(f->getIndex()).enabled ? Qt::Checked - : Qt::Unchecked; - } + return true; } } return QVariant(); @@ -77,11 +73,10 @@ bool DFFFramesTreeModel::setData(const QModelIndex& index, ModelFrame* f = static_cast(index.internalPointer()); if (role == Qt::CheckStateRole) { - if (index.column() == 0 && skeleton) { + if (index.column() == 0) { if ((Qt::CheckState)value.toInt() == Qt::Checked) { - skeleton->setEnabled(f, true); + RW_UNIMPLEMENTED("Hiding Frames"); } else { - skeleton->setEnabled(f, false); } return true; } @@ -97,7 +92,7 @@ Qt::ItemFlags DFFFramesTreeModel::flags(const QModelIndex& index) const { Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; - if (index.column() == 0 && skeleton) { + if (index.column() == 0) { flags |= Qt::ItemIsUserCheckable; } diff --git a/rwviewer/models/DFFFramesTreeModel.hpp b/rwviewer/models/DFFFramesTreeModel.hpp index 236578c7..f4ec521f 100644 --- a/rwviewer/models/DFFFramesTreeModel.hpp +++ b/rwviewer/models/DFFFramesTreeModel.hpp @@ -5,14 +5,12 @@ #include class Clump; -class Skeleton; class DFFFramesTreeModel : public QAbstractItemModel { Clump* model; - Skeleton* skeleton; public: - explicit DFFFramesTreeModel(Clump* m, Skeleton* skel, QObject* parent = 0); + explicit DFFFramesTreeModel(Clump* m, QObject* parent = 0); virtual int columnCount(const QModelIndex& parent = QModelIndex()) const; diff --git a/rwviewer/views/ModelViewer.cpp b/rwviewer/views/ModelViewer.cpp index 2baecf28..be210123 100644 --- a/rwviewer/views/ModelViewer.cpp +++ b/rwviewer/views/ModelViewer.cpp @@ -1,6 +1,5 @@ #include "ModelViewer.hpp" #include -#include #include #include #include @@ -9,7 +8,7 @@ ModelViewer::ModelViewer(ViewerWidget* viewer, QWidget* parent, Qt::WindowFlags f) - : ViewerInterface(parent, f), viewing(nullptr), skeleton(nullptr) { + : ViewerInterface(parent, f), viewing(nullptr) { mainSplit = new QSplitter; mainLayout = new QVBoxLayout; @@ -42,19 +41,14 @@ void ModelViewer::setViewerWidget(ViewerWidget* widget) { void ModelViewer::showModel(Clump* model) { viewing = model; - if (skeleton) { - delete skeleton; - } - skeleton = new Skeleton(); viewerWidget->showModel(model); - frames->setModel(model, nullptr); + frames->setModel(model); } void ModelViewer::showObject(uint16_t object) { viewerWidget->showObject(object); viewing = viewerWidget->currentModel(); - skeleton = viewerWidget->currentObject()->skeleton; - frames->setModel(viewing, skeleton); + frames->setModel(viewing); } void ModelViewer::loadAnimations(const QString& file) { diff --git a/rwviewer/views/ModelViewer.hpp b/rwviewer/views/ModelViewer.hpp index 7154d248..c8085c6d 100644 --- a/rwviewer/views/ModelViewer.hpp +++ b/rwviewer/views/ModelViewer.hpp @@ -15,7 +15,6 @@ class ViewerWidget; class Clump; -class Skeleton; class ModelFramesWidget; class Animation; @@ -23,7 +22,6 @@ class ModelViewer : public ViewerInterface { Q_OBJECT Clump* viewing; - Skeleton* skeleton; QSplitter* mainSplit; QVBoxLayout* mainLayout; diff --git a/rwviewer/widgets/ModelFramesWidget.cpp b/rwviewer/widgets/ModelFramesWidget.cpp index 4fa3bb15..51720ce5 100644 --- a/rwviewer/widgets/ModelFramesWidget.cpp +++ b/rwviewer/widgets/ModelFramesWidget.cpp @@ -33,7 +33,7 @@ ModelFramesWidget::ModelFramesWidget(QWidget* parent, Qt::WindowFlags flags) setLayout(_layout); } -void ModelFramesWidget::setModel(Clump* model, Skeleton* skeleton) { +void ModelFramesWidget::setModel(Clump* model) { if (framemodel) { delete framemodel; framemodel = nullptr; @@ -41,7 +41,7 @@ void ModelFramesWidget::setModel(Clump* model, Skeleton* skeleton) { } gmodel = model; if (model != nullptr) { - framemodel = new DFFFramesTreeModel(model, skeleton, this); + framemodel = new DFFFramesTreeModel(model, this); tree->setModel(framemodel); tree->setDisabled(false); connect(tree->selectionModel(), diff --git a/rwviewer/widgets/ModelFramesWidget.hpp b/rwviewer/widgets/ModelFramesWidget.hpp index cdc96907..3bdf48f8 100644 --- a/rwviewer/widgets/ModelFramesWidget.hpp +++ b/rwviewer/widgets/ModelFramesWidget.hpp @@ -30,7 +30,7 @@ public: public slots: - void setModel(Clump* model, Skeleton* skeleton); + void setModel(Clump* model); signals: diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e663ed70..e8d4eb3d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -38,7 +38,6 @@ set(TEST_SOURCES "test_rwbstream.cpp" "test_SaveGame.cpp" "test_scriptmachine.cpp" - "test_skeleton.cpp" "test_state.cpp" "test_text.cpp" "test_trafficdirector.cpp" diff --git a/tests/test_animation.cpp b/tests/test_animation.cpp index 77f24f96..36848543 100644 --- a/tests/test_animation.cpp +++ b/tests/test_animation.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include "test_globals.hpp" @@ -10,7 +9,6 @@ BOOST_AUTO_TEST_SUITE(AnimationTests) #if RW_TEST_WITH_DATA BOOST_AUTO_TEST_CASE(test_matrix) { { - Skeleton skeleton; Animation animation; /** Models are currently needed to relate animation bones <=> model diff --git a/tests/test_skeleton.cpp b/tests/test_skeleton.cpp deleted file mode 100644 index cc7ad527..00000000 --- a/tests/test_skeleton.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include -#include - -BOOST_AUTO_TEST_SUITE(SkeletonTests) - -BOOST_AUTO_TEST_CASE(test_methods) { - Skeleton::FrameTransform t1{glm::vec3(0.f, 0.f, 0.f), - glm::quat(0.f, 0.f, 0.f, 0.f)}; - Skeleton::FrameTransform t2{glm::vec3(1.f, 0.f, 0.f), - glm::quat(0.f, 0.f, 1.f, 0.f)}; - - Skeleton skeleton; - - skeleton.setAllData({{0, {t1, t2, true}}}); - - BOOST_CHECK(skeleton.getData(0).a.translation == t1.translation); - BOOST_CHECK(skeleton.getData(0).a.rotation == t1.rotation); - - BOOST_CHECK(skeleton.getData(0).b.translation == t2.translation); - BOOST_CHECK(skeleton.getData(0).b.rotation == t2.rotation); - - BOOST_CHECK(skeleton.getData(0).enabled); - - skeleton.setData(0, {t2, t1, false}); - - BOOST_CHECK(skeleton.getData(0).a.translation == t2.translation); - BOOST_CHECK(skeleton.getData(0).a.rotation == t2.rotation); - - BOOST_CHECK(skeleton.getData(0).b.translation == t1.translation); - BOOST_CHECK(skeleton.getData(0).b.rotation == t1.rotation); - - BOOST_CHECK(!skeleton.getData(0).enabled); -} - -BOOST_AUTO_TEST_CASE(test_interpolate) { - Skeleton::FrameTransform t1{glm::vec3(0.f, 0.f, 0.f), - glm::quat(0.f, 0.f, 0.f, 0.f)}; - Skeleton::FrameTransform t2{glm::vec3(1.f, 0.f, 0.f), - glm::quat(0.f, 0.f, 1.f, 0.f)}; - - Skeleton skeleton; - - skeleton.setAllData({{0, {t2, t1, true}}}); - - /** Without calling Skeleton::interpolate(alpha) the result is identity */ - - BOOST_CHECK(skeleton.getInterpolated(0).translation == - Skeleton::IdentityTransform.translation); - BOOST_CHECK(skeleton.getInterpolated(0).rotation == - Skeleton::IdentityTransform.rotation); - - skeleton.interpolate(0.f); - - BOOST_CHECK(skeleton.getInterpolated(0).translation == t1.translation); - BOOST_CHECK(skeleton.getInterpolated(0).rotation == t1.rotation); - - skeleton.interpolate(1.f); - - BOOST_CHECK(skeleton.getInterpolated(0).translation == t2.translation); - BOOST_CHECK(skeleton.getInterpolated(0).rotation == t2.rotation); -} -BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/test_vehicle.cpp b/tests/test_vehicle.cpp index d5082d8d..a50dedc7 100644 --- a/tests/test_vehicle.cpp +++ b/tests/test_vehicle.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include "test_globals.hpp" From 5f6f3fe66f94222f8c529088d36166f08db3ddd8 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sun, 8 Jan 2017 21:04:40 +0000 Subject: [PATCH 16/19] Implement vehicle LOD rendering --- rwengine/src/objects/VehicleObject.cpp | 11 ++++++ rwengine/src/objects/VehicleObject.hpp | 5 +++ rwengine/src/render/ObjectRenderer.cpp | 50 +++++++++++++++----------- 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/rwengine/src/objects/VehicleObject.cpp b/rwengine/src/objects/VehicleObject.cpp index 2792b178..6af37b78 100644 --- a/rwengine/src/objects/VehicleObject.cpp +++ b/rwengine/src/objects/VehicleObject.cpp @@ -146,6 +146,17 @@ VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, setModel(getVehicle()->getModel()); setClump(ClumpPtr(getModelInfo()->getModel()->clone())); + // Locate the Atomics for the chassis_hi and chassis_vlo frames + for (const auto& atomic : getClump()->getAtomics()) { + auto frame = atomic->getFrame().get(); + if (frame->getName() == "chassis_vlo") { + chassislow_ = atomic.get(); + } + if (frame->getName() == "chassis_hi") { + chassishigh_ = atomic.get(); + } + } + // Create meta-data for dummy parts auto chassisframe = getClump()->findFrame("chassis_dummy"); RW_CHECK(chassisframe, "Vehicle has no chassis_dummy"); diff --git a/rwengine/src/objects/VehicleObject.hpp b/rwengine/src/objects/VehicleObject.hpp index 180497cc..91b1507b 100644 --- a/rwengine/src/objects/VehicleObject.hpp +++ b/rwengine/src/objects/VehicleObject.hpp @@ -23,6 +23,8 @@ private: float brake; bool handbrake; + Atomic* chassishigh_ = nullptr; + Atomic* chassislow_ = nullptr; public: VehicleInfoHandle info; glm::u8vec3 colourPrimary; @@ -64,6 +66,9 @@ public: return getModelInfo(); } + Atomic* getHighLOD() const { return chassishigh_; } + Atomic* getLowLOD() const { return chassislow_; } + Type type() { return Vehicle; } diff --git a/rwengine/src/render/ObjectRenderer.cpp b/rwengine/src/render/ObjectRenderer.cpp index bc0098f3..bc415f40 100644 --- a/rwengine/src/render/ObjectRenderer.cpp +++ b/rwengine/src/render/ObjectRenderer.cpp @@ -18,11 +18,13 @@ constexpr float kDrawDistanceFactor = 1.0f; constexpr float kWorldDrawDistanceFactor = kDrawDistanceFactor; -#if 0 // There's no distance based culling for these types of objects yet constexpr float kVehicleDrawDistanceFactor = kDrawDistanceFactor; +#if 0 // There's no distance based culling for these types of objects yet constexpr float kPedestrianDrawDistanceFactor = kDrawDistanceFactor; #endif constexpr float kMagicLODDistance = 330.f; +constexpr float kVehicleLODDistance = 70.f; +constexpr float kVehicleDrawDistance = 280.f; RenderKey createKey(bool transparent, float normalizedDepth, Renderer::Textures& textures) { @@ -233,52 +235,58 @@ void ObjectRenderer::renderCharacter(CharacterObject* pedestrian, void ObjectRenderer::renderVehicle(VehicleObject* vehicle, RenderList& outList) { - RW_CHECK(vehicle->getClump(), "Vehicle clump is null"); - if (!vehicle->getClump()) { + const auto& clump = vehicle->getClump(); + RW_CHECK(clump, "Vehicle clump is null"); + if (!clump) { + return; + } + + float mindist = glm::length(vehicle->getPosition() - m_camera.position); + if (mindist < kVehicleLODDistance * kVehicleDrawDistanceFactor) { + // Swich visibility to the high LOD + vehicle->getHighLOD()->setFlag(Atomic::ATOMIC_RENDER, true); + vehicle->getLowLOD()->setFlag(Atomic::ATOMIC_RENDER, false); + } + else if (mindist < kVehicleDrawDistance * kVehicleDrawDistanceFactor) { + // Switch to low + vehicle->getHighLOD()->setFlag(Atomic::ATOMIC_RENDER, false); + vehicle->getLowLOD()->setFlag(Atomic::ATOMIC_RENDER, true); + } + else { + culled++; return; } - const auto& clump = vehicle->getClump(); renderClump(clump.get(), glm::mat4(), vehicle, outList); auto modelinfo = vehicle->getVehicle(); - - // Draw wheels n' stuff auto woi = m_world->data->findModelInfo(modelinfo->wheelmodel_); - if (!woi || !woi->isLoaded()) { + if (!woi || !woi->isLoaded() || !woi->getDistanceAtomic(mindist)) { return; } - auto wheelatomic = woi->getAtomic(0); + auto wheelatomic = woi->getDistanceAtomic(mindist); for (size_t w = 0; w < vehicle->info->wheels.size(); ++w) { auto& wi = vehicle->physVehicle->getWheelInfo(w); // Construct our own matrix so we can use the local transform vehicle->physVehicle->updateWheelTransform(w, false); - /// @todo migrate this into Vehicle physics tick so we can - /// interpolate old -> new - - glm::mat4 wheelM; auto up = -wi.m_wheelDirectionCS; auto right = wi.m_wheelAxleCS; auto fwd = up.cross(right); btQuaternion steerQ(up, wi.m_steering); btQuaternion rollQ(right, -wi.m_rotation); - btMatrix3x3 basis(right[0], fwd[0], up[0], right[1], fwd[1], up[1], right[2], fwd[2], up[2]); - - btTransform t; - t.setBasis(btMatrix3x3(steerQ) * btMatrix3x3(rollQ) * basis); - t.setOrigin(wi.m_chassisConnectionPointCS + - wi.m_wheelDirectionCS * - wi.m_raycastInfo.m_suspensionLength); - + btTransform t( + btMatrix3x3(steerQ) * btMatrix3x3(rollQ) * basis, + wi.m_chassisConnectionPointCS + + wi.m_wheelDirectionCS * wi.m_raycastInfo.m_suspensionLength); + glm::mat4 wheelM; t.getOpenGLMatrix(glm::value_ptr(wheelM)); wheelM = clump->getFrame()->getWorldTransform() * wheelM; - wheelM = glm::scale(wheelM, glm::vec3(modelinfo->wheelscale_)); if (wi.m_chassisConnectionPointCS.x() < 0.f) { wheelM = glm::scale(wheelM, glm::vec3(-1.f, 1.f, 1.f)); From 308d1d6deb6c94b9624324b35acd17acc8a2e57f Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Mon, 9 Jan 2017 00:10:33 +0000 Subject: [PATCH 17/19] Implement Building LOD transitions --- rwengine/src/data/ModelData.cpp | 24 ++++++++++++ rwengine/src/data/ModelData.hpp | 51 ++++++++++++++++++++++++- rwengine/src/engine/GameData.cpp | 7 ++++ rwengine/src/engine/GameWorld.cpp | 18 +-------- rwengine/src/loaders/LoaderIDE.cpp | 8 +--- rwengine/src/objects/InstanceObject.cpp | 8 +++- rwengine/src/objects/InstanceObject.hpp | 5 +-- rwengine/src/render/ObjectRenderer.cpp | 18 +++++---- 8 files changed, 103 insertions(+), 36 deletions(-) diff --git a/rwengine/src/data/ModelData.cpp b/rwengine/src/data/ModelData.cpp index 278d0001..88362551 100644 --- a/rwengine/src/data/ModelData.cpp +++ b/rwengine/src/data/ModelData.cpp @@ -1 +1,25 @@ #include "data/ModelData.hpp" + +void SimpleModelInfo::setupBigBuilding(const ModelInfoTable& models) { + if (loddistances_[0] > 300.f && atomics_[2] == nullptr) { + isbigbuilding_ = true; + findRelatedModel(models); + if (related_) { + loddistances_[2] = related_->getLargestLodDistance(); + } else { + loddistances_[2] = 100.f; + } + } +} + +void SimpleModelInfo::findRelatedModel(const ModelInfoTable& models) { + for (const auto& model : models) { + if (model.second.get() == this) continue; + const auto& othername = model.second->name; + if (othername.size() <= 3 || name.size() <= 3) continue; + if (othername.substr(3) == name.substr(3)) { + related_ = static_cast(model.second.get()); + break; + } + } +} diff --git a/rwengine/src/data/ModelData.hpp b/rwengine/src/data/ModelData.hpp index 334fe330..4b0d4386 100644 --- a/rwengine/src/data/ModelData.hpp +++ b/rwengine/src/data/ModelData.hpp @@ -108,6 +108,9 @@ private: std::unique_ptr collision; }; +using ModelInfoTable = + std::unordered_map>; + /** * Model data for simple types * @@ -121,8 +124,6 @@ public: int timeOn = 0; int timeOff = 24; int flags; - /// @todo Remove this? - bool LOD = false; /// Information loaded from PATH sections /// @todo remove this from here too :) std::vector paths; @@ -158,6 +159,15 @@ public: return loddistances_[n]; } + Atomic* getDistanceAtomic(float d) { + for (auto i = 0; i < getNumAtomics(); ++i) { + if (d < loddistances_[i]) { + return atomics_[i].get(); + } + } + return nullptr; + } + void setNumAtomics(int num) { numatomics_ = num; } @@ -204,12 +214,49 @@ public: NO_ZBUFFER_WRITE = 1 << 6, }; + // Set up data for big building objects + void setupBigBuilding(const ModelInfoTable& models); + bool isBigBuilding() const { + return isbigbuilding_; + } + + void findRelatedModel(const ModelInfoTable& models); + + float getLargestLodDistance() const { + return furthest_ != 0 ? loddistances_[furthest_ - 1] + : loddistances_[numatomics_ - 1]; + } + + float getNearLodDistance() const { + return loddistances_[2]; + } + + void determineFurthest() { + furthest_ = 0; + if (numatomics_ == 2) { + furthest_ = loddistances_[0] >= loddistances_[1] ? 1 : 0; + } + if (numatomics_ == 3) { + furthest_ = loddistances_[0] >= loddistances_[1] + ? 1 + : loddistances_[1] >= loddistances_[2] ? 2 : 0; + } + } + + SimpleModelInfo* related() const { + return related_; + } + private: Clump* model_ = nullptr; std::array atomics_; float loddistances_[3] = {}; uint8_t numatomics_ = 0; uint8_t alpha_ = 0; /// @todo ask aap why + bool isbigbuilding_ = 0; + uint8_t furthest_ = 0; + + SimpleModelInfo* related_ = nullptr; }; /** diff --git a/rwengine/src/engine/GameData.cpp b/rwengine/src/engine/GameData.cpp index 45bf8e93..4777e7d2 100644 --- a/rwengine/src/engine/GameData.cpp +++ b/rwengine/src/engine/GameData.cpp @@ -115,6 +115,13 @@ void GameData::loadLevelFile(const std::string& path) { } } } + + for (const auto& model : modelinfo) { + if (model.second->type() == ModelDataType::SimpleInfo) { + auto simple = static_cast(model.second.get()); + simple->setupBigBuilding(modelinfo); + } + } } void GameData::loadIDE(const std::string& path) { diff --git a/rwengine/src/engine/GameWorld.cpp b/rwengine/src/engine/GameWorld.cpp index 6e25b06f..a0422047 100644 --- a/rwengine/src/engine/GameWorld.cpp +++ b/rwengine/src/engine/GameWorld.cpp @@ -124,20 +124,6 @@ bool GameWorld::placeItems(const std::string& name) { } } - // Attempt to Associate LODs. - for (auto& p : instancePool.objects) { - auto object = p.second; - InstanceObject* instance = static_cast(object); - auto modelinfo = instance->getModelInfo(); - if (!modelinfo->LOD && modelinfo->name.length() > 3) { - auto lodInstit = - modelInstances.find("LOD" + modelinfo->name.substr(3)); - if (lodInstit != modelInstances.end()) { - instance->LODinstance = lodInstit->second; - } - } - } - return true; } else { logger->error("Data", "Failed to load IPL " + path); @@ -170,8 +156,8 @@ InstanceObject* GameWorld::createInstance(const uint16_t id, "World", "Instance with missing model: " + std::to_string(id)); } - auto instance = new InstanceObject( - this, pos, rot, glm::vec3(1.f, 1.f, 1.f), oi, nullptr, dydata); + auto instance = + new InstanceObject(this, pos, rot, glm::vec3(1.f), oi, dydata); instancePool.insert(instance); allObjects.push_back(instance); diff --git a/rwengine/src/loaders/LoaderIDE.cpp b/rwengine/src/loaders/LoaderIDE.cpp index 29c67d36..0c84a9b7 100644 --- a/rwengine/src/loaders/LoaderIDE.cpp +++ b/rwengine/src/loaders/LoaderIDE.cpp @@ -82,6 +82,8 @@ bool LoaderIDE::load(const std::string &filename, const PedStatsList &stats) { objs->setLodDistance(i, atof(buff.c_str())); } + objs->determineFurthest(); + getline(strstream, buff, ','); objs->flags = atoi(buff.c_str()); @@ -96,12 +98,6 @@ bool LoaderIDE::load(const std::string &filename, const PedStatsList &stats) { objs->timeOff = 24; } - /// @todo Figure out how LOD stuff is intended to work - if (objs->name.find("LOD", 0, 3) != std::string::npos && - objs->name != "LODistancoast01") { - objs->LOD = true; - } - objects.emplace(objs->id(), std::move(objs)); break; } diff --git a/rwengine/src/objects/InstanceObject.cpp b/rwengine/src/objects/InstanceObject.cpp index 82572cc7..5490d956 100644 --- a/rwengine/src/objects/InstanceObject.cpp +++ b/rwengine/src/objects/InstanceObject.cpp @@ -7,13 +7,12 @@ InstanceObject::InstanceObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, const glm::vec3& scale, - BaseModelInfo* modelinfo, InstanceObject* lod, + BaseModelInfo* modelinfo, std::shared_ptr dyn) : GameObject(engine, pos, rot, modelinfo) , health(100.f) , scale(scale) , body(nullptr) - , LODinstance(lod) , dynamics(dyn) , _enablePhysics(false) { if (modelinfo) { @@ -21,6 +20,11 @@ InstanceObject::InstanceObject(GameWorld* engine, const glm::vec3& pos, setPosition(pos); setRotation(rot); + // Disable the main island LOD + if (modelinfo->name.find("IslandLOD") != std::string::npos) { + setVisible(false); + } + /// @todo store path information properly if (modelinfo->type() == ModelDataType::SimpleInfo) { auto simpledata = static_cast(modelinfo); diff --git a/rwengine/src/objects/InstanceObject.hpp b/rwengine/src/objects/InstanceObject.hpp index 4ca7f1ef..9e1b0e06 100644 --- a/rwengine/src/objects/InstanceObject.hpp +++ b/rwengine/src/objects/InstanceObject.hpp @@ -22,13 +22,12 @@ class InstanceObject : public GameObject { public: glm::vec3 scale; std::unique_ptr body; - InstanceObject* LODinstance; std::shared_ptr dynamics; bool _enablePhysics; InstanceObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, const glm::vec3& scale, - BaseModelInfo* modelinfo, InstanceObject* lod, + BaseModelInfo* modelinfo, std::shared_ptr dyn); ~InstanceObject(); @@ -44,7 +43,7 @@ public: void changeModel(BaseModelInfo* incoming); - virtual void setPosition(const glm::vec3 &pos); + virtual void setPosition(const glm::vec3& pos); virtual void setRotation(const glm::quat& r); virtual bool takeDamage(const DamageInfo& damage); diff --git a/rwengine/src/render/ObjectRenderer.cpp b/rwengine/src/render/ObjectRenderer.cpp index bc415f40..69c55218 100644 --- a/rwengine/src/render/ObjectRenderer.cpp +++ b/rwengine/src/render/ObjectRenderer.cpp @@ -168,19 +168,23 @@ void ObjectRenderer::renderInstance(InstanceObject* instance, float mindist = glm::length(instance->getPosition() - m_camera.position); - if (mindist < kMagicLODDistance && modelinfo->LOD) { - // @todo this should check if it might be best to render anyway + if (mindist > modelinfo->getLargestLodDistance()) { + culled++; return; } - Atomic* distanceatomic = nullptr; - for (int i = 0; i < modelinfo->getNumAtomics(); i++) { - auto atomicdistance = modelinfo->getLodDistance(i); - if (mindist < atomicdistance * kDrawDistanceFactor) { - distanceatomic = modelinfo->getAtomic(i); + if (modelinfo->isBigBuilding() && + mindist < modelinfo->getNearLodDistance() && + mindist < kMagicLODDistance) { + auto related = modelinfo->related(); + if (!related || related->isLoaded()) { + culled++; + return; } } + Atomic* distanceatomic = + modelinfo->getDistanceAtomic(mindist / kDrawDistanceFactor); if (!distanceatomic) { return; } From e1f7d11c8283fced24cbca16ee22ab1e5b5f6da1 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Mon, 9 Jan 2017 20:56:49 +0000 Subject: [PATCH 18/19] Fix off-by-one error in Simple Model atomic lookup --- rwengine/src/engine/GameData.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rwengine/src/engine/GameData.cpp b/rwengine/src/engine/GameData.cpp index 4777e7d2..e4960fc7 100644 --- a/rwengine/src/engine/GameData.cpp +++ b/rwengine/src/engine/GameData.cpp @@ -365,7 +365,7 @@ TextureArchive GameData::loadTextureArchive(const std::string& name) { void GameData::getNameAndLod(std::string& name, int& lod) { auto lodpos = name.rfind("_l"); if (lodpos != std::string::npos) { - lod = std::atoi(name.substr(lodpos + 1).c_str()); + lod = std::atoi(name.substr(lodpos + 2).c_str()); name = name.substr(0, lodpos); } } From d6e2057f8f2a90be41d6ff1d3d4c08123dee50fd Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Sat, 14 Jan 2017 23:18:16 +0000 Subject: [PATCH 19/19] Apply LOD multiplier correctly when rendering --- rwengine/src/render/ObjectRenderer.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/rwengine/src/render/ObjectRenderer.cpp b/rwengine/src/render/ObjectRenderer.cpp index 69c55218..b8cc5eb1 100644 --- a/rwengine/src/render/ObjectRenderer.cpp +++ b/rwengine/src/render/ObjectRenderer.cpp @@ -16,7 +16,7 @@ #include #endif -constexpr float kDrawDistanceFactor = 1.0f; +constexpr float kDrawDistanceFactor = 1.5f; constexpr float kWorldDrawDistanceFactor = kDrawDistanceFactor; constexpr float kVehicleDrawDistanceFactor = kDrawDistanceFactor; #if 0 // There's no distance based culling for these types of objects yet @@ -166,7 +166,8 @@ void ObjectRenderer::renderInstance(InstanceObject* instance, return; } - float mindist = glm::length(instance->getPosition() - m_camera.position); + float mindist = glm::length(instance->getPosition() - m_camera.position) / + kDrawDistanceFactor; if (mindist > modelinfo->getLargestLodDistance()) { culled++; @@ -233,7 +234,8 @@ void ObjectRenderer::renderCharacter(CharacterObject* pedestrian, auto simple = m_world->data->findModelInfo(weapon->modelID); auto itematomic = simple->getAtomic(0); - renderAtomic(itematomic, handFrame->getWorldTransform(), nullptr, outList); + renderAtomic(itematomic, handFrame->getWorldTransform(), nullptr, + outList); } } @@ -245,23 +247,20 @@ void ObjectRenderer::renderVehicle(VehicleObject* vehicle, return; } - float mindist = glm::length(vehicle->getPosition() - m_camera.position); - if (mindist < kVehicleLODDistance * kVehicleDrawDistanceFactor) { + float mindist = glm::length(vehicle->getPosition() - m_camera.position) / kVehicleDrawDistanceFactor; + if (mindist < kVehicleLODDistance) { // Swich visibility to the high LOD vehicle->getHighLOD()->setFlag(Atomic::ATOMIC_RENDER, true); vehicle->getLowLOD()->setFlag(Atomic::ATOMIC_RENDER, false); - } - else if (mindist < kVehicleDrawDistance * kVehicleDrawDistanceFactor) { + } else if (mindist < kVehicleDrawDistance) { // Switch to low vehicle->getHighLOD()->setFlag(Atomic::ATOMIC_RENDER, false); vehicle->getLowLOD()->setFlag(Atomic::ATOMIC_RENDER, true); - } - else { + } else { culled++; return; } - renderClump(clump.get(), glm::mat4(), vehicle, outList); auto modelinfo = vehicle->getVehicle();