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