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