]> git.tdb.fi Git - libs/gl.git/blob - source/render/object.cpp
Mark constant data as const
[libs/gl.git] / source / render / object.cpp
1 #include <msp/datafile/collection.h>
2 #include <msp/fs/utils.h>
3 #include <msp/strings/format.h>
4 #include "error.h"
5 #include "material.h"
6 #include "mesh.h"
7 #include "object.h"
8 #include "objectinstance.h"
9 #include "program.h"
10 #include "programdata.h"
11 #include "renderer.h"
12 #include "resourcemanager.h"
13 #include "technique.h"
14
15 using namespace std;
16
17 namespace Msp {
18 namespace GL {
19
20 const Matrix Object::identity_matrix;
21
22 Object::Object():
23         lods(1),
24         lod0_watched(false)
25 { }
26
27 Object::Object(const Mesh *m, const Technique *t):
28         lods(1),
29         lod0_watched(false)
30 {
31         set_mesh(m);
32         set_technique(t);
33 }
34
35 // TODO should have copy-c'tor to set watch on lod0 mesh if necessary
36
37 Object::~Object()
38 {
39         if(lods[0].mesh && lod0_watched)
40                 if(ResourceManager *rm = lods[0].mesh->get_manager())
41                         rm->unobserve_resource(*lods[0].mesh, *this);
42 }
43
44 Object::LevelOfDetail &Object::get_lod(unsigned i, const char *caller)
45 {
46         if(i>lods.size())
47                 throw out_of_range(caller);
48         if(i>0 && (!lods[0].mesh || !lods[0].technique))
49                 throw invalid_operation(caller);
50
51         if(i==lods.size())
52                 lods.push_back(lods.back());
53
54         return lods[i];
55 }
56
57 void Object::set_mesh(unsigned i, const Mesh *m)
58 {
59         const Mesh *&ptr = get_lod(i, "Object::set_mesh").mesh;
60         if(i==0 && ptr && lod0_watched)
61                 if(ResourceManager *rm = ptr->get_manager())
62                         rm->unobserve_resource(*ptr, *this);
63         ptr = m;
64         lod0_watched = false;
65
66         if(i==0 && m)
67                 if(ResourceManager *rm = m->get_manager())
68                 {
69                         rm->observe_resource(*m, *this);
70                         lod0_watched = true;
71                 }
72
73         update_bounding_sphere();
74 }
75
76 void Object::update_bounding_sphere()
77 {
78         vector<Vector3> points;
79         for(const LevelOfDetail &l: lods)
80         {
81                 if(!l.mesh || !l.mesh->is_loaded())
82                         continue;
83
84                 const VertexArray &vertices = l.mesh->get_vertices();
85
86                 int offset = vertices.get_format().offset(VERTEX3);
87                 bool three = true;
88                 if(offset<0)
89                 {
90                         offset = vertices.get_format().offset(VERTEX2);
91                         three = false;
92                         if(offset<0)
93                                 continue;
94                 }
95
96                 unsigned n_vertices = vertices.size();
97                 points.reserve(points.size()+n_vertices);
98                 for(unsigned j=0; j<n_vertices; ++j)
99                 {
100                         const float *v = reinterpret_cast<const float *>(vertices[j]+offset);
101                         points.push_back(Vector3(v[0], v[1], (three ? v[2] : 0.0f)));
102                 }
103         }
104
105         /* Don't touch the bounding sphere if we had no vertices to avoid
106         overwriting a possible hint. */
107         if(points.empty())
108                 return;
109
110         bounding_sphere = Geometry::BoundingSphere<float, 3>::from_point_cloud(points.begin(), points.end());
111 }
112
113 const Mesh *Object::get_mesh(unsigned i) const
114 {
115         if(i>=lods.size())
116                 return 0;
117
118         return lods[i].mesh;
119 }
120
121 void Object::set_technique(unsigned i, const Technique *t)
122 {
123         get_lod(i, "Object::set_technique").technique = t;
124 }
125
126 const Technique *Object::get_technique(unsigned i) const
127 {
128         if(i>=lods.size())
129                 return 0;
130
131         return lods[i].technique;
132 }
133
134 void Object::render(Renderer &renderer, Tag tag) const
135 {
136         const RenderPass *pass = get_pass(tag, 0);
137         if(!pass)
138                 return;
139
140         const Mesh *mesh = lods.front().mesh;
141         if (!mesh)
142                 throw logic_error("no mesh");
143
144         Renderer::Push push(renderer);
145         pass->apply(renderer);
146
147         setup_render(renderer, tag);
148         mesh->draw(renderer);
149         finish_render(renderer, tag);
150 }
151
152 void Object::render(Renderer &renderer, const ObjectInstance &inst, Tag tag) const
153 {
154         unsigned lod = min<unsigned>(inst.get_level_of_detail(renderer), lods.size()-1);
155         const RenderPass *pass = get_pass(tag, lod);
156         if(!pass)
157                 return;
158
159         const Mesh *mesh = lods[lod].mesh;
160         if (!mesh)
161                 throw logic_error("no mesh");
162
163         Renderer::Push push(renderer);
164         pass->apply(renderer);
165
166         setup_render(renderer, tag);
167         inst.setup_render(renderer, tag);
168         mesh->draw(renderer);
169         inst.finish_render(renderer, tag);
170         finish_render(renderer, tag);
171 }
172
173 const RenderPass *Object::get_pass(Tag tag, unsigned lod) const
174 {
175         const Technique *tech = lods[lod].technique;
176         if(!tech)
177                 throw logic_error("no technique");
178         return tech->find_pass(tag);
179 }
180
181 void Object::resource_loaded(Resource &res)
182 {
183         if(&res==lods.front().mesh && bounding_sphere.is_empty())
184                 update_bounding_sphere();
185 }
186
187 void Object::resource_removed(Resource &res)
188 {
189         if(&res==lods.front().mesh)
190                 lod0_watched = false;
191 }
192
193
194 Object::Loader::Loader(Object &o):
195         LodLoader(o, 0, 0)
196 {
197         init();
198 }
199
200 Object::Loader::Loader(Object &o, Collection &c):
201         LodLoader(o, 0, &c)
202 {
203         init();
204 }
205
206 void Object::Loader::init()
207 {
208         add("bounding_sphere_hint", &Loader::bounding_sphere_hint);
209         add("level_of_detail", &Loader::level_of_detail);
210 }
211
212 void Object::Loader::finish()
213 {
214         obj.update_bounding_sphere();
215 }
216
217 void Object::Loader::bounding_sphere_hint(float x, float y, float z, float r)
218 {
219         obj.bounding_sphere = Geometry::BoundingSphere<float, 3>(Vector3(x, y, z), r);
220 }
221
222 void Object::Loader::level_of_detail(unsigned i)
223 {
224         LodLoader ldr(obj, i, coll);
225         load_sub_with(ldr);
226 }
227
228
229 Object::LodLoader::LodLoader(Object &o, unsigned i, Collection *c):
230         DataFile::CollectionObjectLoader<Object>(o, c),
231         index(i),
232         lod(obj.get_lod(index, "Object::LodLoader::LodLoader"))
233 {
234         add("mesh",      &LodLoader::mesh_inline);
235         add("mesh",      &LodLoader::mesh);
236         add("technique", &LodLoader::technique_inline);
237         add("technique", &LodLoader::technique);
238 }
239
240 void Object::LodLoader::mesh(const string &n)
241 {
242         obj.set_mesh(index, &get_collection().get<Mesh>(n));
243 }
244
245 void Object::LodLoader::mesh_inline()
246 {
247         RefPtr<Mesh> msh = new Mesh;
248         load_sub(*msh);
249         get_collection().add(format("%s/lod%d.mesh", FS::basename(get_source()), index), msh.get());
250         lod.mesh = msh.release();
251 }
252
253 void Object::LodLoader::technique(const string &n)
254 {
255         obj.set_technique(index, &get_collection().get<Technique>(n));
256 }
257
258 void Object::LodLoader::technique_inline()
259 {
260         RefPtr<Technique> tech = new Technique;
261         Technique::Loader ldr(*tech, get_collection());
262         string name = format("%s/lod%d.tech", FS::basename(get_source()), index);
263         ldr.set_inline_base_name(name);
264         load_sub(*tech, get_collection());
265         get_collection().add(name, tech.get());
266         lod.technique = tech.release();
267 }
268
269 } // namespace GL
270 } // namespace Msp