]> git.tdb.fi Git - libs/gl.git/blob - source/renderer.cpp
Avoid re-applying shader data unnecessarily
[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 "renderer.h"
9 #include "texture.h"
10 #include "texturing.h"
11 #include "vertexarray.h"
12 #include "windingtest.h"
13
14 using namespace std;
15
16 namespace Msp {
17 namespace GL {
18
19 Renderer::Renderer(const Camera *c):
20         mtx_stack(*this),
21         mtx_changed(false),
22         camera(c),
23         state_stack(1),
24         state(&state_stack.back()),
25         vertex_array(0),
26         vertex_array_changed(false),
27         element_buffer(0)
28 {
29         MatrixStack::modelview().push();
30         if(camera)
31         {
32                 MatrixStack::projection().push();
33                 camera->apply();
34                 mtx_stack.load(camera->get_matrix());
35         }
36         else
37                 mtx_stack.load(MatrixStack::modelview().top());
38 }
39
40 Renderer::~Renderer()
41 {
42         if(camera)
43                 MatrixStack::projection().pop();
44         MatrixStack::modelview().pop();
45
46         Texturing::unbind();
47         Texture::unbind_from(0);
48         Material::unbind();
49         Program::unbind();
50         Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
51         WindingTest::unbind();
52 }
53
54 void Renderer::set_texture(const Texture *t)
55 {
56         state->texture = t;
57         state->texturing = 0;
58 }
59
60 void Renderer::set_texturing(const Texturing *t)
61 {
62         state->texturing = t;
63         state->texture = 0;
64 }
65
66 void Renderer::set_material(const Material *m)
67 {
68         state->material = m;
69 }
70
71 void Renderer::set_shader(const Program *p, const ProgramData *d)
72 {
73         state->shprog = p;
74         if(d)
75                 state->shdata.assign(1, d);
76         else
77                 state->shdata.clear();
78         shdata_changed = true;
79 }
80
81 void Renderer::add_shader_data(const ProgramData *d)
82 {
83         if(!state->shprog)
84                 throw invalid_operation("Renderer::add_shader_data");
85
86         state->shdata.push_back(d);
87         shdata_changed = true;
88 }
89
90 void Renderer::set_vertex_array(const VertexArray *a)
91 {
92         vertex_array_changed = (a!=vertex_array);
93         vertex_array = a;
94 }
95
96 void Renderer::set_element_buffer(const Buffer *b)
97 {
98         element_buffer = b;
99 }
100
101 void Renderer::set_winding_test(const WindingTest *w)
102 {
103         state->winding_test = w;
104 }
105
106 void Renderer::push_state()
107 {
108         state_stack.push_back(state_stack.back());
109         state = &state_stack.back();
110         mtx_stack.push();
111 }
112
113 void Renderer::pop_state()
114 {
115         if(state_stack.size()==1)
116                 throw stack_underflow("Renderer::pop_state");
117
118         state_stack.pop_back();
119         state = &state_stack.back();
120         mtx_stack.pop();
121         mtx_changed = true;
122         shdata_changed = true;
123 }
124
125 void Renderer::escape()
126 {
127         apply_state();
128         Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
129 }
130
131 void Renderer::draw(const Batch &batch)
132 {
133         if(!vertex_array)
134                 throw invalid_operation("Renderer::draw");
135
136         apply_state();
137
138         // Until VertexArray acquires VAO support and becomes Bindable
139         if(vertex_array_changed)
140         {
141                 vertex_array->apply();
142                 vertex_array_changed = false;
143         }
144
145         if(element_buffer)
146                 element_buffer->bind_to(ELEMENT_ARRAY_BUFFER);
147         else
148                 Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
149
150         batch.draw();
151 }
152
153 void Renderer::apply_state()
154 {
155         // We let the objects themselves figure out if the binding has changed
156
157         if(state->texturing)
158                 state->texturing->bind();
159         else
160         {
161                 Texturing::unbind();
162                 if(state->texture)
163                         state->texture->bind_to(0);
164                 else
165                         Texture::unbind_from(0);
166         }
167
168         if(state->material)
169                 state->material->bind();
170         else
171                 Material::unbind();
172
173         if(state->shprog)
174         {
175                 state->shprog->bind();
176                 if(shdata_changed)
177                 {
178                         for(vector<const ProgramData *>::const_iterator i=state->shdata.begin(); i!=state->shdata.end(); ++i)
179                                 (*i)->apply();
180                         shdata_changed = false;
181                 }
182         }
183         else
184                 Program::unbind();
185
186         if(state->winding_test)
187                 state->winding_test->bind();
188         else
189                 WindingTest::unbind();
190
191         if(mtx_changed)
192         {
193                 MatrixStack::modelview() = mtx_stack.top();
194                 mtx_changed = false;
195         }
196 }
197
198
199 Renderer::State::State():
200         texture(0),
201         texturing(0),
202         material(0),
203         shprog(0),
204         winding_test(0)
205 { }
206
207
208 Renderer::MtxStack::MtxStack(Renderer &r):
209         renderer(r)
210 { }
211
212 void Renderer::MtxStack::update()
213 {
214         renderer.mtx_changed = true;
215 }
216
217 } // namespace GL
218 } // namespace Msp