- Latest Ogre version from 1.9 branch, compiled with Boost and Threading support (OGRE_THREAD_SUPPORT 2)
- Based on OgreJNI, i.e., the activity is created in Java
- I subclassed Ogre::Archive to handle requests for HTTP-URLs by going through Android's URLConnection class (the idea was to get a persistent download cache for free)
In order to keep rendering while downloads are in progress, I use Ogre's background loading feature:
Code: Select all
Ogre::TexturePtr tex = static_cast<Ogre::TexturePtr>(
Ogre::TextureManager::getSingleton().create(url, group) );
tex->setBackgroundLoaded(true);
Ogre::ResourceBackgroundQueue* rbq = Ogre::ResourceBackgroundQueue::getSingletonPtr();
Ogre::BackgroundProcessTicket ticket = rbq->load("Texture", url, group, false, 0, 0, &g_texDownloadCB);
// create or clone material, prepare texture units, set texture name, leave information for operationCompleted(), etc.
Code: Select all
pSceneMgr->getEntity(tex_download_tickets_[ticket].node)->setMaterialName(tex_download_tickets_[ticket].material);
However, when I switch to the Home screen and then back to my app's activity, only the textures that are not loaded in the background are re-initialized, all background-loaded textures stay black. From my archive class I see that no requests are made for these.
Code: Select all
JNIEXPORT void JNICALL Java_com_example_maps_MapsJNI_initWindow(JNIEnv * env, jobject obj, jobject surface)
{
if(surface)
{
ANativeWindow* nativeWnd = ANativeWindow_fromSurface(env, surface);
if (nativeWnd && gRoot)
{
if (!gRenderWnd)
{
// Create scene when starting activity
}
else
{
// Resume activity. This does *not* trigger reloads of background-loaded textures :(
static_cast<Ogre::AndroidEGLWindow*>(gRenderWnd)->_createInternalResources(nativeWnd, NULL);
}
}
}
}
Unfortunately, obvious (to Ogre beginners like me) solutions like reloadAll() don't work and every idea I tried so far didn't work or caused other problems.
For example, somewhere inside _createInternalResources(), textures are reloaded by calling Ogre::Resource::reload(), which in turn calls unload() and load(). However, reload() does not have a background flag like load() does, so all background-loaded textures are unloaded, but not reloaded. Calling reload() on such a resource basically just unloads it (and sets the load state to "unloaded"). As far as I understand, this behaviour means that the engine loses track of which textures should be loaded and I'd have to keep track of them manually.
So I tried that and created a task that I placed into the work queue for background processing:
Code: Select all
Ogre::WorkQueue* wq = Ogre::Root::getSingleton().getWorkQueue();
Ogre::uint16 channel = wq->getChannel("Custom/ResourceReload");
wq->addRequest(channel, 42, Ogre::Any(reload_list));
Code: Select all
for(size_t i = 0; i < list->size(); i++)
{
list->at(i)->unload();
//list->at(i)->load(true); <-- not safe in background (different EGL context)
list->at(i)->prepare(true);
// How to trigger loading texture? Do I have to notify someone?
}
Code: Select all
I/OGRE (26052): Texture: http://192.168.0.15/test.png: Loading 1 faces(PF_R8G8B8,2048x2048x1) with 11 hardware generated mipmaps from Image. Internal format is PF_R8G8B8,2048x2048x1.
As all of this got quite complicated, I'm wondering if there isn't a really obvious thing that I'm missing that will make the background-loaded textures reload automatically on the background thread. Any hints, pointers or clarifications are more than welcome!
Thanks,
Robert