From 2a92fb57f72f8934b961adf3efd46bc8bbe85036 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Feb 2015 00:02:10 +0100 Subject: [PATCH] Add FlipController --- components/nifosg/controller.cpp | 21 ++++++ components/nifosg/controller.hpp | 19 ++++++ components/nifosg/nifloader.cpp | 107 ++++++++++++++++++++++--------- components/nifosg/nifloader.hpp | 23 ++++--- 4 files changed, 130 insertions(+), 40 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 8ac7f004c..041036e5b 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -310,5 +311,25 @@ void MaterialColorControllerValue::setValue(float time) mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); } +FlipControllerValue::FlipControllerValue(osg::StateSet* target, const Nif::NiFlipController *ctrl, + std::vector > textures) + : mTexSlot(ctrl->mTexSlot) + , mDelta(ctrl->mDelta) + , mTextures(textures) + , mTarget(target) +{ +} + +void FlipControllerValue::setValue(float time) +{ + if (mDelta == 0) + return; + int curTexture = int(time / mDelta) % mTextures.size(); + osg::Texture2D* tex = dynamic_cast(mTarget->getAttribute(osg::StateAttribute::TEXTURE)); + if (!tex) + return; + tex->setImage(mTextures[curTexture].get()); +} + } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index af09bda64..421f00277 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -12,6 +12,10 @@ #include //UVController +// FlipController +#include +#include + #include @@ -217,6 +221,21 @@ namespace NifOsg virtual void setValue(float time); }; + // untested + class FlipControllerValue : public ControllerValue + { + private: + osg::StateSet* mTarget; + int mTexSlot; + float mDelta; + std::vector > mTextures; + + public: + FlipControllerValue(osg::StateSet* target, const Nif::NiFlipController* ctrl, std::vector > textures); + + virtual void setValue(float time); + }; + } #endif diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 135578888..34c2f0ce0 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -220,7 +220,7 @@ namespace NifOsg } mRootNode = parentNode; - handleNode(nifNode, parentNode, false, std::map()); + handleNode(nifNode, parentNode, false, std::map(), 0); } void Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode) @@ -249,16 +249,16 @@ namespace NifOsg mSkeleton = skel; mRootNode->addChild(mSkeleton); - handleNode(nifNode, mSkeleton, true, std::map()); + handleNode(nifNode, mSkeleton, true, std::map(), 0); } - void Loader::applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures) + void Loader::applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; for (size_t i = 0; i boundTextures) + std::map boundTextures, int animflags, bool collisionNode) { osg::ref_ptr transformNode; if (createSkeleton) @@ -294,11 +294,16 @@ namespace NifOsg transformNode->setMatrix(toMatrix(nifNode->trafo)); } + if (nifNode->recType == Nif::RC_NiBSAnimationNode) + animflags |= nifNode->flags; + // Hide collision shapes, but don't skip the subgraph // We still need to animate the hidden bones so the physics system can access them - // FIXME: skip creation of the TriShapes if (nifNode->recType == Nif::RC_RootCollisionNode) + { + collisionNode = true; transformNode->setNodeMask(0); + } // We could probably skip hidden nodes entirely if they don't have a VisController that // might make them visible later @@ -308,22 +313,22 @@ namespace NifOsg // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp) parentNode->insertChild(0, transformNode); - applyNodeProperties(nifNode, transformNode, boundTextures); + applyNodeProperties(nifNode, transformNode, boundTextures, animflags); - if (nifNode->recType == Nif::RC_NiTriShape) + if (nifNode->recType == Nif::RC_NiTriShape && !collisionNode) { const Nif::NiTriShape* triShape = static_cast(nifNode); if (!createSkeleton || triShape->skin.empty()) - handleTriShape(triShape, transformNode, boundTextures); + handleTriShape(triShape, transformNode, boundTextures, animflags); else - handleSkinnedTriShape(triShape, transformNode, boundTextures); + handleSkinnedTriShape(triShape, transformNode, boundTextures, animflags); if (!nifNode->controller.empty()) - handleMeshControllers(nifNode, transformNode, boundTextures); + handleMeshControllers(nifNode, transformNode, boundTextures, animflags); } if (!nifNode->controller.empty()) - handleNodeControllers(nifNode, transformNode); + handleNodeControllers(nifNode, transformNode, animflags); const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) @@ -332,12 +337,12 @@ namespace NifOsg for(size_t i = 0;i < children.length();++i) { if(!children[i].empty()) - handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures); + handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, collisionNode); } } } - void Loader::handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures) + void Loader::handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map &boundTextures, int animflags) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -349,12 +354,12 @@ namespace NifOsg texUnits.insert(it->first); boost::shared_ptr dest(new UVControllerValue(transformNode->getOrCreateStateSet() , uvctrl->data.getPtr(), texUnits)); - createController(uvctrl, dest, 0); + createController(uvctrl, dest, animflags); } } } - void Loader::handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode) + void Loader::handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) { bool seenKeyframeCtrl = false; for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) @@ -372,7 +377,7 @@ namespace NifOsg boost::shared_ptr dest(new KeyframeControllerValue(transformNode, mNif, key->data.getPtr(), transformNode->getMatrix().getRotate(), nifNode->trafo.scale)); - createController(key, dest, 0); + createController(key, dest, animflags); seenKeyframeCtrl = true; } } @@ -380,12 +385,12 @@ namespace NifOsg { const Nif::NiVisController* visctrl = static_cast(ctrl.getPtr()); boost::shared_ptr dest(new VisControllerValue(transformNode, visctrl->data.getPtr())); - createController(visctrl, dest, 0); + createController(visctrl, dest, animflags); } } } - void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::StateSet *stateset) + void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -393,20 +398,59 @@ namespace NifOsg { const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); boost::shared_ptr dest(new AlphaControllerValue(stateset, alphactrl->data.getPtr())); - createController(alphactrl, dest, 0); + createController(alphactrl, dest, animflags); } else if (ctrl->recType == Nif::RC_NiMaterialColorController) { const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); boost::shared_ptr dest(new MaterialColorControllerValue(stateset, matctrl->data.getPtr())); - createController(matctrl, dest, 0); + createController(matctrl, dest, animflags); } else std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; } } - void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, const std::map& boundTextures) + void Loader::handleTextureControllers(const Nif::Property *texProperty, osg::StateSet *stateset, int animflags) + { + for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) + { + if (ctrl->recType == Nif::RC_NiFlipController) + { + const Nif::NiFlipController* flipctrl = static_cast(ctrl.getPtr()); + std::vector > textures; + for (unsigned int i=0; imSources.length(); ++i) + { + Nif::NiSourceTexturePtr st = flipctrl->mSources[i]; + if (st.empty()) + continue; + + // FIXME: replace by ResourceHelpers + std::string filename (st->filename); + Misc::StringUtils::toLower(filename); + filename = "textures\\" + filename; + size_t found = filename.find(".tga"); + if (found == std::string::npos) + found = filename.find(".bmp"); + if (found != std::string::npos) + filename.replace(found, 4, ".dds"); + + // tx_creature_werewolf.dds isn't loading in the correct format without this option + osgDB::Options* opts = new osgDB::Options; + opts->setOptionString("dds_dxt1_detect_rgba"); + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); + osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->getFile(filename.c_str()), opts); + textures.push_back(osg::ref_ptr(result.getImage())); + } + boost::shared_ptr dest(new FlipControllerValue(stateset, flipctrl, textures)); + createController(flipctrl, dest, animflags); + } + else + std::cerr << "Unexpected texture controller " << ctrl->recName << std::endl; + } + } + + void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, const std::map& boundTextures, int animflags) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -486,10 +530,10 @@ namespace NifOsg // above the actual renderable would be tedious. std::vector materialProps; collectMaterialProperties(triShape, materialProps); - applyMaterialProperties(geometry->getOrCreateStateSet(), materialProps, !data->colors.empty()); + applyMaterialProperties(geometry->getOrCreateStateSet(), materialProps, !data->colors.empty(), animflags); } - void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures) + void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geometry; if(!triShape->controller.empty()) @@ -510,7 +554,7 @@ namespace NifOsg if (!geometry.get()) geometry = new osg::Geometry; - triShapeToGeometry(triShape, geometry.get(), boundTextures); + triShapeToGeometry(triShape, geometry.get(), boundTextures, animflags); osg::ref_ptr geode (new osg::Geode); geode->addDrawable(geometry.get()); @@ -518,10 +562,10 @@ namespace NifOsg parentNode->addChild(geode.get()); } - void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures) + void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geometry (new osg::Geometry); - triShapeToGeometry(triShape, geometry.get(), boundTextures); + triShapeToGeometry(triShape, geometry.get(), boundTextures, animflags); osg::ref_ptr rig(new osgAnimation::RigGeometry); rig->setSourceGeometry(geometry); @@ -569,7 +613,7 @@ namespace NifOsg } void Loader::handleProperty(const Nif::Property *property, const Nif::Node* nifNode, - osg::Node *node, std::map& boundTextures) + osg::Node *node, std::map& boundTextures, int animflags) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -693,6 +737,8 @@ namespace NifOsg std::cerr << "Warning: unhandled internal texture " << std::endl; continue; } + + // FIXME: replace by ResourceHelpers std::string filename (st->filename); Misc::StringUtils::toLower(filename); filename = "textures\\" + filename; @@ -758,6 +804,7 @@ namespace NifOsg stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); boundTextures.erase(i); } + handleTextureControllers(texprop, stateset, animflags); } break; } @@ -773,7 +820,7 @@ namespace NifOsg } } - void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors) + void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors, int animflags) { int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty osg::Material* mat = new osg::Material; @@ -801,7 +848,7 @@ namespace NifOsg mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); if (!matprop->controller.empty()) - handleMaterialControllers(matprop, stateset); + handleMaterialControllers(matprop, stateset, animflags); break; } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 3b2443eb9..7f4aa7ea4 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -50,30 +50,33 @@ namespace NifOsg private: /// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform. - void handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, std::map boundTextures); + void handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, + std::map boundTextures, int animflags, bool collisionNode=false); - void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map& boundTextures); + void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map& boundTextures, int animflags); - void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode); + void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags); - void handleMaterialControllers(const Nif::Property* materialProperty, osg::StateSet* stateset); + void handleMaterialControllers(const Nif::Property* materialProperty, osg::StateSet* stateset, int animflags); + + void handleTextureControllers(const Nif::Property* texProperty, osg::StateSet* stateset, int animflags); void handleProperty (const Nif::Property* property, const Nif::Node* nifNode, - osg::Node* node, std::map& boundTextures); + osg::Node* node, std::map& boundTextures, int animflags); // Creates an osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. - void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures); + void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); // Fills the vertex data for the given TriShape into the given Geometry. - void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, const std::map& boundTextures); + void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, const std::map& boundTextures, int animflags); // Creates a skinned osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. - void handleSkinnedTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures); + void handleSkinnedTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); // Applies the Properties of the given nifNode onto the StateSet of the given OSG node. - void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map& boundTextures); + void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map& boundTextures, int animflags); - void applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors); + void applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, bool hasVertexColors, int animflags); void createController(const Nif::Controller* ctrl, boost::shared_ptr value, int animflags);