Add FlipController

c++11
scrawl 10 years ago
parent 6c8613ae35
commit 2a92fb57f7

@ -3,6 +3,7 @@
#include <osg/MatrixTransform> #include <osg/MatrixTransform>
#include <osg/TexMat> #include <osg/TexMat>
#include <osg/Material> #include <osg/Material>
#include <osg/Texture2D>
#include <osgAnimation/MorphGeometry> #include <osgAnimation/MorphGeometry>
#include <osg/io_utils> #include <osg/io_utils>
@ -310,5 +311,25 @@ void MaterialColorControllerValue::setValue(float time)
mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse);
} }
FlipControllerValue::FlipControllerValue(osg::StateSet* target, const Nif::NiFlipController *ctrl,
std::vector<osg::ref_ptr<osg::Image> > 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<osg::Texture2D*>(mTarget->getAttribute(osg::StateAttribute::TEXTURE));
if (!tex)
return;
tex->setImage(mTextures[curTexture].get());
}
} }

@ -12,6 +12,10 @@
#include <set> //UVController #include <set> //UVController
// FlipController
#include <osg/Image>
#include <osg/ref_ptr>
#include <osg/Timer> #include <osg/Timer>
@ -217,6 +221,21 @@ namespace NifOsg
virtual void setValue(float time); virtual void setValue(float time);
}; };
// untested
class FlipControllerValue : public ControllerValue
{
private:
osg::StateSet* mTarget;
int mTexSlot;
float mDelta;
std::vector<osg::ref_ptr<osg::Image> > mTextures;
public:
FlipControllerValue(osg::StateSet* target, const Nif::NiFlipController* ctrl, std::vector<osg::ref_ptr<osg::Image> > textures);
virtual void setValue(float time);
};
} }
#endif #endif

