#include <algorithm>
+#include <typeinfo>
+#include <msp/debug/demangle.h>
+#include <msp/strings/format.h>
#include <msp/time/utils.h>
#include "resourcemanager.h"
+#include "resources.h"
#include "resourcewatcher.h"
using namespace std;
namespace Msp {
namespace GL {
+resource_load_error::resource_load_error(const string &name, const string &err):
+ runtime_error(format("%s: %s", name, err))
+{ }
+
+resource_load_error::resource_load_error(const string &name, const exception &exc):
+ runtime_error(format("%s: %s: %s", name, Debug::demangle(typeid(exc).name()), exc.what()))
+{ }
+
+
ResourceManager::ResourceManager():
policy(LOAD_ON_DEMAND),
async_loads(true),
}
void ResourceManager::set_resource_location(Resource &r, DataFile::Collection &c, const string &n)
+{
+ set_resource_location(r, ResourceLocation(c, n));
+}
+
+void ResourceManager::set_resource_location(Resource &r, const ResourceLocation &l)
{
ManagedResource &managed = get_item(resources, &r);
- managed.collection = &c;
- managed.name = n;
+ managed.location = l;
if(policy==LOAD_IMMEDIATELY)
load_resource(r);
}
+const ResourceManager::ResourceLocation *ResourceManager::get_resource_location(const Resource &r) const
+{
+ const ManagedResource &managed = get_item(resources, &r);
+ return managed.location.collection ? &managed.location : 0;
+}
+
void ResourceManager::load_resource(Resource &r)
{
ManagedResource &managed = get_item(resources, &r);
- if(!managed.collection)
+ if(!managed.location.collection)
throw runtime_error("no location");
if(managed.state!=ManagedResource::NOT_LOADED)
if(async_loads)
{
managed.state = ManagedResource::LOAD_QUEUED;
- queue.push_back(&managed);
+ LoadQueue::iterator i;
+ for(i=queue.begin(); (i!=queue.end() && (*i)->load_priority>=managed.load_priority); ++i) ;
+ queue.insert(i, &managed);
}
else
{
}
}
+bool ResourceManager::is_resource_loaded(const Resource &r) const
+{
+ ManagedResource *managed = reinterpret_cast<ManagedResource *>(r.get_manager_data());
+ return managed ? managed->state==ManagedResource::LOADED : false;
+}
+
void ResourceManager::resource_used(const Resource &r)
{
ManagedResource *managed = reinterpret_cast<ManagedResource *>(r.get_manager_data());
+ if(!managed)
+ return;
if(managed->state==ManagedResource::NOT_LOADED && policy!=LOAD_MANUALLY)
load_resource(*managed->resource);
}
+ResourceManager::ResourceLocation::ResourceLocation():
+ collection(0)
+{ }
+
+ResourceManager::ResourceLocation::ResourceLocation(DataFile::Collection &c, const string &n):
+ collection(&c),
+ name(n)
+{ }
+
+
ResourceManager::ManagedResource::ManagedResource(Resource &r):
resource(&r),
- collection(0),
+ load_priority(r.get_load_priority()),
io(0),
loader(0),
state(NOT_LOADED),
void ResourceManager::ManagedResource::start_loading()
{
- io = collection->open_raw(name);
- loader = resource->load(*io);
+ io = location.collection->open_raw(location.name);
+ if(!io)
+ throw resource_load_error(location.name, "open failed");
+
+ const Resources *res = dynamic_cast<Resources *>(location.collection);
+ loader = resource->load(*io, res);
if(!loader)
{
delete io;
if(ManagedResource *managed = front(async_queue))
{
- managed->process(false);
+ try
+ {
+ managed->process(false);
+ }
+ catch(const exception &e)
+ {
+ MutexLock lock(queue_mutex);
+ error_queue.push_back(resource_load_error(managed->location.name, e));
+ managed->state = ManagedResource::LOAD_ERROR;
+ }
MutexLock lock(queue_mutex);
sync_queue.splice(sync_queue.end(), async_queue, async_queue.begin());
{
{
MutexLock lock(queue_mutex);
+
+ if(!error_queue.empty())
+ {
+ resource_load_error err = error_queue.front();
+ error_queue.pop_front();
+ throw err;
+ }
+
unsigned async_size = async_queue.size();
if(async_size==0 && size==capacity)
++capacity;
bool any_finished = false;
while(ManagedResource *managed = front(sync_queue))
{
- if(managed->process(true))
+ if(managed->state==ManagedResource::LOAD_ERROR || managed->process(true))
{
managed->finish_loading();
any_finished = true;