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)
mShape->mVisualCollisionType = Resource::VisualCollisionType::Camera;
bool generateCollisionShape = !hasCollisionShape;
handleNode(filename, nif.getVersion(), *node, nullptr, 0, generateCollisionShape, isAnimated,
generateCollisionShape, false, mShape->mVisualCollisionType);
handleNode(filename, *node, nullptr, 0, generateCollisionShape, isAnimated, generateCollisionShape, false,
mShape->mVisualCollisionType);
}
if (mCompoundShape)
@ -268,8 +268,8 @@ namespace NifBullet
return true;
}
void BulletNifLoader::handleNode(const std::string& fileName, unsigned int nifVersion, const Nif::Node& node,
const Nif::Parent* parent, int flags, bool isCollisionNode, bool isAnimated, bool autogenerated, bool avoid,
void BulletNifLoader::handleNode(const std::string& fileName, const Nif::Node& node, const Nif::Parent* parent,
int flags, bool isCollisionNode, bool isAnimated, bool autogenerated, bool avoid,
Resource::VisualCollisionType& visualCollisionType)
{
// TODO: allow on-the fly collision switching via toggling this flag
@ -301,7 +301,13 @@ namespace NifBullet
<< ". Treating it as a common NiTriShape.";
// Check for extra data
std::vector<Nif::ExtraPtr> extraCollection;
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)
{
@ -326,10 +332,13 @@ namespace NifBullet
return;
}
}
}
if (nifVersion > Nif::NIFFile::NIFVersion::VER_MW && Misc::StringUtils::ciEqual(node.name, "EditorMarker"))
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 (isCollisionNode)
{
@ -355,8 +364,8 @@ namespace NifBullet
continue;
assert(std::find(child->parents.begin(), child->parents.end(), ninode) != child->parents.end());
handleNode(fileName, nifVersion, child.get(), &currentParent, flags, isCollisionNode, isAnimated,
autogenerated, avoid, visualCollisionType);
handleNode(fileName, child.get(), &currentParent, flags, isCollisionNode, isAnimated, autogenerated,
avoid, visualCollisionType);
}
}
}

