]> git.tdb.fi Git - libs/gl.git/blob - source/render/rendertarget.cpp
Add debug name capability to more classes
[libs/gl.git] / source / render / rendertarget.cpp
1 #include <msp/core/maputils.h>
2 #include <msp/strings/format.h>
3 #include "error.h"
4 #include "renderbuffer.h"
5 #include "rendertarget.h"
6
7 using namespace std;
8
9 namespace Msp {
10 namespace GL {
11
12 RenderTargetFormat::RenderTargetFormat():
13         count(0)
14 { }
15
16 RenderTargetFormat::RenderTargetFormat(RenderOutput o):
17         count(1)
18 {
19         outputs[0] = o;
20 }
21
22 RenderTargetFormat RenderTargetFormat::operator,(RenderOutput o) const
23 {
24         if(count>=MAX_OUTPUTS)
25                 throw invalid_operation("RenderTargetFormat::operator,");
26
27         RenderTargetFormat result = *this;
28         result.outputs[result.count++] = o;
29
30         return result;
31 }
32
33 RenderTargetFormat RenderTargetFormat::operator,(PixelFormat f) const
34 {
35         if(!count)
36                 throw invalid_operation("RenderTargetFormat::operator,");
37
38         PixelComponents comp = get_components(f);
39         DataType type = get_component_type(f);
40         unsigned size = 0;
41         unsigned char out = outputs[count-1];
42         if(get_output_type(out)>=get_output_type(RENDER_DEPTH))
43         {
44                 if(comp!=DEPTH_COMPONENT)
45                         throw invalid_argument("RenderTargetFormat::operator,");
46                 switch(type)
47                 {
48                 case UNSIGNED_SHORT: size = 0; break;
49                 case UNSIGNED_INT: size = 2; break;
50                 case FLOAT: size = 3; break;
51                 default: throw invalid_argument("RenderTargetFormat::operator,");
52                 }
53         }
54         else
55         {
56                 if(comp!=RED && comp!=RG && comp!=RGB && comp!=RGBA)
57                         throw invalid_argument("RenderTargetformat::operator,");
58                 switch(type)
59                 {
60                 case UNSIGNED_BYTE: size = 0; break;
61                 case HALF_FLOAT: size = 2; break;
62                 case FLOAT: size = 3; break;
63                 default: throw invalid_argument("RenderTargetFormat::operator,");
64                 }
65         }
66
67         out = (out&~15) | (size<<2) | (get_component_count(f)-1);
68         RenderTargetFormat result = *this;
69         result.outputs[result.count-1] = out;
70
71         return result;
72 }
73
74 int RenderTargetFormat::index(RenderOutput o) const
75 {
76         unsigned type = get_output_type(o);
77         unsigned i = 0;
78         for(const unsigned char *j=begin(); j!=end(); ++j, ++i)
79                 if(get_output_type(*j)==type)
80                         return i;
81         return -1;
82 }
83
84
85 PixelFormat get_output_pixelformat(unsigned char o)
86 {
87         PixelComponents comp;
88         DataType type;
89         if(get_output_type(o)>=get_output_type(RENDER_DEPTH))
90         {
91                 static DataType types[4] = { UNSIGNED_SHORT, UNSIGNED_SHORT, UNSIGNED_INT, FLOAT };
92                 comp = DEPTH_COMPONENT;
93                 type = types[(o>>2)&3];
94         }
95         else
96         {
97                 static PixelComponents components[4] = { RED, RG, RGB, RGBA };
98                 static DataType types[4] = { UNSIGNED_BYTE, UNSIGNED_SHORT, HALF_FLOAT, FLOAT };
99                 comp = components[o&3];
100                 type = types[(o>>2)&3];
101         }
102
103         return make_pixelformat(comp, type);
104 }
105
106
107 RenderTarget::RenderTarget(unsigned w, unsigned h, RenderOutput o)
108 {
109         init(w, h, 0, o);
110 }
111
112 RenderTarget::RenderTarget(unsigned w, unsigned h, const RenderTargetFormat &f)
113 {
114         init(w, h, 0, f);
115 }
116
117 RenderTarget::RenderTarget(unsigned w, unsigned h, unsigned s, const RenderTargetFormat &f)
118 {
119         init(w, h, s, f);
120 }
121
122 void RenderTarget::init(unsigned w, unsigned h, unsigned s, const RenderTargetFormat &f)
123 {
124         width = w;
125         height = h;
126         samples = s;
127         format = f;
128
129         for(const unsigned char *i=format.begin(); i!=format.end(); ++i)
130         {
131                 unsigned type = get_output_type(*i);
132                 FramebufferAttachment att;
133                 if(type>=get_output_type(RENDER_DEPTH))
134                         att = DEPTH_ATTACHMENT;
135                 else
136                         att = static_cast<FramebufferAttachment>(COLOR_ATTACHMENT0+type);
137
138                 PixelFormat pf = get_output_pixelformat(*i);
139
140                 TargetBuffer tgt;
141                 if(samples)
142                 {
143                         tgt.buffer = new Renderbuffer;
144                         tgt.buffer->storage_multisample(samples, pf, width, height);
145                         fbo.attach(att, *tgt.buffer);
146                 }
147                 else
148                 {
149                         tgt.texture = new Texture2D;
150                         tgt.texture->storage(pf, width, height, 1);
151                         Sampler &sampler = tgt.texture->get_default_sampler();
152                         sampler.set_filter(NEAREST);
153                         sampler.set_wrap(CLAMP_TO_EDGE);
154                         fbo.attach(att, *tgt.texture);
155                 }
156                 buffers.push_back(tgt);
157         }
158
159         fbo.require_complete();
160 }
161
162 RenderTarget::~RenderTarget()
163 {
164         for(vector<TargetBuffer>::iterator i=buffers.begin(); i!=buffers.end(); ++i)
165         {
166                 if(samples)
167                         delete i->buffer;
168                 else
169                         delete i->texture;
170         }
171 }
172
173 void RenderTarget::set_texture_filter(TextureFilter filt)
174 {
175         if(!samples)
176         {
177                 for(vector<TargetBuffer>::iterator i=buffers.begin(); i!=buffers.end(); ++i)
178                         i->texture->get_default_sampler().set_filter(filt);
179         }
180 }
181
182 const Texture2D &RenderTarget::get_target_texture(unsigned i) const
183 {
184         if(i>=buffers.size())
185                 throw out_of_range("RenderTarget::get_target_texture");
186         if(samples)
187                 throw invalid_operation("RenderTarget::get_target_texture");
188
189         return *buffers[i].texture;
190 }
191
192 const Texture2D &RenderTarget::get_target_texture(RenderOutput o) const
193 {
194         int index = format.index(o);
195         if(index<0)
196                 throw key_error(o);
197
198         return get_target_texture(index);
199 }
200
201 void RenderTarget::blit_from(const RenderTarget &other)
202 {
203         fbo.blit_from(other.fbo, COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT, false);
204 }
205
206 void RenderTarget::set_debug_name(const string &name)
207 {
208 #ifdef DEBUG
209         fbo.set_debug_name(name+" [FBO]");
210         unsigned i = 0;
211         for(const unsigned char *j=format.begin(); j!=format.end(); ++i, ++j)
212         {
213                 unsigned type = get_output_type(*j);
214
215                 string buf_name;
216                 if(type>=get_output_type(RENDER_DEPTH))
217                         buf_name = name+"/depth";
218                 else
219                         buf_name = Msp::format("%s/color%d", name, type);
220
221                 if(samples)
222                         buffers[i].buffer->set_debug_name(buf_name+".tex2d");
223                 else
224                         buffers[i].texture->set_debug_name(buf_name+".rbuf");
225         }
226 #else
227         (void)name;
228 #endif
229 }
230
231 } // namespace GL
232 } // namespace Msp