fernandotonon/QtMeshEditor

View on GitHub
src/SkeletonDebug.cpp

Summary

Maintainability
Test Coverage
A
90%
#include "SkeletonDebug.h"
 
#include <QTimer>
 
#include "Manager.h"
TODO found
// TODO Remove defenitively this cam (for overlay purpose, but this has to be driven app level)
SkeletonDebug::SkeletonDebug(Ogre::Entity* entity, Ogre::SceneManager *man, /*Ogre::Camera *cam,*/ float boneSize, float scaleAxes)
{
mEntity = entity;
mSceneMan = man;
//mCamera = cam;
 
Variable `mScaleAxes` is assigned in constructor body. Consider performing initialization in initialization list.
mScaleAxes = scaleAxes;
 
mBoneSize = boneSize;
 
createAxesMaterial();
createBoneMaterial();
createAxesMesh();
createBoneMesh();
 
mShowAxes = true;
mShowBones = true;
mShowNames = true;
 
std::map<std::string, Ogre::Entity*> mapEntities;
 
int numBones = mEntity->getSkeleton()->getNumBones();
 
for(unsigned short int iBone = 0; iBone < numBones; ++iBone)
{
Ogre::Bone* pBone = mEntity->getSkeleton()->getBone(iBone);
if ( !pBone )
{
assert(false);
continue;
}
 
Ogre::Entity *ent;
Ogre::TagPoint *tp;
 
// Absolutely HAVE to create bone representations first. Otherwise we would get the wrong child count
// because an attached object counts as a child
// Would be nice to have a function that only gets the children that are bones...
unsigned short numChildren = pBone->numChildren();
if(numChildren == 0)
{
// There are no children, but we should still represent the bone
// Creates a bone of length 1 for leaf bones (bones without children)
ent = mSceneMan->createEntity("SkeletonDebug/BoneMesh");
tp = mEntity->attachObjectToBone(pBone->getName(), (Ogre::MovableObject*)ent);
mBoneEntities.push_back(ent);
 
Ogre::Vector3 v = pBone->getPosition();
// If the length is zero, no point in creating the bone representation
float length = v.length();
if(length < 0.00001f)
continue;
tp->setScale(length, length, length);
}
else
{
for(int i = 0; i < numChildren; ++i)
{
Ogre::Vector3 v = pBone->getChild(i)->getPosition();
// If the length is zero, no point in creating the bone representation
float length = v.length();
if(length < 0.00001f)
continue;
 
ent = mSceneMan->createEntity("SkeletonDebug/BoneMesh");
tp = mEntity->attachObjectToBone(pBone->getName(), (Ogre::MovableObject*)ent);
mBoneEntities.push_back(ent);
 
tp->setScale(length, length, length);
}
}
 
mapEntities[pBone->getName().data()] = ent;
 
ent = mSceneMan->createEntity("SkeletonDebug/AxesMesh");
tp = mEntity->attachObjectToBone(pBone->getName(), (Ogre::MovableObject*)ent);
// Make sure we don't wind up with tiny/giant axes and that one axis doesnt get squashed
tp->setScale((mScaleAxes/mEntity->getParentSceneNode()->getScale().x), (mScaleAxes/mEntity->getParentSceneNode()->getScale().y), (mScaleAxes/mEntity->getParentSceneNode()->getScale().z));
mAxisEntities.push_back(ent);
 
/* Ogre::String name = mEntity->getName() + "SkeletonDebug/BoneText/Bone_";
name += iBone;
ObjectTextDisplay *overlay = new ObjectTextDisplay(name, pBone, mCamera, mEntity);
overlay->enable(true);
overlay->setText(pBone->getName());
mTextOverlays.push_back(overlay);*/
}
 
showAxes(false);
showBones(false);
showNames(false);
 
mTimer = new QTimer();
connect(mTimer, &QTimer::timeout, this, [=](){
// Set Selected Bone to Red from user data info
for(auto ent: mBoneEntities){
ent->setMaterial(mBoneMatPtr);
ent->setVisible(mShowBones);
}
for(auto bone : mEntity->getSkeleton()->getBones())
{
if(!bone->getUserObjectBindings().getUserAny("selected").has_value())
continue;
 
if(!Ogre::any_cast<bool>(bone->getUserObjectBindings().getUserAny("selected")))
continue;
 
if(mapEntities.find(bone->getName()) == mapEntities.end())
continue;
 
Ogre::Entity* ent = mapEntities.find(bone->getName())->second;
ent->setMaterial(mBoneMatSelectedPtr);
ent->setVisible(mShowBones);
}
 
});
mTimer->start(0);
}
 
