1 #include <msp/datafile/collection.h>
2 #include <msp/strings/format.h>
7 #include "objectinstance.h"
9 #include "programdata.h"
11 #include "resourcemanager.h"
12 #include "technique.h"
13 #include "texturing.h"
25 Object::Object(const Mesh *m, const Technique *t):
35 if(lods[0].mesh && lod0_watched)
36 if(ResourceManager *rm = lods[0].mesh->get_manager())
37 rm->unwatch_resource(*lods[0].mesh, *this);
40 Object::LevelOfDetail &Object::get_lod(unsigned i, const char *caller)
43 throw out_of_range(caller);
44 if(i>0 && (!lods[0].mesh || !lods[0].technique))
45 throw invalid_operation(caller);
48 lods.push_back(lods.back());
53 void Object::set_mesh(unsigned i, const Mesh *m)
55 RefPtr<const Mesh> &ptr = get_lod(i, "Object::set_mesh").mesh;
56 if(i==0 && ptr && lod0_watched)
57 if(ResourceManager *rm = ptr->get_manager())
58 rm->unwatch_resource(*ptr, *this);
64 if(ResourceManager *rm = m->get_manager())
66 rm->watch_resource(*m, *this);
70 update_bounding_sphere();
73 void Object::update_bounding_sphere()
75 vector<Vector3> points;
76 for(vector<LevelOfDetail>::const_iterator i=lods.begin(); i!=lods.end(); ++i)
78 if(!i->mesh || !i->mesh->is_loaded())
81 const VertexArray &vertices = i->mesh->get_vertices();
83 int offset = vertices.get_format().offset(VERTEX3);
87 offset = vertices.get_format().offset(VERTEX2);
93 unsigned n_vertices = vertices.size();
94 points.reserve(points.size()+n_vertices);
95 for(unsigned j=0; j<n_vertices; ++j)
97 const float *v = vertices[j];
98 points.push_back(Vector3(v[offset], v[offset+1], (three ? v[offset+2] : 0.0f)));
102 /* Don't touch the bounding sphere if we had no vertices to avoid
103 overwriting a possible hint. */
107 bounding_sphere = Geometry::BoundingSphere<float, 3>::from_point_cloud(points.begin(), points.end());
110 const Mesh *Object::get_mesh(unsigned i) const
115 return lods[i].mesh.get();
118 void Object::set_technique(unsigned i, const Technique *t)
120 RefPtr<const Technique> &ptr = get_lod(i, "Object::set_technique").technique;
125 const Technique *Object::get_technique(unsigned i) const
130 return lods[i].technique.get();
133 void Object::render(const Tag &tag) const
135 const RenderPass *pass = get_pass(tag, 0);
139 Bind bind_shader(pass->get_shader_program());
140 if(pass->get_shader_data())
141 pass->get_shader_data()->apply();
142 Bind bind_material(pass->get_material());
143 Bind bind_texturing(pass->get_texturing());
145 lods.front().mesh->draw();
148 void Object::render(Renderer &renderer, const Tag &tag) const
150 const RenderPass *pass = get_pass(tag, 0);
154 Renderer::Push push(renderer);
155 pass->apply(renderer);
157 setup_render(renderer, tag);
158 lods.front().mesh->draw(renderer);
159 finish_render(renderer, tag);
162 void Object::render(Renderer &renderer, const ObjectInstance &inst, const Tag &tag) const
164 unsigned lod = min<unsigned>(inst.get_level_of_detail(renderer), lods.size()-1);
165 const RenderPass *pass = get_pass(tag, lod);
169 Renderer::Push push(renderer);
170 pass->apply(renderer);
172 setup_render(renderer, tag);
173 inst.setup_render(renderer, tag);
174 lods[lod].mesh->draw(renderer);
175 inst.finish_render(renderer, tag);
176 finish_render(renderer, tag);
179 const RenderPass *Object::get_pass(const Tag &tag, unsigned lod) const
181 const Technique *tech = lods[lod].technique.get();
183 throw logic_error("no technique");
184 if(!tech->has_pass(tag))
186 return &tech->get_pass(tag);
189 void Object::resource_loaded(Resource &res)
191 if(&res==lods.front().mesh.get() && bounding_sphere.is_empty())
192 update_bounding_sphere();
195 void Object::resource_removed(Resource &res)
197 if(&res==lods.front().mesh.get())
198 lod0_watched = false;
202 Object::Loader::Loader(Object &o):
208 Object::Loader::Loader(Object &o, Collection &c):
214 void Object::Loader::init()
216 add("bounding_sphere_hint", &Loader::bounding_sphere_hint);
217 add("level_of_detail", &Loader::level_of_detail);
220 void Object::Loader::finish()
222 obj.update_bounding_sphere();
225 void Object::Loader::bounding_sphere_hint(float x, float y, float z, float r)
227 obj.bounding_sphere = Geometry::BoundingSphere<float, 3>(Vector3(x, y, z), r);
230 void Object::Loader::level_of_detail(unsigned i)
232 LodLoader ldr(obj, i, coll);
237 Object::LodLoader::LodLoader(Object &o, unsigned i, Collection *c):
238 DataFile::CollectionObjectLoader<Object>(o, c),
240 lod(obj.get_lod(index, "Object::LodLoader::LodLoader"))
242 add("mesh", &LodLoader::mesh_inline);
243 add("mesh", &LodLoader::mesh);
244 add("technique", &LodLoader::technique_inline);
245 add("technique", &LodLoader::technique);
248 void Object::LodLoader::mesh(const string &n)
250 obj.set_mesh(index, &get_collection().get<Mesh>(n));
253 void Object::LodLoader::mesh_inline()
255 RefPtr<Mesh> msh = new Mesh;
260 void Object::LodLoader::technique(const std::string &n)
262 obj.set_technique(index, &get_collection().get<Technique>(n));
265 void Object::LodLoader::technique_inline()
267 RefPtr<Technique> tech = new Technique;
269 load_sub(*tech, get_collection());
272 lod.technique = tech;