mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-29 04:20:29 +00:00
Don't create Ogre animations for skeletons
This commit is contained in:
parent
7e2995bc2f
commit
512ff3687a
@ -676,6 +676,32 @@ class NIFObjectLoader
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk)
|
||||||
|
{
|
||||||
|
TextKeyMap textkeys;
|
||||||
|
for(size_t i = 0;i < tk->list.size();i++)
|
||||||
|
{
|
||||||
|
const std::string &str = tk->list[i].text;
|
||||||
|
std::string::size_type pos = 0;
|
||||||
|
while(pos < str.length())
|
||||||
|
{
|
||||||
|
if(::isspace(str[pos]))
|
||||||
|
{
|
||||||
|
pos++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos));
|
||||||
|
std::string result = str.substr(pos, nextpos-pos);
|
||||||
|
textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result)));
|
||||||
|
|
||||||
|
pos = nextpos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return textkeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void createObjects(const std::string &name, const std::string &group,
|
static void createObjects(const std::string &name, const std::string &group,
|
||||||
Ogre::SceneManager *sceneMgr, const Nif::Node *node,
|
Ogre::SceneManager *sceneMgr, const Nif::Node *node,
|
||||||
ObjectList &objectlist, int flags, int animflags, int partflags)
|
ObjectList &objectlist, int flags, int animflags, int partflags)
|
||||||
@ -704,7 +730,7 @@ class NIFObjectLoader
|
|||||||
const Nif::NiTextKeyExtraData *tk = static_cast<const Nif::NiTextKeyExtraData*>(e.getPtr());
|
const Nif::NiTextKeyExtraData *tk = static_cast<const Nif::NiTextKeyExtraData*>(e.getPtr());
|
||||||
|
|
||||||
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex);
|
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex);
|
||||||
objectlist.mTextKeys[trgtid] = NIFSkeletonLoader::extractTextKeys(tk);
|
objectlist.mTextKeys[trgtid] = extractTextKeys(tk);
|
||||||
}
|
}
|
||||||
else if(e->recType == Nif::RC_NiStringExtraData)
|
else if(e->recType == Nif::RC_NiStringExtraData)
|
||||||
{
|
{
|
||||||
|
@ -11,142 +11,7 @@
|
|||||||
namespace NifOgre
|
namespace NifOgre
|
||||||
{
|
{
|
||||||
|
|
||||||
void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector<const Nif::NiKeyframeController*> &ctrls, const std::vector<std::string> &targets, float startTime, float stopTime)
|
void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent)
|
||||||
{
|
|
||||||
Ogre::Animation *anim = skel->createAnimation(name, stopTime);
|
|
||||||
|
|
||||||
for(size_t i = 0;i < ctrls.size();i++)
|
|
||||||
{
|
|
||||||
const Nif::NiKeyframeController *kfc = ctrls[i];
|
|
||||||
if(kfc->data.empty())
|
|
||||||
continue;
|
|
||||||
const Nif::NiKeyframeData *kf = kfc->data.getPtr();
|
|
||||||
|
|
||||||
/* Get the keyframes and make sure they're sorted first to last */
|
|
||||||
const Nif::QuaternionKeyList &quatkeys = kf->mRotations;
|
|
||||||
const Nif::Vector3KeyList &trankeys = kf->mTranslations;
|
|
||||||
const Nif::FloatKeyList &scalekeys = kf->mScales;
|
|
||||||
|
|
||||||
Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin();
|
|
||||||
Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin();
|
|
||||||
Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin();
|
|
||||||
|
|
||||||
Ogre::Bone *bone = skel->getBone(targets[i]);
|
|
||||||
// NOTE: For some reason, Ogre doesn't like the node track ID being different from
|
|
||||||
// the bone ID
|
|
||||||
Ogre::NodeAnimationTrack *nodetrack = anim->hasNodeTrack(bone->getHandle()) ?
|
|
||||||
anim->getNodeTrack(bone->getHandle()) :
|
|
||||||
anim->createNodeTrack(bone->getHandle(), bone);
|
|
||||||
|
|
||||||
Ogre::Quaternion lastquat, curquat;
|
|
||||||
Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f);
|
|
||||||
Ogre::Vector3 lastscale(1.0f), curscale(1.0f);
|
|
||||||
if(quatiter != quatkeys.mKeys.end())
|
|
||||||
lastquat = curquat = quatiter->mValue;
|
|
||||||
if(traniter != trankeys.mKeys.end())
|
|
||||||
lasttrans = curtrans = traniter->mValue;
|
|
||||||
if(scaleiter != scalekeys.mKeys.end())
|
|
||||||
lastscale = curscale = Ogre::Vector3(scaleiter->mValue);
|
|
||||||
|
|
||||||
bool didlast = false;
|
|
||||||
while(!didlast)
|
|
||||||
{
|
|
||||||
float curtime = std::numeric_limits<float>::max();
|
|
||||||
|
|
||||||
//Get latest time
|
|
||||||
if(quatiter != quatkeys.mKeys.end())
|
|
||||||
curtime = std::min(curtime, quatiter->mTime);
|
|
||||||
if(traniter != trankeys.mKeys.end())
|
|
||||||
curtime = std::min(curtime, traniter->mTime);
|
|
||||||
if(scaleiter != scalekeys.mKeys.end())
|
|
||||||
curtime = std::min(curtime, scaleiter->mTime);
|
|
||||||
|
|
||||||
curtime = std::max(curtime, startTime);
|
|
||||||
if(curtime >= stopTime)
|
|
||||||
{
|
|
||||||
didlast = true;
|
|
||||||
curtime = stopTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the latest quaternions, translations, and scales for the
|
|
||||||
// current time
|
|
||||||
while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime)
|
|
||||||
{
|
|
||||||
lastquat = curquat;
|
|
||||||
if(++quatiter != quatkeys.mKeys.end())
|
|
||||||
curquat = quatiter->mValue;
|
|
||||||
}
|
|
||||||
while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime)
|
|
||||||
{
|
|
||||||
lasttrans = curtrans;
|
|
||||||
if(++traniter != trankeys.mKeys.end())
|
|
||||||
curtrans = traniter->mValue;
|
|
||||||
}
|
|
||||||
while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime)
|
|
||||||
{
|
|
||||||
lastscale = curscale;
|
|
||||||
if(++scaleiter != scalekeys.mKeys.end())
|
|
||||||
curscale = Ogre::Vector3(scaleiter->mValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ogre::TransformKeyFrame *kframe;
|
|
||||||
kframe = nodetrack->createNodeKeyFrame(curtime);
|
|
||||||
if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin())
|
|
||||||
kframe->setRotation(curquat);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Nif::QuaternionKeyList::VecType::const_iterator last = quatiter-1;
|
|
||||||
float diff = (curtime-last->mTime) / (quatiter->mTime-last->mTime);
|
|
||||||
kframe->setRotation(Ogre::Quaternion::nlerp(diff, lastquat, curquat));
|
|
||||||
}
|
|
||||||
if(traniter == trankeys.mKeys.end() || traniter == trankeys.mKeys.begin())
|
|
||||||
kframe->setTranslate(curtrans);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Nif::Vector3KeyList::VecType::const_iterator last = traniter-1;
|
|
||||||
float diff = (curtime-last->mTime) / (traniter->mTime-last->mTime);
|
|
||||||
kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff));
|
|
||||||
}
|
|
||||||
if(scaleiter == scalekeys.mKeys.end() || scaleiter == scalekeys.mKeys.begin())
|
|
||||||
kframe->setScale(curscale);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1;
|
|
||||||
float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime);
|
|
||||||
kframe->setScale(lastscale + ((curscale-lastscale)*diff));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
anim->optimise();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TextKeyMap NIFSkeletonLoader::extractTextKeys(const Nif::NiTextKeyExtraData *tk)
|
|
||||||
{
|
|
||||||
TextKeyMap textkeys;
|
|
||||||
for(size_t i = 0;i < tk->list.size();i++)
|
|
||||||
{
|
|
||||||
const std::string &str = tk->list[i].text;
|
|
||||||
std::string::size_type pos = 0;
|
|
||||||
while(pos < str.length())
|
|
||||||
{
|
|
||||||
if(::isspace(str[pos]))
|
|
||||||
{
|
|
||||||
pos++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos));
|
|
||||||
std::string result = str.substr(pos, nextpos-pos);
|
|
||||||
textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result)));
|
|
||||||
|
|
||||||
pos = nextpos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return textkeys;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector<Nif::NiKeyframeController const*> &ctrls, Ogre::Bone *parent)
|
|
||||||
{
|
{
|
||||||
Ogre::Bone *bone;
|
Ogre::Bone *bone;
|
||||||
if(!skel->hasBone(node->name))
|
if(!skel->hasBone(node->name))
|
||||||
@ -175,29 +40,16 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node,
|
|||||||
Nif::ControllerPtr ctrl = node->controller;
|
Nif::ControllerPtr ctrl = node->controller;
|
||||||
while(!ctrl.empty())
|
while(!ctrl.empty())
|
||||||
{
|
{
|
||||||
if(ctrl->recType == Nif::RC_NiKeyframeController)
|
if(!(ctrl->recType == Nif::RC_NiParticleSystemController ||
|
||||||
ctrls.push_back(static_cast<const Nif::NiKeyframeController*>(ctrl.getPtr()));
|
ctrl->recType == Nif::RC_NiVisController ||
|
||||||
else if(!(ctrl->recType == Nif::RC_NiParticleSystemController ||
|
ctrl->recType == Nif::RC_NiUVController ||
|
||||||
ctrl->recType == Nif::RC_NiVisController ||
|
ctrl->recType == Nif::RC_NiKeyframeController ||
|
||||||
ctrl->recType == Nif::RC_NiUVController ||
|
ctrl->recType == Nif::RC_NiGeomMorpherController
|
||||||
ctrl->recType == Nif::RC_NiGeomMorpherController
|
))
|
||||||
))
|
|
||||||
warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName());
|
warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName());
|
||||||
ctrl = ctrl->next;
|
ctrl = ctrl->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
Nif::ExtraPtr e = node->extra;
|
|
||||||
while(!e.empty())
|
|
||||||
{
|
|
||||||
if(e->recType == Nif::RC_NiTextKeyExtraData && !animroot)
|
|
||||||
{
|
|
||||||
const Nif::NiTextKeyExtraData *tk = static_cast<const Nif::NiTextKeyExtraData*>(e.getPtr());
|
|
||||||
textkeys = extractTextKeys(tk);
|
|
||||||
animroot = bone;
|
|
||||||
}
|
|
||||||
e = e->extra;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(node);
|
const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(node);
|
||||||
if(ninode)
|
if(ninode)
|
||||||
{
|
{
|
||||||
@ -205,7 +57,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node,
|
|||||||
for(size_t i = 0;i < children.length();i++)
|
for(size_t i = 0;i < children.length();i++)
|
||||||
{
|
{
|
||||||
if(!children[i].empty())
|
if(!children[i].empty())
|
||||||
buildBones(skel, children[i].getPtr(), animroot, textkeys, ctrls, bone);
|
buildBones(skel, children[i].getPtr(), bone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -218,68 +70,14 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource)
|
|||||||
Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName()));
|
Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName()));
|
||||||
const Nif::Node *node = static_cast<const Nif::Node*>(nif->getRoot(0));
|
const Nif::Node *node = static_cast<const Nif::Node*>(nif->getRoot(0));
|
||||||
|
|
||||||
std::vector<const Nif::NiKeyframeController*> ctrls;
|
|
||||||
Ogre::Bone *animroot = NULL;
|
|
||||||
TextKeyMap textkeys;
|
|
||||||
try {
|
try {
|
||||||
buildBones(skel, node, animroot, textkeys, ctrls);
|
buildBones(skel, node);
|
||||||
}
|
}
|
||||||
catch(std::exception &e) {
|
catch(std::exception &e) {
|
||||||
std::cerr<< "Exception while loading "<<skel->getName() <<std::endl;
|
std::cerr<< "Exception while loading "<<skel->getName() <<std::endl;
|
||||||
std::cerr<< e.what() <<std::endl;
|
std::cerr<< e.what() <<std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Animations without textkeys don't get Ogre::Animation objects. */
|
|
||||||
if(!animroot)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::vector<std::string> targets;
|
|
||||||
// TODO: If ctrls.size() == 0, check for a .kf file sharing the name of the .nif file
|
|
||||||
if(ctrls.size() == 0) // No animations? Then we're done.
|
|
||||||
return;
|
|
||||||
|
|
||||||
float maxtime = 0.0f;
|
|
||||||
for(size_t i = 0;i < ctrls.size();i++)
|
|
||||||
{
|
|
||||||
const Nif::NiKeyframeController *ctrl = ctrls[i];
|
|
||||||
maxtime = std::max(maxtime, ctrl->timeStop);
|
|
||||||
Nif::Named *target = dynamic_cast<Nif::Named*>(ctrl->target.getPtr());
|
|
||||||
if(target != NULL)
|
|
||||||
targets.push_back(target->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(targets.size() != ctrls.size())
|
|
||||||
{
|
|
||||||
warn("Target size mismatch ("+Ogre::StringConverter::toString(targets.size())+" targets, "+
|
|
||||||
Ogre::StringConverter::toString(ctrls.size())+" controllers)");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string currentgroup;
|
|
||||||
TextKeyMap::const_iterator keyiter = textkeys.begin();
|
|
||||||
for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++)
|
|
||||||
{
|
|
||||||
std::string::size_type sep = keyiter->second.find(':');
|
|
||||||
if((sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) ||
|
|
||||||
(sep == sizeof("soundgen")-1 && keyiter->second.compare(0, sep, "soundgen") == 0) ||
|
|
||||||
(sep == sizeof("sound")-1 && keyiter->second.compare(0, sep, "sound") == 0))
|
|
||||||
continue;
|
|
||||||
currentgroup = keyiter->second.substr(0, sep);
|
|
||||||
|
|
||||||
if(skel->hasAnimation(currentgroup))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
TextKeyMap::const_iterator lastkeyiter = textkeys.end();
|
|
||||||
while((--lastkeyiter)->first > keyiter->first)
|
|
||||||
{
|
|
||||||
if(lastkeyiter->second.find(':') == currentgroup.length() &&
|
|
||||||
lastkeyiter->second.compare(0, currentgroup.length(), currentgroup) == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,8 +36,7 @@ class NIFSkeletonLoader : public Ogre::ManualResourceLoader
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector<const Nif::NiKeyframeController*> &ctrls, const std::vector<std::string> &targets, float startTime, float stopTime);
|
void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent=NULL);
|
||||||
void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector<Nif::NiKeyframeController const*> &ctrls, Ogre::Bone *parent=NULL);
|
|
||||||
|
|
||||||
// Lookup to retrieve an Ogre bone handle for a given Nif record index
|
// Lookup to retrieve an Ogre bone handle for a given Nif record index
|
||||||
std::map<int,int> mNifToOgreHandleMap;
|
std::map<int,int> mNifToOgreHandleMap;
|
||||||
@ -46,7 +45,6 @@ class NIFSkeletonLoader : public Ogre::ManualResourceLoader
|
|||||||
static LoaderMap sLoaders;
|
static LoaderMap sLoaders;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk);
|
|
||||||
void loadResource(Ogre::Resource *resource);
|
void loadResource(Ogre::Resource *resource);
|
||||||
|
|
||||||
static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node);
|
static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user