SkeletonDebug::~SkeletonDebug()
{
auto attachedObjects = mEntity->getAttachedObjects();
for(auto object : attachedObjects)
{
Ogre::Entity* e = (Ogre::Entity*)object;
if(e->getMesh().get()->getName().compare("SkeletonDebug/AxesMesh") ||
e->getMesh().get()->getName().compare("SkeletonDebug/BoneMesh"))
{
Manager::getSingleton()->getSceneMgr()->destroyEntity(e);
}
}
}
 
void SkeletonDebug::update()
{
/*std::vector<ObjectTextDisplay*>::iterator it;
for(it = mTextOverlays.begin(); it < mTextOverlays.end(); it++)
{
((ObjectTextDisplay*)*it)->update();
}*/
}
 
void SkeletonDebug::showAxes(bool show)
{
// Don't change anything if we are already in the proper state
if(mShowAxes == show)
return;
 
mShowAxes = show;
 
std::vector<Ogre::Entity*>::iterator it;
for(it = mAxisEntities.begin(); it < mAxisEntities.end(); ++it)
{
((Ogre::Entity*)*it)->setVisible(show);
}
}
 
void SkeletonDebug::showBones(bool show)
{
// Don't change anything if we are already in the proper state
if(mShowBones == show)
return;
 
mShowBones = show;
 
std::vector<Ogre::Entity*>::iterator it;
for(it = mBoneEntities.begin(); it < mBoneEntities.end(); ++it)
{
((Ogre::Entity*)*it)->setVisible(show);
}
 
}
 
void SkeletonDebug::showNames(bool show)
{
// Don't change anything if we are already in the proper state
if(mShowNames == show)
return;
 
mShowNames = show;
 
/*std::vector<ObjectTextDisplay*>::iterator it;
for(it = mTextOverlays.begin(); it < mTextOverlays.end(); it++)
{
((ObjectTextDisplay*)*it)->enable(show);
}*/
}
 
void SkeletonDebug::createAxesMaterial()
{
Ogre::String matName = "SkeletonDebug/AxesMat";
 
mAxisMatPtr = Ogre::static_pointer_cast<Ogre::Material>(Ogre::MaterialManager::getSingleton().getByName(matName));
if (!mAxisMatPtr)
{
mAxisMatPtr = Ogre::static_pointer_cast<Ogre::Material>(Ogre::MaterialManager::getSingleton().create(matName, Ogre::ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME));
 
// First pass for axes that are partially within the model (shows transparency)
Ogre::Pass* p = mAxisMatPtr->getTechnique(0)->getPass(0);
p->setLightingEnabled(false);
p->setPolygonModeOverrideable(false);
p->setVertexColourTracking(Ogre::TVC_AMBIENT);
p->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
p->setCullingMode(Ogre::CULL_NONE);
p->setDepthWriteEnabled(false);
p->setDepthCheckEnabled(false);
 
// Second pass for the portion of the axis that is outside the model (solid colour)
Ogre::Pass* p2 = mAxisMatPtr->getTechnique(0)->createPass();
p2->setLightingEnabled(false);
p2->setPolygonModeOverrideable(false);
p2->setVertexColourTracking(Ogre::TVC_AMBIENT);
p2->setCullingMode(Ogre::CULL_NONE);
p2->setDepthWriteEnabled(false);
}
}
 
