]> git.tdb.fi Git - libs/gl.git/blob - source/renderer.cpp
Renderer no longer needs to track vertex array changes
[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         element_buffer(0)
27 {
28         state_stack.reserve(16);
29         shdata_stack.reserve(32);
30         state = &state_stack.back();
31
32         MatrixStack::modelview().push();
33         if(camera)
34         {
35                 MatrixStack::projection().push();
36                 camera->apply();
37                 mtx_stack.load(camera->get_matrix());
38         }
39         else
40                 mtx_stack.load(MatrixStack::modelview().top());
41 }
42
43 Renderer::~Renderer()
44 {
45         if(camera)
46                 MatrixStack::projection().pop();
47         MatrixStack::modelview().pop();
48
49         Texturing::unbind();
50         Texture::unbind_from(0);
51         Material::unbind();
52         Program::unbind();
53         Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
54         WindingTest::unbind();
55 }
56
57 void Renderer::set_texture(const Texture *t)
58 {
59         state->texture = t;
60         state->texturing = 0;
61 }
62
63 void Renderer::set_texturing(const Texturing *t)
64 {
65         state->texturing = t;
66         state->texture = 0;
67 }
68
69 void Renderer::set_material(const Material *m)
70 {
71         state->material = m;
72 }
73
74 void Renderer::set_shader_program(const Program *p, const ProgramData *d)
75 {
76         state->shprog = p;
77         if(p && d)
78                 add_shader_data(*d);
79
80         /* Even if we have no new shdata, the existing ones need to be re-applied
81         to the new program */
82         shdata_changed = true;
83 }
84
85 void Renderer::add_shader_data(const ProgramData &d)
86 {
87         shdata_stack.push_back(&d);
88         state->shdata_count = shdata_stack.size();
89         shdata_changed = true;
90 }
91
92 void Renderer::set_vertex_array(const VertexArray *a)
93 {
94         vertex_array = a;
95 }
96
97 void Renderer::set_element_buffer(const Buffer *b)
98 {
99         element_buffer = b;
100 }
101
102 void Renderer::set_winding_test(const WindingTest *w)
103 {
104         state->winding_test = w;
105 }
106
107 void Renderer::push_state()
108 {
109         state_stack.push_back(state_stack.back());
110         state = &state_stack.back();
111         mtx_stack.push();
112 }
113
114 void Renderer::pop_state()
115 {
116         if(state_stack.size()==1)
117                 throw stack_underflow("Renderer::pop_state");
118
119         state_stack.pop_back();
120         state = &state_stack.back();
121         if(shdata_stack.size()>state->shdata_count)
122                 shdata_stack.erase(shdata_stack.begin()+state->shdata_count, shdata_stack.end());
123         mtx_stack.pop();
124         mtx_changed = true;
125         shdata_changed = true;
126 }
127
128 void Renderer::escape()
129 {
130         apply_state();
131         Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
132 }
133
134 void Renderer::exclude(const Renderable &renderable)
135 {
136         excluded.insert(&renderable);
137 }
138
139 void Renderer::include(const Renderable &renderable)
140 {
141         excluded.erase(&renderable);
142 }
143
144 void Renderer::render(const Renderable &renderable, const Tag &tag)
145 {
146         if(!excluded.count(&renderable))
147                 renderable.render(*this, tag);
148 }
149
150 void Renderer::draw(const Batch &batch)
151 {
152         if(!vertex_array)
153                 throw invalid_operation("Renderer::draw");
154
155         apply_state();
156
157         vertex_array->apply();
158
159         if(element_buffer)
160                 element_buffer->bind_to(ELEMENT_ARRAY_BUFFER);
161         else
162                 Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
163
164         batch.draw();
165 }
166
167 void Renderer::apply_state()
168 {
169         // We let the objects themselves figure out if the binding has changed
170
171         if(state->texturing)
172                 state->texturing->bind();
173         else
174         {
175                 Texturing::unbind();
176                 if(state->texture)
177                         state->texture->bind_to(0);
178                 else
179                         Texture::unbind_from(0);
180         }
181
182         if(state->material)
183                 state->material->bind();
184         else
185                 Material::unbind();
186
187         if(state->shprog)
188         {
189                 state->shprog->bind();
190                 if(shdata_changed)
191                 {
192                         for(vector<const ProgramData *>::const_iterator i=shdata_stack.begin(); i!=shdata_stack.end(); ++i)
193                                 (*i)->apply();
194                         shdata_changed = false;
195                 }
196         }
197         else
198                 Program::unbind();
199
200         if(state->winding_test)
201                 state->winding_test->bind();
202         else
203                 WindingTest::unbind();
204
205         if(mtx_changed)
206         {
207                 MatrixStack::modelview() = mtx_stack.top();
208                 mtx_changed = false;
209         }
210 }
211
212
213 Renderer::State::State():
214         texture(0),
215         texturing(0),
216         material(0),
217         shprog(0),
218         shdata_count(0),
219         winding_test(0)
220 { }
221
222
223 Renderer::MtxStack::MtxStack(Renderer &r):
224         renderer(r)
225 { }
226
227 void Renderer::MtxStack::update()
228 {
229         renderer.mtx_changed = true;
230 }
231
232 } // namespace GL
233 } // namespace Msp