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