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