X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fobject.cpp;h=1852f91b50222ead401dfa177605c31d9d1ee21b;hp=f710a7a9c8c5ced2f2e6647c54a16848a90a7fe7;hb=71240e5c5ef7165313664ee9fe81df95c0eff10b;hpb=25c81b4953dd38993250321b9407ce8b0139cbeb diff --git a/source/object.cpp b/source/object.cpp index f710a7a9..1852f91b 100644 --- a/source/object.cpp +++ b/source/object.cpp @@ -1,13 +1,6 @@ -/* $Id$ - -This file is part of libmspgl -Copyright © 2007-2011 Mikko Rasa, Mikkosoft Productions -Distributed under the LGPL -*/ - #include -#include -#include "except.h" +#include +#include "error.h" #include "material.h" #include "mesh.h" #include "object.h" @@ -15,6 +8,7 @@ Distributed under the LGPL #include "program.h" #include "programdata.h" #include "renderer.h" +#include "resourcemanager.h" #include "technique.h" #include "texturing.h" @@ -23,155 +17,248 @@ using namespace std; namespace Msp { namespace GL { +Matrix Object::identity_matrix; + Object::Object(): - meshes(1) + lods(1), + lod0_watched(false) { } +Object::Object(const Mesh *m, const Technique *t): + lods(1), + lod0_watched(false) +{ + set_mesh(m); + set_technique(t); +} + +// TODO should have copy-c'tor to set watch on lod0 mesh if necessary + Object::~Object() { + if(lods[0].mesh && lod0_watched) + if(ResourceManager *rm = lods[0].mesh->get_manager()) + rm->unwatch_resource(*lods[0].mesh, *this); } -void Object::set_mesh(unsigned i, const Mesh *m) +Object::LevelOfDetail &Object::get_lod(unsigned i, const char *caller) { - if(i>meshes.size()) - throw InvalidParameterValue("LODs must be continuous"); + if(i>lods.size()) + throw out_of_range(caller); + if(i>0 && (!lods[0].mesh || !lods[0].technique)) + throw invalid_operation(caller); - if(i==meshes.size()) - meshes.push_back(m); - else - meshes[i] = m; - meshes[i].keep(); + if(i==lods.size()) + lods.push_back(lods.back()); + + return lods[i]; } -void Object::set_technique(const Technique *t) +void Object::set_mesh(unsigned i, const Mesh *m) { - technique = t; - technique.keep(); + RefPtr &ptr = get_lod(i, "Object::set_mesh").mesh; + if(i==0 && ptr && lod0_watched) + if(ResourceManager *rm = ptr->get_manager()) + rm->unwatch_resource(*ptr, *this); + ptr = m; + ptr.keep(); + lod0_watched = false; + + if(i==0 && m) + if(ResourceManager *rm = m->get_manager()) + { + rm->watch_resource(*m, *this); + lod0_watched = true; + } + + update_bounding_sphere(); } -void Object::render(const Tag &tag) const +void Object::update_bounding_sphere() { - const RenderPass *pass = get_pass(tag); - if(!pass) + vector points; + for(vector::const_iterator i=lods.begin(); i!=lods.end(); ++i) + { + if(!i->mesh || !i->mesh->is_loaded()) + continue; + + const VertexArray &vertices = i->mesh->get_vertices(); + + int offset = vertices.get_format().offset(VERTEX3); + bool three = true; + if(offset<0) + { + offset = vertices.get_format().offset(VERTEX2); + three = false; + if(offset<0) + continue; + } + + unsigned n_vertices = vertices.size(); + points.reserve(points.size()+n_vertices); + for(unsigned j=0; jget_shader_program()); - if(pass->get_shader_data()) - pass->get_shader_data()->apply(); - Bind bind_material(pass->get_material()); - Bind bind_texturing(pass->get_texturing()); + bounding_sphere = Geometry::BoundingSphere::from_point_cloud(points.begin(), points.end()); +} + +const Mesh *Object::get_mesh(unsigned i) const +{ + if(i>=lods.size()) + return 0; + + return lods[i].mesh.get(); +} + +void Object::set_technique(unsigned i, const Technique *t) +{ + RefPtr &ptr = get_lod(i, "Object::set_technique").technique; + ptr = t; + ptr.keep(); +} + +const Technique *Object::get_technique(unsigned i) const +{ + if(i>=lods.size()) + return 0; - meshes.front()->draw(); + return lods[i].technique.get(); } void Object::render(Renderer &renderer, const Tag &tag) const { - const RenderPass *pass = get_pass(tag); + const RenderPass *pass = get_pass(tag, 0); if(!pass) return; Renderer::Push push(renderer); - renderer.set_shader(pass->get_shader_program(), pass->get_shader_data()); - renderer.set_material(pass->get_material()); - renderer.set_texturing(pass->get_texturing()); + pass->apply(renderer); - meshes.front()->draw(renderer); + setup_render(renderer, tag); + lods.front().mesh->draw(renderer); + finish_render(renderer, tag); } void Object::render(Renderer &renderer, const ObjectInstance &inst, const Tag &tag) const { - const RenderPass *pass = get_pass(tag); + unsigned lod = min(inst.get_level_of_detail(renderer), lods.size()-1); + const RenderPass *pass = get_pass(tag, lod); if(!pass) return; Renderer::Push push(renderer); - renderer.set_shader(pass->get_shader_program(), pass->get_shader_data()); - renderer.set_material(pass->get_material()); - renderer.set_texturing(pass->get_texturing()); + pass->apply(renderer); + setup_render(renderer, tag); inst.setup_render(renderer, tag); - unsigned lod = min(inst.get_level_of_detail(), meshes.size()-1); - meshes[lod]->draw(renderer); + lods[lod].mesh->draw(renderer); inst.finish_render(renderer, tag); + finish_render(renderer, tag); } -const RenderPass *Object::get_pass(const Tag &tag) const +const RenderPass *Object::get_pass(const Tag &tag, unsigned lod) const { - if(!technique || !technique->has_pass(tag)) + const Technique *tech = lods[lod].technique.get(); + if(!tech) + throw logic_error("no technique"); + if(!tech->has_pass(tag)) return 0; - return &technique->get_pass(tag); + return &tech->get_pass(tag); +} + +void Object::resource_loaded(Resource &res) +{ + if(&res==lods.front().mesh.get() && bounding_sphere.is_empty()) + update_bounding_sphere(); +} + +void Object::resource_removed(Resource &res) +{ + if(&res==lods.front().mesh.get()) + lod0_watched = false; } Object::Loader::Loader(Object &o): - DataFile::CollectionObjectLoader(o, 0) + LodLoader(o, 0, 0) { init(); } Object::Loader::Loader(Object &o, Collection &c): - DataFile::CollectionObjectLoader(o, &c) + LodLoader(o, 0, &c) { init(); } void Object::Loader::init() { - allow_pointer_reload = false; + add("bounding_sphere_hint", &Loader::bounding_sphere_hint); + add("level_of_detail", &Loader::level_of_detail); +} - add("mesh", static_cast(&Loader::mesh)); - add("mesh", static_cast(&Loader::mesh)); - add("mesh", static_cast(&Loader::mesh)); - add("mesh", static_cast(&Loader::mesh)); - // Deprecated alias, will be removed - add("lod_mesh", static_cast(&Loader::mesh)); - add("technique", static_cast(&Loader::technique)); - add("technique", static_cast(&Loader::technique)); +void Object::Loader::finish() +{ + obj.update_bounding_sphere(); } -void Object::Loader::mesh() +void Object::Loader::bounding_sphere_hint(float x, float y, float z, float r) { - RefPtr msh = new Mesh; - load_sub(*msh); - obj.meshes.front() = msh; + obj.bounding_sphere = Geometry::BoundingSphere(Vector3(x, y, z), r); } -void Object::Loader::mesh(unsigned l) +void Object::Loader::level_of_detail(unsigned i) { - if(l>obj.meshes.size()) - throw InvalidParameterValue("LODs must be continuous"); + LodLoader ldr(obj, i, coll); + load_sub_with(ldr); +} - RefPtr msh = new Mesh; - load_sub(*msh); - if(l==obj.meshes.size()) - obj.meshes.push_back(msh); - else - obj.meshes[l] = msh; + +Object::LodLoader::LodLoader(Object &o, unsigned i, Collection *c): + DataFile::CollectionObjectLoader(o, c), + index(i), + lod(obj.get_lod(index, "Object::LodLoader::LodLoader")) +{ + add("mesh", &LodLoader::mesh_inline); + add("mesh", &LodLoader::mesh); + add("technique", &LodLoader::technique_inline); + add("technique", &LodLoader::technique); +} + +void Object::LodLoader::mesh(const string &n) +{ + obj.set_mesh(index, &get_collection().get(n)); } -void Object::Loader::mesh(const std::string &n) +void Object::LodLoader::mesh_inline() { - obj.set_mesh(get_collection().get(n)); + RefPtr msh = new Mesh; + load_sub(*msh); + lod.mesh = msh; } -void Object::Loader::mesh(unsigned l, const string &n) +void Object::LodLoader::technique(const std::string &n) { - obj.set_mesh(l, get_collection().get(n)); + obj.set_technique(index, &get_collection().get(n)); } -void Object::Loader::technique() +void Object::LodLoader::technique_inline() { RefPtr tech = new Technique; if(coll) load_sub(*tech, get_collection()); else load_sub(*tech); - obj.technique = tech; -} - -void Object::Loader::technique(const std::string &n) -{ - obj.set_technique(get_collection().get(n)); + lod.technique = tech; } } // namespace GL