]> git.tdb.fi Git - libs/gl.git/blob - source/framebuffer.cpp
Drop Id tags and copyright notices from files
[libs/gl.git] / source / framebuffer.cpp
1 #include "extension.h"
2 #include "ext_framebuffer_blit.h"
3 #include "ext_framebuffer_object.h"
4 #include "framebuffer.h"
5 #include "misc.h"
6 #include "renderbuffer.h"
7 #include "texture2d.h"
8
9 using namespace std;
10
11 namespace Msp {
12 namespace GL {
13
14 Framebuffer::Framebuffer(unsigned i):
15         id(i),
16         dirty(0)
17 {
18         if(id)
19                 throw InvalidParameterValue("System framebuffer must have id 0");
20
21         int viewport[4];
22         glGetIntegerv(GL_VIEWPORT, viewport);
23         width = viewport[2];
24         height = viewport[3];
25 }
26
27 Framebuffer::Framebuffer():
28         width(0),
29         height(0),
30         dirty(0)
31 {
32         static RequireExtension _ext("GL_EXT_framebuffer_object");
33
34         glGenFramebuffersEXT(1, &id);
35 }
36
37 Framebuffer::~Framebuffer()
38 {
39         if(id)
40                 glDeleteFramebuffersEXT(1, &id);
41         if(current()==this)
42                 unbind();
43 }
44
45 void Framebuffer::update_attachment(unsigned mask) const
46 {
47         if(current()==this)
48         {
49                 GLenum color_buf = GL_NONE;
50                 for(unsigned i=0; i<attachments.size(); ++i)
51                 {
52                         const Attachment &attch = attachments[i];
53                         if(mask&(1<<i))
54                         {
55                                 if(attch.type==GL_RENDERBUFFER_EXT)
56                                         glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attch.attachment, GL_RENDERBUFFER_EXT, attch.rbuf->get_id());
57                                 else if(attch.type==GL_TEXTURE_2D)
58                                 {
59                                         static_cast<Texture2D *>(attch.tex)->allocate(attch.level);
60                                         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attch.attachment, attch.type, attch.tex->get_id(), attch.level);
61                                 }
62                                 else
63                                         glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attch.attachment, 0, 0);
64                         }
65
66                         if(attch.attachment>=COLOR_ATTACHMENT0 && attch.attachment<=COLOR_ATTACHMENT3)
67                                 color_buf = attch.attachment;
68                 }
69
70                 glDrawBuffer(color_buf);
71         }
72         else
73                 dirty |= mask;
74 }
75
76 void Framebuffer::check_size()
77 {
78         for(vector<Attachment>::iterator i=attachments.begin(); i!=attachments.end(); ++i)
79                 if(i->type)
80                 {
81                         if(i->type==GL_RENDERBUFFER_EXT)
82                         {
83                                 width = i->rbuf->get_width();
84                                 height = i->rbuf->get_height();
85                         }
86                         else if(i->type==GL_TEXTURE_2D)
87                         {
88                                 Texture2D *tex = static_cast<Texture2D *>(i->tex);
89                                 width = tex->get_width();
90                                 height = tex->get_height();
91                         }
92                         if(current()==this)
93                                 glViewport(0, 0, width, height);
94                         break;
95                 }
96 }
97
98 void Framebuffer::attach(FramebufferAttachment attch, Renderbuffer &rbuf)
99 {
100         if(!id)
101                 throw InvalidState("Can't attach to system framebuffer");
102
103         unsigned i = get_attachment_index(attch);
104         attachments[i].set(rbuf);
105         update_attachment(1<<i);
106         check_size();
107 }
108
109 void Framebuffer::attach(FramebufferAttachment attch, Texture2D &tex, unsigned level)
110 {
111         if(!id)
112                 throw InvalidState("Can't attach to system framebuffer");
113
114         unsigned i = get_attachment_index(attch);
115         attachments[i].set(tex, level);
116         update_attachment(1<<i);
117         check_size();
118 }
119
120 void Framebuffer::detach(FramebufferAttachment attch)
121 {
122         if(!id)
123                 throw InvalidState("Can't detach from system framebuffer");
124
125         unsigned i = get_attachment_index(attch);
126         attachments[i].clear();
127         update_attachment(1<<i);
128         check_size();
129 }
130
131 FramebufferStatus Framebuffer::check_status() const
132 {
133         Bind _bind(this, true);
134         return static_cast<FramebufferStatus>(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
135 }
136
137 void Framebuffer::clear(BufferBits bits)
138 {
139         Bind _bind(this, true);
140         glClear(bits);
141 }
142
143 void Framebuffer::blit_from(const Framebuffer &other, int sx0, int sy0, int sx1, int sy1, int dx0, int dy0, int dx1, int dy1, BufferBits bits, bool filter)
144 {
145         static RequireExtension _ext("GL_EXT_framebuffer_blit");
146
147         const Framebuffer *old = current();
148         if(set_current(this))
149         {
150                 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, id);
151                 if(dirty)
152                 {
153                         update_attachment(dirty);
154                         dirty = 0;
155                 }
156         }
157         if(old!=&other)
158                 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, other.id);
159
160         glBlitFramebufferEXT(sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1, bits, (filter ? GL_LINEAR : GL_NEAREST));
161
162         set_current(old);
163         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (old ? old->id : 0));
164 }
165
166 void Framebuffer::blit_from(const Framebuffer &other, int sx, int sy, unsigned wd, unsigned ht, int dx, int dy, BufferBits bits)
167 {
168         blit_from(other, sx, sy, sx+wd, sy+ht, dx, dy, dx+wd, dy+ht, bits, false);
169 }
170
171 void Framebuffer::blit_from(const Framebuffer &other, BufferBits bits, bool filter)
172 {
173         blit_from(other, 0, 0, other.width, other.height, 0, 0, width, height, bits, filter);
174 }
175
176 void Framebuffer::bind() const
177 {
178         if(set_current(this))
179         {
180                 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
181                 if(dirty)
182                 {
183                         update_attachment(dirty);
184                         dirty = 0;
185                 }
186                 if(width && height)
187                         glViewport(0, 0, width, height);
188         }
189 }
190
191 const Framebuffer *Framebuffer::current()
192 {       
193         if(!cur_obj)
194                 cur_obj = &system();
195         return cur_obj;
196 }
197
198 void Framebuffer::unbind()
199 {
200         system().bind();
201 }
202
203 Framebuffer &Framebuffer::system()
204 {
205         static Framebuffer sys_framebuf(0);
206         return sys_framebuf;
207 }
208
209 unsigned Framebuffer::get_attachment_index(FramebufferAttachment attch)
210 {
211         for(unsigned i=0; i<attachments.size(); ++i)
212                 if(attachments[i].attachment==attch)
213                         return i;
214         attachments.push_back(Attachment(attch));
215         return attachments.size()-1;
216 }
217
218
219 Framebuffer::Attachment::Attachment(FramebufferAttachment a):
220         attachment(a),
221         type(0),
222         level(0)
223 { }
224
225 void Framebuffer::Attachment::set(Renderbuffer &r)
226 {
227         type = GL_RENDERBUFFER_EXT;
228         rbuf = &r;
229         level = 0;
230 }
231
232 void Framebuffer::Attachment::set(Texture &t, unsigned l)
233 {
234         type = t.get_target();
235         tex = &t;
236         level = l;
237 }
238
239 void Framebuffer::Attachment::clear()
240 {
241         type = 0;
242 }
243
244 } // namespace GL
245 } // namespace Msp