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