Hide NIF loader details in the implementation file

This commit is contained in:
scrawl 2015-03-23 16:10:18 +01:00
parent d6dea31b88
commit ff9e2b03a0
2 changed files with 944 additions and 960 deletions

View file

@ -285,24 +285,6 @@ namespace
int mSourceIndex; int mSourceIndex;
}; };
osg::ref_ptr<osg::Geometry> handleMorphGeometry(const Nif::NiGeomMorpherController* morpher)
{
osg::ref_ptr<osgAnimation::MorphGeometry> morphGeom = new osgAnimation::MorphGeometry;
morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE);
// No normals available in the MorphData
morphGeom->setMorphNormals(false);
const std::vector<Nif::NiMorphData::MorphData>& morphs = morpher->data.getPtr()->mMorphs;
// Note we are not interested in morph 0, which just contains the original vertices
for (unsigned int i = 1; i < morphs.size(); ++i)
{
osg::ref_ptr<osg::Geometry> morphTarget = new osg::Geometry;
morphTarget->setVertexArray(new osg::Vec3Array(morphs[i].mVertices.size(), &morphs[i].mVertices[0]));
morphGeom->addMorphTarget(morphTarget, 0.f);
}
return morphGeom;
}
void extractTextKeys(const Nif::NiTextKeyExtraData *tk, NifOsg::TextKeyMap &textkeys) void extractTextKeys(const Nif::NiTextKeyExtraData *tk, NifOsg::TextKeyMap &textkeys)
{ {
for(size_t i = 0;i < tk->list.size();i++) for(size_t i = 0;i < tk->list.size();i++)
@ -352,7 +334,19 @@ namespace NifOsg
sShowMarkers = show; sShowMarkers = show;
} }
void Loader::loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex, TextKeyMap& textKeys) class LoaderImpl
{
public:
const VFS::Manager* mResourceManager;
bool mShowMarkers;
LoaderImpl(const VFS::Manager* resourceManager, bool showMarkers)
: mResourceManager(resourceManager)
, mShowMarkers(showMarkers)
{
}
void loadKf(Nif::NIFFilePtr nif, osg::Node *rootNode, int sourceIndex, TextKeyMap& textKeys)
{ {
if(nif->numRoots() < 1) if(nif->numRoots() < 1)
{ {
@ -409,10 +403,8 @@ namespace NifOsg
rootNode->accept(visitor); rootNode->accept(visitor);
} }
osg::Node* Loader::load(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) osg::Node* load(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys)
{ {
mNif = nif;
if (nif->numRoots() < 1) if (nif->numRoots() < 1)
nif->fail("Found no root nodes"); nif->fail("Found no root nodes");
@ -422,16 +414,12 @@ namespace NifOsg
if (nifNode == NULL) if (nifNode == NULL)
nif->fail("First root was not a node, but a " + r->recName); nif->fail("First root was not a node, but a " + r->recName);
mRootNode = parentNode;
osg::Node* created = handleNode(nifNode, parentNode, false, std::map<int, int>(), 0, 0, false, textKeys); osg::Node* created = handleNode(nifNode, parentNode, false, std::map<int, int>(), 0, 0, false, textKeys);
return created; return created;
} }
osg::Node* Loader::loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys) osg::Node* loadAsSkeleton(Nif::NIFFilePtr nif, osg::Group *parentNode, TextKeyMap* textKeys)
{ {
mNif = nif;
if (nif->numRoots() < 1) if (nif->numRoots() < 1)
nif->fail("Found no root nodes"); nif->fail("Found no root nodes");
@ -445,14 +433,12 @@ namespace NifOsg
osg::ref_ptr<osgAnimation::Skeleton> skel = new osgAnimation::Skeleton; osg::ref_ptr<osgAnimation::Skeleton> skel = new osgAnimation::Skeleton;
parentNode->addChild(skel); parentNode->addChild(skel);
mRootNode = parentNode;
handleNode(nifNode, skel, true, std::map<int, int>(), 0, 0, false, textKeys); handleNode(nifNode, skel, true, std::map<int, int>(), 0, 0, false, textKeys);
return skel; return skel;
} }
void Loader::applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, std::map<int, int>& boundTextures, int animflags) void 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)
@ -462,7 +448,7 @@ namespace NifOsg
} }
} }
void Loader::setupController(const Nif::Controller* ctrl, Controller* toSetup, int animflags) void setupController(const Nif::Controller* ctrl, Controller* toSetup, int animflags)
{ {
//bool autoPlay = animflags & Nif::NiNode::AnimFlag_AutoPlay; //bool autoPlay = animflags & Nif::NiNode::AnimFlag_AutoPlay;
//if (autoPlay) //if (autoPlay)
@ -471,8 +457,9 @@ namespace NifOsg
toSetup->mFunction = boost::shared_ptr<ControllerFunction>(new ControllerFunction(ctrl, 1 /*autoPlay*/)); toSetup->mFunction = boost::shared_ptr<ControllerFunction>(new ControllerFunction(ctrl, 1 /*autoPlay*/));
} }
osg::Node* Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton,
std::map<int, int> boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys) osg::Node* handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton,
std::map<int, int> boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL)
{ {
osg::ref_ptr<osg::MatrixTransform> transformNode; osg::ref_ptr<osg::MatrixTransform> transformNode;
if (nifNode->recType == Nif::RC_NiBillboardNode) if (nifNode->recType == Nif::RC_NiBillboardNode)
@ -491,6 +478,10 @@ namespace NifOsg
{ {
transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo)); transformNode = new osg::MatrixTransform(toMatrix(nifNode->trafo));
} }
if (!rootNode)
rootNode = transformNode;
// Ignoring name for non-bone nodes for now. We might need it later in isolated cases, e.g. AttachLight. // Ignoring name for non-bone nodes for now. We might need it later in isolated cases, e.g. AttachLight.
// 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)
@ -518,7 +509,7 @@ namespace NifOsg
// String markers may contain important information // String markers may contain important information
// affecting the entire subtree of this obj // affecting the entire subtree of this obj
// TODO: implement show markers flag // TODO: implement show markers flag
if(sd->string == "MRK" && !sShowMarkers) if(sd->string == "MRK" && !mShowMarkers)
{ {
// Marker objects. These meshes are only visible in the editor. // Marker objects. These meshes are only visible in the editor.
skipMeshes = true; skipMeshes = true;
@ -560,7 +551,7 @@ namespace NifOsg
} }
if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles)
handleParticleSystem(nifNode, transformNode, animflags, particleflags); handleParticleSystem(nifNode, transformNode, animflags, particleflags, rootNode);
if (!nifNode->controller.empty()) if (!nifNode->controller.empty())
handleNodeControllers(nifNode, transformNode, animflags); handleNodeControllers(nifNode, transformNode, animflags);
@ -576,14 +567,14 @@ 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, animflags, particleflags, skipMeshes, textKeys); handleNode(children[i].getPtr(), transformNode, createSkeleton, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode);
} }
} }
return transformNode; return transformNode;
} }
void Loader::handleMeshControllers(const Nif::Node *nifNode, osg::MatrixTransform *transformNode, const std::map<int, int> &boundTextures, int animflags) void 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)
{ {
@ -605,7 +596,7 @@ namespace NifOsg
} }
} }
void Loader::handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags)
{ {
for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next)
{ {
@ -633,7 +624,8 @@ namespace NifOsg
} }
} }
void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags)
void handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, 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)
{ {
@ -660,7 +652,8 @@ namespace NifOsg
} }
} }
void Loader::handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, osg::StateSet *stateset, int animflags)
void handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, osg::StateSet *stateset, int animflags)
{ {
for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next)
{ {
@ -676,13 +669,14 @@ namespace NifOsg
if (st.empty()) if (st.empty())
continue; continue;
std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, resourceManager); std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mResourceManager);
// TODO: replace with texture manager
// tx_creature_werewolf.dds isn't loading in the correct format without this option // tx_creature_werewolf.dds isn't loading in the correct format without this option
osgDB::Options* opts = new osgDB::Options; osgDB::Options* opts = new osgDB::Options;
opts->setOptionString("dds_dxt1_detect_rgba"); opts->setOptionString("dds_dxt1_detect_rgba");
osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds");
osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->get(filename.c_str()), opts); osgDB::ReaderWriter::ReadResult result = reader->readImage(*mResourceManager->get(filename.c_str()), opts);
textures.push_back(osg::ref_ptr<osg::Image>(result.getImage())); textures.push_back(osg::ref_ptr<osg::Image>(result.getImage()));
} }
osg::ref_ptr<FlipController> callback(new FlipController(flipctrl, textures)); osg::ref_ptr<FlipController> callback(new FlipController(flipctrl, textures));
@ -695,7 +689,44 @@ namespace NifOsg
} }
} }
void Loader::handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags) void handleParticleAffectors(Nif::ExtraPtr e, osg::Group *attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf)
{
osgParticle::ModularProgram* program = new osgParticle::ModularProgram;
attachTo->addChild(program);
program->setParticleSystem(partsys);
program->setReferenceFrame(rf);
for (; !e.empty(); e = e->extra)
{
if (e->recType == Nif::RC_NiParticleGrowFade)
{
const Nif::NiParticleGrowFade *gf = static_cast<const Nif::NiParticleGrowFade*>(e.getPtr());
GrowFadeAffector* affector = new GrowFadeAffector(gf->growTime, gf->fadeTime);
program->addOperator(affector);
}
else if (e->recType == Nif::RC_NiGravity)
{
const Nif::NiGravity* gr = static_cast<const Nif::NiGravity*>(e.getPtr());
GravityAffector* affector = new GravityAffector(gr);
program->addOperator(affector);
}
else if (e->recType == Nif::RC_NiParticleColorModifier)
{
const Nif::NiParticleColorModifier *cl = static_cast<const Nif::NiParticleColorModifier*>(e.getPtr());
const Nif::NiColorData *clrdata = cl->data.getPtr();
ParticleColorAffector* affector = new ParticleColorAffector(clrdata);
program->addOperator(affector);
}
else if (e->recType == Nif::RC_NiParticleRotation)
{
// TODO: Implement?
}
else
std::cerr << "Unhandled particle modifier " << e->recName << std::endl;
}
}
void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, int animflags, int particleflags, osg::Node* rootNode)
{ {
osg::ref_ptr<ParticleSystem> partsys (new ParticleSystem); osg::ref_ptr<ParticleSystem> partsys (new ParticleSystem);
partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT);
@ -800,7 +831,7 @@ namespace NifOsg
// Creating emitters will need to be changed when cloning a scenegraph is implemented, the particleSystem pointer would become invalid // Creating emitters will need to be changed when cloning a scenegraph is implemented, the particleSystem pointer would become invalid
FindRecIndexVisitor find (partctrl->emitter->recIndex); FindRecIndexVisitor find (partctrl->emitter->recIndex);
mRootNode->accept(find); rootNode->accept(find);
if (!find.mFound) if (!find.mFound)
{ {
std::cerr << "can't find emitter node, wrong node order?" << std::endl; std::cerr << "can't find emitter node, wrong node order?" << std::endl;
@ -816,41 +847,8 @@ namespace NifOsg
setupController(partctrl, callback, animflags); setupController(partctrl, callback, animflags);
emitter->setUpdateCallback(callback); emitter->setUpdateCallback(callback);
// ----------- affector (must be after emitters in the scene graph) // affectors must be attached *after* the emitter in the scene graph for correct update order
osgParticle::ModularProgram* program = new osgParticle::ModularProgram; handleParticleAffectors(partctrl->extra, emitterNode, partsys.get(), rf);
program->setParticleSystem(partsys);
program->setReferenceFrame(rf);
emitterNode->addChild(program);
for (Nif::ExtraPtr e = partctrl->extra; !e.empty(); e = e->extra)
{
if (e->recType == Nif::RC_NiParticleGrowFade)
{
const Nif::NiParticleGrowFade *gf = static_cast<const Nif::NiParticleGrowFade*>(e.getPtr());
GrowFadeAffector* affector = new GrowFadeAffector(gf->growTime, gf->fadeTime);
program->addOperator(affector);
}
else if (e->recType == Nif::RC_NiGravity)
{
const Nif::NiGravity* gr = static_cast<const Nif::NiGravity*>(e.getPtr());
GravityAffector* affector = new GravityAffector(gr);
program->addOperator(affector);
}
else if (e->recType == Nif::RC_NiParticleColorModifier)
{
const Nif::NiParticleColorModifier *cl = static_cast<const Nif::NiParticleColorModifier*>(e.getPtr());
const Nif::NiColorData *clrdata = cl->data.getPtr();
ParticleColorAffector* affector = new ParticleColorAffector(clrdata);
program->addOperator(affector);
}
else if (e->recType == Nif::RC_NiParticleRotation)
{
// TODO: Implement?
}
else
std::cerr << "Unhandled particle modifier " << e->recName << std::endl;
}
// -----------
osg::ref_ptr<osg::Geode> geode (new osg::Geode); osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->addDrawable(partsys); geode->addDrawable(partsys);
@ -879,7 +877,7 @@ namespace NifOsg
parentNode->addChild(updater); parentNode->addChild(updater);
} }
void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map<int, int>& boundTextures, int animflags) void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map<int, int>& boundTextures, int animflags)
{ {
const Nif::NiTriShapeData* data = triShape->data.getPtr(); const Nif::NiTriShapeData* data = triShape->data.getPtr();
@ -962,7 +960,7 @@ namespace NifOsg
applyMaterialProperties(parentGeode, materialProps, !data->colors.empty(), animflags); applyMaterialProperties(parentGeode, materialProps, !data->colors.empty(), animflags);
} }
void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map<int, int>& boundTextures, int animflags) void 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())
@ -994,7 +992,25 @@ namespace NifOsg
parentNode->addChild(geode); parentNode->addChild(geode);
} }
void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map<int, int>& boundTextures, int animflags) osg::ref_ptr<osg::Geometry> handleMorphGeometry(const Nif::NiGeomMorpherController* morpher)
{
osg::ref_ptr<osgAnimation::MorphGeometry> morphGeom = new osgAnimation::MorphGeometry;
morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE);
// No normals available in the MorphData
morphGeom->setMorphNormals(false);
const std::vector<Nif::NiMorphData::MorphData>& morphs = morpher->data.getPtr()->mMorphs;
// Note we are not interested in morph 0, which just contains the original vertices
for (unsigned int i = 1; i < morphs.size(); ++i)
{
osg::ref_ptr<osg::Geometry> morphTarget = new osg::Geometry;
morphTarget->setVertexArray(new osg::Vec3Array(morphs[i].mVertices.size(), &morphs[i].mVertices[0]));
morphGeom->addMorphTarget(morphTarget, 0.f);
}
return morphGeom;
}
void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map<int, int>& boundTextures, int animflags)
{ {
osg::ref_ptr<osg::Geode> geode (new osg::Geode); osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->setName(triShape->name); // name will be used for part filtering geode->setName(triShape->name); // name will be used for part filtering
@ -1045,7 +1061,8 @@ namespace NifOsg
parentNode->addChild(trans); parentNode->addChild(trans);
} }
void Loader::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, int animflags) osg::Node *node, std::map<int, int>& boundTextures, int animflags)
{ {
osg::StateSet* stateset = node->getOrCreateStateSet(); osg::StateSet* stateset = node->getOrCreateStateSet();
@ -1171,13 +1188,14 @@ namespace NifOsg
continue; continue;
} }
std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, resourceManager); std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, mResourceManager);
// TODO: replace with texture manager
// tx_creature_werewolf.dds isn't loading in the correct format without this option // tx_creature_werewolf.dds isn't loading in the correct format without this option
osgDB::Options* opts = new osgDB::Options; osgDB::Options* opts = new osgDB::Options;
opts->setOptionString("dds_dxt1_detect_rgba"); opts->setOptionString("dds_dxt1_detect_rgba");
osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds"); osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("dds");
osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->get(filename.c_str()), opts); osgDB::ReaderWriter::ReadResult result = reader->readImage(*mResourceManager->get(filename.c_str()), opts);
osg::Image* image = result.getImage(); osg::Image* image = result.getImage();
osg::Texture2D* texture2d = new osg::Texture2D; osg::Texture2D* texture2d = new osg::Texture2D;
texture2d->setUnRefImageDataAfterApply(true); texture2d->setUnRefImageDataAfterApply(true);
@ -1246,7 +1264,7 @@ namespace NifOsg
} }
} }
void Loader::applyMaterialProperties(osg::Node* node, const std::vector<const Nif::Property*>& properties, void applyMaterialProperties(osg::Node* node, const std::vector<const Nif::Property*>& properties,
bool hasVertexColors, int animflags) bool hasVertexColors, int animflags)
{ {
osg::StateSet* stateset = node->getOrCreateStateSet(); osg::StateSet* stateset = node->getOrCreateStateSet();
@ -1307,4 +1325,25 @@ namespace NifOsg
stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); stateset->setAttributeAndModes(mat, osg::StateAttribute::ON);
} }
};
osg::Node* Loader::load(Nif::NIFFilePtr file, osg::Group *parentNode, TextKeyMap *textKeys)
{
LoaderImpl loader(resourceManager, sShowMarkers);
return loader.load(file, parentNode, textKeys);
}
osg::Node* Loader::loadAsSkeleton(Nif::NIFFilePtr file, osg::Group *parentNode, TextKeyMap *textKeys)
{
LoaderImpl loader(resourceManager, sShowMarkers);
return loader.loadAsSkeleton(file, parentNode, textKeys);
}
void Loader::loadKf(Nif::NIFFilePtr kf, osg::Node *rootNode, int sourceIndex, TextKeyMap &textKeys)
{
LoaderImpl loader(resourceManager, sShowMarkers);
loader.loadKf(kf, rootNode, sourceIndex, textKeys);
}
} }

