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