1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-20 05:53:50 +00:00

Move common stuff to scene util, fix errors with 1st person meshes

This commit is contained in:
Kyle Cooley 2018-07-17 21:28:05 -05:00 committed by Andrei Kortunov
parent 8444ee9981
commit e2ac392a40
8 changed files with 290 additions and 165 deletions

View file

@ -9,6 +9,7 @@
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcemanager.hpp> #include <components/resource/resourcemanager.hpp>
#include <components/resource/scenemanager.hpp> #include <components/resource/scenemanager.hpp>
#include <components/sceneutil/actorutil.hpp>
#include <components/sceneutil/attach.hpp> #include <components/sceneutil/attach.hpp>
#include <components/sceneutil/skeleton.hpp> #include <components/sceneutil/skeleton.hpp>
#include <components/sceneutil/visitor.hpp> #include <components/sceneutil/visitor.hpp>
@ -45,35 +46,21 @@ namespace CSVRender
// Remove children // Remove children
mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); mBaseNode->removeChildren(0, mBaseNode->getNumChildren());
try
{
// Npcs and creatures are handled differently // Npcs and creatures are handled differently
if (mType == CSMWorld::UniversalId::Type_Npc) if (mType == CSMWorld::UniversalId::Type_Npc)
{ {
auto& npc = dynamic_cast<const CSMWorld::Record<ESM::NPC>& >(referenceables.getRecord(mId)).get(); 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();
auto isBeast = [&](std::string race) -> bool { bool is1stPerson = false;
int index = races.searchId(race); bool isFemale = !npc.isMale();
if (index != -1 && !races.getRecord(index).isDeleted()) bool isBeast = race.mData.mFlags & ESM::Race::Beast;
return races.getRecord(index).get().mData.mFlags & ESM::Race::Beast; bool isWerewolf = false;
else
return false;
};
// Load skeleton // Load skeleton
std::string skeletonResource; std::string skeletonModel = SceneUtil::getActorSkeleton(is1stPerson, isFemale, isBeast, isWerewolf);
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()); skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS());
{ {
osg::ref_ptr<osg::Node> temp = sceneMgr->getInstance(skeletonModel); osg::ref_ptr<osg::Node> temp = sceneMgr->getInstance(skeletonModel);
@ -91,16 +78,10 @@ namespace CSVRender
SceneUtil::NodeMapVisitor nmVisitor(nodeMap); SceneUtil::NodeMapVisitor nmVisitor(nodeMap);
mSkeleton->accept(nmVisitor); 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 // Female mesh has some drawables attached, get rid of them
SceneUtil::HideDrawablesVisitor hdVisitor; SceneUtil::CleanObjectRootVisitor cleanVisitor;
mSkeleton->accept(hdVisitor); mSkeleton->accept(cleanVisitor);
cleanVisitor.remove();
// Convenience method to retrieve the mesh name of a body part // Convenience method to retrieve the mesh name of a body part
auto getBodyPartMesh = [&](std::string bpName) -> std::string { auto getBodyPartMesh = [&](std::string bpName) -> std::string {
@ -121,7 +102,15 @@ namespace CSVRender
auto& record = bodyParts.getRecord(i); auto& record = bodyParts.getRecord(i);
if (!record.isDeleted()) 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;
};
auto& bodyPart = record.get(); auto& bodyPart = record.get();
if (bodyPart.mData.mType != ESM::BodyPart::MT_Skin || is1stPersonPart(bodyPart.mId))
continue;
bpMap.emplace( bpMap.emplace(
BPRaceKey(bodyPart.mData.mPart, bodyPart.mData.mFlags & FemaleFlag ? 1 : 0, bodyPart.mRace), BPRaceKey(bodyPart.mData.mPart, bodyPart.mData.mFlags & FemaleFlag ? 1 : 0, bodyPart.mRace),
MeshPrefix + bodyPart.mModel); MeshPrefix + bodyPart.mModel);
@ -138,11 +127,16 @@ namespace CSVRender
// Retrieve mesh name if necessary // Retrieve mesh name if necessary
if (mesh.empty()) if (mesh.empty())
{ {
auto meshResult = r2bpMap.find(BPRaceKey(ESM::getMeshPart(type), npc.isMale() ? 0 : 1, npc.mRace)); auto meshResult = r2bpMap.find(BPRaceKey(ESM::getMeshPart(type), isFemale ? 1 : 0, npc.mRace));
if (meshResult != r2bpMap.end()) if (meshResult != r2bpMap.end())
{ {
mesh = meshResult->second; 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 // Attach to skeleton
@ -151,16 +145,6 @@ namespace CSVRender
if (!mesh.empty() && node != nodeMap.end()) if (!mesh.empty() && node != nodeMap.end())
{ {
auto instance = sceneMgr->getInstance(mesh); auto instance = sceneMgr->getInstance(mesh);
if (!npc.isMale() && type == ESM::PRT_LHand) {
SceneUtil::NodeMapVisitor::NodeMap handNodeMap;
SceneUtil::NodeMapVisitor nmVisitor(handNodeMap);
instance->accept(nmVisitor);
std::cout << "Left hand\n";
for (auto it : handNodeMap) {
std::cout << it.first << std::endl;
}
}
SceneUtil::attach(instance, mSkeleton, boneName, node->second); SceneUtil::attach(instance, mSkeleton, boneName, node->second);
} }
}; };
@ -193,4 +177,9 @@ namespace CSVRender
mSkeleton->setActive(SceneUtil::Skeleton::Active); mSkeleton->setActive(SceneUtil::Skeleton::Active);
} }
} }
catch (std::exception& e)
{
std::cout << "Caught exception: " << e.what() << std::endl;
}
}
} }

