]> git.tdb.fi Git - libs/gl.git/blob - source/renderer.cpp
Better tracking of Renderer matrix changes
[libs/gl.git] / source / renderer.cpp
1 /* $Id$
2
3 This file is part of libmspgl
4 Copyright © 2011  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <msp/core/except.h>
9 #include "batch.h"
10 #include "buffer.h"
11 #include "camera.h"
12 #include "material.h"
13 #include "program.h"
14 #include "programdata.h"
15 #include "renderer.h"
16 #include "texture.h"
17 #include "texturing.h"
18 #include "vertexarray.h"
19
20 using namespace std;
21
22 namespace Msp {
23 namespace GL {
24
25 Renderer::Renderer(const Camera *c):
26         mtx_stack(*this),
27         mtx_changed(false),
28         camera(c),
29         state_stack(1),
30         state(&state_stack.back()),
31         vertex_array(0),
32         vertex_array_changed(false),
33         element_buffer(0)
34 {
35         MatrixStack::modelview().push();
36         if(camera)
37         {
38                 MatrixStack::projection().push();
39                 camera->apply();
40                 mtx_stack.load(camera->get_matrix());
41         }
42         else
43                 mtx_stack.load(MatrixStack::modelview().top());
44 }
45
46 Renderer::~Renderer()
47 {
48         if(camera)
49                 MatrixStack::projection().pop();
50         MatrixStack::modelview().pop();
51
52         Texturing::unbind();
53         Texture::unbind_from(0);
54         Material::unbind();
55         Program::unbind();
56         Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
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_shader(const Program *p, const ProgramData *d)
77 {
78         state->shprog = p;
79         if(d)
80                 state->shdata.assign(1, d);
81         else
82                 state->shdata.clear();
83 }
84
85 void Renderer::add_shader_data(const ProgramData *d)
86 {
87         if(!state->shprog)
88                 throw InvalidState("No shader program");
89
90         state->shdata.push_back(d);
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::push_state()
105 {
106         state_stack.push_back(state_stack.back());
107         state = &state_stack.back();
108         mtx_stack.push();
109 }
110
111 void Renderer::pop_state()
112 {
113         if(state_stack.size()==1)
114                 throw InvalidState("Can't pop the last state");
115
116         state_stack.pop_back();
117         state = &state_stack.back();
118         mtx_stack.pop();
119         mtx_changed = true;
120 }
121
122 void Renderer::escape()
123 {
124         apply_state();
125         Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
126 }
127
128 void Renderer::draw(const Batch &batch)
129 {
130         if(!vertex_array)
131                 throw InvalidState("Can't draw without a vertex array");
132
133         apply_state();
134
135         // Until VertexArray acquires VAO support and becomes Bindable
136         if(vertex_array_changed)
137                 vertex_array->apply();
138
139         if(element_buffer)
140                 element_buffer->bind_to(ELEMENT_ARRAY_BUFFER);
141         else
142                 Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
143
144         batch.draw();
145 }
146
147 void Renderer::apply_state()
148 {
149         // We let the objects themselves figure out if the binding has changed
150
151         if(state->texturing)
152                 state->texturing->bind();
153         else
154         {
155                 Texturing::unbind();
156                 if(state->texture)
157                         state->texture->bind_to(0);
158                 else
159                         Texture::unbind_from(0);
160         }
161
162         if(state->material)
163                 state->material->bind();
164         else
165                 Material::unbind();
166
167         if(state->shprog)
168         {
169                 state->shprog->bind();
170                 for(vector<const ProgramData *>::const_iterator i=state->shdata.begin(); i!=state->shdata.end(); ++i)
171                         (*i)->apply();
172         }
173         else
174                 Program::unbind();
175
176         if(mtx_changed)
177         {
178                 MatrixStack::modelview() = mtx_stack.top();
179                 mtx_changed = false;
180         }
181 }
182
183
184 Renderer::State::State():
185         texture(0),
186         texturing(0),
187         material(0),
188         shprog(0)
189 { }
190
191
192 Renderer::MtxStack::MtxStack(Renderer &r):
193         renderer(r)
194 { }
195
196 void Renderer::MtxStack::update()
197 {
198         renderer.mtx_changed = true;
199 }
200
201 } // namespace GL
202 } // namespace Msp