]> git.tdb.fi Git - libs/gl.git/blob - source/object.cpp
Properly handle the case where an object doesn't have a main texture but its techniqu...
[libs/gl.git] / source / object.cpp
1 /* $Id$
2
3 This file is part of libmspgl
4 Copyright © 2007  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <msp/strings/formatter.h>
9 #include "except.h"
10 #include "material.h"
11 #include "mesh.h"
12 #include "object.h"
13 #include "objectinstance.h"
14 #include "objectpass.h"
15 #include "program.h"
16 #include "programdata.h"
17 #include "technique.h"
18 #include "texture.h"
19 #include "texunit.h"
20
21 using namespace std;
22
23 namespace Msp {
24 namespace GL {
25
26 Object::Object():
27         meshes(1, static_cast<Mesh *>(0)),
28         technique(0),
29         main_texture(0),
30         material(0)
31 { }
32
33 Object::~Object()
34 {
35 }
36
37 bool Object::has_pass(const Tag &tag) const
38 {
39         if(technique)
40                 return technique->has_pass(tag);
41         else
42                 return tag.id==0;
43 }
44
45 void Object::render(const Tag &tag) const
46 {
47         const ObjectPass *pass=get_pass(tag);
48         setup_render(pass);
49         meshes[0]->draw();
50         finish_render(pass);
51 }
52
53 void Object::render(const ObjectInstance &inst, const Tag &tag) const
54 {
55         const ObjectPass *pass=get_pass(tag);
56         setup_render(pass);
57         render_instance(inst, tag);
58         meshes[0]->draw();
59         finish_render(pass);
60 }
61
62 const ObjectPass *Object::get_pass(const Tag &tag) const
63 {
64         if(technique)
65                 return &technique->get_pass(tag);
66         else if(tag.id==0)
67                 return 0;
68         throw KeyError("Unknown pass");
69 }
70
71 void Object::setup_render(const ObjectPass *pass) const
72 {
73         if(!meshes[0])
74                 throw InvalidState("Trying to render Object without mesh");
75
76         if(pass && pass->shprog)
77         {
78                 pass->shprog->bind();
79                 pass->shdata->apply();
80                 for(unsigned i=0; i<textures.size(); ++i)
81                 {
82                         TexUnit::activate(i);
83                         textures[i]->bind();
84                 }
85         }
86         else if(main_texture && (!pass || pass->use_textures))
87                 main_texture->bind();
88
89         if(material)
90                 material->bind();
91 }
92
93 void Object::finish_render(const ObjectPass *pass) const
94 {
95         if(pass && pass->shprog)
96         {
97                 Program::unbind();
98                 for(unsigned i=textures.size(); i--;)
99                 {
100                         TexUnit::activate(i);
101                         Texture::unbind();
102                 }
103         }
104         else if(main_texture)
105                 Texture::unbind();
106
107         if(material)
108                 Material::unbind();
109 }
110
111 void Object::render_instance(const ObjectInstance &inst, const Tag &tag) const
112 {
113         inst.setup_render(tag);
114         unsigned lod=min(inst.get_level_of_detail(), meshes.size()-1);
115         meshes[lod]->draw();
116         inst.finish_render(tag);
117 }
118
119
120 Object::Loader::Loader(Object &o, Collection &c):
121         obj(o),
122         coll(c)
123 {
124         add("lod_mesh", &Loader::lod_mesh);
125         add("material", &Object::material);
126         add("material_inline", &Loader::material_inline);
127         add("mesh",     &Loader::mesh);
128         add("shader_texture", &Loader::shader_texture);
129         add("technique", &Loader::technique);
130         add("texture",  &Loader::texture);
131 }
132
133 void Object::Loader::finish()
134 {
135         if(obj.technique && !obj.main_texture)
136                 obj.main_texture=obj.technique->get_main_texture();
137         for(unsigned i=0; i<obj.textures.size(); ++i)
138         {
139                 if(!obj.textures[i])
140                 {
141                         obj.textures[i]=obj.technique->get_texture(i);
142                         if(!obj.textures[i])
143                                 throw Exception("Object does not specify all textures required by Technique");
144                 }
145         }
146 }
147
148 void Object::Loader::lod_mesh(unsigned l, const string &n)
149 {
150         obj.meshes.resize(l+1, 0);
151         obj.meshes[l]=coll.get<Mesh>(n);
152 }
153
154 void Object::Loader::material_inline()
155 {
156         RefPtr<Material> mat=new Material;
157         load_sub(*mat);
158         coll.add(format("_%p", mat.get()), mat.get());
159         obj.material=mat.release();
160 }
161
162 void Object::Loader::mesh(const string &n)
163 {
164         obj.meshes[0]=coll.get<Mesh>(n);
165 }
166
167 void Object::Loader::shader_texture(const string &n)
168 {
169         if(!obj.technique)
170                 throw InvalidState("Can't specify shader textures without a Technique");
171
172         unsigned eqsign=n.find('=');
173         if(eqsign==string::npos)
174                 throw InvalidParameterValue("Must specify texture slot name");
175
176         obj.textures[obj.technique->get_texture_index(n.substr(0, eqsign))]=coll.get<Texture>(n.substr(eqsign+1));
177 }
178
179 void Object::Loader::technique(const string &n)
180 {
181         obj.technique=coll.get<Technique>(n);
182         obj.textures.resize(obj.technique->get_n_textures());
183         obj.material=obj.technique->get_material();
184 }
185
186 void Object::Loader::texture(const string &n)
187 {
188         if(obj.main_texture)
189                 throw Exception("Only one main texture may be specified");
190
191         Texture *tex=coll.get<Texture>(n);
192         if(obj.technique)
193                 obj.textures[obj.technique->get_texture_index("texture")]=tex;
194         obj.main_texture=tex;
195 }
196
197 } // namespace GL
198 } // namespace Msp