]> git.tdb.fi Git - libs/gl.git/blob - source/pipeline.cpp
Add a constructor to Pipeline which takes the size from a View
[libs/gl.git] / source / pipeline.cpp
1 #include <msp/core/maputils.h>
2 #include "blend.h"
3 #include "camera.h"
4 #include "framebuffer.h"
5 #include "lighting.h"
6 #include "pipeline.h"
7 #include "postprocessor.h"
8 #include "renderbuffer.h"
9 #include "renderer.h"
10 #include "tests.h"
11 #include "texture2d.h"
12 #include "view.h"
13
14 using namespace std;
15
16 namespace Msp {
17 namespace GL {
18
19 Pipeline::Pipeline(unsigned w, unsigned h, bool d)
20 {
21         init(w, h);
22         hdr = d;
23 }
24
25 Pipeline::Pipeline(const View &view)
26 {
27         init(view.get_width(), view.get_height());
28 }
29
30 void Pipeline::init(unsigned w, unsigned h)
31 {
32         camera = 0;
33         width = w;
34         height = h;
35         hdr = false;
36         samples = 0;
37         target_ms = 0;
38         target[0] = 0;
39         target[1] = 0;
40 }
41
42 Pipeline::~Pipeline()
43 {
44         delete target[0];
45         delete target[1];
46         delete target_ms;
47 }
48
49 void Pipeline::set_hdr(bool h)
50 {
51         if(h==hdr)
52                 return;
53
54         bool old_hdr= hdr;
55         hdr = h;
56         try
57         {
58                 create_targets(2);
59         }
60         catch(...)
61         {
62                 hdr = old_hdr;
63                 throw;
64         }
65 }
66
67 void Pipeline::set_multisample(unsigned s)
68 {
69         if(s==samples)
70                 return;
71
72         unsigned old_samples = samples;
73         samples = s;
74         try
75         {
76                 create_targets(1);
77         }
78         catch(...)
79         {
80                 samples = old_samples;
81                 throw;
82         }
83 }
84
85 void Pipeline::set_camera(const Camera *c)
86 {
87         camera = c;
88 }
89
90 Pipeline::Pass &Pipeline::add_pass(const Tag &tag)
91 {
92         passes.push_back(Pass(tag, 0));
93         return passes.back();
94 }
95
96 void Pipeline::add_renderable(Renderable &r)
97 {
98         for(vector<Slot>::iterator i=renderables.begin(); i!=renderables.end(); ++i)
99                 if(i->renderable==&r)
100                 {
101                         i->passes.clear();
102                         return;
103                 }
104
105         renderables.push_back(&r);
106 }
107
108 void Pipeline::add_renderable_for_pass(Renderable &r, const Tag &tag)
109 {
110         for(vector<Slot>::iterator i=renderables.begin(); i!=renderables.end(); ++i)
111                 if(i->renderable==&r)
112                 {
113                         i->passes.insert(tag);
114                         return;
115                 }
116
117         renderables.push_back(&r);
118         renderables.back().passes.insert(tag);
119 }
120
121 void Pipeline::remove_renderable(Renderable &r)
122 {
123         for(vector<Slot>::iterator i=renderables.begin(); i!=renderables.end(); ++i)
124                 if(i->renderable==&r)
125                 {
126                         renderables.erase(i);
127                         return;
128                 }
129 }
130
131 Pipeline::Pass &Pipeline::add_pass(const Tag &tag, Renderable &r)
132 {
133         passes.push_back(Pass(tag, &r));
134         return passes.back();
135 }
136
137 void Pipeline::add_postprocessor(PostProcessor &pp)
138 {
139         postproc.push_back(&pp);
140         try
141         {
142                 create_targets(0);
143         }
144         catch(...)
145         {
146                 postproc.pop_back();
147                 throw;
148         }
149 }
150
151 void Pipeline::setup_frame(Renderer &renderer)
152 {
153         for(PassList::const_iterator i=passes.begin(); i!=passes.end(); ++i)
154                 if(Renderable *renderable = i->get_renderable())
155                         renderable->setup_frame(renderer);
156         for(vector<Slot>::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
157                 i->renderable->setup_frame(renderer);
158 }
159
160 void Pipeline::finish_frame()
161 {
162         for(PassList::const_iterator i=passes.begin(); i!=passes.end(); ++i)
163                 if(Renderable *renderable = i->get_renderable())
164                         renderable->finish_frame();
165         for(vector<Slot>::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
166                 i->renderable->finish_frame();
167 }
168
169 void Pipeline::render()
170 {
171         Renderer renderer(camera);
172         setup_frame(renderer);
173         render(renderer);
174         finish_frame();
175 }
176
177 void Pipeline::render(Renderer &renderer, const Tag &tag) const
178 {
179         if(tag.id)
180                 return;
181
182         const Framebuffer *out_fbo = Framebuffer::current();
183         // These is a no-ops but will ensure the related state gets restored
184         BindRestore restore_fbo(out_fbo);
185         BindRestore restore_depth_test(DepthTest::current());
186         BindRestore restore_blend(Blend::current());
187
188         if(target[0])
189         {
190                 Framebuffer &fbo = (samples ? target_ms : target[0])->get_framebuffer();
191                 fbo.bind();
192                 fbo.clear(COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT);
193         }
194
195
196         for(PassList::const_iterator i=passes.begin(); i!=passes.end(); ++i)
197         {
198                 if(const DepthTest *dt = i->get_depth_test())
199                         dt->bind();
200                 else
201                         DepthTest::unbind();
202
203                 if(const Blend *b = i->get_blend())
204                         b->bind();
205                 else
206                         Blend::unbind();
207
208                 renderer.set_lighting(i->get_lighting());
209                 renderer.set_clipping(i->get_clipping());
210
211                 if(const Renderable *renderable = i->get_renderable())
212                         renderer.render(*renderable, i->get_tag());
213
214                 for(vector<Slot>::const_iterator j=renderables.begin(); j!=renderables.end(); ++j)
215                         if(j->passes.empty() || j->passes.count(i->get_tag()))
216                                 renderer.render(*j->renderable, i->get_tag());
217         }
218
219         if(target[0])
220         {
221                 DepthTest::unbind();
222                 Blend::unbind();
223
224                 if(samples)
225                         target[0]->blit_from(*target_ms);
226
227                 for(unsigned i=0; i<postproc.size(); ++i)
228                 {
229                         unsigned j = i%2;
230                         if(i+1<postproc.size())
231                                 target[1-j]->get_framebuffer().bind();
232                         else
233                                 out_fbo->bind();
234                         const Texture2D &color = target[j]->get_target_texture(RENDER_COLOR);
235                         const Texture2D &depth = target[j]->get_target_texture(RENDER_DEPTH);
236                         postproc[i]->render(renderer, color, depth);
237                 }
238         }
239 }
240
241 void Pipeline::create_targets(unsigned recreate)
242 {
243         if(recreate>=2)
244         {
245                 delete target[0];
246                 delete target[1];
247                 target[0] = 0;
248                 target[1] = 0;
249         }
250         if(recreate>=1)
251         {
252                 delete target_ms;
253                 target_ms = 0;
254         }
255
256         PixelFormat color_pf = (hdr ? RGB16F : RGB);
257         RenderTargetFormat fmt = (RENDER_COLOR,color_pf, RENDER_DEPTH);
258         if(!postproc.empty() || samples)
259         {
260                 if(!target[0])
261                         target[0] = new RenderTarget(width, height, fmt);
262                 if(!target[1] && postproc.size()>1)
263                         target[1] = new RenderTarget(width, height, fmt);
264         }
265
266         if(!target_ms && samples)
267                 target_ms = new RenderTarget(width, height, samples, fmt);
268 }
269
270
271 Pipeline::Pass::Pass(const Tag &t, Renderable *r):
272         tag(t),
273         lighting(0),
274         depth_test(0),
275         blend(0),
276         clipping(0),
277         renderable(r)
278 { }
279
280 void Pipeline::Pass::set_lighting(const Lighting *l)
281 {
282         lighting = l;
283 }
284
285 void Pipeline::Pass::set_depth_test(const DepthTest *d)
286 {
287         depth_test = d;
288 }
289
290 void Pipeline::Pass::set_blend(const Blend *b)
291 {
292         blend = b;
293 }
294
295 void Pipeline::Pass::set_clipping(const Clipping *c)
296 {
297         clipping =c;
298 }
299
300
301 Pipeline::Slot::Slot(Renderable *r):
302         renderable(r)
303 { }
304
305 } // namespace GL
306 } // namespace Msp