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