mirror of
https://github.com/OpenMW/openmw.git
synced 2025-07-06 05:11:36 +00:00
Handle editor marker bit in BSXFlags
This commit is contained in:
parent
788a4d32aa
commit
19fb9f8e14
3 changed files with 78 additions and 50 deletions
|
@ -182,8 +182,8 @@ namespace NifBullet
|
||||||
if (hasCollisionNode && !hasCollisionShape)
|
if (hasCollisionNode && !hasCollisionShape)
|
||||||
mShape->mVisualCollisionType = Resource::VisualCollisionType::Camera;
|
mShape->mVisualCollisionType = Resource::VisualCollisionType::Camera;
|
||||||
bool generateCollisionShape = !hasCollisionShape;
|
bool generateCollisionShape = !hasCollisionShape;
|
||||||
handleNode(filename, nif.getVersion(), *node, nullptr, 0, generateCollisionShape, isAnimated,
|
handleNode(filename, *node, nullptr, 0, generateCollisionShape, isAnimated, generateCollisionShape, false,
|
||||||
generateCollisionShape, false, mShape->mVisualCollisionType);
|
mShape->mVisualCollisionType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mCompoundShape)
|
if (mCompoundShape)
|
||||||
|
@ -268,8 +268,8 @@ namespace NifBullet
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BulletNifLoader::handleNode(const std::string& fileName, unsigned int nifVersion, const Nif::Node& node,
|
void BulletNifLoader::handleNode(const std::string& fileName, const Nif::Node& node, const Nif::Parent* parent,
|
||||||
const Nif::Parent* parent, int flags, bool isCollisionNode, bool isAnimated, bool autogenerated, bool avoid,
|
int flags, bool isCollisionNode, bool isAnimated, bool autogenerated, bool avoid,
|
||||||
Resource::VisualCollisionType& visualCollisionType)
|
Resource::VisualCollisionType& visualCollisionType)
|
||||||
{
|
{
|
||||||
// TODO: allow on-the fly collision switching via toggling this flag
|
// TODO: allow on-the fly collision switching via toggling this flag
|
||||||
|
@ -301,7 +301,13 @@ namespace NifBullet
|
||||||
<< ". Treating it as a common NiTriShape.";
|
<< ". Treating it as a common NiTriShape.";
|
||||||
|
|
||||||
// Check for extra data
|
// Check for extra data
|
||||||
|
std::vector<Nif::ExtraPtr> extraCollection;
|
||||||
for (Nif::ExtraPtr e = node.extra; !e.empty(); e = e->next)
|
for (Nif::ExtraPtr e = node.extra; !e.empty(); e = e->next)
|
||||||
|
extraCollection.emplace_back(e);
|
||||||
|
for (const auto& extraNode : node.extralist)
|
||||||
|
if (!extraNode.empty())
|
||||||
|
extraCollection.emplace_back(extraNode);
|
||||||
|
for (const auto& e : extraCollection)
|
||||||
{
|
{
|
||||||
if (e->recType == Nif::RC_NiStringExtraData)
|
if (e->recType == Nif::RC_NiStringExtraData)
|
||||||
{
|
{
|
||||||
|
@ -326,11 +332,14 @@ namespace NifBullet
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (e->recType == Nif::RC_BSXFlags)
|
||||||
|
{
|
||||||
|
auto bsxFlags = static_cast<const Nif::NiIntegerExtraData*>(e.getPtr());
|
||||||
|
if (bsxFlags->data & 32) // Editor marker flag
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nifVersion > Nif::NIFFile::NIFVersion::VER_MW && Misc::StringUtils::ciEqual(node.name, "EditorMarker"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (isCollisionNode)
|
if (isCollisionNode)
|
||||||
{
|
{
|
||||||
// NOTE: a trishape with hasBounds=true, but no BBoxCollision flag should NOT go through handleNiTriShape!
|
// NOTE: a trishape with hasBounds=true, but no BBoxCollision flag should NOT go through handleNiTriShape!
|
||||||
|
@ -355,8 +364,8 @@ namespace NifBullet
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
assert(std::find(child->parents.begin(), child->parents.end(), ninode) != child->parents.end());
|
assert(std::find(child->parents.begin(), child->parents.end(), ninode) != child->parents.end());
|
||||||
handleNode(fileName, nifVersion, child.get(), ¤tParent, flags, isCollisionNode, isAnimated,
|
handleNode(fileName, child.get(), ¤tParent, flags, isCollisionNode, isAnimated, autogenerated,
|
||||||
autogenerated, avoid, visualCollisionType);
|
avoid, visualCollisionType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,8 +52,8 @@ namespace NifBullet
|
||||||
private:
|
private:
|
||||||
bool findBoundingBox(const Nif::Node& node, const std::string& filename);
|
bool findBoundingBox(const Nif::Node& node, const std::string& filename);
|
||||||
|
|
||||||
void handleNode(const std::string& fileName, unsigned int nifVersion, const Nif::Node& node,
|
void handleNode(const std::string& fileName, const Nif::Node& node, const Nif::Parent* parent, int flags,
|
||||||
const Nif::Parent* parent, int flags, bool isCollisionNode, bool isAnimated, bool autogenerated, bool avoid,
|
bool isCollisionNode, bool isAnimated, bool autogenerated, bool avoid,
|
||||||
Resource::VisualCollisionType& visualCollisionType);
|
Resource::VisualCollisionType& visualCollisionType);
|
||||||
|
|
||||||
bool hasRootCollisionNode(const Nif::Node& rootNode) const;
|
bool hasRootCollisionNode(const Nif::Node& rootNode) const;
|
||||||
|
|
|
@ -319,6 +319,19 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct HandleNodeArgs
|
||||||
|
{
|
||||||
|
unsigned int mNifVersion;
|
||||||
|
Resource::ImageManager* mImageManager;
|
||||||
|
SceneUtil::TextKeyMap* mTextKeys;
|
||||||
|
std::vector<unsigned int> mBoundTextures = {};
|
||||||
|
int mAnimFlags = 0;
|
||||||
|
bool mSkipMeshes = false;
|
||||||
|
bool mHasMarkers = false;
|
||||||
|
bool mHasAnimatedParents = false;
|
||||||
|
osg::Node* mRootNode = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
osg::ref_ptr<osg::Node> load(Nif::FileView nif, Resource::ImageManager* imageManager)
|
osg::ref_ptr<osg::Node> load(Nif::FileView nif, Resource::ImageManager* imageManager)
|
||||||
{
|
{
|
||||||
const size_t numRoots = nif.numRoots();
|
const size_t numRoots = nif.numRoots();
|
||||||
|
@ -341,8 +354,10 @@ namespace NifOsg
|
||||||
created->setDataVariance(osg::Object::STATIC);
|
created->setDataVariance(osg::Object::STATIC);
|
||||||
for (const Nif::Node* root : roots)
|
for (const Nif::Node* root : roots)
|
||||||
{
|
{
|
||||||
auto node = handleNode(nif.getVersion(), root, nullptr, nullptr, imageManager,
|
auto node = handleNode(root, nullptr, nullptr,
|
||||||
std::vector<unsigned int>(), 0, false, false, false, &textkeys->mTextKeys);
|
{ .mNifVersion = nif.getVersion(),
|
||||||
|
.mImageManager = imageManager,
|
||||||
|
.mTextKeys = &textkeys->mTextKeys });
|
||||||
created->addChild(node);
|
created->addChild(node);
|
||||||
}
|
}
|
||||||
if (mHasNightDayLabel)
|
if (mHasNightDayLabel)
|
||||||
|
@ -598,19 +613,11 @@ namespace NifOsg
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::Node> handleNode(unsigned int nifVersion, const Nif::Node* nifNode, const Nif::Parent* parent,
|
osg::ref_ptr<osg::Node> handleNode(
|
||||||
osg::Group* parentNode, Resource::ImageManager* imageManager, std::vector<unsigned int> boundTextures,
|
const Nif::Node* nifNode, const Nif::Parent* parent, osg::Group* parentNode, HandleNodeArgs args)
|
||||||
int animflags, bool skipMeshes, bool hasMarkers, bool hasAnimatedParents, SceneUtil::TextKeyMap* textKeys,
|
|
||||||
osg::Node* rootNode = nullptr)
|
|
||||||
{
|
{
|
||||||
if (rootNode)
|
if (args.mRootNode && Misc::StringUtils::ciEqual(nifNode->name, "Bounding Box"))
|
||||||
{
|
return nullptr;
|
||||||
if (Misc::StringUtils::ciEqual(nifNode->name, "Bounding Box"))
|
|
||||||
return nullptr;
|
|
||||||
if (nifVersion > Nif::NIFFile::NIFVersion::VER_MW && !Loader::getShowMarkers()
|
|
||||||
&& Misc::StringUtils::ciEqual(nifNode->name, "EditorMarker"))
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Group> node = createNode(nifNode);
|
osg::ref_ptr<osg::Group> node = createNode(nifNode);
|
||||||
|
|
||||||
|
@ -624,8 +631,8 @@ namespace NifOsg
|
||||||
if (parentNode)
|
if (parentNode)
|
||||||
parentNode->addChild(node);
|
parentNode->addChild(node);
|
||||||
|
|
||||||
if (!rootNode)
|
if (!args.mRootNode)
|
||||||
rootNode = node;
|
args.mRootNode = node;
|
||||||
|
|
||||||
// The original NIF record index is used for a variety of features:
|
// The original NIF record index is used for a variety of features:
|
||||||
// - finding the correct emitter node for a particle system
|
// - finding the correct emitter node for a particle system
|
||||||
|
@ -644,10 +651,10 @@ namespace NifOsg
|
||||||
|
|
||||||
for (const auto& e : extraCollection)
|
for (const auto& e : extraCollection)
|
||||||
{
|
{
|
||||||
if (e->recType == Nif::RC_NiTextKeyExtraData && textKeys)
|
if (e->recType == Nif::RC_NiTextKeyExtraData && args.mTextKeys)
|
||||||
{
|
{
|
||||||
const Nif::NiTextKeyExtraData* tk = static_cast<const Nif::NiTextKeyExtraData*>(e.getPtr());
|
const Nif::NiTextKeyExtraData* tk = static_cast<const Nif::NiTextKeyExtraData*>(e.getPtr());
|
||||||
extractTextKeys(tk, *textKeys);
|
extractTextKeys(tk, *args.mTextKeys);
|
||||||
}
|
}
|
||||||
else if (e->recType == Nif::RC_NiStringExtraData)
|
else if (e->recType == Nif::RC_NiStringExtraData)
|
||||||
{
|
{
|
||||||
|
@ -660,7 +667,7 @@ namespace NifOsg
|
||||||
if (sd->string == "MRK" && !Loader::getShowMarkers())
|
if (sd->string == "MRK" && !Loader::getShowMarkers())
|
||||||
{
|
{
|
||||||
// Marker objects. These meshes are only visible in the editor.
|
// Marker objects. These meshes are only visible in the editor.
|
||||||
hasMarkers = true;
|
args.mHasMarkers = true;
|
||||||
}
|
}
|
||||||
else if (sd->string == "BONE")
|
else if (sd->string == "BONE")
|
||||||
{
|
{
|
||||||
|
@ -672,10 +679,16 @@ namespace NifOsg
|
||||||
Misc::OsgUserValues::sExtraData, sd->string.substr(extraDataIdentifer.length()));
|
Misc::OsgUserValues::sExtraData, sd->string.substr(extraDataIdentifer.length()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (e->recType == Nif::RC_BSXFlags)
|
||||||
|
{
|
||||||
|
auto bsxFlags = static_cast<const Nif::NiIntegerExtraData*>(e.getPtr());
|
||||||
|
if (bsxFlags->data & 32) // Editor marker flag
|
||||||
|
args.mHasMarkers = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nifNode->recType == Nif::RC_NiBSAnimationNode || nifNode->recType == Nif::RC_NiBSParticleNode)
|
if (nifNode->recType == Nif::RC_NiBSAnimationNode || nifNode->recType == Nif::RC_NiBSParticleNode)
|
||||||
animflags = nifNode->flags;
|
args.mAnimFlags = nifNode->flags;
|
||||||
|
|
||||||
if (nifNode->recType == Nif::RC_NiSortAdjustNode)
|
if (nifNode->recType == Nif::RC_NiSortAdjustNode)
|
||||||
{
|
{
|
||||||
|
@ -699,7 +712,7 @@ namespace NifOsg
|
||||||
// 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
|
||||||
if (nifNode->recType == Nif::RC_RootCollisionNode)
|
if (nifNode->recType == Nif::RC_RootCollisionNode)
|
||||||
{
|
{
|
||||||
skipMeshes = true;
|
args.mSkipMeshes = true;
|
||||||
node->setNodeMask(Loader::getHiddenNodeMask());
|
node->setNodeMask(Loader::getHiddenNodeMask());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -716,8 +729,8 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasVisController)
|
if (!hasVisController)
|
||||||
skipMeshes = true; // skip child meshes, but still create the child node hierarchy for animating
|
args.mSkipMeshes = true; // skip child meshes, but still create the child node hierarchy for
|
||||||
// collision shapes
|
// animating collision shapes
|
||||||
|
|
||||||
node->setNodeMask(Loader::getHiddenNodeMask());
|
node->setNodeMask(Loader::getHiddenNodeMask());
|
||||||
}
|
}
|
||||||
|
@ -727,37 +740,44 @@ namespace NifOsg
|
||||||
|
|
||||||
osg::ref_ptr<SceneUtil::CompositeStateSetUpdater> composite = new SceneUtil::CompositeStateSetUpdater;
|
osg::ref_ptr<SceneUtil::CompositeStateSetUpdater> composite = new SceneUtil::CompositeStateSetUpdater;
|
||||||
|
|
||||||
applyNodeProperties(nifNode, node, composite, imageManager, boundTextures, animflags);
|
applyNodeProperties(nifNode, node, composite, args.mImageManager, args.mBoundTextures, args.mAnimFlags);
|
||||||
|
|
||||||
const bool isGeometry = isTypeGeometry(nifNode->recType);
|
const bool isGeometry = isTypeGeometry(nifNode->recType);
|
||||||
|
|
||||||
if (isGeometry && !skipMeshes)
|
if (isGeometry && !args.mSkipMeshes)
|
||||||
{
|
{
|
||||||
const bool isMarker = hasMarkers && Misc::StringUtils::ciStartsWith(nifNode->name, "tri editormarker");
|
bool skip;
|
||||||
if (!isMarker && !Misc::StringUtils::ciStartsWith(nifNode->name, "shadow")
|
if (args.mNifVersion <= Nif::NIFFile::NIFVersion::VER_MW)
|
||||||
&& !Misc::StringUtils::ciStartsWith(nifNode->name, "tri shadow"))
|
{
|
||||||
|
skip = (args.mHasMarkers && Misc::StringUtils::ciStartsWith(nifNode->name, "tri editormarker"))
|
||||||
|
|| Misc::StringUtils::ciStartsWith(nifNode->name, "shadow")
|
||||||
|
|| Misc::StringUtils::ciStartsWith(nifNode->name, "tri shadow");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
skip = args.mHasMarkers && Misc::StringUtils::ciStartsWith(nifNode->name, "EditorMarker");
|
||||||
|
if (!skip)
|
||||||
{
|
{
|
||||||
Nif::NiSkinInstancePtr skin = static_cast<const Nif::NiGeometry*>(nifNode)->skin;
|
Nif::NiSkinInstancePtr skin = static_cast<const Nif::NiGeometry*>(nifNode)->skin;
|
||||||
|
|
||||||
if (skin.empty())
|
if (skin.empty())
|
||||||
handleGeometry(nifNode, parent, node, composite, boundTextures, animflags);
|
handleGeometry(nifNode, parent, node, composite, args.mBoundTextures, args.mAnimFlags);
|
||||||
else
|
else
|
||||||
handleSkinnedGeometry(nifNode, parent, node, composite, boundTextures, animflags);
|
handleSkinnedGeometry(nifNode, parent, node, composite, args.mBoundTextures, args.mAnimFlags);
|
||||||
|
|
||||||
if (!nifNode->controller.empty())
|
if (!nifNode->controller.empty())
|
||||||
handleMeshControllers(nifNode, node, composite, boundTextures, animflags);
|
handleMeshControllers(nifNode, node, composite, args.mBoundTextures, args.mAnimFlags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nifNode->recType == Nif::RC_NiParticles)
|
if (nifNode->recType == Nif::RC_NiParticles)
|
||||||
handleParticleSystem(nifNode, parent, node, composite, animflags);
|
handleParticleSystem(nifNode, parent, node, composite, args.mAnimFlags);
|
||||||
|
|
||||||
if (composite->getNumControllers() > 0)
|
if (composite->getNumControllers() > 0)
|
||||||
{
|
{
|
||||||
osg::Callback* cb = composite;
|
osg::Callback* cb = composite;
|
||||||
if (composite->getNumControllers() == 1)
|
if (composite->getNumControllers() == 1)
|
||||||
cb = composite->getController(0);
|
cb = composite->getController(0);
|
||||||
if (animflags & Nif::NiNode::AnimFlag_AutoPlay)
|
if (args.mAnimFlags & Nif::NiNode::AnimFlag_AutoPlay)
|
||||||
node->addCullCallback(cb);
|
node->addCullCallback(cb);
|
||||||
else
|
else
|
||||||
node->addUpdateCallback(
|
node->addUpdateCallback(
|
||||||
|
@ -765,10 +785,10 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAnimated = false;
|
bool isAnimated = false;
|
||||||
handleNodeControllers(nifNode, node, animflags, isAnimated);
|
handleNodeControllers(nifNode, node, args.mAnimFlags, isAnimated);
|
||||||
hasAnimatedParents |= isAnimated;
|
args.mHasAnimatedParents |= isAnimated;
|
||||||
// Make sure empty nodes and animated shapes are not optimized away so the physics system can find them.
|
// Make sure empty nodes and animated shapes are not optimized away so the physics system can find them.
|
||||||
if (isAnimated || (hasAnimatedParents && ((skipMeshes || hasMarkers) || isGeometry)))
|
if (isAnimated || (args.mHasAnimatedParents && ((args.mSkipMeshes || args.mHasMarkers) || isGeometry)))
|
||||||
node->setDataVariance(osg::Object::DYNAMIC);
|
node->setDataVariance(osg::Object::DYNAMIC);
|
||||||
|
|
||||||
// LOD and Switch nodes must be wrapped by a transform (the current node) to support transformations
|
// LOD and Switch nodes must be wrapped by a transform (the current node) to support transformations
|
||||||
|
@ -809,8 +829,7 @@ namespace NifOsg
|
||||||
const Nif::Parent currentParent{ *ninode, parent };
|
const Nif::Parent currentParent{ *ninode, parent };
|
||||||
for (const auto& child : children)
|
for (const auto& child : children)
|
||||||
if (!child.empty())
|
if (!child.empty())
|
||||||
handleNode(nifVersion, child.getPtr(), ¤tParent, currentNode, imageManager, boundTextures,
|
handleNode(child.getPtr(), ¤tParent, currentNode, args);
|
||||||
animflags, skipMeshes, hasMarkers, hasAnimatedParents, textKeys, rootNode);
|
|
||||||
|
|
||||||
// Propagate effects to the the direct subgraph instead of the node itself
|
// Propagate effects to the the direct subgraph instead of the node itself
|
||||||
// This simulates their "affected node list" which Morrowind appears to replace with the subgraph (?)
|
// This simulates their "affected node list" which Morrowind appears to replace with the subgraph (?)
|
||||||
|
@ -819,7 +838,7 @@ namespace NifOsg
|
||||||
if (!effect.empty())
|
if (!effect.empty())
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::StateSet> effectStateSet = new osg::StateSet;
|
osg::ref_ptr<osg::StateSet> effectStateSet = new osg::StateSet;
|
||||||
if (handleEffect(effect.getPtr(), effectStateSet, imageManager))
|
if (handleEffect(effect.getPtr(), effectStateSet, args.mImageManager))
|
||||||
for (unsigned int i = 0; i < currentNode->getNumChildren(); ++i)
|
for (unsigned int i = 0; i < currentNode->getNumChildren(); ++i)
|
||||||
currentNode->getChild(i)->getOrCreateStateSet()->merge(*effectStateSet);
|
currentNode->getChild(i)->getOrCreateStateSet()->merge(*effectStateSet);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue