]> git.tdb.fi Git - libs/gl.git/blob - source/render/renderer.cpp
Support inline scenes within other scenes
[libs/gl.git] / source / render / renderer.cpp
1 #include "batch.h"
2 #include "buffer.h"
3 #include "camera.h"
4 #include "error.h"
5 #include "framebuffer.h"
6 #include "lighting.h"
7 #include "material.h"
8 #include "program.h"
9 #include "programdata.h"
10 #include "renderable.h"
11 #include "renderer.h"
12 #include "resourcemanager.h"
13 #include "sampler.h"
14 #include "texture.h"
15 #include "vertexarray.h"
16 #include "vertexsetup.h"
17
18 using namespace std;
19
20 namespace Msp {
21 namespace GL {
22
23 Renderer::Renderer():
24         changed(0)
25 {
26         state_stack.reserve(16);
27         state_stack.push_back(State());
28         shdata_stack.reserve(32);
29         state = &state_stack.back();
30         add_shader_data(standard_shdata);
31 }
32
33 Renderer::~Renderer()
34 {
35         end();
36 }
37
38 void Renderer::set_camera(const Camera &c)
39 {
40         state->camera = &c;
41         add_shader_data(c.get_shader_data());
42         set_matrix(Matrix());
43 }
44
45 void Renderer::set_matrix(const Matrix &matrix)
46 {
47         state->model_matrix = matrix;
48         changed |= MATRIX;
49 }
50
51 void Renderer::transform(const Matrix &matrix)
52 {
53         state->model_matrix *= matrix;
54         changed |= MATRIX;
55 }
56
57 void Renderer::set_framebuffer(const Framebuffer *f)
58 {
59         state->framebuffer = f;
60 }
61
62 void Renderer::set_viewport(const Rect *v)
63 {
64         state->viewport = v;
65 }
66
67 void Renderer::set_scissor(const Rect *s)
68 {
69         state->scissor = s;
70 }
71
72 void Renderer::set_texture(Tag tag, const Texture *tex, const Sampler *samp)
73 {
74         if(tex)
75                 if(ResourceManager *res_mgr = tex->get_manager())
76                         res_mgr->resource_used(*tex);
77
78         if(texture_stack.size()>state->texture_count)
79         {
80                 BoundTexture &bt = texture_stack[state->texture_count];
81                 if(bt.tag==tag && bt.texture==tex && bt.sampler==samp)
82                 {
83                         ++state->texture_count;
84                         return;
85                 }
86                 else
87                         flush_textures();
88         }
89
90         for(auto i=texture_stack.end(); i!=texture_stack.begin(); )
91                 if((--i)->tag==tag)
92                 {
93                         i->replaced = texture_stack.size();
94                         break;
95                 }
96
97         texture_stack.push_back(BoundTexture());
98         BoundTexture &bound_tex = texture_stack.back();
99         bound_tex.tag = tag;
100         bound_tex.texture = tex;
101         bound_tex.sampler = samp;
102         state->texture_count = texture_stack.size();
103 }
104
105 void Renderer::flush_textures()
106 {
107         for(unsigned i=0; i<state->texture_count; ++i)
108                 if(texture_stack[i].replaced>=static_cast<int>(state->texture_count))
109                         texture_stack[i].replaced = -1;
110
111         texture_stack.erase(texture_stack.begin()+state->texture_count, texture_stack.end());
112 }
113
114 void Renderer::set_material(const Material *m)
115 {
116         if(m)
117                 add_shader_data(m->get_shader_data());
118 }
119
120 void Renderer::set_lighting(const Lighting *l)
121 {
122         if(l)
123                 add_shader_data(l->get_shader_data());
124 }
125
126 void Renderer::set_shader_program(const Program *p, const ProgramData *d)
127 {
128         state->shprog = p;
129         if(p && d)
130                 add_shader_data(*d);
131 }
132
133 void Renderer::add_shader_data(const ProgramData &d)
134 {
135         if(state->shdata_count<shdata_stack.size())
136         {
137                 const BoundProgramData &top = shdata_stack.back();
138                 if(top.shdata==&d && top.generation==d.get_generation())
139                 {
140                         ++state->shdata_count;
141                         return;
142                 }
143         }
144
145         flush_shader_data_();
146         shdata_stack.push_back(&d);
147         state->shdata_count = shdata_stack.size();
148         changed |= SHADER_DATA;
149 }
150
151 void Renderer::flush_shader_data_()
152 {
153         if(shdata_stack.size()>state->shdata_count)
154                 shdata_stack.erase(shdata_stack.begin()+state->shdata_count, shdata_stack.end());
155 }
156
157 void Renderer::set_vertex_setup(const VertexSetup *vs)
158 {
159         state->vertex_setup = vs;
160 }
161
162 void Renderer::set_front_face(FaceWinding winding)
163 {
164         state->front_face = winding;
165 }
166
167 void Renderer::set_face_cull(CullMode cull)
168 {
169         state->face_cull = cull;
170 }
171
172 void Renderer::set_depth_test(const DepthTest *dt)
173 {
174         state->depth_test = dt;
175 }
176
177 void Renderer::set_stencil_test(const StencilTest *st)
178 {
179         state->stencil_test = st;
180 }
181
182 void Renderer::set_blend(const Blend *b)
183 {
184         state->blend = b;
185 }
186
187 void Renderer::set_object_lod_bias(unsigned b)
188 {
189         state->object_lod_bias = b;
190 }
191
192 void Renderer::push_state()
193 {
194         state_stack.push_back(state_stack.back());
195         state = &state_stack.back();
196 }
197
198 void Renderer::pop_state()
199 {
200         if(state_stack.size()==1)
201                 throw stack_underflow("Renderer::pop_state");
202
203         state_stack.pop_back();
204         state = &state_stack.back();
205         changed |= MATRIX;
206 }
207
208 void Renderer::end()
209 {
210         if(state_stack.size()>1)
211                 throw invalid_operation("Renderer::end");
212
213         *state = State();
214         shdata_stack.clear();
215         add_shader_data(standard_shdata);
216         excluded.clear();
217
218         commands.use_pipeline(0);
219 }
220
221 void Renderer::exclude(const Renderable &renderable)
222 {
223         excluded.insert(&renderable);
224 }
225
226 void Renderer::include(const Renderable &renderable)
227 {
228         excluded.erase(&renderable);
229 }
230
231 void Renderer::render(const Renderable &renderable, Tag tag)
232 {
233         if(!excluded.count(&renderable))
234                 renderable.render(*this, tag);
235 }
236
237 void Renderer::clear(const ClearValue *values)
238 {
239         pipeline_state.set_framebuffer(state->framebuffer);
240         pipeline_state.set_viewport(state->viewport);
241         pipeline_state.set_scissor(state->scissor);
242         commands.use_pipeline(&pipeline_state);
243         commands.clear(values);
244 }
245
246 void Renderer::draw(const Batch &batch)
247 {
248         apply_state();
249         batch.refresh();
250         commands.use_pipeline(&pipeline_state);
251         commands.draw(batch);
252 }
253
254 void Renderer::draw_instanced(const Batch &batch, unsigned count)
255 {
256         apply_state();
257         batch.refresh();
258         commands.use_pipeline(&pipeline_state);
259         commands.draw_instanced(batch, count);
260 }
261
262 void Renderer::resolve_multisample(Framebuffer &target)
263 {
264         if(!state->framebuffer)
265                 throw invalid_operation("Renderer::resolve_multisample");
266
267         unsigned width = state->framebuffer->get_width();
268         unsigned height = state->framebuffer->get_height();
269         if(target.get_width()!=width || target.get_height()!=height)
270                 throw incompatible_data("Renderer::resolve_multisample");
271
272         pipeline_state.set_framebuffer(state->framebuffer);
273         commands.use_pipeline(&pipeline_state);
274         commands.resolve_multisample(target);
275 }
276
277 void Renderer::begin_query(const QueryPool &pool, unsigned index)
278 {
279         commands.begin_query(pool, index);
280 }
281
282 void Renderer::end_query(const QueryPool &pool, unsigned index)
283 {
284         commands.end_query(pool, index);
285 }
286
287 void Renderer::apply_state()
288 {
289         if(!state->shprog)
290                 throw invalid_operation("Renderer::apply_state");
291
292         if(changed&MATRIX)
293         {
294                 standard_shdata.uniform("world_obj_matrix", state->model_matrix);
295                 LinAl::SquareMatrix<float, 3> nm = state->model_matrix.block<3, 3>(0, 0);
296                 nm = transpose(invert(nm));
297                 standard_shdata.uniform("world_obj_normal_matrix", nm);
298                 changed &= ~MATRIX;
299         }
300
301         pipeline_state.set_framebuffer(state->framebuffer);
302         pipeline_state.set_viewport(state->viewport);
303         pipeline_state.set_scissor(state->scissor);
304
305         bool shprog_changed = (state->shprog!=pipeline_state.get_shader_program());
306         pipeline_state.set_shader_program(state->shprog);
307
308         if(state->vertex_setup)
309         {
310                 if(const VertexArray *array = state->vertex_setup->get_vertex_array())
311                         array->refresh();
312                 if(const VertexArray *array = state->vertex_setup->get_instance_array())
313                         array->refresh();
314         }
315         pipeline_state.set_vertex_setup(state->vertex_setup);
316
317         pipeline_state.set_front_face(state->front_face);
318         pipeline_state.set_face_cull(state->face_cull);
319
320         if(state->texture_count<texture_stack.size())
321                 flush_textures();
322
323         for(const BoundTexture &t: texture_stack)
324         {
325                 int unit = (t.tag.id ? state->shprog->get_uniform_binding(t.tag) : t.unit);
326                 if(unit>=0)
327                         pipeline_state.set_texture(unit, t.texture, t.sampler);
328         }
329
330         bool shdata_changed = changed&SHADER_DATA;
331         for(auto i=shdata_stack.begin(); (!shdata_changed && i!=shdata_stack.end()); ++i)
332                 shdata_changed = (i->shdata->get_generation()!=i->generation);
333         bool extra_shdata = (shdata_stack.size()>state->shdata_count);
334
335         if(shdata_changed || shprog_changed || extra_shdata)
336         {
337                 if(extra_shdata)
338                         shdata_stack.erase(shdata_stack.begin()+state->shdata_count, shdata_stack.end());
339                 for(const BoundProgramData &d: shdata_stack)
340                 {
341                         d.shdata->apply(*state->shprog, pipeline_state);
342                         d.generation = d.shdata->get_generation();
343                 }
344                 changed &= ~SHADER_DATA;
345         }
346
347         pipeline_state.set_depth_test(state->depth_test);
348         pipeline_state.set_stencil_test(state->stencil_test);
349         pipeline_state.set_blend(state->blend);
350 }
351
352
353 Renderer::BoundProgramData::BoundProgramData(const ProgramData *d):
354         shdata(d)
355 { }
356
357 } // namespace GL
358 } // namespace Msp