f2f12d50c441fc70cf2439a025057dac13ff4b05
[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                         fbo.attach(att, *tgt.texture);
152                 }
153                 buffers.push_back(tgt);
154         }
155 }
156
157 RenderTarget::~RenderTarget()
158 {
159         for(vector<TargetBuffer>::iterator i=buffers.begin(); i!=buffers.end(); ++i)
160         {
161                 if(samples)
162                         delete i->buffer;
163                 else
164                         delete i->texture;
165         }
166 }
167
168 const Texture2D &RenderTarget::get_target_texture(unsigned i) const
169 {
170         if(i>=buffers.size())
171                 throw out_of_range("RenderTarget::get_target_texture");
172         if(samples)
173                 throw invalid_operation("RenderTarget::get_target_texture");
174
175         return *buffers[i].texture;
176 }
177
178 const Texture2D &RenderTarget::get_target_texture(RenderOutput o) const
179 {
180         int index = format.index(o);
181         if(index<0)
182                 throw key_error(o);
183
184         return get_target_texture(index);
185 }
186
187 void RenderTarget::set_debug_name(const string &name)
188 {
189 #ifdef DEBUG
190         fbo.set_debug_name(name+" [FBO]");
191         unsigned i = 0;
192         for(const unsigned char *j=format.begin(); j!=format.end(); ++i, ++j)
193         {
194                 unsigned type = get_output_type(*j);
195
196                 string buf_name;
197                 if(type>=get_output_type(RENDER_DEPTH))
198                         buf_name = name+"/depth";
199                 else
200                         buf_name = Msp::format("%s/color%d", name, type);
201
202                 if(samples)
203                         buffers[i].buffer->set_debug_name(buf_name+".rbuf");
204                 else
205                         buffers[i].texture->set_debug_name(buf_name+".tex2d");
206         }
207 #else
208         (void)name;
209 #endif
210 }
211
212 } // namespace GL
213 } // namespace Msp