--- /dev/null
+#include "resource.h"
+#include "resourcemanager.h"
+
+namespace Msp {
+namespace GL {
+
+Resource::Resource():
+ manager(0)
+{ }
+
+Resource::~Resource()
+{
+ if(manager)
+ manager->remove_resource(*this);
+}
+
+void Resource::set_manager(ResourceManager *m)
+{
+ if(manager)
+ manager->remove_resource(*this);
+ manager = m;
+ if(manager)
+ manager->add_resource(*this);
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_RESOURCE_H_
+#define MSP_GL_RESOURCE_H_
+
+#include <msp/io/seekable.h>
+
+namespace Msp {
+namespace GL {
+
+class ResourceManager;
+
+class Resource
+{
+public:
+ class AsyncLoader
+ {
+ protected:
+ AsyncLoader() { }
+ public:
+ virtual ~AsyncLoader() { }
+
+ virtual bool needs_sync() const = 0;
+ virtual bool process() = 0;
+ };
+
+protected:
+ ResourceManager *manager;
+
+ Resource();
+public:
+ virtual ~Resource();
+
+ void set_manager(ResourceManager *);
+ virtual AsyncLoader *load(IO::Seekable &) = 0;
+ virtual void unload() = 0;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <msp/time/utils.h>
+#include "resourcemanager.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+ResourceManager::ResourceManager():
+ policy(LOAD_ON_DEMAND),
+ async_loads(true),
+ thread(*this)
+{ }
+
+ResourceManager::~ResourceManager()
+{
+ thread.terminate();
+}
+
+void ResourceManager::add_resource(Resource &r)
+{
+ insert_unique(resources, &r, ManagedResource(r));
+}
+
+void ResourceManager::set_resource_location(Resource &r, DataFile::Collection &c, const string &n)
+{
+ ManagedResource &managed = get_item(resources, &r);
+ managed.collection = &c;
+ managed.name = n;
+
+ if(policy==LOAD_IMMEDIATELY)
+ load_resource(r);
+}
+
+void ResourceManager::load_resource(const Resource &r)
+{
+ ManagedResource &managed = get_item(resources, &r);
+ if(!managed.collection)
+ throw runtime_error("no location");
+
+ if(managed.loader)
+ return;
+
+ managed.io = managed.collection->open_raw(managed.name);
+ managed.loader = managed.resource->load(*managed.io);
+
+ queue.push_back(&managed);
+}
+
+void ResourceManager::remove_resource(Resource &r)
+{
+ ManagedResource *loading = thread.get_resource();
+ if(loading && loading->resource==&r)
+ thread.set_resource(0);
+
+ remove_existing(resources, &r);
+}
+
+void ResourceManager::tick()
+{
+ LoadingThread::State thread_state = thread.get_state();
+ if(thread_state==LoadingThread::SYNC_PENDING)
+ thread.sync();
+ else if(thread_state==LoadingThread::IDLE && !queue.empty())
+ {
+ ManagedResource *managed = queue.front();
+ queue.pop_front();
+ thread.set_resource(managed);
+ }
+}
+
+
+ResourceManager::ManagedResource::ManagedResource(Resource &r):
+ resource(&r),
+ collection(0),
+ io(0),
+ loader(0)
+{ }
+
+
+ResourceManager::LoadingThread::LoadingThread(ResourceManager &m):
+ manager(m),
+ sem(1),
+ resource(0),
+ state(IDLE)
+{
+ launch();
+}
+
+void ResourceManager::LoadingThread::main()
+{
+ while(state!=TERMINATING)
+ {
+ sem.wait();
+
+ if(state==BUSY)
+ {
+ Resource::AsyncLoader *ldr = resource->loader;
+ bool finished = false;
+ while(!finished && !ldr->needs_sync())
+ finished = ldr->process();
+
+ if(finished)
+ state = LOAD_FINISHED;
+ else
+ state = SYNC_PENDING;
+ }
+ }
+}
+
+void ResourceManager::LoadingThread::set_resource(ManagedResource *r)
+{
+ if(state!=IDLE)
+ {
+ while(state==BUSY) ;
+ // Force finish to clean up the loader
+ state = LOAD_FINISHED;
+ sync();
+ }
+
+ resource = r;
+ state = BUSY;
+ sem.signal();
+}
+
+void ResourceManager::LoadingThread::sync()
+{
+ State s = state;
+ bool finished = (s==LOAD_FINISHED);
+ if(s==SYNC_PENDING)
+ {
+ Resource::AsyncLoader *ldr = resource->loader;
+ while(!finished && ldr->needs_sync())
+ finished = ldr->process();
+
+ if(!finished)
+ {
+ state = BUSY;
+ sem.signal();
+ return;
+ }
+ }
+
+ if(finished)
+ {
+ delete resource->loader;
+ resource->loader = 0;
+ delete resource->io;
+ resource->io = 0;
+ resource = 0;
+ state = IDLE;
+ }
+}
+
+void ResourceManager::LoadingThread::terminate()
+{
+ while(state==BUSY) ;
+ state = TERMINATING;
+ sem.signal();
+ join();
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_RESOURCEMANAGER_H_
+#define MSP_GL_RESOURCEMANAGER_H_
+
+#include <msp/core/mutex.h>
+#include <msp/core/semaphore.h>
+#include <msp/core/thread.h>
+#include <msp/datafile/collection.h>
+#include "resource.h"
+
+namespace Msp {
+namespace GL {
+
+class ResourceManager
+{
+public:
+ enum LoadingPolicy
+ {
+ LOAD_IMMEDIATELY,
+ LOAD_ON_DEMAND,
+ LOAD_MANUALLY
+ };
+
+private:
+ struct ManagedResource
+ {
+ Resource *resource;
+ DataFile::Collection *collection;
+ std::string name;
+ IO::Seekable *io;
+ Resource::AsyncLoader *loader;
+
+ ManagedResource(Resource &);
+ };
+
+ class LoadingThread: public Thread
+ {
+ public:
+ enum State
+ {
+ IDLE,
+ SYNC_PENDING,
+ BUSY,
+ LOAD_FINISHED,
+ TERMINATING
+ };
+
+ private:
+ ResourceManager &manager;
+ Semaphore sem;
+ ManagedResource *volatile resource;
+ volatile State state;
+
+ public:
+ LoadingThread(ResourceManager &);
+
+ private:
+ virtual void main();
+
+ public:
+ void set_resource(ManagedResource *);
+ ManagedResource *get_resource() const { return resource; }
+ void sync();
+ State get_state() const { return state; }
+
+ void terminate();
+ };
+
+ typedef std::list<ManagedResource *> LoadQueue;
+
+ LoadingPolicy policy;
+ bool async_loads;
+ std::map<const Resource *, ManagedResource> resources;
+ std::list<ManagedResource *> queue;
+ LoadingThread thread;
+
+public:
+ ResourceManager();
+ ~ResourceManager();
+
+ void set_loading_policy(LoadingPolicy);
+ void set_async_loads(bool);
+
+ void add_resource(Resource &);
+ void set_resource_location(Resource &, DataFile::Collection &, const std::string &);
+ void load_resource(const Resource &);
+ void remove_resource(Resource &);
+
+ void tick();
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
#include "object.h"
#include "pose.h"
#include "program.h"
+#include "resourcemanager.h"
#include "resources.h"
#include "technique.h"
#include "texture2d.h"
Resources::Resources():
default_tex_filter(LINEAR_MIPMAP_LINEAR),
- srgb_conversion(false)
+ srgb_conversion(false),
+ resource_manager(0)
{
add_type<Animation>().suffix(".anim").keyword("animation");
add_type<Armature>().suffix(".arma").keyword("armature");
srgb_conversion = c;
}
+void Resources::set_resource_manager(ResourceManager *m)
+{
+ resource_manager = m;
+}
+
Texture2D *Resources::create_texture2d(const string &name)
{
string ext = FS::extpart(name);
namespace Msp {
namespace GL {
+class ResourceManager;
class Texture2D;
/**
private:
TextureFilter default_tex_filter;
bool srgb_conversion;
+ ResourceManager *resource_manager;
public:
Resources();
bool get_srgb_conversion() const { return srgb_conversion; }
+ void set_resource_manager(ResourceManager *);
+
protected:
Texture2D *create_texture2d(const std::string &);
};