]> git.tdb.fi Git - libs/gl.git/blob - source/resourcemanager.cpp
Foundation for a resource management system
[libs/gl.git] / source / resourcemanager.cpp
1 #include <msp/time/utils.h>
2 #include "resourcemanager.h"
3
4 using namespace std;
5
6 namespace Msp {
7 namespace GL {
8
9 ResourceManager::ResourceManager():
10         policy(LOAD_ON_DEMAND),
11         async_loads(true),
12         thread(*this)
13 { }
14
15 ResourceManager::~ResourceManager()
16 {
17         thread.terminate();
18 }
19
20 void ResourceManager::add_resource(Resource &r)
21 {
22         insert_unique(resources, &r, ManagedResource(r));
23 }
24
25 void ResourceManager::set_resource_location(Resource &r, DataFile::Collection &c, const string &n)
26 {
27         ManagedResource &managed = get_item(resources, &r);
28         managed.collection = &c;
29         managed.name = n;
30
31         if(policy==LOAD_IMMEDIATELY)
32                 load_resource(r);
33 }
34
35 void ResourceManager::load_resource(const Resource &r)
36 {
37         ManagedResource &managed = get_item(resources, &r);
38         if(!managed.collection)
39                 throw runtime_error("no location");
40
41         if(managed.loader)
42                 return;
43
44         managed.io = managed.collection->open_raw(managed.name);
45         managed.loader = managed.resource->load(*managed.io);
46
47         queue.push_back(&managed);
48 }
49
50 void ResourceManager::remove_resource(Resource &r)
51 {
52         ManagedResource *loading = thread.get_resource();
53         if(loading && loading->resource==&r)
54                 thread.set_resource(0);
55
56         remove_existing(resources, &r);
57 }
58
59 void ResourceManager::tick()
60 {
61         LoadingThread::State thread_state = thread.get_state();
62         if(thread_state==LoadingThread::SYNC_PENDING)
63                 thread.sync();
64         else if(thread_state==LoadingThread::IDLE && !queue.empty())
65         {
66                 ManagedResource *managed = queue.front();
67                 queue.pop_front();
68                 thread.set_resource(managed);
69         }
70 }
71
72
73 ResourceManager::ManagedResource::ManagedResource(Resource &r):
74         resource(&r),
75         collection(0),
76         io(0),
77         loader(0)
78 { }
79
80
81 ResourceManager::LoadingThread::LoadingThread(ResourceManager &m):
82         manager(m),
83         sem(1),
84         resource(0),
85         state(IDLE)
86 {
87         launch();
88 }
89
90 void ResourceManager::LoadingThread::main()
91 {
92         while(state!=TERMINATING)
93         {
94                 sem.wait();
95
96                 if(state==BUSY)
97                 {
98                         Resource::AsyncLoader *ldr = resource->loader;
99                         bool finished = false;
100                         while(!finished && !ldr->needs_sync())
101                                 finished = ldr->process();
102
103                         if(finished)
104                                 state = LOAD_FINISHED;
105                         else
106                                 state = SYNC_PENDING;
107                 }
108         }
109 }
110
111 void ResourceManager::LoadingThread::set_resource(ManagedResource *r)
112 {
113         if(state!=IDLE)
114         {
115                 while(state==BUSY) ;
116                 // Force finish to clean up the loader
117                 state = LOAD_FINISHED;
118                 sync();
119         }
120
121         resource = r;
122         state = BUSY;
123         sem.signal();
124 }
125
126 void ResourceManager::LoadingThread::sync()
127 {
128         State s = state;
129         bool finished = (s==LOAD_FINISHED);
130         if(s==SYNC_PENDING)
131         {
132                 Resource::AsyncLoader *ldr = resource->loader;
133                 while(!finished && ldr->needs_sync())
134                         finished = ldr->process();
135
136                 if(!finished)
137                 {
138                         state = BUSY;
139                         sem.signal();
140                         return;
141                 }
142         }
143
144         if(finished)
145         {
146                 delete resource->loader;
147                 resource->loader = 0;
148                 delete resource->io;
149                 resource->io = 0;
150                 resource = 0;
151                 state = IDLE;
152         }
153 }
154
155 void ResourceManager::LoadingThread::terminate()
156 {
157         while(state==BUSY) ;
158         state = TERMINATING;
159         sem.signal();
160         join();
161 }
162
163 } // namespace GL
164 } // namespace Msp