Loading resources w/o ResourceGroup

Problems building or running the engine, queries about how to use features etc.
Post Reply
User avatar
Moohasha
Gnoll
Posts: 672
Joined: Fri Dec 07, 2007 7:37 pm
x 8

Loading resources w/o ResourceGroup

Post by Moohasha »

I have folders with thousands of images in them, and loading them to the ResourceGroupManager takes a long time. I'm not going to use all the images, but any of them could be used. So I have two questions:
  • 1) How can I load textures from a location that's not defined as a resource group? (rel or abs path)

    2) How can I check to make sure that a texture which isn't loaded yet exists before trying to load it? If I call TextureManager::load() and the image doesn't exist, it throws an exception. But if the image doesn't exist, I want to load a different image instead that I know exists.
Black holes are where God divided by 0

User avatar
Moohasha
Gnoll
Posts: 672
Joined: Fri Dec 07, 2007 7:37 pm
x 8

Post by Moohasha »

Really, my main concern is loading images from a known location (ie, ".\images\subfolder\image1.jpg") without having to add that location to the ResourceGroupManager. That would save me a load of time and trouble.
Black holes are where God divided by 0

User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Post by xavier »

1) Use a ManualResourceLoader

2) Use ResourceManager::resourceExists()

http://www.ogre3d.org/docs/api/html/cla ... 6fe308ad6b
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.

User avatar
Moohasha
Gnoll
Posts: 672
Joined: Fri Dec 07, 2007 7:37 pm
x 8

Post by Moohasha »

1) Use a ManualResourceLoader
Thanks, I'll give that a shot.
2) Use ResourceManager::resourceExists()
I've tried that, but it always returns false until the resource is actually loaded. I'm trying to find out if the resource even exists on the hard drive (ie, is there a file called someimage.jpg?).
Black holes are where God divided by 0

User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Post by xavier »

You are probably better off using native filesystem calls. If you re cross-platform it's rather simple to make an abstraction for the underlying APIs. For a Win32 example,

http://blog.kowalczyk.info/kb/check-if- ... ndows.html
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.

User avatar
Moohasha
Gnoll
Posts: 672
Joined: Fri Dec 07, 2007 7:37 pm
x 8

Re: Loading resources w/o ResourceGroup

Post by Moohasha »

Ok, I thought I might have to do that, I just wanted to see if there was a way in Ogre first. Thanks Xavier, that example looks great!
Black holes are where God divided by 0

User avatar
Moohasha
Gnoll
Posts: 672
Joined: Fri Dec 07, 2007 7:37 pm
x 8

Re: Loading resources w/o ResourceGroup

Post by Moohasha »

I'm playing around with the ManualResourceLoader, and it looks like that's just a way to control the creation of a resource on my own, but I still have to find a way to load the image without first adding it to a resource location. Is there no way to do this in Ogre, or am I just (hopefully) missing something? Do I have to write my own code (ie, not using Ogre) to load an image from a specified location and then copy it into an Image as a DataStreamPtr? I just want to do something like:

Code: Select all

Ogre::Image image;
image.load(absFileName);  // absFileName is not in any loaded resource location
texture->loadImage(image);
Black holes are where God divided by 0

User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Re: Loading resources w/o ResourceGroup

Post by xavier »

The OgreCollada code does exactly this. To wit (this is ColladaImage.cpp; ignore the DDS hack):

Code: Select all

/*
-----------------------------------------------------------------------------
This source file is part of NESE
    (Networked Extensible Simulation Environment)

For the latest info, see http://www.clashofsteel.net/

Copyright (c) The Clash Of Steel Team
Also see acknowledgements in Readme.txt

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

-----------------------------------------------------------------------------
*/

#include "stdafx.h"

// We do not need to check for uniqueness of textures -- COLLADA will have sorted 
// that out for us already.
// Since we are creating the texture outside of the normal resource manager path,
// we need to make and instantiate a manual loader for each texture we encounter.
// We can track the loader by its associated texture name, so that when Ogre comes
// calling for a texture to be loaded, we invoke the loader for that texture.


namespace OgreCollada
{
	// extreme fallback texture -- 2x2 hot pink
	static UInt8 s_RGB[] = {128, 0, 255, 128, 0, 255, 128, 0, 255, 128, 0, 255};
	
	class TextureLoader : public Ogre::ManualResourceLoader
	{
	public:
		TextureLoader(const FCDImage* pImage, IResourceNotification* pCallback = 0)
		{
			// extract the pertinent information from the FCDImage
			m_fileName = CONVERT_STRING(pImage->GetFilename().c_str());
			m_pCallback = pCallback;
		}

