]> git.tdb.fi Git - libs/gl.git/blob - source/pipeline.cpp
Add a rendering supervisor class
[libs/gl.git] / source / pipeline.cpp
1 /* $Id$
2
3 This file is part of libmspgl
4 Copyright © 2009-2011  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include "blend.h"
9 #include "camera.h"
10 #include "effect.h"
11 #include "except.h"
12 #include "framebuffer.h"
13 #include "lighting.h"
14 #include "pipeline.h"
15 #include "postprocessor.h"
16 #include "renderbuffer.h"
17 #include "renderer.h"
18 #include "tests.h"
19 #include "texture2d.h"
20
21 using namespace std;
22
23 namespace Msp {
24 namespace GL {
25
26 Pipeline::Pipeline(unsigned w, unsigned h, bool d):
27         camera(0),
28         width(w),
29         height(h),
30         hdr(d),
31         fbo(0),
32         color_buf(0),
33         depth_buf(0)
34 { }
35
36 Pipeline::~Pipeline()
37 {
38         delete fbo;
39         delete color_buf;
40         delete depth_buf;
41 }
42
43 void Pipeline::set_camera(const Camera *c)
44 {
45         camera = c;
46 }
47
48 PipelinePass &Pipeline::add_pass(const Tag &tag)
49 {
50         if(passes.count(tag))
51                 throw KeyError("Pass already exists");
52
53         PipelinePass &pass = passes[tag];
54         pass_order.push_back(tag);
55         return pass;
56 }
57
58 PipelinePass &Pipeline::get_pass(const Tag &tag)
59 {
60         PassMap::iterator i = passes.find(tag);
61         if(i==passes.end())
62                 throw KeyError("Unknown pass");
63         return i->second;
64 }
65
66 const PipelinePass &Pipeline::get_pass(const Tag &tag) const
67 {
68         PassMap::const_iterator i = passes.find(tag);
69         if(i==passes.end())
70                 throw KeyError("Unknown pass");
71         return i->second;
72 }
73
74 void Pipeline::add_renderable(const Renderable &r)
75 {
76         for(vector<Slot>::iterator i=renderables.begin(); i!=renderables.end(); ++i)
77                 if(i->renderable==&r)
78                 {
79                         i->passes.clear();
80                         return;
81                 }
82
83         renderables.push_back(&r);
84 }
85
86 void Pipeline::add_renderable_for_pass(const Renderable &r, const Tag &tag)
87 {
88         for(vector<Slot>::iterator i=renderables.begin(); i!=renderables.end(); ++i)
89                 if(i->renderable==&r)
90                 {
91                         i->passes.insert(tag);
92                         return;
93                 }
94
95         renderables.push_back(&r);
96         renderables.back().passes.insert(tag);
97 }
98
99 void Pipeline::remove_renderable(const Renderable &r)
100 {
101         for(vector<Slot>::iterator i=renderables.begin(); i!=renderables.end(); ++i)
102                 if(i->renderable==&r)
103                 {
104                         renderables.erase(i);
105                         return;
106                 }
107 }
108
109 void Pipeline::add_effect(Effect &e)
110 {
111         effects.push_back(&e);
112 }
113
114 void Pipeline::add_postprocessor(PostProcessor &pp)
115 {
116         postproc.push_back(&pp);
117         if(!fbo)
118         {
119                 fbo = new Framebuffer;
120
121                 color_buf = new Texture2D;
122                 color_buf->set_min_filter(NEAREST);
123                 color_buf->set_mag_filter(NEAREST);
124                 color_buf->set_wrap(CLAMP_TO_EDGE);
125                 color_buf->storage((hdr ? RGB16F : RGB), width, height);
126                 fbo->attach(COLOR_ATTACHMENT0, *color_buf, 0);
127
128                 depth_buf = new Texture2D;
129                 depth_buf->set_min_filter(NEAREST);
130                 depth_buf->set_mag_filter(NEAREST);
131                 depth_buf->set_wrap(CLAMP_TO_EDGE);
132                 depth_buf->storage(DEPTH_COMPONENT, width, height);
133                 fbo->attach(DEPTH_ATTACHMENT, *depth_buf, 0);
134         }
135 }
136
137 void Pipeline::render(Renderer &renderer, const Tag &tag) const
138 {
139         const PipelinePass &pass = get_pass(tag);
140
141         Bind bind_depth_test(pass.depth_test);
142         Bind bind_blend(pass.blend);
143         Bind bind_lighting(pass.lighting);
144
145         for(vector<Effect *>::const_iterator i=pass.effects.begin(); i!=pass.effects.end(); ++i)
146                 (*i)->prepare();
147
148         for(vector<Slot>::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
149                 if(i->passes.empty() || i->passes.count(tag))
150                         i->renderable->render(renderer, tag);
151
152         for(vector<Effect *>::const_iterator i=pass.effects.end(); i!=pass.effects.begin();)
153                 (*--i)->cleanup();
154 }
155
156 void Pipeline::render_all() const
157 {
158         if(camera)
159                 camera->apply();
160
161         if(fbo)
162         {
163                 fbo->bind();
164                 fbo->clear(COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT);
165         }
166
167         for(vector<Effect *>::const_iterator i=effects.begin(); i!=effects.end(); ++i)
168                 (*i)->prepare();
169
170         Renderer renderer(camera);
171         for(vector<Tag>::const_iterator i=pass_order.begin(); i!=pass_order.end(); ++i)
172                 render(renderer, *i);
173
174         for(vector<Effect *>::const_iterator i=effects.end(); i!=effects.begin();)
175                 (*--i)->cleanup();
176
177         if(fbo)
178                 Framebuffer::unbind();
179
180         // XXX Need two color buffer textures to handle multiple post-processors correctly
181         for(vector<PostProcessor *>::const_iterator i=postproc.begin(); i!=postproc.end(); ++i)
182                 (*i)->render(*color_buf, *depth_buf);
183 }
184
185
186 Pipeline::Slot::Slot(const Renderable *r):
187         renderable(r)
188 { }
189
190 } // namespace GL
191 } // namespace Msp