View file

@ -1339,7 +1339,7 @@ namespace MWRender
{ {
osg::ref_ptr<osg::Node> created = sceneMgr->getInstance(model); osg::ref_ptr<osg::Node> created = sceneMgr->getInstance(model);
CleanObjectRootVisitor removeDrawableVisitor; SceneUtil::CleanObjectRootVisitor removeDrawableVisitor;
created->accept(removeDrawableVisitor); created->accept(removeDrawableVisitor);
removeDrawableVisitor.remove(); removeDrawableVisitor.remove();
@ -1408,7 +1408,7 @@ namespace MWRender
if (isCreature) if (isCreature)
{ {
RemoveTriBipVisitor removeTriBipVisitor; SceneUtil::RemoveTriBipVisitor removeTriBipVisitor;
mObjectRoot->accept(removeTriBipVisitor); mObjectRoot->accept(removeTriBipVisitor);
removeTriBipVisitor.remove(); removeTriBipVisitor.remove();
} }

View file

@ -15,6 +15,7 @@
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp> #include <components/resource/scenemanager.hpp>
#include <components/sceneutil/actorutil.hpp>
#include <components/sceneutil/attach.hpp> #include <components/sceneutil/attach.hpp>
#include <components/sceneutil/visitor.hpp> #include <components/sceneutil/visitor.hpp>
#include <components/sceneutil/skeleton.hpp> #include <components/sceneutil/skeleton.hpp>
@ -451,37 +452,15 @@ void NpcAnimation::updateNpcBase()
} }
} }
bool is1stPerson = mViewMode == VM_FirstPerson;
bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
std::string smodel; std::string smodel = SceneUtil::getActorSkeleton(is1stPerson, isFemale, isBeast, isWerewolf);
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";
}
smodel = Misc::ResourceHelpers::correctActorModelPath(smodel, mResourceSystem->getVFS()); smodel = Misc::ResourceHelpers::correctActorModelPath(smodel, mResourceSystem->getVFS());
setObjectRoot(smodel, true, true, false); setObjectRoot(smodel, true, true, false);
if(mViewMode != VM_FirstPerson) if(!is1stPerson)
{ {
const std::string base = "meshes\\xbase_anim.nif"; const std::string base = "meshes\\xbase_anim.nif";
if (smodel != base) if (smodel != base)

View file

@ -51,6 +51,7 @@ add_component_dir (shader
add_component_dir (sceneutil add_component_dir (sceneutil
clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller
lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer
actorutil
) )
add_component_dir (nif add_component_dir (nif

View 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";
}
}
}

View 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

View file

@ -1,5 +1,7 @@
#include "visitor.hpp" #include "visitor.hpp"
#include <iostream>
#include <osg/Drawable> #include <osg/Drawable>
#include <osg/MatrixTransform> #include <osg/MatrixTransform>
@ -67,8 +69,91 @@ namespace SceneUtil
traverse(trans); 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));
}
} }
} }

View file

@ -68,7 +68,8 @@ namespace SceneUtil
NodeMapVisitor(NodeMap& map) NodeMapVisitor(NodeMap& map)
: osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
, mMap(map) , mMap(map)
{} {
}
void apply(osg::MatrixTransform& trans); void apply(osg::MatrixTransform& trans);
@ -76,18 +77,47 @@ namespace SceneUtil
NodeMap& mMap; NodeMap& mMap;
}; };
/// Hides all attached drawables /// @brief Base class for visitors that remove nodes from a scene graph.
class HideDrawablesVisitor : public osg::NodeVisitor /// Subclasses need to fill the mToRemove vector.
/// To use, node->accept(removeVisitor); removeVisitor.remove();
class RemoveVisitor : public osg::NodeVisitor
{ {
public: public:
HideDrawablesVisitor() RemoveVisitor()
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) : 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 #endif