		// here's where the real magic happens -- when Ogre calls for a texture, we need
		// to get it from disk and fill in the Ogre::Texture resource with it.
		void loadResource(Ogre::Resource* pResource)
		{
			Ogre::Texture* pTex = static_cast<Ogre::Texture*>(pResource);
			Ogre::Image img;

			// extract extension from filename
			size_t pos = m_fileName.find_last_of('.');
			Ogre::String ext = m_fileName.substr(pos+1);

			// prefer .dds to anything else; fall back to original filename if .dds does not exist
			Ogre::String ddsName = m_fileName.substr(0, pos) + ".dds";

			std::ifstream i, j;
			Ogre::FileStreamDataStream* pFS = 0;
			i.open(ddsName.c_str(), std::ios::binary);
			if (i.is_open())
			{
				pFS = new Ogre::FileStreamDataStream(&i, false);
				ext = "dds";
			}
			else
			{
				j.open(m_fileName.c_str(), std::ios::binary);
				pFS = new Ogre::FileStreamDataStream(&j, false);
			}
			Ogre::DataStreamPtr strm(pFS);

			if (!strm->size() || strm->size() == 0xffffffff)
			{
				// call out for the default texture instead
				if (m_pCallback)
				{
					printf("Could not load texture '%s', calling out for default texture\n", m_fileName.substr(0, pos).c_str());
					m_pCallback->getDefaultTexture(img);
					assert(img.getWidth() != 0 && img.getHeight() != 0);
					//assert(img.getFormat() != Ogre::PF_UNKNOWN); // GGJ - until Ogre applies my patch to init Image::mFormat...
				}

				// last resort...
				//if (img.getFormat() == Ogre::PF_UNKNOWN) 
				if (img.getWidth() == 0 || img.getHeight() == 0)
				{
					// fall back to our very simple and very hardcoded hot-pink version
					Ogre::DataStreamPtr altStrm(new Ogre::MemoryDataStream(s_RGB, sizeof(s_RGB)));
					img.loadRawData(altStrm, 2, 2, Ogre::PF_R8G8B8);
					printf("Could not load texture '%s' or its default, this texture will be pink\n", m_fileName.substr(0, pos).c_str());
				}
			}
			else
			{
				// TODO: allow for alternate resource group names
				img.load(strm, ext);
				i.close();
			}

			Ogre::ConstImagePtrList images;
			images.push_back(&img);
			pTex->_loadImages(images);
		}

	private:
		Ogre::String m_fileName;
		IResourceNotification* m_pCallback;
	};

	template <class _V>
	class TextureLoaderList : public std::list<_V>
	{
	public:
		TextureLoaderList() {}
		~TextureLoaderList()
		{
			for (typename std::list<_V>::iterator it = this->begin(); it != this->end(); ++it)
			{
				delete *it;
			}
		}
	};

	// we have this for automatic cleanup of the manual loader pointers on app exit
	static TextureLoaderList<TextureLoader*> loaderList;

	void ImpExpImpl::addTexture(FCDImage* pImage)
	{
		Ogre::TextureManager* pTexMgr = m_pRoot->getTextureManager();
		TextureLoader* pLoader = new TextureLoader(pImage, m_pCallback);
		loaderList.push_back(pLoader);

		Ogre::TexturePtr pTex = pTexMgr->createOrRetrieve(
			CONVERT_STRING(pImage->GetDaeId().c_str()), 
			m_resGroupName,
			true,
			pLoader
		).first;

		pImage->SetUserHandle(pTex.getPointer());
		pTex->_notifyOrigin(pImage->GetFilename().c_str());

		if (m_pCallback)
			m_pCallback->resourceCreated(pTex.getPointer(), pImage);
	}
}
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.

User avatar
Moohasha
Gnoll
Posts: 672
Joined: Fri Dec 07, 2007 7:37 pm
x 8

Re: Loading resources w/o ResourceGroup

Post by Moohasha »

Man, I appreciate the help, but I'm not going to download and use a seperate plugin for the sole purpose of loading images without specifying a ResourceGroupLocation. I'll just figure out how to load the data into a DataStreamPtr and load it that way. Thanks for the help though. It's much appreciated.
Black holes are where God divided by 0

User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Re: Loading resources w/o ResourceGroup

Post by xavier »

I'm not telling you to download and install a separate plugin.

I'm giving you real-life, working (as in it's currently in an existing published product) example source code, that does exactly what you want, with an explanation of where it comes from so that you can have some context for understanding why it's done the way it is. Sorry if that wasn't clear (apparently it wasn't).
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.

User avatar
Moohasha
Gnoll
Posts: 672
Joined: Fri Dec 07, 2007 7:37 pm
x 8

Re: Loading resources w/o ResourceGroup

Post by Moohasha »

You know, I woke up this morning realizing that very thing, and thought "Hey, I can at least look at how it is done in the source code xavier posted." :oops:
Sorry for the misunderstanding, and thanks for the solution! By the way, I wasn't frustrated with you for your suggestion, I was frustrated that it "appeared" that there was no straightforward solution, but I was wrr....I was wro.......(boy, this is hard)...I was wrrrrrrong! :lol:
Thanks again!
Black holes are where God divided by 0

User avatar
Ben811
Gnoblar
Posts: 14
Joined: Fri Nov 11, 2005 3:12 pm
Location: Germany
Contact:

Re: Loading resources w/o ResourceGroup

Post by Ben811 »

Hi,

I had the same problem and I know that this had worked before with OGRE 1.4 to load images from absolute paths.
I debuged the code and came to this point inside of the OgreResourceGroupManager (line 718)

Code: Select all

// Search the hard way
LocationList::iterator li, liend;
liend = grp->locationList.end();
for (li = grp->locationList.begin(); li != liend; ++li)
{
    Archive* arch = (*li)->archive;
    if (arch->exists(resourceName))
    {
       DataStreamPtr ptr = arch->open(resourceName);
       if (mLoadingListener)
          mLoadingListener->resourceStreamOpened(resourceName, groupName, resourceBeingLoaded, ptr);
       return ptr;
    }
}
The

Code: Select all

if (arch->exists(resourceName))
function returns true if you supply an absolute path for the image (it searches via stat) and if this comparison returns true:

Code: Select all

ret = Ogre::StringUtil::startsWith(full_path, mName, false);
So a much easier and working solution for this problem will be to add an absolute path to your resources.cfg file like:

Code: Select all

# Resource locations to be added to the default path
[General]
FileSystem=./Media
FileSystem=./Media/fonts
FileSystem=./Media/materials/scripts
FileSystem=./Media/materials/textures
FileSystem=./Media/gui
FileSystem=M:\MySVN\
If this directory does not contain images initial loading does not consume time and you are able to load all images below this directory!

Cheers,

Ben
Interested in the things you can see?
Visit our website and take part in development...
http://www.3DmeetsTV.com

Post Reply