]> git.tdb.fi Git - libs/gl.git/blob - source/renderer.cpp
Add missing initializer
[libs/gl.git] / source / renderer.cpp
1 #include "batch.h"
2 #include "buffer.h"
3 #include "camera.h"
4 #include "error.h"
5 #include "lighting.h"
6 #include "material.h"
7 #include "mesh.h"
8 #include "program.h"
9 #include "programdata.h"
10 #include "renderable.h"
11 #include "renderer.h"
12 #include "texture.h"
13 #include "texturing.h"
14 #include "vertexarray.h"
15 #include "windingtest.h"
16
17 using namespace std;
18
19 namespace Msp {
20 namespace GL {
21
22 Renderer::Renderer(const Camera *c):
23         mtx_stack(*this),
24         mtx_changed(false),
25         camera(c),
26         state_stack(1),
27         lighting_changed(false),
28         element_buffer(0)
29 {
30         state_stack.reserve(16);
31         shdata_stack.reserve(32);
32         state = &state_stack.back();
33
34         MatrixStack::modelview().push();
35         if(camera)
36         {
37                 MatrixStack::projection().push();
38                 camera->apply();
39                 mtx_stack.load(camera->get_matrix());
40                 standard_shdata.uniform("projection_matrix", camera->get_projection_matrix());
41         }
42         else
43         {
44                 standard_shdata.uniform("projection_matrix", MatrixStack::projection().top());
45                 mtx_stack.load(MatrixStack::modelview().top());
46         }
47 }
48
49 Renderer::~Renderer()
50 {
51         if(camera)
52                 MatrixStack::projection().pop();
53         MatrixStack::modelview().pop();
54
55         Mesh::unbind();
56         Texturing::unbind();
57         Texture::unbind_from(0);
58         Material::unbind();
59         Lighting::unbind();
60         Program::unbind();
61         Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
62         WindingTest::unbind();
63 }
64
65 void Renderer::set_texture(const Texture *t)
66 {
67         state->texture = t;
68         state->texturing = 0;
69 }
70
71 void Renderer::set_texturing(const Texturing *t)
72 {
73         state->texturing = t;
74         state->texture = 0;
75 }
76
77 void Renderer::set_material(const Material *m)
78 {
79         state->material = m;
80 }
81
82 void Renderer::set_lighting(const Lighting *l)
83 {
84         state->lighting = l;
85         state->lighting_matrix = mtx_stack.top();
86         if(l)
87                 /* XXX I'm not happy with this, but can't come up with anything better
88                 right now. */
89                 const_cast<Lighting *>(l)->update_shader_data(mtx_stack.top());
90         lighting_changed = true;
91 }
92
93 void Renderer::set_shader_program(const Program *p, const ProgramData *d)
94 {
95         state->shprog = p;
96         if(p && d)
97                 add_shader_data(*d);
98
99         /* Even if we have no new shdata, the existing ones need to be re-applied
100         to the new program */
101         shdata_changed = true;
102 }
103
104 void Renderer::add_shader_data(const ProgramData &d)
105 {
106         shdata_stack.push_back(&d);
107         state->shdata_count = shdata_stack.size();
108         shdata_changed = true;
109 }
110
111 void Renderer::set_mesh(const Mesh *m)
112 {
113         state->mesh = m;
114 }
115
116 void Renderer::set_element_buffer(const Buffer *b)
117 {
118         element_buffer = b;
119 }
120
121 void Renderer::set_winding_test(const WindingTest *w)
122 {
123         state->winding_test = w;
124 }
125
126 void Renderer::set_reverse_winding(bool r)
127 {
128         state->reverse_winding = r;
129 }
130
131 void Renderer::push_state()
132 {
133         state_stack.push_back(state_stack.back());
134         state = &state_stack.back();
135         mtx_stack.push();
136 }
137
138 void Renderer::pop_state()
139 {
140         if(state_stack.size()==1)
141                 throw stack_underflow("Renderer::pop_state");
142
143         state_stack.pop_back();
144         state = &state_stack.back();
145         if(shdata_stack.size()>state->shdata_count)
146                 shdata_stack.erase(shdata_stack.begin()+state->shdata_count, shdata_stack.end());
147         mtx_stack.pop();
148         mtx_changed = true;
149         shdata_changed = true;
150 }
151
152 void Renderer::escape()
153 {
154         apply_state();
155         Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
156 }
157
158 void Renderer::exclude(const Renderable &renderable)
159 {
160         excluded.insert(&renderable);
161 }
162
163 void Renderer::include(const Renderable &renderable)
164 {
165         excluded.erase(&renderable);
166 }
167
168 void Renderer::render(const Renderable &renderable, const Tag &tag)
169 {
170         if(!excluded.count(&renderable))
171                 renderable.render(*this, tag);
172 }
173
174 void Renderer::draw(const Batch &batch)
175 {
176         apply_state();
177
178         bool legacy_bindings = (!state->shprog || state->shprog->uses_legacy_variables());
179         if(legacy_bindings)
180         {
181                 if(element_buffer)
182                         element_buffer->bind_to(ELEMENT_ARRAY_BUFFER);
183                 else
184                         Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
185         }
186
187         batch.draw();
188 }
189
190 void Renderer::apply_state()
191 {
192         /* We (mostly) let the objects themselves figure out if the binding has
193         changed */
194
195         bool legacy_bindings = (!state->shprog || state->shprog->uses_legacy_variables());
196
197         if(state->texturing)
198                 state->texturing->bind();
199         else
200         {
201                 Texturing::unbind();
202                 if(state->texture)
203                         state->texture->bind_to(0);
204                 else
205                         Texture::unbind_from(0);
206         }
207
208         if(legacy_bindings)
209         {
210                 if(state->material)
211                         state->material->bind();
212                 else
213                         Material::unbind();
214
215                 if(lighting_changed)
216                 {
217                         if(state->lighting)
218                         {
219                                 MatrixStack::modelview() = state->lighting_matrix;
220                                 state->lighting->bind();
221                                 mtx_changed = true;
222                                 lighting_changed = false;
223                         }
224                         else
225                                 Lighting::unbind();
226                 }
227         }
228
229         if(state->shprog)
230         {
231                 state->shprog->bind();
232
233                 if(!legacy_bindings)
234                 {
235                         const Matrix &m = mtx_stack.top();
236                         standard_shdata.uniform("eye_obj_matrix", mtx_stack.top());
237                         LinAl::SquareMatrix<float, 3> nm;
238                         for(unsigned i=0; i<3; ++i)
239                                 for(unsigned j=0; j<3; ++j)
240                                         nm(i, j) = m(i, j);
241                         nm = transpose(invert(nm));
242                         standard_shdata.uniform_matrix3("eye_obj_normal_matrix", &nm(0, 0));
243                         if(state->lighting)
244                                 state->lighting->get_shader_data().apply();
245                         if(state->material)
246                                 state->material->get_shader_data().apply();
247                         standard_shdata.apply();
248                 }
249
250                 if(shdata_changed)
251                 {
252                         for(vector<const ProgramData *>::const_iterator i=shdata_stack.begin(); i!=shdata_stack.end(); ++i)
253                                 (*i)->apply();
254                         shdata_changed = false;
255                 }
256         }
257         else
258                 Program::unbind();
259
260         if(state->mesh)
261         {
262                 if(legacy_bindings)
263                 {
264                         Mesh::unbind();
265                         state->mesh->get_vertices().apply();
266                 }
267                 else
268                         state->mesh->bind();
269         }
270         else
271                 Mesh::unbind();
272
273         if(state->winding_test)
274         {
275                 if(state->reverse_winding)
276                         state->winding_test->get_reverse().bind();
277                 else
278                         state->winding_test->bind();
279         }
280         else
281                 WindingTest::unbind();
282
283         if(legacy_bindings && mtx_changed)
284         {
285                 MatrixStack::modelview() = mtx_stack.top();
286                 mtx_changed = false;
287         }
288 }
289
290
291 Renderer::State::State():
292         texture(0),
293         texturing(0),
294         material(0),
295         lighting(0),
296         shprog(0),
297         shdata_count(0),
298         mesh(0),
299         winding_test(0),
300         reverse_winding(false)
301 { }
302
303
304 Renderer::MtxStack::MtxStack(Renderer &r):
305         renderer(r)
306 { }
307
308 void Renderer::MtxStack::update()
309 {
310         renderer.mtx_changed = true;
311 }
312
313 } // namespace GL
314 } // namespace Msp