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