From a8ade56c80cbf64e45f6b40b1f3b1250ad95cc82 Mon Sep 17 00:00:00 2001 From: gugus Date: Thu, 13 Jan 2011 17:51:50 +0100 Subject: [PATCH] Add a bullet Shape Loader --- CMakeLists.txt | 6 + components/nif/nif_file.cpp | 3 +- components/nif/record.hpp | 3 +- components/nifbullet/bullet_nif_loader.cpp | 386 +++++++++++++++++++++ components/nifbullet/bullet_nif_loader.hpp | 236 +++++++++++++ components/nifbullet/test/test.cpp | 209 +++++++++++ 6 files changed, 841 insertions(+), 2 deletions(-) create mode 100644 components/nifbullet/bullet_nif_loader.cpp create mode 100644 components/nifbullet/bullet_nif_loader.hpp create mode 100644 components/nifbullet/test/test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b5dcdbb47..63c65381b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,6 +81,12 @@ set(NIFOGRE_HEADER ${COMP_DIR}/nifogre/ogre_nif_loader.hpp) source_group(components\\nifogre FILES ${NIFOGRE} ${NIFOGRE_HEADER}) +set(NIFBULLET + ${COMP_DIR}/nifbullet/ogre_bullet_loader.cpp) +set(NIFBULLET_HEADER + ${COMP_DIR}/nifbullet/bullet_nif_loader.hpp) +source_group(components\\nifbullet FILES ${NIFBULLET} ${NIFBULLET_HEADER}) + set(TO_UTF8 ${COMP_DIR}/to_utf8/to_utf8.cpp) set(TO_UTF8_HEADER diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index fb1b988a7..6a4eb337c 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -83,7 +83,6 @@ void NIFFile::parse() // NiNodes if(rec == "NiNode" || rec == "AvoidNode" || - rec == "RootCollisionNode" || rec == "NiBSParticleNode" || rec == "NiBSAnimationNode" || rec == "NiBillboardNode") { r = new NiNode; r->recType = RC_NiNode; } @@ -93,6 +92,8 @@ void NIFFile::parse() else if(rec == "NiRotatingParticles") { r = new NiRotatingParticles; r->recType = RC_NiRotatingParticles; } else if(rec == "NiAutoNormalParticles") { r = new NiAutoNormalParticles; r->recType = RC_NiAutoNormalParticles; } else if(rec == "NiCamera") { r = new NiCamera; r->recType = RC_NiCamera; } + else if(rec == "RootCollisionNode"){ r = new NiNode; r->recType = RC_RootCollisionNode; }// a root collision node is exactly like a node + //that's why there is no need to create a new type // Properties else if(rec == "NiTexturingProperty") { r = new NiTexturingProperty; r->recType = RC_NiTexturingProperty; } diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 9be3faf8d..8b8910118 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -79,7 +79,8 @@ enum RecordType RC_NiAutoNormalParticlesData, RC_NiSequenceStreamHelper, RC_NiSourceTexture, - RC_NiSkinInstance + RC_NiSkinInstance, + RC_RootCollisionNode }; /// Base class for all records diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp new file mode 100644 index 000000000..6ce26e8a5 --- /dev/null +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -0,0 +1,386 @@ +/* +OpenMW - The completely unofficial reimplementation of Morrowind +Copyright (C) 2008-2010 Nicolay Korslund +Email: < korslund@gmail.com > +WWW: http://openmw.sourceforge.net/ + +This file (ogre_nif_loader.cpp) is part of the OpenMW package. + +OpenMW is distributed as free software: you can redistribute it +and/or modify it under the terms of the GNU General Public License +version 3, as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +version 3 along with this program. If not, see +http://www.gnu.org/licenses/ . + +*/ + +#include "bullet_nif_loader.hpp" +#include +#include + +#include +#include "../nif/nif_file.hpp" +#include "../nif/node.hpp" +#include "../nif/data.hpp" +#include "../nif/property.hpp" +#include "../nif/controller.hpp" +#include "../nif/extra.hpp" +#include + +#include +#include +// For warning messages +#include + +// float infinity +#include + +typedef unsigned char ubyte; + +using namespace std; +using namespace Ogre; +using namespace Nif; +using namespace Mangle::VFS; + + +BulletShape::BulletShape(Ogre::ResourceManager* creator, const Ogre::String &name, + Ogre::ResourceHandle handle, const Ogre::String &group, bool isManual, + Ogre::ManualResourceLoader *loader) : +Ogre::Resource(creator, name, handle, group, isManual, loader) +{ + /* If you were storing a pointer to an object, then you would set that pointer to NULL here. + */ + + /* For consistency with StringInterface, but we don't add any parameters here + That's because the Resource implementation of StringInterface is to + list all the options that need to be set before loading, of which + we have none as such. Full details can be set through scripts. + */ + Shape = NULL; + createParamDictionary("BulletShape"); +} + +BulletShape::~BulletShape() +{ +} + +// farm out to BulletShapeLoader +void BulletShape::loadImpl() +{ + mLoader->loadResource(this); +} + +void BulletShape::deleteShape(btCollisionShape* mShape) +{ + if(mShape!=NULL) + { + if(mShape->isCompound()) + { + btCompoundShape* ms = static_cast(Shape); + btCompoundShapeChild* child = ms->getChildList(); + int a = ms->getNumChildShapes(); + for(int i=0; i getChildShape(i)); + } + } + delete mShape; + } + mShape = NULL; +} + +void BulletShape::unloadImpl() +{ + deleteShape(Shape); +} + +//TODO:change this? +size_t BulletShape::calculateSize() const +{ + return 1; +} + + +//============================================================================================================= +template<> BulletShapeManager *Ogre::Singleton::ms_Singleton = 0; + +BulletShapeManager *BulletShapeManager::getSingletonPtr() +{ + return ms_Singleton; +} + +BulletShapeManager &BulletShapeManager::getSingleton() +{ + assert(ms_Singleton); + return(*ms_Singleton); +} + +BulletShapeManager::BulletShapeManager() +{ + mResourceType = "BulletShape"; + + // low, because it will likely reference other resources + mLoadOrder = 30.0f; + + // this is how we register the ResourceManager with OGRE + Ogre::ResourceGroupManager::getSingleton()._registerResourceManager(mResourceType, this); +} + +BulletShapeManager::~BulletShapeManager() +{ + // and this is how we unregister it + Ogre::ResourceGroupManager::getSingleton()._unregisterResourceManager(mResourceType); +} + +BulletShapePtr BulletShapeManager::load(const Ogre::String &name, const Ogre::String &group) +{ + BulletShapePtr textf = getByName(name); + + if (textf.isNull()) + textf = create(name, group); + + textf->load(); + return textf; +} + +Ogre::Resource *BulletShapeManager::createImpl(const Ogre::String &name, Ogre::ResourceHandle handle, + const Ogre::String &group, bool isManual, Ogre::ManualResourceLoader *loader, + const Ogre::NameValuePairList *createParams) +{ + BulletShape* res = new BulletShape(this, name, handle, group, isManual, loader); + //if(isManual) + //{ + //loader->loadResource(res); + //} + return res; +} + +//==================================================================================================== +Ogre::Matrix3 ManualBulletShapeLoader::getMatrix(Nif::Transformation* tr) +{ + Ogre::Matrix3 rot(tr->rotation.v[0].array[0],tr->rotation.v[0].array[1],tr->rotation.v[0].array[2], + tr->rotation.v[1].array[0],tr->rotation.v[1].array[1],tr->rotation.v[1].array[2], + tr->rotation.v[2].array[0],tr->rotation.v[2].array[1],tr->rotation.v[2].array[2]); + return rot; +} +Ogre::Vector3 ManualBulletShapeLoader::getVector(Nif::Transformation* tr) +{ + Ogre::Vector3 vect3(tr->pos.array[0],tr->pos.array[1],tr->pos.array[2]); + return vect3; +} + +btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 m) +{ + Ogre::Quaternion oquat(m); + btQuaternion quat; + quat.setW(oquat.w); + quat.setX(oquat.x); + quat.setY(oquat.y); + quat.setZ(oquat.z); + return quat; +} + +btVector3 ManualBulletShapeLoader::getbtVector(Nif::Vector v) +{ + btVector3 a(v.array[0],v.array[1],v.array[2]); + return a; +} + +void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) +{ + cShape = static_cast(resource); + resourceName = cShape->getName(); + + currentShape = new btCompoundShape(); + cShape->Shape = currentShape; + + if (!vfs) vfs = new OgreVFS(resourceGroup); + + if (!vfs->isFile(resourceName)) + { + warn("File not found."); + return; + } + + // Load the NIF. TODO: Wrap this in a try-catch block once we're out + // of the early stages of development. Right now we WANT to catch + // every error as early and intrusively as possible, as it's most + // likely a sign of incomplete code rather than faulty input. + Nif::NIFFile nif(vfs->open(resourceName), resourceName); + + if (nif.numRecords() < 1) + { + warn("Found no records in NIF."); + return; + } + + + // The first record is assumed to be the root node + Nif::Record *r = nif.getRecord(0); + assert(r != NULL); + + Nif::Node *node = dynamic_cast(r); + + if (node == NULL) + { + warn("First record in file was not a node, but a " + + r->recName.toString() + ". Skipping file."); + return; + } + + handleNode(node,0,Ogre::Matrix3::IDENTITY,Ogre::Vector3::ZERO,1,false); +} + +void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, + Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScale,bool isCollisionNode) +{ + // Accumulate the flags from all the child nodes. This works for all + // the flags we currently use, at least. + flags |= node->flags; + + // Check for extra data + Nif::Extra *e = node; + while (!e->extra.empty()) + { + // Get the next extra data in the list + e = e->extra.getPtr(); + assert(e != NULL); + + if (e->recType == Nif::RC_NiStringExtraData) + { + // String markers may contain important information + // affecting the entire subtree of this node + Nif::NiStringExtraData *sd = (Nif::NiStringExtraData*)e; + + if (sd->string == "NCO") + { + // No collision. Use an internal flag setting to mark this. + // We ignor this node! + flags |= 0x800; + return; + } + else if (sd->string == "MRK") + // Marker objects. These are only visible in the + // editor. Until and unless we add an editor component to + // the engine, just skip this entire node. + return; + } + } + + //transfo of parents node + curent node + Ogre::Matrix3 finalRot; + Ogre::Vector3 finalPos; + float finalScale; + + Nif::Transformation &final = *((Nif::Transformation*)node->trafo); + Ogre::Vector3 nodePos = getVector(&final); + Ogre::Matrix3 nodeRot = getMatrix(&final); + + finalPos = nodePos + parentPos; + finalRot = parentRot*nodeRot; + finalScale = final.scale*parentScale; + + + // For NiNodes, loop through children + if (node->recType == Nif::RC_NiNode) + { + Nif::NodeList &list = ((Nif::NiNode*)node)->children; + int n = list.length(); + for (int i=0; irecType == Nif::RC_NiTriShape && isCollisionNode) handleNiTriShape(dynamic_cast(node), flags,finalRot,finalPos,finalScale); + else if(node->recType = Nif::RC_RootCollisionNode) + { + Nif::NodeList &list = ((Nif::NiNode*)node)->children; + int n = list.length(); + for (int i=0; i