void SkeletonDebug::createBoneMaterial()
{
Ogre::String matName = "SkeletonDebug/BoneMat";
 
mBoneMatPtr = Ogre::static_pointer_cast<Ogre::Material>(Ogre::MaterialManager::getSingleton().getByName(matName));
 
if (!mBoneMatPtr)
{
mBoneMatPtr = Ogre::static_pointer_cast<Ogre::Material>(Ogre::MaterialManager::getSingleton().create(matName, Ogre::ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME));
 
Ogre::Pass* p = mBoneMatPtr->getTechnique(0)->getPass(0);
p->setLightingEnabled(false);
p->setPolygonModeOverrideable(false);
p->setVertexColourTracking(Ogre::TVC_AMBIENT);
p->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
p->setCullingMode(Ogre::CULL_ANTICLOCKWISE);
p->setDepthWriteEnabled(false);
p->setDepthCheckEnabled(false);
}
 
// Create a red bone material for selected bones
Ogre::String matName2 = "SkeletonDebug/BoneMatSelected";
 
mBoneMatSelectedPtr = Ogre::static_pointer_cast<Ogre::Material>(Ogre::MaterialManager::getSingleton().getByName(matName2));
 
if (!mBoneMatSelectedPtr)
{
SkeletonDebug::mBoneMatSelectedPtr = Ogre::static_pointer_cast<Ogre::Material>(Ogre::MaterialManager::getSingleton().create(matName2, Ogre::ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME));
 
Ogre::Pass* p = mBoneMatSelectedPtr->getTechnique(0)->getPass(0);
p->setLightingEnabled(true);
p->setDepthWriteEnabled(false);
p->setDepthCheckEnabled(false);
p->setVertexColourTracking(Ogre::TVC_AMBIENT);
p->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
p->setCullingMode(Ogre::CULL_ANTICLOCKWISE);
p->setDiffuse(1,0,0,1);
p->setAmbient(1,0,0);
p->setEmissive(1,0,0);
}
 
}
 