@ -220,7 +220,7 @@ namespace NifOsg
} }
mRootNode = parentNode; mRootNode = parentNode;
handleNode(nifNode, parentNode, false, std::map<int, int>()); handleNode(nifNode, parentNode, false, std::map<int, int>(), 0);
} }
void Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode) void Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode)
@ -249,16 +249,16 @@ namespace NifOsg
mSkeleton = skel; mSkeleton = skel;
mRootNode->addChild(mSkeleton); mRootNode->addChild(mSkeleton);
handleNode(nifNode, mSkeleton, true, std::map<int, int>()); handleNode(nifNode, mSkeleton, true, std::map<int, int>(), 0);
} }
void Loader::applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map<int, int>& boundTextures) void Loader::applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map<int, int>& boundTextures, int animflags)
{ {
const Nif::PropertyList& props = nifNode->props; const Nif::PropertyList& props = nifNode->props;
for (size_t i = 0; i <props.length();++i) for (size_t i = 0; i <props.length();++i)
{ {
if (!props[i].empty()) if (!props[i].empty())
handleProperty(props[i].getPtr(), nifNode, applyTo, boundTextures); handleProperty(props[i].getPtr(), nifNode, applyTo, boundTextures, animflags);
} }
} }
@ -276,7 +276,7 @@ namespace NifOsg
} }
void Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, void Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton,
std::map<int, int> boundTextures) std::map<int, int> boundTextures, int animflags, bool collisionNode)
{ {
osg::ref_ptr<osg::MatrixTransform> transformNode; osg::ref_ptr<osg::MatrixTransform> transformNode;
if (createSkeleton) if (createSkeleton)
@ -294,11 +294,16 @@ namespace NifOsg
transformNode->setMatrix(toMatrix(nifNode->trafo)); transformNode->setMatrix(toMatrix(nifNode->trafo));
} }
if (nifNode->recType == Nif::RC_NiBSAnimationNode)
animflags |= nifNode->flags;
// Hide collision shapes, but don't skip the subgraph // Hide collision shapes, but don't skip the subgraph
// We still need to animate the hidden bones so the physics system can access them // 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) if (nifNode->recType == Nif::RC_RootCollisionNode)
{
collisionNode = true;
transformNode->setNodeMask(0); transformNode->setNodeMask(0);
}
// We could probably skip hidden nodes entirely if they don't have a VisController that // We could probably skip hidden nodes entirely if they don't have a VisController that
// might make them visible later // 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) // Insert bones at position 0 to prevent update order problems (see comment in osg Skeleton.cpp)
parentNode->insertChild(0, transformNode); 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<const Nif::NiTriShape*>(nifNode); const Nif::NiTriShape* triShape = static_cast<const Nif::NiTriShape*>(nifNode);
if (!createSkeleton || triShape->skin.empty()) if (!createSkeleton || triShape->skin.empty())
handleTriShape(triShape, transformNode, boundTextures); handleTriShape(triShape, transformNode, boundTextures, animflags);
else else
handleSkinnedTriShape(triShape, transformNode, boundTextures); handleSkinnedTriShape(triShape, transformNode, boundTextures, animflags);
if (!nifNode->controller.empty()) if (!nifNode->controller.empty())
handleMeshControllers(nifNode, transformNode, boundTextures); handleMeshControllers(nifNode, transformNode, boundTextures, animflags);
} }
if (!nifNode->controller.empty()) if (!nifNode->controller.empty())
handleNodeControllers(nifNode, transformNode); handleNodeControllers(nifNode, transformNode, animflags);
const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(nifNode); const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(nifNode);
if(ninode) if(ninode)
@ -332,12 +337,12 @@ namespace NifOsg
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())
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<int, int> &boundTextures) void Loader::handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map<int, int> &boundTextures, int animflags)
{ {
for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next)
{ {
@ -349,12 +354,12 @@ namespace NifOsg
texUnits.insert(it->first); texUnits.insert(it->first);
boost::shared_ptr<ControllerValue> dest(new UVControllerValue(transformNode->getOrCreateStateSet() boost::shared_ptr<ControllerValue> dest(new UVControllerValue(transformNode->getOrCreateStateSet()
, uvctrl->data.getPtr(), texUnits)); , 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; bool seenKeyframeCtrl = false;
for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next)
@ -372,7 +377,7 @@ namespace NifOsg
boost::shared_ptr<ControllerValue> dest(new KeyframeControllerValue(transformNode, mNif, key->data.getPtr(), boost::shared_ptr<ControllerValue> dest(new KeyframeControllerValue(transformNode, mNif, key->data.getPtr(),
transformNode->getMatrix().getRotate(), nifNode->trafo.scale)); transformNode->getMatrix().getRotate(), nifNode->trafo.scale));
createController(key, dest, 0); createController(key, dest, animflags);
seenKeyframeCtrl = true; seenKeyframeCtrl = true;
} }
} }
@ -380,12 +385,12 @@ namespace NifOsg
{ {
const Nif::NiVisController* visctrl = static_cast<const Nif::NiVisController*>(ctrl.getPtr()); const Nif::NiVisController* visctrl = static_cast<const Nif::NiVisController*>(ctrl.getPtr());
boost::shared_ptr<ControllerValue> dest(new VisControllerValue(transformNode, visctrl->data.getPtr())); boost::shared_ptr<ControllerValue> 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) for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next)
{ {
@ -393,20 +398,59 @@ namespace NifOsg
{ {
const Nif::NiAlphaController* alphactrl = static_cast<const Nif::NiAlphaController*>(ctrl.getPtr()); const Nif::NiAlphaController* alphactrl = static_cast<const Nif::NiAlphaController*>(ctrl.getPtr());
boost::shared_ptr<ControllerValue> dest(new AlphaControllerValue(stateset, alphactrl->data.getPtr())); boost::shared_ptr<ControllerValue> dest(new AlphaControllerValue(stateset, alphactrl->data.getPtr()));
createController(alphactrl, dest, 0); createController(alphactrl, dest, animflags);
} }
else if (ctrl->recType == Nif::RC_NiMaterialColorController) else if (ctrl->recType == Nif::RC_NiMaterialColorController)
{ {
const Nif::NiMaterialColorController* matctrl = static_cast<const Nif::NiMaterialColorController*>(ctrl.getPtr()); const Nif::NiMaterialColorController* matctrl = static_cast<const Nif::NiMaterialColorController*>(ctrl.getPtr());
boost::shared_ptr<ControllerValue> dest(new MaterialColorControllerValue(stateset, matctrl->data.getPtr())); boost::shared_ptr<ControllerValue> dest(new MaterialColorControllerValue(stateset, matctrl->data.getPtr()));
createController(matctrl, dest, 0); createController(matctrl, dest, animflags);
} }
else else
std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; std::cerr << "Unexpected material controller " << ctrl->recType << std::endl;
} }
} }
void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, const std::map<int, int>& 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<const Nif::NiFlipController*>(ctrl.getPtr());
std::vector<osg::ref_ptr<osg::Image> > textures;
for (unsigned int i=0; i<flipctrl->mSources.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<osg::Image>(result.getImage()));
}
boost::shared_ptr<ControllerValue> 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<int, int>& boundTextures, int animflags)
{ {
const Nif::NiTriShapeData* data = triShape->data.getPtr(); const Nif::NiTriShapeData* data = triShape->data.getPtr();
@ -486,10 +530,10 @@ namespace NifOsg
// above the actual renderable would be tedious. // above the actual renderable would be tedious.
std::vector<const Nif::Property*> materialProps; std::vector<const Nif::Property*> materialProps;
collectMaterialProperties(triShape, 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<int, int>& boundTextures) void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map<int, int>& boundTextures, int animflags)
{ {
osg::ref_ptr<osg::Geometry> geometry; osg::ref_ptr<osg::Geometry> geometry;
if(!triShape->controller.empty()) if(!triShape->controller.empty())
@ -510,7 +554,7 @@ namespace NifOsg
if (!geometry.get()) if (!geometry.get())
geometry = new osg::Geometry; geometry = new osg::Geometry;
triShapeToGeometry(triShape, geometry.get(), boundTextures); triShapeToGeometry(triShape, geometry.get(), boundTextures, animflags);
osg::ref_ptr<osg::Geode> geode (new osg::Geode); osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->addDrawable(geometry.get()); geode->addDrawable(geometry.get());
@ -518,10 +562,10 @@ namespace NifOsg
parentNode->addChild(geode.get()); parentNode->addChild(geode.get());
} }
void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map<int, int>& boundTextures) void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map<int, int>& boundTextures, int animflags)
{ {
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry); osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
triShapeToGeometry(triShape, geometry.get(), boundTextures); triShapeToGeometry(triShape, geometry.get(), boundTextures, animflags);
osg::ref_ptr<osgAnimation::RigGeometry> rig(new osgAnimation::RigGeometry); osg::ref_ptr<osgAnimation::RigGeometry> rig(new osgAnimation::RigGeometry);
rig->setSourceGeometry(geometry); rig->setSourceGeometry(geometry);
@ -569,7 +613,7 @@ namespace NifOsg
} }
void Loader::handleProperty(const Nif::Property *property, const Nif::Node* nifNode, void Loader::handleProperty(const Nif::Property *property, const Nif::Node* nifNode,
osg::Node *node, std::map<int, int>& boundTextures) osg::Node *node, std::map<int, int>& boundTextures, int animflags)
{ {
osg::StateSet* stateset = node->getOrCreateStateSet(); osg::StateSet* stateset = node->getOrCreateStateSet();
@ -693,6 +737,8 @@ namespace NifOsg
std::cerr << "Warning: unhandled internal texture " << std::endl; std::cerr << "Warning: unhandled internal texture " << std::endl;
continue; continue;
} }
// FIXME: replace by ResourceHelpers
std::string filename (st->filename); std::string filename (st->filename);
Misc::StringUtils::toLower(filename); Misc::StringUtils::toLower(filename);
filename = "textures\\" + filename; filename = "textures\\" + filename;
@ -758,6 +804,7 @@ namespace NifOsg
stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF);
boundTextures.erase(i); boundTextures.erase(i);
} }
handleTextureControllers(texprop, stateset, animflags);
} }
break; break;
} }
@ -773,7 +820,7 @@ namespace NifOsg
} }
} }
void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector<const Nif::Property*>& properties, bool hasVertexColors) void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector<const Nif::Property*>& properties, bool hasVertexColors, int animflags)
{ {
int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty
osg::Material* mat = new osg::Material; osg::Material* mat = new osg::Material;
@ -801,7 +848,7 @@ namespace NifOsg
mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness);
if (!matprop->controller.empty()) if (!matprop->controller.empty())
handleMaterialControllers(matprop, stateset); handleMaterialControllers(matprop, stateset, animflags);
break; break;
} }

