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