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