@ -50,30 +50,33 @@ namespace NifOsg
private: private:
/// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform. /// @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<int, int> boundTextures); void handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton,
std::map<int, int> boundTextures, int animflags, bool collisionNode=false);
void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map<int, int>& boundTextures); void handleMeshControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, const std::map<int, int>& 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, void handleProperty (const Nif::Property* property, const Nif::Node* nifNode,
osg::Node* node, std::map<int, int>& boundTextures); osg::Node* node, std::map<int, int>& boundTextures, int animflags);
// Creates an osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. // 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<int, int>& boundTextures); void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map<int, int>& boundTextures, int animflags);
// Fills the vertex data for the given TriShape into the given Geometry. // Fills the vertex data for the given TriShape into the given Geometry.
void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, const std::map<int, int>& boundTextures); void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, const std::map<int, int>& boundTextures, int animflags);
// Creates a skinned osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. // 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<int, int>& boundTextures); void handleSkinnedTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map<int, int>& boundTextures, int animflags);
// Applies the Properties of the given nifNode onto the StateSet of the given OSG node. // 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<int, int>& boundTextures); void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map<int, int>& boundTextures, int animflags);
void applyMaterialProperties(osg::StateSet* stateset, const std::vector<const Nif::Property*>& properties, bool hasVertexColors); void applyMaterialProperties(osg::StateSet* stateset, const std::vector<const Nif::Property*>& properties, bool hasVertexColors, int animflags);
void createController(const Nif::Controller* ctrl, boost::shared_ptr<ControllerValue> value, int animflags); void createController(const Nif::Controller* ctrl, boost::shared_ptr<ControllerValue> value, int animflags);

Loading…
Cancel
Save