diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 0a1d5eb09..5300d6ab4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -192,24 +192,38 @@ namespace }; // Removes all drawables from a graph. - class RemoveDrawableVisitor : public RemoveVisitor + class CleanObjectRootVisitor : public RemoveVisitor { public: virtual void apply(osg::Drawable& drw) { - applyImpl(drw); + applyDrawable(drw); } virtual void apply(osg::Group& node) { - traverse(node); + applyNode(node); } virtual void apply(osg::MatrixTransform& node) { - traverse(node); + applyNode(node); + } + virtual void apply(osg::Node& node) + { + applyNode(node); } - void applyImpl(osg::Node& node) + void applyNode(osg::Node& node) + { + if (node.getStateSet()) + node.setStateSet(NULL); + + if (node.getNodeMask() == 0x1 && node.getNumParents() == 1) + mToRemove.push_back(std::make_pair(&node, node.getParent(0))); + else + traverse(node); + } + void applyDrawable(osg::Node& node) { osg::NodePath::iterator parent = getNodePath().end()-2; // We know that the parent is a Group because only Groups can have children. @@ -1123,6 +1137,32 @@ namespace MWRender state->second.mLoopingEnabled = enabled; } + osg::ref_ptr getModelInstance(Resource::SceneManager* sceneMgr, const std::string& model, bool baseonly) + { + if (baseonly) + { + typedef std::map > Cache; + static Cache cache; + Cache::iterator found = cache.find(model); + if (found == cache.end()) + { + osg::ref_ptr created = sceneMgr->getInstance(model); + + CleanObjectRootVisitor removeDrawableVisitor; + created->accept(removeDrawableVisitor); + removeDrawableVisitor.remove(); + + cache.insert(std::make_pair(model, created)); + + return sceneMgr->createInstance(created); + } + else + return sceneMgr->createInstance(found->second); + } + else + return sceneMgr->createInstance(model); + } + void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature) { osg::ref_ptr previousStateset; @@ -1144,7 +1184,8 @@ namespace MWRender if (!forceskeleton) { - osg::ref_ptr created = mResourceSystem->getSceneManager()->getInstance(model, mInsert); + osg::ref_ptr created = getModelInstance(mResourceSystem->getSceneManager(), model, baseonly); + mInsert->addChild(created); mObjectRoot = created->asGroup(); if (!mObjectRoot) { @@ -1156,7 +1197,7 @@ namespace MWRender } else { - osg::ref_ptr created = mResourceSystem->getSceneManager()->getInstance(model); + osg::ref_ptr created = getModelInstance(mResourceSystem->getSceneManager(), model, baseonly); osg::ref_ptr skel = dynamic_cast(created.get()); if (!skel) { @@ -1171,13 +1212,6 @@ namespace MWRender if (previousStateset) mObjectRoot->setStateSet(previousStateset); - if (baseonly) - { - RemoveDrawableVisitor removeDrawableVisitor; - mObjectRoot->accept(removeDrawableVisitor); - removeDrawableVisitor.remove(); - } - if (isCreature) { RemoveTriBipVisitor removeTriBipVisitor; diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index b7dda6276..d050d5448 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -538,10 +538,15 @@ namespace Resource osg::ref_ptr SceneManager::createInstance(const std::string& name) { osg::ref_ptr scene = getTemplate(name); - osg::ref_ptr cloned = osg::clone(scene.get(), SceneUtil::CopyOp()); + return createInstance(scene); + } + + osg::ref_ptr SceneManager::createInstance(const osg::Node *base) + { + osg::ref_ptr cloned = osg::clone(base, SceneUtil::CopyOp()); // add a ref to the original template, to hint to the cache that it's still being used and should be kept in cache - cloned->getOrCreateUserDataContainer()->addUserObject(new TemplateRef(scene)); + cloned->getOrCreateUserDataContainer()->addUserObject(new TemplateRef(base)); // we can skip any scene graphs without update callbacks since we know that particle emitters will have an update callback set if (cloned->getNumChildrenRequiringUpdateTraversal() > 0) diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 62ffe0871..fdd1d6583 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -93,6 +93,10 @@ namespace Resource /// @note Thread safe. osg::ref_ptr cacheInstance(const std::string& name); + osg::ref_ptr createInstance(const std::string& name); + + osg::ref_ptr createInstance(const osg::Node* base); + /// Get an instance of the given scene template /// @see getTemplate /// @note Thread safe. @@ -141,8 +145,6 @@ namespace Resource private: - osg::ref_ptr createInstance(const std::string& name); - std::auto_ptr mShaderManager; bool mForceShaders; bool mClampLighting; diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 33fd9186f..b68d419a3 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -317,34 +317,43 @@ namespace Shader { const ShaderRequirements& reqs = mRequirements.back(); - osg::ref_ptr sourceGeometry = &geometry; - SceneUtil::RigGeometry* rig = dynamic_cast(&geometry); - if (rig) - sourceGeometry = rig->getSourceGeometry(); + bool useShader = reqs.mShaderRequired || mForceShaders; + bool generateTangents = reqs.mTexStageRequiringTangents != -1; - if (mAllowedToModifyStateSets) + if (mAllowedToModifyStateSets && (useShader || generateTangents)) { + osg::ref_ptr sourceGeometry = &geometry; + SceneUtil::RigGeometry* rig = dynamic_cast(&geometry); + if (rig) + sourceGeometry = rig->getSourceGeometry(); + + bool requiresSetGeometry = false; + // make sure that all UV sets are there for (std::map::const_iterator it = reqs.mTextures.begin(); it != reqs.mTextures.end(); ++it) { if (sourceGeometry->getTexCoordArray(it->first) == NULL) + { sourceGeometry->setTexCoordArray(it->first, sourceGeometry->getTexCoordArray(0)); + requiresSetGeometry = true; + } } + + if (generateTangents) + { + osg::ref_ptr generator (new osgUtil::TangentSpaceGenerator); + generator->generate(sourceGeometry, reqs.mTexStageRequiringTangents); + + sourceGeometry->setTexCoordArray(7, generator->getTangentArray(), osg::Array::BIND_PER_VERTEX); + requiresSetGeometry = true; + } + + if (rig && requiresSetGeometry) + rig->setSourceGeometry(sourceGeometry); } - if (reqs.mTexStageRequiringTangents != -1 && mAllowedToModifyStateSets) - { - osg::ref_ptr generator (new osgUtil::TangentSpaceGenerator); - generator->generate(sourceGeometry, reqs.mTexStageRequiringTangents); - - sourceGeometry->setTexCoordArray(7, generator->getTangentArray(), osg::Array::BIND_PER_VERTEX); - } - - if (rig) - rig->setSourceGeometry(sourceGeometry); - // TODO: find a better place for the stateset - if (reqs.mShaderRequired || mForceShaders) + if (useShader) createProgram(reqs, geometry); }