1 #include <msp/datafile/collection.h>
2 #include <msp/fs/utils.h>
3 #include <msp/strings/format.h>
8 #include "objectinstance.h"
10 #include "programdata.h"
12 #include "resourcemanager.h"
13 #include "technique.h"
20 Matrix Object::identity_matrix;
27 Object::Object(const Mesh *m, const Technique *t):
35 // TODO should have copy-c'tor to set watch on lod0 mesh if necessary
39 if(lods[0].mesh && lod0_watched)
40 if(ResourceManager *rm = lods[0].mesh->get_manager())
41 rm->unobserve_resource(*lods[0].mesh, *this);
44 Object::LevelOfDetail &Object::get_lod(unsigned i, const char *caller)
47 throw out_of_range(caller);
48 if(i>0 && (!lods[0].mesh || !lods[0].technique))
49 throw invalid_operation(caller);
52 lods.push_back(lods.back());
57 void Object::set_mesh(unsigned i, const Mesh *m)
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);
67 if(ResourceManager *rm = m->get_manager())
69 rm->observe_resource(*m, *this);
73 update_bounding_sphere();
76 void Object::update_bounding_sphere()
78 vector<Vector3> points;
79 for(vector<LevelOfDetail>::const_iterator i=lods.begin(); i!=lods.end(); ++i)
81 if(!i->mesh || !i->mesh->is_loaded())
84 const VertexArray &vertices = i->mesh->get_vertices();
86 int offset = vertices.get_format().offset(VERTEX3);
90 offset = vertices.get_format().offset(VERTEX2);
96 unsigned n_vertices = vertices.size();
97 points.reserve(points.size()+n_vertices);
98 for(unsigned j=0; j<n_vertices; ++j)
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)));
105 /* Don't touch the bounding sphere if we had no vertices to avoid
106 overwriting a possible hint. */
110 bounding_sphere = Geometry::BoundingSphere<float, 3>::from_point_cloud(points.begin(), points.end());
113 const Mesh *Object::get_mesh(unsigned i) const
121 void Object::set_technique(unsigned i, const Technique *t)
123 get_lod(i, "Object::set_technique").technique = t;
126 const Technique *Object::get_technique(unsigned i) const
131 return lods[i].technique;
134 void Object::render(Renderer &renderer, Tag tag) const
136 const RenderPass *pass = get_pass(tag, 0);
140 const Mesh *mesh = lods.front().mesh;
142 throw logic_error("no mesh");
144 Renderer::Push push(renderer);
145 pass->apply(renderer);
147 setup_render(renderer, tag);
148 mesh->draw(renderer);
149 finish_render(renderer, tag);
152 void Object::render(Renderer &renderer, const ObjectInstance &inst, Tag tag) const
154 unsigned lod = min<unsigned>(inst.get_level_of_detail(renderer), lods.size()-1);
155 const RenderPass *pass = get_pass(tag, lod);
159 const Mesh *mesh = lods[lod].mesh;
161 throw logic_error("no mesh");
163 Renderer::Push push(renderer);
164 pass->apply(renderer);
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);
173 const RenderPass *Object::get_pass(Tag tag, unsigned lod) const
175 const Technique *tech = lods[lod].technique;
177 throw logic_error("no technique");
178 return tech->find_pass(tag);
181 void Object::resource_loaded(Resource &res)
183 if(&res==lods.front().mesh && bounding_sphere.is_empty())
184 update_bounding_sphere();
187 void Object::resource_removed(Resource &res)
189 if(&res==lods.front().mesh)
190 lod0_watched = false;
194 Object::Loader::Loader(Object &o):
200 Object::Loader::Loader(Object &o, Collection &c):
206 void Object::Loader::init()
208 add("bounding_sphere_hint", &Loader::bounding_sphere_hint);
209 add("level_of_detail", &Loader::level_of_detail);
212 void Object::Loader::finish()
214 obj.update_bounding_sphere();
217 void Object::Loader::bounding_sphere_hint(float x, float y, float z, float r)
219 obj.bounding_sphere = Geometry::BoundingSphere<float, 3>(Vector3(x, y, z), r);
222 void Object::Loader::level_of_detail(unsigned i)
224 LodLoader ldr(obj, i, coll);
229 Object::LodLoader::LodLoader(Object &o, unsigned i, Collection *c):
230 DataFile::CollectionObjectLoader<Object>(o, c),
232 lod(obj.get_lod(index, "Object::LodLoader::LodLoader"))
234 add("mesh", &LodLoader::mesh_inline);
235 add("mesh", &LodLoader::mesh);
236 add("technique", &LodLoader::technique_inline);
237 add("technique", &LodLoader::technique);
240 void Object::LodLoader::mesh(const string &n)
242 obj.set_mesh(index, &get_collection().get<Mesh>(n));
245 void Object::LodLoader::mesh_inline()
247 RefPtr<Mesh> msh = new Mesh;
249 get_collection().add(format("%s/lod%d.mesh", FS::basename(get_source()), index), msh.get());
250 lod.mesh = msh.release();
253 void Object::LodLoader::technique(const string &n)
255 obj.set_technique(index, &get_collection().get<Technique>(n));
258 void Object::LodLoader::technique_inline()
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();