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