]> git.tdb.fi Git - libs/gl.git/blob - source/core/framebuffer.cpp
Check the flat qualifier from the correct member
[libs/gl.git] / source / core / framebuffer.cpp
1 #include "error.h"
2 #include "framebuffer.h"
3 #include "texture2d.h"
4 #include "texture2dmultisample.h"
5 #include "texture3d.h"
6 #include "windowview.h"
7
8 using namespace std;
9
10 namespace Msp {
11 namespace GL {
12
13 framebuffer_incomplete::framebuffer_incomplete(const std::string &reason):
14         runtime_error(reason)
15 { }
16
17
18 Framebuffer::Framebuffer(bool s):
19         FramebufferBackend(s)
20 { }
21
22 Framebuffer::Framebuffer():
23         FramebufferBackend(false)
24 { }
25
26 Framebuffer::Framebuffer(FrameAttachment fa):
27         Framebuffer()
28 {
29         set_format(fa);
30 }
31
32 Framebuffer::Framebuffer(const FrameFormat &f):
33         Framebuffer()
34 {
35         set_format(f);
36 }
37
38 void Framebuffer::set_format(const FrameFormat &fmt)
39 {
40         if(!format.empty())
41                 throw invalid_operation("Framebuffer::set_format");
42         if(fmt.empty() || !is_format_supported(fmt))
43                 throw invalid_argument("Framebuffer::set_format");
44
45         format = fmt;
46         attachments.resize(format.size());
47 }
48
49 void Framebuffer::update() const
50 {
51         FramebufferBackend::update(dirty);
52         dirty = 0;
53 }
54
55 void Framebuffer::check_size()
56 {
57         bool first = true;
58         for(Attachment &a: attachments)
59                 if(a.tex)
60                 {
61                         unsigned w = 0;
62                         unsigned h = 0;
63                         unsigned l = 1;
64                         if(const Texture2D *tex2d = dynamic_cast<const Texture2D *>(a.tex))
65                         {
66                                 w = max(tex2d->get_width()>>a.level, 1U);
67                                 h = max(tex2d->get_height()>>a.level, 1U);
68                         }
69                         else if(const Texture2DMultisample *tex2d_ms = dynamic_cast<const Texture2DMultisample *>(a.tex))
70                         {
71                                 w = tex2d_ms->get_width();
72                                 h = tex2d_ms->get_height();
73                         }
74                         else if(const Texture3D *tex3d = dynamic_cast<const Texture3D *>(a.tex))
75                         {
76                                 w = max(tex3d->get_width()>>a.level, 1U);
77                                 h = max(tex3d->get_height()>>a.level, 1U);
78                                 l = (a.layer<0 ? tex3d->get_depth() : 1);
79                         }
80                         else if(const TextureCube *tex_cube = dynamic_cast<const TextureCube *>(a.tex))
81                         {
82                                 w = max(tex_cube->get_size()>>a.level, 1U);
83                                 h = w;
84                                 l = (a.layer<0 ? 6 : 1);
85                         }
86
87                         if(first)
88                         {
89                                 width = w;
90                                 height = h;
91                                 layers = l;
92                                 first = false;
93                         }
94                         else
95                         {
96                                 width = min(width, w);
97                                 height = min(height, h);
98                                 layers = min(layers, l);
99                         }
100                 }
101 }
102
103 void Framebuffer::set_attachment(FrameAttachment attch, Texture &tex, unsigned level, int layer, unsigned samples)
104 {
105         if(format.empty() || attachments.empty())
106                 throw invalid_operation("Framebuffer::attach");
107
108         if((format.get_samples()>1 && samples!=format.get_samples()) || (format.get_samples()==1 && samples))
109                 throw incompatible_data("Framebuffer::attach");
110
111         unsigned i = 0;
112         for(FrameAttachment a: format)
113         {
114                 if(a==attch)
115                 {
116                         attachments[i].set(tex, level, layer);
117                         dirty |= 1<<i;
118                         check_size();
119                         return;
120                 }
121                 ++i;
122         }
123
124         throw incompatible_data("Framebuffer::attach");
125 }
126
127 void Framebuffer::attach(FrameAttachment attch, Texture2D &tex, unsigned level)
128 {
129         set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, 0, 0);
130 }
131
132 void Framebuffer::attach(FrameAttachment attch, Texture2DMultisample &tex)
133 {
134         set_attachment(make_typed_attachment(attch, tex.get_format()), tex, 0, 0, tex.get_samples());
135 }
136
137 void Framebuffer::attach(FrameAttachment attch, Texture3D &tex, unsigned layer, unsigned level)
138 {
139         set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, layer, 0);
140 }
141
142 void Framebuffer::attach(FrameAttachment attch, TextureCube &tex, TextureCubeFace face, unsigned level)
143 {
144         set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, face, 0);
145 }
146
147 void Framebuffer::attach_layered(FrameAttachment attch, Texture3D &tex, unsigned level)
148 {
149         require_layered();
150         set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, -1, 0);
151 }
152
153 void Framebuffer::attach_layered(FrameAttachment attch, TextureCube &tex, unsigned level)
154 {
155         require_layered();
156         set_attachment(make_typed_attachment(attch, tex.get_format()), tex, level, -1, 0);
157 }
158
159 void Framebuffer::detach(FrameAttachment attch)
160 {
161         if(attachments.empty())
162                 throw invalid_operation("Framebuffer::detach");
163
164         int i = format.index(attch);
165         if(i>=0)
166         {
167                 attachments[i].clear();
168                 dirty |= 1<<i;
169                 check_size();
170         }
171 }
172
173 const Texture *Framebuffer::get_attachment(FrameAttachment attch) const
174 {
175         if(attachments.empty())
176                 return 0;
177
178         int i = format.index(attch);
179         return (i>=0 ? attachments[i].tex : 0);
180 }
181
182 const Texture *Framebuffer::get_attachment(unsigned i) const
183 {
184         return (i<attachments.size() ? attachments[i].tex : 0);
185 }
186
187 void Framebuffer::require_complete() const
188 {
189         bool layered = (!attachments.empty() && attachments.front().layer<0);
190         for(const Attachment &a: attachments)
191         {
192                 if(!a.tex)
193                         throw framebuffer_incomplete("missing attachment");
194                 if(layered!=(a.layer<0))
195                         throw framebuffer_incomplete("inconsistent layering");
196         }
197
198         FramebufferBackend::require_complete();
199 }
200
201
202 void Framebuffer::Attachment::set(Texture &t, unsigned l, int z)
203 {
204         tex = &t;
205         level = l;
206         layer = z;
207 }
208
209 void Framebuffer::Attachment::clear()
210 {
211         tex = 0;
212 }
213
214 } // namespace GL
215 } // namespace Msp