]> git.tdb.fi Git - libs/gl.git/blob - source/pipeline.cpp
Move PipelinePass inside Pipeline and make the data members private
[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         Pass &pass = insert_unique(passes, tag, Pass())->second;
64         pass_order.push_back(tag);
65         return pass;
66 }
67
68 Pipeline::Pass &Pipeline::get_pass(const Tag &tag)
69 {
70         return get_item(passes, tag);
71 }
72
73 const Pipeline::Pass &Pipeline::get_pass(const Tag &tag) const
74 {
75         return get_item(passes, tag);
76 }
77
78 void Pipeline::add_renderable(const Renderable &r)
79 {
80         for(vector<Slot>::iterator i=renderables.begin(); i!=renderables.end(); ++i)
81                 if(i->renderable==&r)
82                 {
83                         i->passes.clear();
84                         return;
85                 }
86
87         renderables.push_back(&r);
88 }
89
90 void Pipeline::add_renderable_for_pass(const Renderable &r, const Tag &tag)
91 {
92         for(vector<Slot>::iterator i=renderables.begin(); i!=renderables.end(); ++i)
93                 if(i->renderable==&r)
94                 {
95                         i->passes.insert(tag);
96                         return;
97                 }
98
99         renderables.push_back(&r);
100         renderables.back().passes.insert(tag);
101 }
102
103 void Pipeline::remove_renderable(const Renderable &r)
104 {
105         for(vector<Slot>::iterator i=renderables.begin(); i!=renderables.end(); ++i)
106                 if(i->renderable==&r)
107                 {
108                         renderables.erase(i);
109                         return;
110                 }
111 }
112
113 void Pipeline::add_postprocessor(PostProcessor &pp)
114 {
115         postproc.push_back(&pp);
116         if(!fbo)
117                 create_fbos();
118         {
119         }
120 }
121
122 void Pipeline::render(Renderer &renderer, const Tag &tag) const
123 {
124         const Pass &pass = get_pass(tag);
125
126         Bind bind_depth_test(pass.get_depth_test());
127         Bind bind_blend(pass.get_blend());
128         Bind bind_lighting(pass.get_lighting());
129
130         for(vector<Slot>::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
131                 if(i->passes.empty() || i->passes.count(tag))
132                         i->renderable->render(renderer, tag);
133 }
134
135 void Pipeline::render_all() const
136 {
137         if(camera)
138                 camera->apply();
139
140         if(fbo)
141         {
142                 Framebuffer *f = (fbo_ms ? fbo_ms : fbo);
143                 f->bind();
144                 f->clear(COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT);
145         }
146
147         Renderer renderer(camera);
148         for(vector<Tag>::const_iterator i=pass_order.begin(); i!=pass_order.end(); ++i)
149                 render(renderer, *i);
150
151         if(fbo)
152         {
153                 if(fbo_ms)
154                         fbo->blit_from(*fbo_ms, COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT, false);
155                 Framebuffer::unbind();
156         }
157
158         // XXX Need two color buffer textures to handle multiple post-processors correctly
159         for(vector<PostProcessor *>::const_iterator i=postproc.begin(); i!=postproc.end(); ++i)
160                 (*i)->render(*color_buf, *depth_buf);
161 }
162
163 void Pipeline::create_fbos()
164 {
165         delete fbo;
166         delete color_buf;
167         delete depth_buf;
168
169         delete fbo_ms;
170         fbo_ms = 0;
171         delete color_buf_ms;
172         color_buf_ms = 0;
173         delete depth_buf_ms;
174         depth_buf_ms = 0;
175
176         fbo = new Framebuffer;
177
178         color_buf = new Texture2D;
179         color_buf->set_min_filter(NEAREST);
180         color_buf->set_mag_filter(NEAREST);
181         color_buf->set_wrap(CLAMP_TO_EDGE);
182         color_buf->storage((hdr ? RGB16F : RGB), width, height);
183         fbo->attach(COLOR_ATTACHMENT0, *color_buf, 0);
184
185         depth_buf = new Texture2D;
186         depth_buf->set_min_filter(NEAREST);
187         depth_buf->set_mag_filter(NEAREST);
188         depth_buf->set_wrap(CLAMP_TO_EDGE);
189         depth_buf->storage(DEPTH_COMPONENT, width, height);
190         fbo->attach(DEPTH_ATTACHMENT, *depth_buf, 0);
191
192         if(samples)
193         {
194                 fbo_ms = new Framebuffer;
195
196                 color_buf_ms = new Renderbuffer;
197                 color_buf_ms->storage_multisample(samples, (hdr ? RGB16F : RGB), width, height);
198                 fbo_ms->attach(COLOR_ATTACHMENT0, *color_buf_ms);
199
200                 depth_buf_ms = new Renderbuffer;
201                 depth_buf_ms->storage_multisample(samples, DEPTH_COMPONENT, width, height);
202                 fbo_ms->attach(DEPTH_ATTACHMENT, *depth_buf_ms);
203         }
204 }
205
206
207 Pipeline::Pass::Pass():
208         lighting(0),
209         depth_test(0),
210         blend(0)
211 { }
212
213 void Pipeline::Pass::set_lighting(const Lighting *l)
214 {
215         lighting = l;
216 }
217
218 void Pipeline::Pass::set_depth_test(const DepthTest *d)
219 {
220         depth_test = d;
221 }
222
223 void Pipeline::Pass::set_blend(const Blend *b)
224 {
225         blend = b;
226 }
227
228
229 Pipeline::Slot::Slot(const Renderable *r):
230         renderable(r)
231 { }
232
233 } // namespace GL
234 } // namespace Msp