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