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