mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 21:49:55 +00:00
Handle multiple root nodes (bug #5604)
This commit is contained in:
parent
96e22bd44e
commit
5b6377b061
3 changed files with 81 additions and 68 deletions
|
@ -58,6 +58,7 @@
|
|||
Bug #5557: Diagonal movement is noticeably slower with analogue stick
|
||||
Bug #5588: Randomly clicking on the journal's right-side page when it's empty shows random topics
|
||||
Bug #5603: Setting constant effect cast style doesn't correct effects view
|
||||
Bug #5604: Only one valid NIF root node is loaded from a single file
|
||||
Bug #5611: Usable items with "0 Uses" should be used only once
|
||||
Bug #5622: Can't properly interact with the console when in pause menu
|
||||
Bug #5633: Damage Spells in effect before god mode is enabled continue to hurt the player character and can kill them
|
||||
|
|
|
@ -123,73 +123,79 @@ osg::ref_ptr<Resource::BulletShape> BulletNifLoader::load(const Nif::File& nif)
|
|||
mStaticMesh.reset();
|
||||
mAvoidStaticMesh.reset();
|
||||
|
||||
Nif::Node* node = nullptr;
|
||||
const size_t numRoots = nif.numRoots();
|
||||
std::vector<Nif::Node*> roots;
|
||||
for (size_t i = 0; i < numRoots; ++i)
|
||||
{
|
||||
Nif::Record* r = nif.getRoot(i);
|
||||
assert(r != nullptr);
|
||||
Nif::Node* node = nullptr;
|
||||
if ((node = dynamic_cast<Nif::Node*>(r)))
|
||||
break;
|
||||
roots.emplace_back(node);
|
||||
}
|
||||
const std::string filename = nif.getFilename();
|
||||
if (!node)
|
||||
if (roots.empty())
|
||||
{
|
||||
warn("Found no root nodes in NIF file " + filename);
|
||||
return mShape;
|
||||
}
|
||||
|
||||
if (findBoundingBox(node, filename))
|
||||
// Try to find a valid bounding box first. If one's found for any root node, use that.
|
||||
for (const Nif::Node* node : roots)
|
||||
{
|
||||
const btVector3 halfExtents = Misc::Convert::toBullet(mShape->mCollisionBoxHalfExtents);
|
||||
const btVector3 origin = Misc::Convert::toBullet(mShape->mCollisionBoxTranslate);
|
||||
std::unique_ptr<btCompoundShape> compound (new btCompoundShape);
|
||||
std::unique_ptr<btBoxShape> boxShape(new btBoxShape(halfExtents));
|
||||
btTransform transform = btTransform::getIdentity();
|
||||
transform.setOrigin(origin);
|
||||
compound->addChildShape(transform, boxShape.get());
|
||||
boxShape.release();
|
||||
if (findBoundingBox(node, filename))
|
||||
{
|
||||
const btVector3 halfExtents = Misc::Convert::toBullet(mShape->mCollisionBoxHalfExtents);
|
||||
const btVector3 origin = Misc::Convert::toBullet(mShape->mCollisionBoxTranslate);
|
||||
std::unique_ptr<btCompoundShape> compound (new btCompoundShape);
|
||||
std::unique_ptr<btBoxShape> boxShape(new btBoxShape(halfExtents));
|
||||
btTransform transform = btTransform::getIdentity();
|
||||
transform.setOrigin(origin);
|
||||
compound->addChildShape(transform, boxShape.get());
|
||||
boxShape.release();
|
||||
|
||||
mShape->mCollisionShape = compound.release();
|
||||
return mShape;
|
||||
mShape->mCollisionShape = compound.release();
|
||||
return mShape;
|
||||
}
|
||||
}
|
||||
else
|
||||
// files with the name convention xmodel.nif usually have keyframes stored in a separate file xmodel.kf (see Animation::addAnimSource).
|
||||
// assume all nodes in the file will be animated
|
||||
const bool isAnimated = pathFileNameStartsWithX(filename);
|
||||
|
||||
// If there's no bounding box, we'll have to generate a Bullet collision shape
|
||||
// from the collision data present in every root node.
|
||||
for (const Nif::Node* node : roots)
|
||||
{
|
||||
bool autogenerated = hasAutoGeneratedCollision(node);
|
||||
|
||||
// files with the name convention xmodel.nif usually have keyframes stored in a separate file xmodel.kf (see Animation::addAnimSource).
|
||||
// assume all nodes in the file will be animated
|
||||
const bool isAnimated = pathFileNameStartsWithX(filename);
|
||||
|
||||
handleNode(filename, node, 0, autogenerated, isAnimated, autogenerated);
|
||||
}
|
||||
|
||||
if (mCompoundShape)
|
||||
if (mCompoundShape)
|
||||
{
|
||||
if (mStaticMesh)
|
||||
{
|
||||
if (mStaticMesh)
|
||||
{
|
||||
btTransform trans;
|
||||
trans.setIdentity();
|
||||
std::unique_ptr<btCollisionShape> child(new Resource::TriangleMeshShape(mStaticMesh.get(), true));
|
||||
mCompoundShape->addChildShape(trans, child.get());
|
||||
child.release();
|
||||
mStaticMesh.release();
|
||||
}
|
||||
mShape->mCollisionShape = mCompoundShape.release();
|
||||
}
|
||||
else if (mStaticMesh)
|
||||
{
|
||||
mShape->mCollisionShape = new Resource::TriangleMeshShape(mStaticMesh.get(), true);
|
||||
btTransform trans;
|
||||
trans.setIdentity();
|
||||
std::unique_ptr<btCollisionShape> child(new Resource::TriangleMeshShape(mStaticMesh.get(), true));
|
||||
mCompoundShape->addChildShape(trans, child.get());
|
||||
child.release();
|
||||
mStaticMesh.release();
|
||||
}
|
||||
|
||||
if (mAvoidStaticMesh)
|
||||
{
|
||||
mShape->mAvoidCollisionShape = new Resource::TriangleMeshShape(mAvoidStaticMesh.get(), false);
|
||||
mAvoidStaticMesh.release();
|
||||
}
|
||||
|
||||
return mShape;
|
||||
mShape->mCollisionShape = mCompoundShape.release();
|
||||
}
|
||||
else if (mStaticMesh)
|
||||
{
|
||||
mShape->mCollisionShape = new Resource::TriangleMeshShape(mStaticMesh.get(), true);
|
||||
mStaticMesh.release();
|
||||
}
|
||||
|
||||
if (mAvoidStaticMesh)
|
||||
{
|
||||
mShape->mAvoidCollisionShape = new Resource::TriangleMeshShape(mAvoidStaticMesh.get(), false);
|
||||
mAvoidStaticMesh.release();
|
||||
}
|
||||
|
||||
return mShape;
|
||||
}
|
||||
|
||||
// Find a boundingBox in the node hierarchy.
|
||||
|
@ -228,8 +234,7 @@ bool BulletNifLoader::findBoundingBox(const Nif::Node* node, const std::string&
|
|||
{
|
||||
if(!list[i].empty())
|
||||
{
|
||||
bool found = findBoundingBox (list[i].getPtr(), filename);
|
||||
if (found)
|
||||
if (findBoundingBox(list[i].getPtr(), filename))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -231,6 +231,9 @@ namespace NifOsg
|
|||
size_t mFirstRootTextureIndex = -1;
|
||||
bool mFoundFirstRootTexturingProperty = false;
|
||||
|
||||
bool mHasNightDayLabel = false;
|
||||
bool mHasHerbalismLabel = false;
|
||||
|
||||
// This is used to queue emitters that weren't attached to their node yet.
|
||||
std::vector<std::pair<size_t, osg::ref_ptr<Emitter>>> mEmitterQueue;
|
||||
|
||||
|
@ -294,20 +297,31 @@ namespace NifOsg
|
|||
|
||||
osg::ref_ptr<osg::Node> load(Nif::NIFFilePtr nif, Resource::ImageManager* imageManager)
|
||||
{
|
||||
const Nif::Node* nifNode = nullptr;
|
||||
const size_t numRoots = nif->numRoots();
|
||||
std::vector<const Nif::Node*> roots;
|
||||
for (size_t i = 0; i < numRoots; ++i)
|
||||
{
|
||||
const Nif::Record* r = nif->getRoot(i);
|
||||
const Nif::Node* nifNode = nullptr;
|
||||
if ((nifNode = dynamic_cast<const Nif::Node*>(r)))
|
||||
break;
|
||||
roots.emplace_back(nifNode);
|
||||
}
|
||||
if (!nifNode)
|
||||
if (roots.empty())
|
||||
nif->fail("Found no root nodes");
|
||||
|
||||
osg::ref_ptr<TextKeyMapHolder> textkeys (new TextKeyMapHolder);
|
||||
|
||||
osg::ref_ptr<osg::Node> created = handleNode(nifNode, nullptr, imageManager, std::vector<unsigned int>(), 0, false, false, false, &textkeys->mTextKeys);
|
||||
osg::ref_ptr<osg::Group> created(new osg::Group);
|
||||
created->setDataVariance(osg::Object::STATIC);
|
||||
for (const Nif::Node* root : roots)
|
||||
{
|
||||
auto node = handleNode(root, nullptr, imageManager, std::vector<unsigned int>(), 0, false, false, false, &textkeys->mTextKeys);
|
||||
created->addChild(node);
|
||||
}
|
||||
if (mHasNightDayLabel)
|
||||
created->getOrCreateUserDataContainer()->addDescription(Constants::NightDayLabel);
|
||||
if (mHasHerbalismLabel)
|
||||
created->getOrCreateUserDataContainer()->addDescription(Constants::HerbalismLabel);
|
||||
|
||||
// Attach particle emitters to their nodes which should all be loaded by now.
|
||||
handleQueuedParticleEmitters(created, nif);
|
||||
|
@ -315,18 +329,11 @@ namespace NifOsg
|
|||
if (nif->getUseSkinning())
|
||||
{
|
||||
osg::ref_ptr<SceneUtil::Skeleton> skel = new SceneUtil::Skeleton;
|
||||
|
||||
osg::Group* root = created->asGroup();
|
||||
if (root && root->getDataVariance() == osg::Object::STATIC && !root->asTransform())
|
||||
{
|
||||
skel->setStateSet(root->getStateSet());
|
||||
skel->setName(root->getName());
|
||||
for (unsigned int i=0; i<root->getNumChildren(); ++i)
|
||||
skel->addChild(root->getChild(i));
|
||||
root->removeChildren(0, root->getNumChildren());
|
||||
}
|
||||
else
|
||||
skel->addChild(created);
|
||||
skel->setStateSet(created->getStateSet());
|
||||
skel->setName(created->getName());
|
||||
for (unsigned int i=0; i < created->getNumChildren(); ++i)
|
||||
skel->addChild(created->getChild(i));
|
||||
created->removeChildren(0, created->getNumChildren());
|
||||
created = skel;
|
||||
}
|
||||
|
||||
|
@ -632,7 +639,7 @@ namespace NifOsg
|
|||
}
|
||||
|
||||
if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles)
|
||||
handleParticleSystem(nifNode, node, composite, animflags, rootNode);
|
||||
handleParticleSystem(nifNode, node, composite, animflags);
|
||||
|
||||
if (composite->getNumControllers() > 0)
|
||||
{
|
||||
|
@ -662,10 +669,10 @@ namespace NifOsg
|
|||
const Nif::NiSwitchNode* niSwitchNode = static_cast<const Nif::NiSwitchNode*>(nifNode);
|
||||
osg::ref_ptr<osg::Switch> switchNode = handleSwitchNode(niSwitchNode);
|
||||
node->addChild(switchNode);
|
||||
if (niSwitchNode->name == Constants::NightDayLabel && !SceneUtil::hasUserDescription(rootNode, Constants::NightDayLabel))
|
||||
rootNode->getOrCreateUserDataContainer()->addDescription(Constants::NightDayLabel);
|
||||
else if (niSwitchNode->name == Constants::HerbalismLabel && !SceneUtil::hasUserDescription(rootNode, Constants::HerbalismLabel))
|
||||
rootNode->getOrCreateUserDataContainer()->addDescription(Constants::HerbalismLabel);
|
||||
if (niSwitchNode->name == Constants::NightDayLabel)
|
||||
mHasNightDayLabel = true;
|
||||
else if (niSwitchNode->name == Constants::HerbalismLabel)
|
||||
mHasHerbalismLabel = true;
|
||||
|
||||
currentNode = switchNode;
|
||||
}
|
||||
|
@ -1023,7 +1030,7 @@ namespace NifOsg
|
|||
return emitter;
|
||||
}
|
||||
|
||||
void handleQueuedParticleEmitters(osg::Node* rootNode, Nif::NIFFilePtr nif)
|
||||
void handleQueuedParticleEmitters(osg::Group* rootNode, Nif::NIFFilePtr nif)
|
||||
{
|
||||
for (const auto& emitterPair : mEmitterQueue)
|
||||
{
|
||||
|
@ -1044,7 +1051,7 @@ namespace NifOsg
|
|||
mEmitterQueue.clear();
|
||||
}
|
||||
|
||||
void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, int animflags, osg::Node* rootNode)
|
||||
void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, int animflags)
|
||||
{
|
||||
osg::ref_ptr<ParticleSystem> partsys (new ParticleSystem);
|
||||
partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT);
|
||||
|
|
Loading…
Reference in a new issue