]> git.tdb.fi Git - libs/gl.git/blob - source/pipeline.cpp
Use two FBOs in Pipeline when necessary
[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
13 using namespace std;
14
15 namespace Msp {
16 namespace GL {
17
18 Pipeline::Pipeline(unsigned w, unsigned h, bool d):
19         camera(0),
20         width(w),
21         height(h),
22         hdr(d),
23         samples(0),
24         target_ms(0)
25 {
26         target[0] = 0;
27         target[1] = 0;
28 }
29
30 Pipeline::~Pipeline()
31 {
32         delete target[0];
33         delete target[1];
34         delete target_ms;
35 }
36
37 void Pipeline::set_hdr(bool h)
38 {
39         hdr = h;
40         create_targets(true);
41 }
42
43 void Pipeline::set_multisample(unsigned s)
44 {
45         samples = s;
46         create_targets(false);
47 }
48
49 void Pipeline::set_camera(const Camera *c)
50 {
51         camera = c;
52 }
53
54 Pipeline::Pass &Pipeline::add_pass(const Tag &tag)
55 {
56         passes.push_back(Pass(tag));
57         return passes.back();
58 }
59
60 void Pipeline::add_renderable(const Renderable &r)
61 {
62         for(vector<Slot>::iterator i=renderables.begin(); i!=renderables.end(); ++i)
63                 if(i->renderable==&r)
64                 {
65                         i->passes.clear();
66                         return;
67                 }
68
69         renderables.push_back(&r);
70 }
71
72 void Pipeline::add_renderable_for_pass(const Renderable &r, const Tag &tag)
73 {
74         for(vector<Slot>::iterator i=renderables.begin(); i!=renderables.end(); ++i)
75                 if(i->renderable==&r)
76                 {
77                         i->passes.insert(tag);
78                         return;
79                 }
80
81         renderables.push_back(&r);
82         renderables.back().passes.insert(tag);
83 }
84
85 void Pipeline::remove_renderable(const Renderable &r)
86 {
87         for(vector<Slot>::iterator i=renderables.begin(); i!=renderables.end(); ++i)
88                 if(i->renderable==&r)
89                 {
90                         renderables.erase(i);
91                         return;
92                 }
93 }
94
95 void Pipeline::add_postprocessor(PostProcessor &pp)
96 {
97         postproc.push_back(&pp);
98         create_targets(false);
99 }
100
101 void Pipeline::render(const Tag &tag) const
102 {
103         if(tag.id)
104                 return;
105
106         Renderer renderer(camera);
107         render(renderer, tag);
108 }
109
110 void Pipeline::render(Renderer &renderer, const Tag &tag) const
111 {
112         if(tag.id)
113                 return;
114
115         if(target[0])
116         {
117                 Framebuffer &fbo = (samples ? target_ms->fbo : target[0]->fbo);
118                 // XXX exception safety
119                 fbo.bind();
120                 fbo.clear(COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT);
121         }
122
123         for(PassList::const_iterator i=passes.begin(); i!=passes.end(); ++i)
124         {
125                 Bind bind_depth_test(i->get_depth_test());
126                 Bind bind_blend(i->get_blend());
127                 Bind bind_lighting(i->get_lighting());
128
129                 for(vector<Slot>::const_iterator j=renderables.begin(); j!=renderables.end(); ++j)
130                         if(j->passes.empty() || j->passes.count(i->get_tag()))
131                                 j->renderable->render(renderer, i->get_tag());
132         }
133
134         if(target[0])
135         {
136                 if(samples)
137                         target[0]->fbo.blit_from(target_ms->fbo, COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT, false);
138
139                 for(unsigned i=0; i<postproc.size(); ++i)
140                 {
141                         unsigned j = i%2;
142                         if(i+1<postproc.size())
143                                 target[1-j]->fbo.bind();
144                         else
145                                 Framebuffer::unbind();
146                         postproc[i]->render(target[j]->color, target[j]->depth);
147                 }
148
149                 Framebuffer::unbind();
150         }
151 }
152
153 void Pipeline::create_targets(bool recreate)
154 {
155         if(recreate)
156         {
157                 delete target[0];
158                 delete target[1];
159                 delete target_ms;
160                 target[0] = 0;
161                 target[1] = 0;
162                 target_ms = 0;
163         }
164
165         PixelFormat fmt = (hdr ? RGB16F : RGB);
166         if(!target[0])
167                 target[0] = new RenderTarget(width, height, fmt);
168         if(!target[1] && postproc.size()>1)
169                 target[1] = new RenderTarget(width, height, fmt);
170
171         if(!target_ms && samples)
172                 target_ms = new MultisampleTarget(width, height, samples, fmt);
173 }
174
175
176 Pipeline::Pass::Pass(const Tag &t):
177         tag(t),
178         lighting(0),
179         depth_test(0),
180         blend(0)
181 { }
182
183 void Pipeline::Pass::set_lighting(const Lighting *l)
184 {
185         lighting = l;
186 }
187
188 void Pipeline::Pass::set_depth_test(const DepthTest *d)
189 {
190         depth_test = d;
191 }
192
193 void Pipeline::Pass::set_blend(const Blend *b)
194 {
195         blend = b;
196 }
197
198
199 Pipeline::Slot::Slot(const Renderable *r):
200         renderable(r)
201 { }
202
203
204 Pipeline::RenderTarget::RenderTarget(unsigned w, unsigned h, PixelFormat f)
205 {
206         color.set_min_filter(NEAREST);
207         color.set_mag_filter(NEAREST);
208         color.set_wrap(CLAMP_TO_EDGE);
209         color.storage(f, w, h);
210         fbo.attach(COLOR_ATTACHMENT0, color, 0);
211
212         depth.set_min_filter(NEAREST);
213         depth.set_mag_filter(NEAREST);
214         depth.set_wrap(CLAMP_TO_EDGE);
215         depth.storage(DEPTH_COMPONENT, w, h);
216         fbo.attach(DEPTH_ATTACHMENT, depth, 0);
217 }
218
219
220 Pipeline::MultisampleTarget::MultisampleTarget(unsigned w, unsigned h, unsigned s, PixelFormat f)
221 {
222         color.storage_multisample(s, f, w, h);
223         fbo.attach(COLOR_ATTACHMENT0, color);
224
225         depth.storage_multisample(s, DEPTH_COMPONENT, w, h);
226         fbo.attach(DEPTH_ATTACHMENT, depth);
227 }
228
229 } // namespace GL
230 } // namespace Msp