From c7646ec998bc26fcbb8b5affb0d942153e30bc9d Mon Sep 17 00:00:00 2001 From: codereader Date: Sun, 16 Jan 2022 07:12:02 +0100 Subject: [PATCH] #5584: Skeleton renderable migrated to derive from RenderableGeometry --- install/user.xml | 3 + radiantcore/model/md5/MD5Model.cpp | 6 +- radiantcore/model/md5/MD5Model.h | 13 +- radiantcore/model/md5/MD5ModelNode.cpp | 23 +-- radiantcore/model/md5/MD5ModelNode.h | 11 +- radiantcore/model/md5/RenderableMD5Skeleton.h | 163 +++++++++++------- 6 files changed, 137 insertions(+), 82 deletions(-) diff --git a/install/user.xml b/install/user.xml index 821b1ba533..1d8a02b6ff 100644 --- a/install/user.xml +++ b/install/user.xml @@ -54,6 +54,9 @@ + + + diff --git a/radiantcore/model/md5/MD5Model.cpp b/radiantcore/model/md5/MD5Model.cpp index 583a5341b8..bd2dec4b98 100644 --- a/radiantcore/model/md5/MD5Model.cpp +++ b/radiantcore/model/md5/MD5Model.cpp @@ -13,8 +13,7 @@ namespace md5 { MD5Model::MD5Model() : _polyCount(0), - _vertexCount(0), - _renderableSkeleton(_skeleton) + _vertexCount(0) {} MD5Model::MD5Model(const MD5Model& other) : @@ -24,8 +23,7 @@ MD5Model::MD5Model(const MD5Model& other) : _polyCount(other._polyCount), _vertexCount(other._vertexCount), _filename(other._filename), - _modelPath(other._modelPath), - _renderableSkeleton(_skeleton) + _modelPath(other._modelPath) { // Copy-construct the other model's surfaces, but not its shaders, revert to default for (std::size_t i = 0; i < other._surfaces.size(); ++i) diff --git a/radiantcore/model/md5/MD5Model.h b/radiantcore/model/md5/MD5Model.h index 7af251b8b5..34b3543e85 100644 --- a/radiantcore/model/md5/MD5Model.h +++ b/radiantcore/model/md5/MD5Model.h @@ -7,7 +7,7 @@ #include "parser/DefTokeniser.h" #include "MD5Surface.h" -#include "RenderableMD5Skeleton.h" +#include "MD5Skeleton.h" namespace md5 { @@ -65,9 +65,6 @@ class MD5Model : // The current state of our animated skeleton MD5Skeleton _skeleton; - // The OpenGLRenderable visualising the MD5Skeleton - RenderableMD5Skeleton _renderableSkeleton; - // We need to keep a reference for skin swapping RenderSystemWeakPtr _renderSystem; @@ -87,10 +84,10 @@ class MD5Model : */ void parseFromTokens(parser::DefTokeniser& tok); - RenderableMD5Skeleton& getRenderableSkeleton() - { - return _renderableSkeleton; - } + const MD5Skeleton& getSkeleton() const + { + return _skeleton; + } void updateAABB(); diff --git a/radiantcore/model/md5/MD5ModelNode.cpp b/radiantcore/model/md5/MD5ModelNode.cpp index ba07fc44ed..52093bc80b 100644 --- a/radiantcore/model/md5/MD5ModelNode.cpp +++ b/radiantcore/model/md5/MD5ModelNode.cpp @@ -11,7 +11,9 @@ namespace md5 MD5ModelNode::MD5ModelNode(const MD5ModelPtr& model) : _model(new MD5Model(*model)), // create a copy of the incoming model, we need our own instance - _attachedToShaders(false) + _attachedToShaders(false), + _showSkeleton(RKEY_RENDER_SKELETON), + _renderableSkeleton(_model->getSkeleton(), localToWorld()) { _animationUpdateConnection = _model->signal_ModelAnimationUpdated().connect( sigc::mem_fun(this, &MD5ModelNode::onModelAnimationUpdated) @@ -105,29 +107,30 @@ void MD5ModelNode::onPreRender(const VolumeTest& volume) // Attach renderables (or do nothing if everything is up to date) attachToShaders(); + + if (_showSkeleton.get()) + { + _renderableSkeleton.queueUpdate(); + _renderableSkeleton.update(_renderEntity->getColourShader()); + } + else + { + _renderableSkeleton.clear(); + } } void MD5ModelNode::renderSolid(IRenderableCollector& collector, const VolumeTest& volume) const { assert(_renderEntity); -#if 0 - render(collector, volume, localToWorld(), *_renderEntity); -#endif } void MD5ModelNode::renderWireframe(IRenderableCollector& collector, const VolumeTest& volume) const { assert(_renderEntity); -#if 0 - render(collector, volume, localToWorld(), *_renderEntity); -#endif } void MD5ModelNode::renderHighlights(IRenderableCollector& collector, const VolumeTest& volume) { -#if 0 - render(collector, volume, localToWorld(), *_renderEntity); -#endif auto identity = Matrix4::getIdentity(); for (const auto& surface : _renderableSurfaces) diff --git a/radiantcore/model/md5/MD5ModelNode.h b/radiantcore/model/md5/MD5ModelNode.h index 5646dba6f2..2546bd16df 100644 --- a/radiantcore/model/md5/MD5ModelNode.h +++ b/radiantcore/model/md5/MD5ModelNode.h @@ -7,8 +7,13 @@ #include "scene/Node.h" #include "render/VectorLightList.h" #include "../RenderableModelSurface.h" +#include "registry/CachedKey.h" +#include "RenderableMD5Skeleton.h" -namespace md5 { +namespace md5 +{ + +constexpr const char* const RKEY_RENDER_SKELETON = "user/ui/md5/renderSkeleton"; class MD5ModelNode : public scene::Node, @@ -29,6 +34,10 @@ class MD5ModelNode : sigc::connection _animationUpdateConnection; + registry::CachedKey _showSkeleton; + + RenderableMD5Skeleton _renderableSkeleton; + public: MD5ModelNode(const MD5ModelPtr& model); virtual ~MD5ModelNode(); diff --git a/radiantcore/model/md5/RenderableMD5Skeleton.h b/radiantcore/model/md5/RenderableMD5Skeleton.h index f119883bee..ac4fea7bc6 100644 --- a/radiantcore/model/md5/RenderableMD5Skeleton.h +++ b/radiantcore/model/md5/RenderableMD5Skeleton.h @@ -2,77 +2,122 @@ #include "irender.h" #include "MD5Skeleton.h" +#include "render/RenderableGeometry.h" namespace md5 { class RenderableMD5Skeleton : - public OpenGLRenderable + public render::RenderableGeometry { private: const MD5Skeleton& _skeleton; + const Matrix4& _localToWorld; + + bool _updateNeeded; public: - RenderableMD5Skeleton(const MD5Skeleton& skeleton) : - _skeleton(skeleton) + RenderableMD5Skeleton(const MD5Skeleton& skeleton, const Matrix4& localToWorld) : + _skeleton(skeleton), + _localToWorld(localToWorld), + _updateNeeded(true) {} - void render(const RenderInfo& info) const - { - if (_skeleton.size() == 0) return; - - glBegin(GL_LINES); - - std::size_t numJoints = _skeleton.size(); - - for (std::size_t i = 0; i < _skeleton.size(); ++i) - { - const IMD5Anim::Key& bone = _skeleton.getKey(i); - const Joint& joint = _skeleton.getJoint(i); - - if (joint.parentId != -1) - { - const IMD5Anim::Key& parentBone = _skeleton.getKey(joint.parentId); - - glVertex3dv(parentBone.origin); - glVertex3dv(bone.origin); - } - else - { - glVertex3d(0, 0, 0); - glVertex3dv(bone.origin); - } - } - - for (std::size_t i = 0; i < numJoints; ++i) - { - const IMD5Anim::Key& joint = _skeleton.getKey(i); - - Vector3 x(2,0,0); - Vector3 y(0,2,0); - Vector3 z(0,0,2); - - x = joint.orientation.transformPoint(x); - y = joint.orientation.transformPoint(y); - z = joint.orientation.transformPoint(z); - - Vector3 origin(joint.origin); - - glColor3f(1, 0, 0); - glVertex3dv(origin); - glVertex3dv(origin + x); - - glColor3f(0, 1, 0); - glVertex3dv(origin); - glVertex3dv(origin + y); - - glColor3f(0, 0, 1); - glVertex3dv(origin); - glVertex3dv(origin + z); - } - - glEnd(); - } + void queueUpdate() + { + _updateNeeded = true; + } + +protected: + void updateGeometry() override + { + if (!_updateNeeded) return; + + _updateNeeded = false; + + if (_skeleton.size() == 0) + { + clear(); + return; + } + + std::vector vertices; + std::vector indices; + + auto numJoints = _skeleton.size(); + + for (auto i = 0; i < numJoints; ++i) + { + const auto& bone = _skeleton.getKey(i); + const auto& joint = _skeleton.getJoint(i); + + if (joint.parentId != -1) + { + const auto& parentBone = _skeleton.getKey(joint.parentId); + + indices.push_back(static_cast(vertices.size())); + vertices.push_back(toVertex(parentBone.origin)); + + indices.push_back(static_cast(vertices.size())); + vertices.push_back(toVertex(bone.origin)); + } + else + { + indices.push_back(static_cast(vertices.size())); + vertices.push_back(toVertex({ 0, 0, 0 })); + + indices.push_back(static_cast(vertices.size())); + vertices.push_back(toVertex(bone.origin)); + } + } + + for (auto i = 0; i < numJoints; ++i) + { + const auto& joint = _skeleton.getKey(i); + + Vector3 x(2, 0, 0); + Vector3 y(0, 2, 0); + Vector3 z(0, 0, 2); + + x = joint.orientation.transformPoint(x); + y = joint.orientation.transformPoint(y); + z = joint.orientation.transformPoint(z); + + Vector3 origin(joint.origin); + + // x axis + indices.push_back(static_cast(vertices.size())); + vertices.push_back(toVertex(origin, { 1, 0, 0, 1 })); + indices.push_back(static_cast(vertices.size())); + vertices.push_back(toVertex(origin + x, { 1, 0, 0, 1 })); + + // y axis + indices.push_back(static_cast(vertices.size())); + vertices.push_back(toVertex(origin, { 0, 1, 0, 1 })); + indices.push_back(static_cast(vertices.size())); + vertices.push_back(toVertex(origin + y, { 0, 1, 0, 1 })); + + // z axis + indices.push_back(static_cast(vertices.size())); + vertices.push_back(toVertex(origin, { 0, 0, 1, 1 })); + indices.push_back(static_cast(vertices.size())); + vertices.push_back(toVertex(origin + z, { 0, 0, 1, 1 })); + } + + // Move the skeleton to world space + for (auto& v : vertices) + { + v.vertex = _localToWorld * v.vertex; + } + + RenderableGeometry::updateGeometry(render::GeometryType::Lines, vertices, indices); + } + +private: + ArbitraryMeshVertex toVertex(const Vector3& vertex, const Vector4& colour = { 1, 1, 1, 1 }) + { + return { vertex, {0, 0, 0}, {1, 0}, colour }; + } }; } // namespace