diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index f663cdf14..443b20710 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -62,6 +62,83 @@ ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&) namespace NifOgre { + +// FIXME: Should not be here. +class VisController +{ +public: + class Value : public Ogre::ControllerValue + { + private: + Ogre::Bone *mTarget; + + // FIXME: We are not getting all objects here. Skinned meshes get + // attached to the object's root node, and won't be connected via a + // TagPoint. + static void setVisible(Ogre::Node *node, int vis) + { + Ogre::Node::ChildNodeIterator iter = node->getChildIterator(); + while(iter.hasMoreElements()) + { + node = iter.getNext(); + setVisible(node, vis); + + Ogre::TagPoint *tag = dynamic_cast(node); + if(tag != NULL) + { + Ogre::MovableObject *obj = tag->getChildObject(); + if(obj != NULL) + obj->setVisible(vis); + } + } + } + + public: + Value(Ogre::Bone *target) : mTarget(target) + { } + + virtual Ogre::Real getValue() const + { + // Should not be called + return 1.0f; + } + + virtual void setValue(Ogre::Real value) + { + int vis = static_cast(value); + setVisible(mTarget, vis); + } + }; + + class Function : public Ogre::ControllerFunction + { + private: + std::vector mData; + + public: + Function(const Nif::NiVisData *data) + : Ogre::ControllerFunction(false), + mData(data->mVis) + { } + + virtual Ogre::Real calculate(Ogre::Real value) + { + if(mData.size() == 0) + return 1.0f; + + if(mData[0].time >= value) + return mData[0].isSet; + for(size_t i = 1;i < mData.size();i++) + { + if(mData[i].time > value) + return mData[i-1].isSet; + } + return mData.back().isSet; + } + }; +}; + + // Helper class that computes the bounding box and of a mesh class BoundsFinder { @@ -330,7 +407,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro { if(ctrl->recType == Nif::RC_NiKeyframeController) ctrls.push_back(static_cast(ctrl.getPtr())); - else if(!(ctrl->recType == Nif::RC_NiParticleSystemController + else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || + ctrl->recType == Nif::RC_NiVisController )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; @@ -1129,7 +1207,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { Ogre::ParticleEmitter *emitter = partsys->addEmitter("Point"); - emitter->setDirection(Ogre::Vector3::UNIT_Z); + emitter->setDirection(Ogre::Vector3(0.0f, 0.0f, std::cos(partctrl->verticalDir))); + emitter->setAngle(Ogre::Radian(partctrl->verticalAngle)); emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom, partctrl->velocity+partctrl->velocityRandom); emitter->setEmissionRate(partctrl->emitRate); @@ -1270,6 +1349,26 @@ class NIFMeshLoader : Ogre::ManualResourceLoader e = e->extra; } + Nif::ControllerPtr ctrl = node->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiVisController) + { + const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); + + const Nif::Named *target = dynamic_cast(ctrl->target.getPtr()); + if(!target) target = node; + + Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(target->name); + Ogre::SharedPtr > srcval; /* Filled in later */ + Ogre::SharedPtr > dstval(OGRE_NEW VisController::Value(trgtbone)); + Ogre::SharedPtr > func(OGRE_NEW VisController::Function(vis->data.getPtr())); + + entities.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + ctrl = ctrl->next; + } + if(node->recType == Nif::RC_NiTriShape && !(flags&0x01)) // Not hidden { const Nif::NiTriShape *shape = static_cast(node);