void SkeletonDebug::createBoneMesh()
{
Ogre::String meshName = "SkeletonDebug/BoneMesh";
 
mBoneMeshPtr = Ogre::static_pointer_cast<Ogre::Mesh>(Ogre::MeshManager::getSingleton().getByName(meshName));
if(!mBoneMeshPtr)
{
Ogre::ManualObject mo("tmp");
mo.begin(mBoneMatPtr->getName());
 
Ogre::Vector3 basepos[6] =
{
Ogre::Vector3(0,0,0),
Ogre::Vector3(mBoneSize, mBoneSize*2, mBoneSize),
Ogre::Vector3(-mBoneSize, mBoneSize*2, mBoneSize),
Ogre::Vector3(-mBoneSize, mBoneSize*2, -mBoneSize),
Ogre::Vector3(mBoneSize, mBoneSize*2, -mBoneSize),
Ogre::Vector3(0, mBoneSize*2, 0),
};
 
// Two colours so that we can distinguish the sides of the bones (we don't use any lighting on the material)
Ogre::ColourValue col = Ogre::ColourValue(0.5f, 0.5f, 0.5f, 1.0f);
Ogre::ColourValue col1 = Ogre::ColourValue(0.6f, 0.6f, 0.6f, 1.0f);
 
mo.position(basepos[0]);
mo.colour(col);
mo.position(basepos[2]);
mo.colour(col);
mo.position(basepos[1]);
mo.colour(col);
 
mo.position(basepos[0]);
mo.colour(col1);
mo.position(basepos[3]);
mo.colour(col1);
mo.position(basepos[2]);
mo.colour(col1);
 
mo.position(basepos[0]);
mo.colour(col);
mo.position(basepos[4]);
mo.colour(col);
mo.position(basepos[3]);
mo.colour(col);
 
mo.position(basepos[0]);
mo.colour(col1);
mo.position(basepos[1]);
mo.colour(col1);
mo.position(basepos[4]);
mo.colour(col1);
 
mo.position(basepos[1]);
mo.colour(col1);
mo.position(basepos[2]);
mo.colour(col1);
mo.position(basepos[5]);
mo.colour(col1);
 
mo.position(basepos[2]);
mo.colour(col);
mo.position(basepos[3]);
mo.colour(col);
mo.position(basepos[5]);
mo.colour(col);
 
mo.position(basepos[3]);
mo.colour(col1);
mo.position(basepos[4]);
mo.colour(col1);
mo.position(basepos[5]);
mo.colour(col1);
 
mo.position(basepos[4]);
mo.colour(col);
mo.position(basepos[1]);
mo.colour(col);
mo.position(basepos[5]);
mo.colour(col);
 
// indices
mo.triangle(0, 1, 2);
mo.triangle(3, 4, 5);
mo.triangle(6, 7, 8);
mo.triangle(9, 10, 11);
mo.triangle(12, 13, 14);
mo.triangle(15, 16, 17);
mo.triangle(18, 19, 20);
mo.triangle(21, 22, 23);
 
mo.end();
 
mBoneMeshPtr = mo.convertToMesh(meshName, Ogre::ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
}
}
 
void SkeletonDebug::createAxesMesh()
{
Ogre::String meshName = "SkeletonDebug/AxesMesh";
 
mAxesMeshPtr = Ogre::static_pointer_cast<Ogre::Mesh>(Ogre::MeshManager::getSingleton().getByName(meshName));
if (!mAxesMeshPtr)
{
Ogre::ManualObject mo("tmp");
mo.begin(mAxisMatPtr->getName());
/* 3 axes, each made up of 2 of these (base plane = XY)
* .------------|\
* '------------|/
*/
mo.estimateVertexCount(7 * 2 * 3);
mo.estimateIndexCount(3 * 2 * 3);
Ogre::Quaternion quat[6];
Ogre::ColourValue col[3];
 
// x-axis
quat[0] = Ogre::Quaternion::IDENTITY;
quat[1].FromAxes(Ogre::Vector3::UNIT_X, Ogre::Vector3::NEGATIVE_UNIT_Z, Ogre::Vector3::UNIT_Y);
col[0] = Ogre::ColourValue::Red;
col[0].a = 0.3f;
// y-axis
quat[2].FromAxes(Ogre::Vector3::UNIT_Y, Ogre::Vector3::NEGATIVE_UNIT_X, Ogre::Vector3::UNIT_Z);
quat[3].FromAxes(Ogre::Vector3::UNIT_Y, Ogre::Vector3::UNIT_Z, Ogre::Vector3::UNIT_X);
col[1] = Ogre::ColourValue::Green;
col[1].a = 0.3f;
// z-axis
quat[4].FromAxes(Ogre::Vector3::UNIT_Z, Ogre::Vector3::UNIT_Y, Ogre::Vector3::NEGATIVE_UNIT_X);
quat[5].FromAxes(Ogre::Vector3::UNIT_Z, Ogre::Vector3::UNIT_X, Ogre::Vector3::UNIT_Y);
col[2] = Ogre::ColourValue::Blue;
col[2].a = 0.3f;
 
Ogre::Vector3 basepos[7] =
{
// stalk
Ogre::Vector3(0.0f, 0.05f, 0.0f),
Ogre::Vector3(0.0f, -0.05f, 0.0f),
Ogre::Vector3(0.7f, -0.05f, 0.0f),
Ogre::Vector3(0.7f, 0.05f, 0.0f),
// head
Ogre::Vector3(0.7f, -0.15f, 0.0f),
Ogre::Vector3(1.0f, 0.0f, 0.0f),
Ogre::Vector3(0.7f, 0.15f, 0.0f)
};
 
 
// vertices
// 6 arrows
for (size_t i = 0; i < 6; ++i)
{
// 7 points
for (size_t p = 0; p < 7; ++p)
{
Ogre::Vector3 pos = quat[i] * basepos[p];
mo.position(pos);
mo.colour(col[i / 2]);
}
}
 
// indices
// 6 arrows
for (size_t i = 0; i < 6; ++i)
{
size_t base = i * 7;
mo.triangle(base + 0, base + 1, base + 2);
mo.triangle(base + 0, base + 2, base + 3);
mo.triangle(base + 4, base + 5, base + 6);
}
 
mo.end();
 
mAxesMeshPtr = mo.convertToMesh(meshName, Ogre::ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
}
}