forked from teamnwah/openmw-tes3coop
Support for loading .osg mesh format
This commit is contained in:
parent
21e25f4756
commit
eb2f16d682
7 changed files with 145 additions and 10 deletions
|
@ -19,7 +19,9 @@ void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs)
|
||||||
mVFS = vfs;
|
mVFS = vfs;
|
||||||
mResources.clear();
|
mResources.clear();
|
||||||
|
|
||||||
static const char * const sMeshTypes[] = { "nif", 0 };
|
// maybe we could go over the osgDB::Registry to list all supported node formats
|
||||||
|
|
||||||
|
static const char * const sMeshTypes[] = { "nif", "osg", "osgt", "osgb", "osgx", "osg2", 0 };
|
||||||
|
|
||||||
addResources (Resources (vfs, "meshes", UniversalId::Type_Mesh, sMeshTypes));
|
addResources (Resources (vfs, "meshes", UniversalId::Type_Mesh, sMeshTypes));
|
||||||
addResources (Resources (vfs, "icons", UniversalId::Type_Icon));
|
addResources (Resources (vfs, "icons", UniversalId::Type_Icon));
|
||||||
|
|
|
@ -975,7 +975,7 @@ namespace MWPhysics
|
||||||
void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh)
|
void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<NifBullet::BulletShapeInstance> shapeInstance = mShapeManager->createInstance(mesh);
|
osg::ref_ptr<NifBullet::BulletShapeInstance> shapeInstance = mShapeManager->createInstance(mesh);
|
||||||
if (!shapeInstance->getCollisionShape())
|
if (!shapeInstance || !shapeInstance->getCollisionShape())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Object *obj = new Object(ptr, shapeInstance);
|
Object *obj = new Object(ptr, shapeInstance);
|
||||||
|
@ -1114,9 +1114,10 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh)
|
void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh) {
|
||||||
{
|
|
||||||
osg::ref_ptr<NifBullet::BulletShapeInstance> shapeInstance = mShapeManager->createInstance(mesh);
|
osg::ref_ptr<NifBullet::BulletShapeInstance> shapeInstance = mShapeManager->createInstance(mesh);
|
||||||
|
if (!shapeInstance)
|
||||||
|
return;
|
||||||
|
|
||||||
Actor* actor = new Actor(ptr, shapeInstance, mCollisionWorld);
|
Actor* actor = new Actor(ptr, shapeInstance, mCollisionWorld);
|
||||||
mActors.insert(std::make_pair(ptr, actor));
|
mActors.insert(std::make_pair(ptr, actor));
|
||||||
|
|
|
@ -402,7 +402,7 @@ namespace MWRender
|
||||||
animsrc.reset(new AnimSource);
|
animsrc.reset(new AnimSource);
|
||||||
animsrc->mKeyframes = mResourceSystem->getSceneManager()->getKeyframes(kfname);
|
animsrc->mKeyframes = mResourceSystem->getSceneManager()->getKeyframes(kfname);
|
||||||
|
|
||||||
if (animsrc->mKeyframes->mTextKeys.empty() || animsrc->mKeyframes->mKeyframeControllers.empty())
|
if (!animsrc->mKeyframes || animsrc->mKeyframes->mTextKeys.empty() || animsrc->mKeyframes->mKeyframeControllers.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (NifOsg::KeyframeHolder::KeyframeControllerMap::const_iterator it = animsrc->mKeyframes->mKeyframeControllers.begin();
|
for (NifOsg::KeyframeHolder::KeyframeControllerMap::const_iterator it = animsrc->mKeyframes->mKeyframeControllers.begin();
|
||||||
|
|
|
@ -30,6 +30,13 @@ osg::ref_ptr<BulletShapeInstance> BulletShapeManager::createInstance(const std::
|
||||||
Files::IStreamPtr file = mVFS->get(normalized);
|
Files::IStreamPtr file = mVFS->get(normalized);
|
||||||
|
|
||||||
// TODO: add support for non-NIF formats
|
// TODO: add support for non-NIF formats
|
||||||
|
size_t extPos = normalized.find_last_of('.');
|
||||||
|
std::string ext;
|
||||||
|
if (extPos != std::string::npos && extPos+1 < normalized.size())
|
||||||
|
ext = normalized.substr(extPos+1);
|
||||||
|
|
||||||
|
if (ext != "nif")
|
||||||
|
return NULL;
|
||||||
|
|
||||||
BulletNifLoader loader;
|
BulletNifLoader loader;
|
||||||
// might be worth sharing NIFFiles with SceneManager in some way
|
// might be worth sharing NIFFiles with SceneManager in some way
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
#include <components/sceneutil/clone.hpp>
|
#include <components/sceneutil/clone.hpp>
|
||||||
#include <components/sceneutil/util.hpp>
|
#include <components/sceneutil/util.hpp>
|
||||||
|
|
||||||
|
#include "texturemanager.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -112,6 +114,73 @@ namespace Resource
|
||||||
SceneManager::~SceneManager()
|
SceneManager::~SceneManager()
|
||||||
{
|
{
|
||||||
// this has to be defined in the .cpp file as we can't delete incomplete types
|
// this has to be defined in the .cpp file as we can't delete incomplete types
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Callback to read image files from the VFS.
|
||||||
|
class ImageReadCallback : public osgDB::ReadFileCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ImageReadCallback(Resource::TextureManager* textureMgr)
|
||||||
|
: mTextureManager(textureMgr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual osgDB::ReaderWriter::ReadResult readImage(const std::string& filename, const osgDB::Options* options)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
mTextureManager->getTexture2D(filename, osg::Texture::CLAMP_TO_EDGE, osg::Texture::CLAMP_TO_EDGE);
|
||||||
|
return osgDB::ReaderWriter::ReadResult(mTextureManager->getImage(filename), osgDB::ReaderWriter::ReadResult::FILE_LOADED);
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
return osgDB::ReaderWriter::ReadResult(e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Resource::TextureManager* mTextureManager;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string getFileExtension(const std::string& file)
|
||||||
|
{
|
||||||
|
size_t extPos = file.find_last_of('.');
|
||||||
|
if (extPos != std::string::npos && extPos+1 < file.size())
|
||||||
|
return file.substr(extPos+1);
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Node> load (Files::IStreamPtr file, const std::string& normalizedFilename, Resource::TextureManager* textureMgr)
|
||||||
|
{
|
||||||
|
std::string ext = getFileExtension(normalizedFilename);
|
||||||
|
if (ext == "nif")
|
||||||
|
return NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalizedFilename)), textureMgr);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext);
|
||||||
|
if (!reader)
|
||||||
|
{
|
||||||
|
std::stringstream errormsg;
|
||||||
|
errormsg << "Error loading " << normalizedFilename << ": no readerwriter for '" << ext << "' found" << std::endl;
|
||||||
|
throw std::runtime_error(errormsg.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<osgDB::Options> options (new osgDB::Options);
|
||||||
|
// Set a ReadFileCallback so that image files referenced in the model are read from our virtual file system instead of the osgDB.
|
||||||
|
// Note, for some formats (.obj/.mtl) that reference other (non-image) files a findFileCallback would be necessary.
|
||||||
|
// but findFileCallback does not support virtual files, so we can't implement it.
|
||||||
|
options->setReadFileCallback(new ImageReadCallback(textureMgr));
|
||||||
|
|
||||||
|
osgDB::ReaderWriter::ReadResult result = reader->readNode(*file, options);
|
||||||
|
if (!result.success())
|
||||||
|
{
|
||||||
|
std::stringstream errormsg;
|
||||||
|
errormsg << "Error loading " << normalizedFilename << ": " << result.message() << " code " << result.status() << std::endl;
|
||||||
|
throw std::runtime_error(errormsg.str());
|
||||||
|
}
|
||||||
|
return result.getNode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<const osg::Node> SceneManager::getTemplate(const std::string &name)
|
osg::ref_ptr<const osg::Node> SceneManager::getTemplate(const std::string &name)
|
||||||
|
@ -122,19 +191,19 @@ namespace Resource
|
||||||
Index::iterator it = mIndex.find(normalized);
|
Index::iterator it = mIndex.find(normalized);
|
||||||
if (it == mIndex.end())
|
if (it == mIndex.end())
|
||||||
{
|
{
|
||||||
// TODO: add support for non-NIF formats
|
|
||||||
osg::ref_ptr<osg::Node> loaded;
|
osg::ref_ptr<osg::Node> loaded;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Files::IStreamPtr file = mVFS->get(normalized);
|
Files::IStreamPtr file = mVFS->get(normalized);
|
||||||
|
|
||||||
loaded = NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager);
|
loaded = load(file, normalized, mTextureManager);
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
std::cerr << "Failed to load '" << name << "': " << e.what() << ", using marker_error.nif instead" << std::endl;
|
std::cerr << "Failed to load '" << name << "': " << e.what() << ", using marker_error.nif instead" << std::endl;
|
||||||
Files::IStreamPtr file = mVFS->get("meshes/marker_error.nif");
|
Files::IStreamPtr file = mVFS->get("meshes/marker_error.nif");
|
||||||
loaded = NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager);
|
normalized = "meshes/marker_error.nif";
|
||||||
|
loaded = load(file, normalized, mTextureManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get());
|
osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get());
|
||||||
|
@ -174,6 +243,11 @@ namespace Resource
|
||||||
{
|
{
|
||||||
Files::IStreamPtr file = mVFS->get(normalized);
|
Files::IStreamPtr file = mVFS->get(normalized);
|
||||||
|
|
||||||
|
std::string ext = getFileExtension(normalized);
|
||||||
|
|
||||||
|
if (ext != "nif" && ext != "kf")
|
||||||
|
return NULL;
|
||||||
|
|
||||||
osg::ref_ptr<NifOsg::KeyframeHolder> loaded (new NifOsg::KeyframeHolder);
|
osg::ref_ptr<NifOsg::KeyframeHolder> loaded (new NifOsg::KeyframeHolder);
|
||||||
NifOsg::Loader::loadKf(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), *loaded.get());
|
NifOsg::Loader::loadKf(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), *loaded.get());
|
||||||
|
|
||||||
|
|
|
@ -143,6 +143,57 @@ namespace Resource
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Image> TextureManager::getImage(const std::string &filename)
|
||||||
|
{
|
||||||
|
std::string normalized = filename;
|
||||||
|
mVFS->normalizeFilename(normalized);
|
||||||
|
std::map<std::string, osg::ref_ptr<osg::Image> >::iterator found = mImages.find(normalized);
|
||||||
|
if (found != mImages.end())
|
||||||
|
return found->second;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Files::IStreamPtr stream;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
stream = mVFS->get(normalized.c_str());
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "Failed to open image: " << e.what() << std::endl;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<osgDB::Options> opts (new osgDB::Options);
|
||||||
|
opts->setOptionString("dds_dxt1_detect_rgba"); // tx_creature_werewolf.dds isn't loading in the correct format without this option
|
||||||
|
size_t extPos = normalized.find_last_of('.');
|
||||||
|
std::string ext;
|
||||||
|
if (extPos != std::string::npos && extPos+1 < normalized.size())
|
||||||
|
ext = normalized.substr(extPos+1);
|
||||||
|
osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext);
|
||||||
|
if (!reader)
|
||||||
|
{
|
||||||
|
std::cerr << "Error loading " << filename << ": no readerwriter for '" << ext << "' found" << std::endl;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
osgDB::ReaderWriter::ReadResult result = reader->readImage(*stream, opts);
|
||||||
|
if (!result.success())
|
||||||
|
{
|
||||||
|
std::cerr << "Error loading " << filename << ": " << result.message() << " code " << result.status() << std::endl;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Image* image = result.getImage();
|
||||||
|
if (!checkSupported(image, filename))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mImages.insert(std::make_pair(normalized, image));
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::Texture2D> TextureManager::getTexture2D(const std::string &filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT)
|
osg::ref_ptr<osg::Texture2D> TextureManager::getTexture2D(const std::string &filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT)
|
||||||
{
|
{
|
||||||
std::string normalized = filename;
|
std::string normalized = filename;
|
||||||
|
|
|
@ -34,7 +34,7 @@ namespace Resource
|
||||||
osg::ref_ptr<osg::Texture2D> getTexture2D(const std::string& filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT);
|
osg::ref_ptr<osg::Texture2D> getTexture2D(const std::string& filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT);
|
||||||
|
|
||||||
/// Create or retrieve an Image
|
/// Create or retrieve an Image
|
||||||
//osg::ref_ptr<osg::Image> getImage(const std::string& filename);
|
osg::ref_ptr<osg::Image> getImage(const std::string& filename);
|
||||||
|
|
||||||
const VFS::Manager* getVFS() { return mVFS; }
|
const VFS::Manager* getVFS() { return mVFS; }
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ namespace Resource
|
||||||
|
|
||||||
typedef std::pair<std::pair<int, int>, std::string> MapKey;
|
typedef std::pair<std::pair<int, int>, std::string> MapKey;
|
||||||
|
|
||||||
std::map<std::string, osg::observer_ptr<osg::Image> > mImages;
|
std::map<std::string, osg::ref_ptr<osg::Image> > mImages;
|
||||||
|
|
||||||
std::map<MapKey, osg::ref_ptr<osg::Texture2D> > mTextures;
|
std::map<MapKey, osg::ref_ptr<osg::Texture2D> > mTextures;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue