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