]> git.tdb.fi Git - libs/gl.git/blob - source/renderer.cpp
Remove vertex array tracking from Renderer
[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         element_buffer(0)
28 {
29         state_stack.reserve(16);
30         shdata_stack.reserve(32);
31         state = &state_stack.back();
32
33         MatrixStack::modelview().push();
34         if(camera)
35         {
36                 MatrixStack::projection().push();
37                 camera->apply();
38                 mtx_stack.load(camera->get_matrix());
39         }
40         else
41                 mtx_stack.load(MatrixStack::modelview().top());
42 }
43
44 Renderer::~Renderer()
45 {
46         if(camera)
47                 MatrixStack::projection().pop();
48         MatrixStack::modelview().pop();
49
50         Texturing::unbind();
51         Texture::unbind_from(0);
52         Material::unbind();
53         Lighting::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_element_buffer(const Buffer *b)
102 {
103         element_buffer = b;
104 }
105
106 void Renderer::set_winding_test(const WindingTest *w)
107 {
108         state->winding_test = w;
109 }
110
111 void Renderer::set_reverse_winding(bool r)
112 {
113         state->reverse_winding = r;
114 }
115
116 void Renderer::push_state()
117 {
118         state_stack.push_back(state_stack.back());
119         state = &state_stack.back();
120         mtx_stack.push();
121 }
122
123 void Renderer::pop_state()
124 {
125         if(state_stack.size()==1)
126                 throw stack_underflow("Renderer::pop_state");
127
128         state_stack.pop_back();
129         state = &state_stack.back();
130         if(shdata_stack.size()>state->shdata_count)
131                 shdata_stack.erase(shdata_stack.begin()+state->shdata_count, shdata_stack.end());
132         mtx_stack.pop();
133         mtx_changed = true;
134         shdata_changed = true;
135 }
136
137 void Renderer::escape()
138 {
139         apply_state();
140         Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
141 }
142
143 void Renderer::exclude(const Renderable &renderable)
144 {
145         excluded.insert(&renderable);
146 }
147
148 void Renderer::include(const Renderable &renderable)
149 {
150         excluded.erase(&renderable);
151 }
152
153 void Renderer::render(const Renderable &renderable, const Tag &tag)
154 {
155         if(!excluded.count(&renderable))
156                 renderable.render(*this, tag);
157 }
158
159 void Renderer::draw(const Batch &batch)
160 {
161         apply_state();
162
163         if(element_buffer)
164                 element_buffer->bind_to(ELEMENT_ARRAY_BUFFER);
165         else
166                 Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
167
168         batch.draw();
169 }
170
171 void Renderer::apply_state()
172 {
173         /* We (mostly) let the objects themselves figure out if the binding has
174         changed */
175
176         if(state->texturing)
177                 state->texturing->bind();
178         else
179         {
180                 Texturing::unbind();
181                 if(state->texture)
182                         state->texture->bind_to(0);
183                 else
184                         Texture::unbind_from(0);
185         }
186
187         if(state->material)
188                 state->material->bind();
189         else
190                 Material::unbind();
191
192         if(lighting_changed)
193         {
194                 if(state->lighting)
195                 {
196                         MatrixStack::modelview() = state->lighting_matrix;
197                         state->lighting->bind();
198                         mtx_changed = true;
199                         lighting_changed = false;
200                 }
201                 else
202                         Lighting::unbind();
203         }
204
205         if(state->shprog)
206         {
207                 state->shprog->bind();
208                 if(shdata_changed)
209                 {
210                         for(vector<const ProgramData *>::const_iterator i=shdata_stack.begin(); i!=shdata_stack.end(); ++i)
211                                 (*i)->apply();
212                         shdata_changed = false;
213                 }
214         }
215         else
216                 Program::unbind();
217
218         if(state->winding_test)
219         {
220                 if(state->reverse_winding)
221                         state->winding_test->get_reverse().bind();
222                 else
223                         state->winding_test->bind();
224         }
225         else
226                 WindingTest::unbind();
227
228         if(mtx_changed)
229         {
230                 MatrixStack::modelview() = mtx_stack.top();
231                 mtx_changed = false;
232         }
233 }
234
235
236 Renderer::State::State():
237         texture(0),
238         texturing(0),
239         material(0),
240         lighting(0),
241         shprog(0),
242         shdata_count(0),
243         winding_test(0)
244 { }
245
246
247 Renderer::MtxStack::MtxStack(Renderer &r):
248         renderer(r)
249 { }
250
251 void Renderer::MtxStack::update()
252 {
253         renderer.mtx_changed = true;
254 }
255
256 } // namespace GL
257 } // namespace Msp