@ -52,8 +52,8 @@ namespace NifBullet
private:
bool findBoundingBox(const Nif::Node& node, const std::string& filename);
void handleNode(const std::string& fileName, unsigned int nifVersion, const Nif::Node& node,
const Nif::Parent* parent, int flags, bool isCollisionNode, bool isAnimated, bool autogenerated, bool avoid,
void handleNode(const std::string& fileName, const Nif::Node& node, const Nif::Parent* parent, int flags,
bool isCollisionNode, bool isAnimated, bool autogenerated, bool avoid,
Resource::VisualCollisionType& visualCollisionType);
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)
{
const size_t numRoots = nif.numRoots();
@ -341,8 +354,10 @@ namespace NifOsg
created->setDataVariance(osg::Object::STATIC);
for (const Nif::Node* root : roots)
{
auto node = handleNode(nif.getVersion(), root, nullptr, nullptr, imageManager,
std::vector<unsigned int>(), 0, false, false, false, &textkeys->mTextKeys);
auto node = handleNode(root, nullptr, nullptr,
{ .mNifVersion = nif.getVersion(),
.mImageManager = imageManager,
.mTextKeys = &textkeys->mTextKeys });
created->addChild(node);
}
if (mHasNightDayLabel)
@ -598,19 +613,11 @@ namespace NifOsg
return node;
}
osg::ref_ptr<osg::Node> handleNode(unsigned int nifVersion, const Nif::Node* nifNode, const Nif::Parent* parent,
osg::Group* parentNode, Resource::ImageManager* imageManager, std::vector<unsigned int> boundTextures,
int animflags, bool skipMeshes, bool hasMarkers, bool hasAnimatedParents, SceneUtil::TextKeyMap* textKeys,
osg::Node* rootNode = nullptr)
{
if (rootNode)
osg::ref_ptr<osg::Node> handleNode(
const Nif::Node* nifNode, const Nif::Parent* parent, osg::Group* parentNode, HandleNodeArgs args)
{
if (Misc::StringUtils::ciEqual(nifNode->name, "Bounding Box"))
if (args.mRootNode && 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);
@ -624,8 +631,8 @@ namespace NifOsg
if (parentNode)
parentNode->addChild(node);
if (!rootNode)
rootNode = node;
if (!args.mRootNode)
args.mRootNode = node;
// The original NIF record index is used for a variety of features:
// - finding the correct emitter node for a particle system
@ -644,10 +651,10 @@ namespace NifOsg
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());
extractTextKeys(tk, *textKeys);
extractTextKeys(tk, *args.mTextKeys);
}
else if (e->recType == Nif::RC_NiStringExtraData)
{
@ -660,7 +667,7 @@ namespace NifOsg
if (sd->string == "MRK" && !Loader::getShowMarkers())
{
// Marker objects. These meshes are only visible in the editor.
hasMarkers = true;
args.mHasMarkers = true;
}
else if (sd->string == "BONE")
{
@ -672,10 +679,16 @@ namespace NifOsg
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)
animflags = nifNode->flags;
args.mAnimFlags = nifNode->flags;
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
if (nifNode->recType == Nif::RC_RootCollisionNode)
{
skipMeshes = true;
args.mSkipMeshes = true;
node->setNodeMask(Loader::getHiddenNodeMask());
}
@ -716,8 +729,8 @@ namespace NifOsg
}
if (!hasVisController)
skipMeshes = true; // skip child meshes, but still create the child node hierarchy for animating
// collision shapes
args.mSkipMeshes = true; // skip child meshes, but still create the child node hierarchy for
// animating collision shapes
node->setNodeMask(Loader::getHiddenNodeMask());
}
@ -727,37 +740,44 @@ namespace NifOsg
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);
if (isGeometry && !skipMeshes)
if (isGeometry && !args.mSkipMeshes)
{
bool skip;
if (args.mNifVersion <= Nif::NIFFile::NIFVersion::VER_MW)
{
const bool isMarker = hasMarkers && Misc::StringUtils::ciStartsWith(nifNode->name, "tri editormarker");
if (!isMarker && !Misc::StringUtils::ciStartsWith(nifNode->name, "shadow")
&& !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;
if (skin.empty())
handleGeometry(nifNode, parent, node, composite, boundTextures, animflags);
handleGeometry(nifNode, parent, node, composite, args.mBoundTextures, args.mAnimFlags);
else
handleSkinnedGeometry(nifNode, parent, node, composite, boundTextures, animflags);
handleSkinnedGeometry(nifNode, parent, node, composite, args.mBoundTextures, args.mAnimFlags);
if (!nifNode->controller.empty())
handleMeshControllers(nifNode, node, composite, boundTextures, animflags);
handleMeshControllers(nifNode, node, composite, args.mBoundTextures, args.mAnimFlags);
}
}
if (nifNode->recType == Nif::RC_NiParticles)
handleParticleSystem(nifNode, parent, node, composite, animflags);
handleParticleSystem(nifNode, parent, node, composite, args.mAnimFlags);
if (composite->getNumControllers() > 0)
{
osg::Callback* cb = composite;
if (composite->getNumControllers() == 1)
cb = composite->getController(0);
if (animflags & Nif::NiNode::AnimFlag_AutoPlay)
if (args.mAnimFlags & Nif::NiNode::AnimFlag_AutoPlay)
node->addCullCallback(cb);
else
node->addUpdateCallback(
@ -765,10 +785,10 @@ namespace NifOsg
}
bool isAnimated = false;
handleNodeControllers(nifNode, node, animflags, isAnimated);
hasAnimatedParents |= isAnimated;
handleNodeControllers(nifNode, node, args.mAnimFlags, isAnimated);
args.mHasAnimatedParents |= isAnimated;
// 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);
// 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 };
for (const auto& child : children)
if (!child.empty())
handleNode(nifVersion, child.getPtr(), &currentParent, currentNode, imageManager, boundTextures,
animflags, skipMeshes, hasMarkers, hasAnimatedParents, textKeys, rootNode);
handleNode(child.getPtr(), &currentParent, currentNode, args);
// 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 (?)
@ -819,7 +838,7 @@ namespace NifOsg
if (!effect.empty())
{
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)
currentNode->getChild(i)->getOrCreateStateSet()->merge(*effectStateSet);
}

Loading…
Cancel
Save