View file

@ -9,24 +9,8 @@
namespace osg namespace osg
{ {
class Geometry;
class Group; class Group;
class Node; class Node;
class MatrixTransform;
class StateSet;
class Geode;
}
namespace osgAnimation
{
class Bone;
}
namespace Nif
{
class Node;
class NiTriShape;
class Property;
class Controller;
} }
namespace NifOsg namespace NifOsg
@ -62,45 +46,6 @@ namespace NifOsg
private: private:
/// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform.
osg::Node* handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton,
std::map<int, int> boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys);
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, int animflags);
void handleMaterialControllers(const Nif::Property* materialProperty, osg::Node* node, osg::StateSet* stateset, int animflags);
void handleTextureControllers(const Nif::Property* texProperty, osg::Node* node, osg::StateSet* stateset, int animflags);
void handleProperty (const Nif::Property* property, const Nif::Node* nifNode,
osg::Node* node, std::map<int, int>& boundTextures, int animflags);
void handleParticleSystem(const Nif::Node* nifNode, osg::Group* parentNode, int animflags, int particleflags);
// 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, int animflags);
// Fills the vertex data for the given TriShape into the given Geometry.
void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, osg::Geode* parentGeode, 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.
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.
void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map<int, int>& boundTextures, int animflags);
void applyMaterialProperties(osg::Node* node, const std::vector<const Nif::Property*>& properties,
bool hasVertexColors, int animflags);
// Set up the default input and controller function for the given controller.
void setupController(const Nif::Controller* ctrl, Controller* toSetup, int animflags);
Nif::NIFFilePtr mNif;
osg::Group* mRootNode;
static bool sShowMarkers; static bool sShowMarkers;
}; };