mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-30 15:45:31 +00:00
Move common stuff to scene util, fix errors with 1st person meshes
This commit is contained in:
parent
8444ee9981
commit
e2ac392a40
8 changed files with 290 additions and 165 deletions
|
@ -9,6 +9,7 @@
|
|||
#include <components/misc/resourcehelpers.hpp>
|
||||
#include <components/resource/resourcemanager.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
#include <components/sceneutil/actorutil.hpp>
|
||||
#include <components/sceneutil/attach.hpp>
|
||||
#include <components/sceneutil/skeleton.hpp>
|
||||
#include <components/sceneutil/visitor.hpp>
|
||||
|
@ -45,152 +46,140 @@ namespace CSVRender
|
|||
// Remove children
|
||||
mBaseNode->removeChildren(0, mBaseNode->getNumChildren());
|
||||
|
||||
// Npcs and creatures are handled differently
|
||||
if (mType == CSMWorld::UniversalId::Type_Npc)
|
||||
try
|
||||
{
|
||||
auto& npc = dynamic_cast<const CSMWorld::Record<ESM::NPC>& >(referenceables.getRecord(mId)).get();
|
||||
|
||||
auto isBeast = [&](std::string race) -> bool {
|
||||
int index = races.searchId(race);
|
||||
if (index != -1 && !races.getRecord(index).isDeleted())
|
||||
return races.getRecord(index).get().mData.mFlags & ESM::Race::Beast;
|
||||
else
|
||||
return false;
|
||||
};
|
||||
|
||||
// Load skeleton
|
||||
std::string skeletonResource;
|
||||
if (isBeast(npc.mRace)) {
|
||||
std::cout << "is beast\n";
|
||||
skeletonResource = "base_animkna.nif";
|
||||
}
|
||||
else if (npc.isMale()) {
|
||||
std::cout << "is male\n";
|
||||
skeletonResource = "base_anim.nif";
|
||||
}
|
||||
else {
|
||||
std::cout << "is female\n";
|
||||
skeletonResource = "base_anim_female.nif";
|
||||
}
|
||||
|
||||
std::string skeletonModel = MeshPrefix + skeletonResource;
|
||||
skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS());
|
||||
// Npcs and creatures are handled differently
|
||||
if (mType == CSMWorld::UniversalId::Type_Npc)
|
||||
{
|
||||
osg::ref_ptr<osg::Node> temp = sceneMgr->getInstance(skeletonModel);
|
||||
mSkeleton = dynamic_cast<SceneUtil::Skeleton*>(temp.get());
|
||||
if (!mSkeleton)
|
||||
auto& npc = dynamic_cast<const CSMWorld::Record<ESM::NPC>& >(referenceables.getRecord(mId)).get();
|
||||
auto& race = dynamic_cast<const CSMWorld::Record<ESM::Race>& >(races.getRecord(npc.mRace)).get();
|
||||
|
||||
bool is1stPerson = false;
|
||||
bool isFemale = !npc.isMale();
|
||||
bool isBeast = race.mData.mFlags & ESM::Race::Beast;
|
||||
bool isWerewolf = false;
|
||||
|
||||
// Load skeleton
|
||||
std::string skeletonModel = SceneUtil::getActorSkeleton(is1stPerson, isFemale, isBeast, isWerewolf);
|
||||
skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS());
|
||||
{
|
||||
mSkeleton = new SceneUtil::Skeleton();
|
||||
mSkeleton->addChild(temp);
|
||||
}
|
||||
mBaseNode->addChild(mSkeleton);
|
||||
}
|
||||
|
||||
// Map bone names to bones
|
||||
SceneUtil::NodeMapVisitor::NodeMap nodeMap;
|
||||
SceneUtil::NodeMapVisitor nmVisitor(nodeMap);
|
||||
mSkeleton->accept(nmVisitor);
|
||||
|
||||
if (!npc.isMale()) {
|
||||
for (auto it : nodeMap) {
|
||||
std::cout << it.first << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Female mesh has some drawables attached, get rid of them
|
||||
SceneUtil::HideDrawablesVisitor hdVisitor;
|
||||
mSkeleton->accept(hdVisitor);
|
||||
|
||||
// Convenience method to retrieve the mesh name of a body part
|
||||
auto getBodyPartMesh = [&](std::string bpName) -> std::string {
|
||||
int index = bodyParts.searchId(bpName);
|
||||
if (index != -1 && !bodyParts.getRecord(index).isDeleted())
|
||||
return MeshPrefix + bodyParts.getRecord(index).get().mModel;
|
||||
else
|
||||
return "";
|
||||
};
|
||||
|
||||
using BPRaceKey = std::tuple<int, int, std::string>;
|
||||
using RaceToBPMap = std::map<BPRaceKey, std::string>;
|
||||
// Convenience method to generate a map from body part + race to mesh name
|
||||
auto genRaceToBodyPartMap = [&](RaceToBPMap& bpMap) {
|
||||
int size = bodyParts.getSize();
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
auto& record = bodyParts.getRecord(i);
|
||||
if (!record.isDeleted())
|
||||
osg::ref_ptr<osg::Node> temp = sceneMgr->getInstance(skeletonModel);
|
||||
mSkeleton = dynamic_cast<SceneUtil::Skeleton*>(temp.get());
|
||||
if (!mSkeleton)
|
||||
{
|
||||
auto& bodyPart = record.get();
|
||||
bpMap.emplace(
|
||||
BPRaceKey(bodyPart.mData.mPart, bodyPart.mData.mFlags & FemaleFlag ? 1 : 0, bodyPart.mRace),
|
||||
MeshPrefix + bodyPart.mModel);
|
||||
mSkeleton = new SceneUtil::Skeleton();
|
||||
mSkeleton->addChild(temp);
|
||||
}
|
||||
mBaseNode->addChild(mSkeleton);
|
||||
}
|
||||
};
|
||||
|
||||
// Generate mapping
|
||||
RaceToBPMap r2bpMap;
|
||||
genRaceToBodyPartMap(r2bpMap);
|
||||
// Map bone names to bones
|
||||
SceneUtil::NodeMapVisitor::NodeMap nodeMap;
|
||||
SceneUtil::NodeMapVisitor nmVisitor(nodeMap);
|
||||
mSkeleton->accept(nmVisitor);
|
||||
|
||||
// Convenience method to add a body part
|
||||
auto addBodyPart = [&](ESM::PartReferenceType type, std::string mesh) {
|
||||
// Retrieve mesh name if necessary
|
||||
if (mesh.empty())
|
||||
{
|
||||
auto meshResult = r2bpMap.find(BPRaceKey(ESM::getMeshPart(type), npc.isMale() ? 0 : 1, npc.mRace));
|
||||
if (meshResult != r2bpMap.end())
|
||||
// Female mesh has some drawables attached, get rid of them
|
||||
SceneUtil::CleanObjectRootVisitor cleanVisitor;
|
||||
mSkeleton->accept(cleanVisitor);
|
||||
cleanVisitor.remove();
|
||||
|
||||
// Convenience method to retrieve the mesh name of a body part
|
||||
auto getBodyPartMesh = [&](std::string bpName) -> std::string {
|
||||
int index = bodyParts.searchId(bpName);
|
||||
if (index != -1 && !bodyParts.getRecord(index).isDeleted())
|
||||
return MeshPrefix + bodyParts.getRecord(index).get().mModel;
|
||||
else
|
||||
return "";
|
||||
};
|
||||
|
||||
using BPRaceKey = std::tuple<int, int, std::string>;
|
||||
using RaceToBPMap = std::map<BPRaceKey, std::string>;
|
||||
// Convenience method to generate a map from body part + race to mesh name
|
||||
auto genRaceToBodyPartMap = [&](RaceToBPMap& bpMap) {
|
||||
int size = bodyParts.getSize();
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
mesh = meshResult->second;
|
||||
}
|
||||
}
|
||||
auto& record = bodyParts.getRecord(i);
|
||||
if (!record.isDeleted())
|
||||
{
|
||||
// Method to check if 1st person part or not
|
||||
auto is1stPersonPart = [](std::string name) {
|
||||
return name.size() >= 4 && name.find(".1st", name.size() - 4) != std::string::npos;
|
||||
};
|
||||
|
||||
// Attach to skeleton
|
||||
std::string boneName = ESM::getBoneName(type);
|
||||
auto node = nodeMap.find(boneName);
|
||||
if (!mesh.empty() && node != nodeMap.end())
|
||||
{
|
||||
auto instance = sceneMgr->getInstance(mesh);
|
||||
if (!npc.isMale() && type == ESM::PRT_LHand) {
|
||||
SceneUtil::NodeMapVisitor::NodeMap handNodeMap;
|
||||
SceneUtil::NodeMapVisitor nmVisitor(handNodeMap);
|
||||
instance->accept(nmVisitor);
|
||||
auto& bodyPart = record.get();
|
||||
if (bodyPart.mData.mType != ESM::BodyPart::MT_Skin || is1stPersonPart(bodyPart.mId))
|
||||
continue;
|
||||
|
||||
std::cout << "Left hand\n";
|
||||
for (auto it : handNodeMap) {
|
||||
std::cout << it.first << std::endl;
|
||||
bpMap.emplace(
|
||||
BPRaceKey(bodyPart.mData.mPart, bodyPart.mData.mFlags & FemaleFlag ? 1 : 0, bodyPart.mRace),
|
||||
MeshPrefix + bodyPart.mModel);
|
||||
}
|
||||
}
|
||||
SceneUtil::attach(instance, mSkeleton, boneName, node->second);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Add body parts
|
||||
for (unsigned int i = 0; i < ESM::PRT_Count; ++i)
|
||||
{
|
||||
auto part = static_cast<ESM::PartReferenceType>(i);
|
||||
switch (part)
|
||||
// Generate mapping
|
||||
RaceToBPMap r2bpMap;
|
||||
genRaceToBodyPartMap(r2bpMap);
|
||||
|
||||
// Convenience method to add a body part
|
||||
auto addBodyPart = [&](ESM::PartReferenceType type, std::string mesh) {
|
||||
// Retrieve mesh name if necessary
|
||||
if (mesh.empty())
|
||||
{
|
||||
auto meshResult = r2bpMap.find(BPRaceKey(ESM::getMeshPart(type), isFemale ? 1 : 0, npc.mRace));
|
||||
if (meshResult != r2bpMap.end())
|
||||
{
|
||||
mesh = meshResult->second;
|
||||
}
|
||||
else if (isFemale){
|
||||
meshResult = r2bpMap.find(BPRaceKey(ESM::getMeshPart(type), 0, npc.mRace));
|
||||
if (meshResult != r2bpMap.end())
|
||||
mesh = meshResult->second;
|
||||
}
|
||||
}
|
||||
|
||||
// Attach to skeleton
|
||||
std::string boneName = ESM::getBoneName(type);
|
||||
auto node = nodeMap.find(boneName);
|
||||
if (!mesh.empty() && node != nodeMap.end())
|
||||
{
|
||||
auto instance = sceneMgr->getInstance(mesh);
|
||||
SceneUtil::attach(instance, mSkeleton, boneName, node->second);
|
||||
}
|
||||
};
|
||||
|
||||
// Add body parts
|
||||
for (unsigned int i = 0; i < ESM::PRT_Count; ++i)
|
||||
{
|
||||
case ESM::PRT_Head:
|
||||
addBodyPart(part, getBodyPartMesh(npc.mHead));
|
||||
break;
|
||||
case ESM::PRT_Hair:
|
||||
addBodyPart(part, getBodyPartMesh(npc.mHair));
|
||||
break;
|
||||
case ESM::PRT_Skirt:
|
||||
case ESM::PRT_Shield:
|
||||
case ESM::PRT_RPauldron:
|
||||
case ESM::PRT_LPauldron:
|
||||
case ESM::PRT_Weapon:
|
||||
// No body part mesh associated
|
||||
break;
|
||||
default:
|
||||
addBodyPart(part, "");
|
||||
auto part = static_cast<ESM::PartReferenceType>(i);
|
||||
switch (part)
|
||||
{
|
||||
case ESM::PRT_Head:
|
||||
addBodyPart(part, getBodyPartMesh(npc.mHead));
|
||||
break;
|
||||
case ESM::PRT_Hair:
|
||||
addBodyPart(part, getBodyPartMesh(npc.mHair));
|
||||
break;
|
||||
case ESM::PRT_Skirt:
|
||||
case ESM::PRT_Shield:
|
||||
case ESM::PRT_RPauldron:
|
||||
case ESM::PRT_LPauldron:
|
||||
case ESM::PRT_Weapon:
|
||||
// No body part mesh associated
|
||||
break;
|
||||
default:
|
||||
addBodyPart(part, "");
|
||||
}
|
||||
}
|
||||
// Post setup
|
||||
mSkeleton->markDirty();
|
||||
mSkeleton->setActive(SceneUtil::Skeleton::Active);
|
||||
}
|
||||
// Post setup
|
||||
mSkeleton->markDirty();
|
||||
mSkeleton->setActive(SceneUtil::Skeleton::Active);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cout << "Caught exception: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1339,7 +1339,7 @@ namespace MWRender
|
|||
{
|
||||
osg::ref_ptr<osg::Node> created = sceneMgr->getInstance(model);
|
||||
|
||||
CleanObjectRootVisitor removeDrawableVisitor;
|
||||
SceneUtil::CleanObjectRootVisitor removeDrawableVisitor;
|
||||
created->accept(removeDrawableVisitor);
|
||||
removeDrawableVisitor.remove();
|
||||
|
||||
|
@ -1408,7 +1408,7 @@ namespace MWRender
|
|||
|
||||
if (isCreature)
|
||||
{
|
||||
RemoveTriBipVisitor removeTriBipVisitor;
|
||||
SceneUtil::RemoveTriBipVisitor removeTriBipVisitor;
|
||||
mObjectRoot->accept(removeTriBipVisitor);
|
||||
removeTriBipVisitor.remove();
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
#include <components/sceneutil/actorutil.hpp>
|
||||
#include <components/sceneutil/attach.hpp>
|
||||
#include <components/sceneutil/visitor.hpp>
|
||||
#include <components/sceneutil/skeleton.hpp>
|
||||
|
@ -304,7 +305,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> par
|
|||
void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
|
||||
{
|
||||
assert(viewMode != VM_HeadOnly);
|
||||
if(mViewMode == viewMode)
|
||||
if(mViewMode == viewMode)
|
||||
return;
|
||||
|
||||
mViewMode = viewMode;
|
||||
|
@ -451,37 +452,15 @@ void NpcAnimation::updateNpcBase()
|
|||
}
|
||||
}
|
||||
|
||||
bool is1stPerson = mViewMode == VM_FirstPerson;
|
||||
bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
|
||||
|
||||
std::string smodel;
|
||||
if (mViewMode != VM_FirstPerson)
|
||||
{
|
||||
if (isWerewolf)
|
||||
smodel = "meshes\\wolf\\skin.nif";
|
||||
else if (isBeast)
|
||||
smodel = "meshes\\base_animkna.nif";
|
||||
else if (isFemale)
|
||||
smodel = "meshes\\base_anim_female.nif";
|
||||
else
|
||||
smodel = "meshes\\base_anim.nif";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isWerewolf)
|
||||
smodel = "meshes\\wolf\\skin.1st.nif";
|
||||
else if (isBeast)
|
||||
smodel = "meshes\\base_animkna.1st.nif";
|
||||
else if (isFemale)
|
||||
smodel = "meshes\\base_anim_female.1st.nif";
|
||||
else
|
||||
smodel = "meshes\\base_anim.1st.nif";
|
||||
}
|
||||
|
||||
std::string smodel = SceneUtil::getActorSkeleton(is1stPerson, isFemale, isBeast, isWerewolf);
|
||||
smodel = Misc::ResourceHelpers::correctActorModelPath(smodel, mResourceSystem->getVFS());
|
||||
|
||||
setObjectRoot(smodel, true, true, false);
|
||||
|
||||
if(mViewMode != VM_FirstPerson)
|
||||
if(!is1stPerson)
|
||||
{
|
||||
const std::string base = "meshes\\xbase_anim.nif";
|
||||
if (smodel != base)
|
||||
|
@ -675,7 +654,7 @@ PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const st
|
|||
}
|
||||
|
||||
osg::Vec3f NpcAnimation::runAnimation(float timepassed)
|
||||
{
|
||||
{
|
||||
osg::Vec3f ret = Animation::runAnimation(timepassed);
|
||||
|
||||
mHeadAnimationTime->update(timepassed);
|
||||
|
|
|
@ -51,6 +51,7 @@ add_component_dir (shader
|
|||
add_component_dir (sceneutil
|
||||
clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller
|
||||
lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer
|
||||
actorutil
|
||||
)
|
||||
|
||||
add_component_dir (nif
|
||||
|
|
30
components/sceneutil/actorutil.cpp
Normal file
30
components/sceneutil/actorutil.cpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#include "actorutil.hpp"
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
std::string getActorSkeleton(bool firstPerson, bool isFemale, bool isBeast, bool isWerewolf)
|
||||
{
|
||||
if (!firstPerson)
|
||||
{
|
||||
if (isWerewolf)
|
||||
return "meshes\\wolf\\skin.nif";
|
||||
else if (isBeast)
|
||||
return "meshes\\base_animkna.nif";
|
||||
else if (isFemale)
|
||||
return "meshes\\base_anim_female.nif";
|
||||
else
|
||||
return "meshes\\base_anim.nif";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isWerewolf)
|
||||
return "meshes\\wolf\\skin.1st.nif";
|
||||
else if (isBeast)
|
||||
return "meshes\\base_animkna.1st.nif";
|
||||
else if (isFemale)
|
||||
return "meshes\\base_anim_female.1st.nif";
|
||||
else
|
||||
return "meshes\\base_anim.1st.nif";
|
||||
}
|
||||
}
|
||||
}
|
11
components/sceneutil/actorutil.hpp
Normal file
11
components/sceneutil/actorutil.hpp
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef OPENMW_COMPONENTS_SCENEUTIL_ACTORUTIL_HPP
|
||||
#define OPENMW_COMPONENTS_SCENEUTIL_ACTORUTIL_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
std::string getActorSkeleton(bool firstPerson, bool female, bool beast, bool werewolf);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,5 +1,7 @@
|
|||
#include "visitor.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <osg/Drawable>
|
||||
#include <osg/MatrixTransform>
|
||||
|
||||
|
@ -67,8 +69,91 @@ namespace SceneUtil
|
|||
traverse(trans);
|
||||
}
|
||||
|
||||
void HideDrawablesVisitor::apply(osg::Drawable& drawable)
|
||||
void RemoveVisitor::remove()
|
||||
{
|
||||
drawable.setNodeMask(0);
|
||||
for (RemoveVec::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it)
|
||||
{
|
||||
if (!it->second->removeChild(it->first))
|
||||
std::cerr << "error removing " << it->first->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void CleanObjectRootVisitor::apply(osg::Drawable& drw)
|
||||
{
|
||||
applyDrawable(drw);
|
||||
}
|
||||
|
||||
void CleanObjectRootVisitor::apply(osg::Group& node)
|
||||
{
|
||||
applyNode(node);
|
||||
}
|
||||
|
||||
void CleanObjectRootVisitor::apply(osg::MatrixTransform& node)
|
||||
{
|
||||
applyNode(node);
|
||||
}
|
||||
|
||||
void CleanObjectRootVisitor::apply(osg::Node& node)
|
||||
{
|
||||
applyNode(node);
|
||||
}
|
||||
|
||||
void CleanObjectRootVisitor::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 CleanObjectRootVisitor::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.
|
||||
osg::Group* parentGroup = static_cast<osg::Group*>(*parent);
|
||||
|
||||
// Try to prune nodes that would be empty after the removal
|
||||
if (parent != getNodePath().begin())
|
||||
{
|
||||
// This could be extended to remove the parent's parent, and so on if they are empty as well.
|
||||
// But for NIF files, there won't be a benefit since only TriShapes can be set to STATIC dataVariance.
|
||||
osg::Group* parentParent = static_cast<osg::Group*>(*(parent - 1));
|
||||
if (parentGroup->getNumChildren() == 1 && parentGroup->getDataVariance() == osg::Object::STATIC)
|
||||
{
|
||||
mToRemove.push_back(std::make_pair(parentGroup, parentParent));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mToRemove.push_back(std::make_pair(&node, parentGroup));
|
||||
}
|
||||
|
||||
void RemoveTriBipVisitor::apply(osg::Drawable& drw)
|
||||
{
|
||||
applyImpl(drw);
|
||||
}
|
||||
|
||||
void RemoveTriBipVisitor::apply(osg::Group& node)
|
||||
{
|
||||
traverse(node);
|
||||
}
|
||||
|
||||
void RemoveTriBipVisitor::apply(osg::MatrixTransform& node)
|
||||
{
|
||||
traverse(node);
|
||||
}
|
||||
|
||||
void RemoveTriBipVisitor::applyImpl(osg::Node& node)
|
||||
{
|
||||
const std::string toFind = "tri bip";
|
||||
if (Misc::StringUtils::ciCompareLen(node.getName(), toFind, toFind.size()) == 0)
|
||||
{
|
||||
osg::Group* parent = static_cast<osg::Group*>(*(getNodePath().end()-2));
|
||||
// Not safe to remove in apply(), since the visitor is still iterating the child list
|
||||
mToRemove.push_back(std::make_pair(&node, parent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,7 +68,8 @@ namespace SceneUtil
|
|||
NodeMapVisitor(NodeMap& map)
|
||||
: osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
|
||||
, mMap(map)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
void apply(osg::MatrixTransform& trans);
|
||||
|
||||
|
@ -76,18 +77,47 @@ namespace SceneUtil
|
|||
NodeMap& mMap;
|
||||
};
|
||||
|
||||
/// Hides all attached drawables
|
||||
class HideDrawablesVisitor : public osg::NodeVisitor
|
||||
/// @brief Base class for visitors that remove nodes from a scene graph.
|
||||
/// Subclasses need to fill the mToRemove vector.
|
||||
/// To use, node->accept(removeVisitor); removeVisitor.remove();
|
||||
class RemoveVisitor : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
HideDrawablesVisitor()
|
||||
RemoveVisitor()
|
||||
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
|
||||
{
|
||||
}
|
||||
|
||||
void apply(osg::Drawable& drawable) override;
|
||||
void remove();
|
||||
|
||||
protected:
|
||||
// <node to remove, parent node to remove it from>
|
||||
typedef std::vector<std::pair<osg::Node*, osg::Group*> > RemoveVec;
|
||||
std::vector<std::pair<osg::Node*, osg::Group*> > mToRemove;
|
||||
};
|
||||
|
||||
// Removes all drawables from a graph.
|
||||
class CleanObjectRootVisitor : public RemoveVisitor
|
||||
{
|
||||
public:
|
||||
virtual void apply(osg::Drawable& drw);
|
||||
virtual void apply(osg::Group& node);
|
||||
virtual void apply(osg::MatrixTransform& node);
|
||||
virtual void apply(osg::Node& node);
|
||||
|
||||
void applyNode(osg::Node& node);
|
||||
void applyDrawable(osg::Node& node);
|
||||
};
|
||||
|
||||
class RemoveTriBipVisitor : public RemoveVisitor
|
||||
{
|
||||
public:
|
||||
virtual void apply(osg::Drawable& drw);
|
||||
virtual void apply(osg::Group& node);
|
||||
virtual void apply(osg::MatrixTransform& node);
|
||||
|
||||
void applyImpl(osg::Node& node);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue