Handle editor marker bit in BSXFlags

macos_ci
Petr Mikheev 2 years ago
parent 788a4d32aa
commit 19fb9f8e14

@ -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(), &currentParent, flags, isCollisionNode, isAnimated, handleNode(fileName, child.get(), &currentParent, 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(), &currentParent, currentNode, imageManager, boundTextures, handleNode(child.getPtr(), &currentParent, 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…
Cancel
Save