]> git.tdb.fi Git - libs/gl.git/blob - source/renderer.cpp
Unbind Lighting in Renderer destructor
[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 "program.h"
8 #include "programdata.h"
9 #include "renderable.h"
10 #include "renderer.h"
11 #include "texture.h"
12 #include "texturing.h"
13 #include "vertexarray.h"
14 #include "windingtest.h"
15
16 using namespace std;
17
18 namespace Msp {
19 namespace GL {
20
21 Renderer::Renderer(const Camera *c):
22         mtx_stack(*this),
23         mtx_changed(false),
24         camera(c),
25         state_stack(1),
26         lighting_changed(false),
27         vertex_array(0),
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         }
41         else
42                 mtx_stack.load(MatrixStack::modelview().top());
43 }
44
45 Renderer::~Renderer()
46 {
47         if(camera)
48                 MatrixStack::projection().pop();
49         MatrixStack::modelview().pop();
50
51         Texturing::unbind();
52         Texture::unbind_from(0);
53         Material::unbind();
54         Lighting::unbind();
55         Program::unbind();
56         Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
57         WindingTest::unbind();
58 }
59
60 void Renderer::set_texture(const Texture *t)
61 {
62         state->texture = t;
63         state->texturing = 0;
64 }
65
66 void Renderer::set_texturing(const Texturing *t)
67 {
68         state->texturing = t;
69         state->texture = 0;
70 }
71
72 void Renderer::set_material(const Material *m)
73 {
74         state->material = m;
75 }
76
77 void Renderer::set_lighting(const Lighting *l)
78 {
79         state->lighting = l;
80         state->lighting_matrix = mtx_stack.top();
81         lighting_changed = true;
82 }
83
84 void Renderer::set_shader_program(const Program *p, const ProgramData *d)
85 {
86         state->shprog = p;
87         if(p && d)
88                 add_shader_data(*d);
89
90         /* Even if we have no new shdata, the existing ones need to be re-applied
91         to the new program */
92         shdata_changed = true;
93 }
94
95 void Renderer::add_shader_data(const ProgramData &d)
96 {
97         shdata_stack.push_back(&d);
98         state->shdata_count = shdata_stack.size();
99         shdata_changed = true;
100 }
101
102 void Renderer::set_vertex_array(const VertexArray *a)
103 {
104         vertex_array = a;
105 }
106
107 void Renderer::set_element_buffer(const Buffer *b)
108 {
109         element_buffer = b;
110 }
111
112 void Renderer::set_winding_test(const WindingTest *w)
113 {
114         state->winding_test = w;
115 }
116
117 void Renderer::set_reverse_winding(bool r)
118 {
119         state->reverse_winding = r;
120 }
121
122 void Renderer::push_state()
123 {
124         state_stack.push_back(state_stack.back());
125         state = &state_stack.back();
126         mtx_stack.push();
127 }
128
129 void Renderer::pop_state()
130 {
131         if(state_stack.size()==1)
132                 throw stack_underflow("Renderer::pop_state");
133
134         state_stack.pop_back();
135         state = &state_stack.back();
136         if(shdata_stack.size()>state->shdata_count)
137                 shdata_stack.erase(shdata_stack.begin()+state->shdata_count, shdata_stack.end());
138         mtx_stack.pop();
139         mtx_changed = true;
140         shdata_changed = true;
141 }
142
143 void Renderer::escape()
144 {
145         apply_state();
146         Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
147 }
148
149 void Renderer::exclude(const Renderable &renderable)
150 {
151         excluded.insert(&renderable);
152 }
153
154 void Renderer::include(const Renderable &renderable)
155 {
156         excluded.erase(&renderable);
157 }
158
159 void Renderer::render(const Renderable &renderable, const Tag &tag)
160 {
161         if(!excluded.count(&renderable))
162                 renderable.render(*this, tag);
163 }
164
165 void Renderer::draw(const Batch &batch)
166 {
167         if(!vertex_array)
168                 throw invalid_operation("Renderer::draw");
169
170         apply_state();
171
172         vertex_array->apply();
173
174         if(element_buffer)
175                 element_buffer->bind_to(ELEMENT_ARRAY_BUFFER);
176         else
177                 Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
178
179         batch.draw();
180 }
181
182 void Renderer::apply_state()
183 {
184         /* We (mostly) let the objects themselves figure out if the binding has
185         changed */
186
187         if(state->texturing)
188                 state->texturing->bind();
189         else
190         {
191                 Texturing::unbind();
192                 if(state->texture)
193                         state->texture->bind_to(0);
194                 else
195                         Texture::unbind_from(0);
196         }
197
198         if(state->material)
199                 state->material->bind();
200         else
201                 Material::unbind();
202
203         if(lighting_changed)
204         {
205                 if(state->lighting)
206                 {
207                         MatrixStack::modelview() = state->lighting_matrix;
208                         state->lighting->bind();
209                         mtx_changed = true;
210                         lighting_changed = false;
211                 }
212                 else
213                         Lighting::unbind();
214         }
215
216         if(state->shprog)
217         {
218                 state->shprog->bind();
219                 if(shdata_changed)
220                 {
221                         for(vector<const ProgramData *>::const_iterator i=shdata_stack.begin(); i!=shdata_stack.end(); ++i)
222                                 (*i)->apply();
223                         shdata_changed = false;
224                 }
225         }
226         else
227                 Program::unbind();
228
229         if(state->winding_test)
230         {
231                 if(state->reverse_winding)
232                         state->winding_test->get_reverse().bind();
233                 else
234                         state->winding_test->bind();
235         }
236         else
237                 WindingTest::unbind();
238
239         if(mtx_changed)
240         {
241                 MatrixStack::modelview() = mtx_stack.top();
242                 mtx_changed = false;
243         }
244 }
245
246
247 Renderer::State::State():
248         texture(0),
249         texturing(0),
250         material(0),
251         lighting(0),
252         shprog(0),
253         shdata_count(0),
254         winding_test(0)
255 { }
256
257
258 Renderer::MtxStack::MtxStack(Renderer &r):
259         renderer(r)
260 { }
261
262 void Renderer::MtxStack::update()
263 {
264         renderer.mtx_changed = true;
265 }
266
267 } // namespace GL
268 } // namespace Msp