]> git.tdb.fi Git - libs/gl.git/blob - source/render/rendertarget.cpp
Remove default sampler from Texture
[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         fbo.require_complete();
157 }
158
159 RenderTarget::~RenderTarget()
160 {
161         for(vector<TargetBuffer>::iterator i=buffers.begin(); i!=buffers.end(); ++i)
162         {
163                 if(samples)
164                         delete i->buffer;
165                 else
166                         delete i->texture;
167         }
168 }
169
170 const Texture2D &RenderTarget::get_target_texture(unsigned i) const
171 {
172         if(i>=buffers.size())
173                 throw out_of_range("RenderTarget::get_target_texture");
174         if(samples)
175                 throw invalid_operation("RenderTarget::get_target_texture");
176
177         return *buffers[i].texture;
178 }
179
180 const Texture2D &RenderTarget::get_target_texture(RenderOutput o) const
181 {
182         int index = format.index(o);
183         if(index<0)
184                 throw key_error(o);
185
186         return get_target_texture(index);
187 }
188
189 void RenderTarget::blit_from(const RenderTarget &other)
190 {
191         fbo.blit_from(other.fbo, COLOR_BUFFER_BIT|DEPTH_BUFFER_BIT, false);
192 }
193
194 void RenderTarget::set_debug_name(const string &name)
195 {
196 #ifdef DEBUG
197         fbo.set_debug_name(name+" [FBO]");
198         unsigned i = 0;
199         for(const unsigned char *j=format.begin(); j!=format.end(); ++i, ++j)
200         {
201                 unsigned type = get_output_type(*j);
202
203                 string buf_name;
204                 if(type>=get_output_type(RENDER_DEPTH))
205                         buf_name = name+"/depth";
206                 else
207                         buf_name = Msp::format("%s/color%d", name, type);
208
209                 if(samples)
210                         buffers[i].buffer->set_debug_name(buf_name+".tex2d");
211                 else
212                         buffers[i].texture->set_debug_name(buf_name+".rbuf");
213         }
214 #else
215         (void)name;
216 #endif
217 }
218
219 } // namespace GL
220 } // namespace Msp