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