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