]> git.tdb.fi Git - libs/gl.git/blob - source/object.cpp
Add class Technique to share passes between Objects
[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         for(unsigned i=0; i<obj.textures.size(); ++i)
136         {
137                 if(!obj.textures[i])
138                 {
139                         obj.textures[i]=obj.technique->get_texture(i);
140                         if(!obj.textures[i])
141                                 throw Exception("Object does not specify all textures required by Technique");
142                 }
143         }
144 }
145
146 void Object::Loader::lod_mesh(unsigned l, const string &n)
147 {
148         obj.meshes.resize(l+1, 0);
149         obj.meshes[l]=coll.get<Mesh>(n);
150 }
151
152 void Object::Loader::material_inline()
153 {
154         RefPtr<Material> mat=new Material;
155         load_sub(*mat);
156         coll.add(format("_%p", mat.get()), mat.get());
157         obj.material=mat.release();
158 }
159
160 void Object::Loader::mesh(const string &n)
161 {
162         obj.meshes[0]=coll.get<Mesh>(n);
163 }
164
165 void Object::Loader::shader_texture(const string &n)
166 {
167         if(!obj.technique)
168                 throw InvalidState("Can't specify shader textures without a Technique");
169
170         unsigned eqsign=n.find('=');
171         if(eqsign==string::npos)
172                 throw InvalidParameterValue("Must specify texture slot name");
173
174         obj.textures[obj.technique->get_texture_index(n.substr(0, eqsign))]=coll.get<Texture>(n.substr(eqsign+1));
175 }
176
177 void Object::Loader::technique(const string &n)
178 {
179         obj.technique=coll.get<Technique>(n);
180         obj.textures.resize(obj.technique->get_n_textures());
181         obj.material=obj.technique->get_material();
182 }
183
184 void Object::Loader::texture(const string &n)
185 {
186         if(obj.main_texture)
187                 throw Exception("Only one main texture may be specified");
188
189         Texture *tex=coll.get<Texture>(n);
190         if(obj.technique)
191                 obj.textures[obj.technique->get_texture_index("texture")]=tex;
192         obj.main_texture=tex;
193 }
194
195 } // namespace GL
196 } // namespace Msp