Package glitter :: Package framebuffers :: Module framebuffer
[hide private]
[frames] | no frames]

Source Code for Module glitter.framebuffers.framebuffer

  1  """Framebuffer object class. 
  2   
  3  @warn: Framebuffers are currently bound for drawing only (C{GL_DRAW_FRAMEBUFFER}, not C{GL_READ_FRAMEBUFFER}). 
  4  @todo: Implement binding for reading; wrap C{glReadPixels}, C{glBlitFramebuffer}, C{glCopyTexSubImage} and related framebuffer copy functions. 
  5  @todo: Add properties for C{viewport}, C{color_writemask}, C{depth_writemask}, 
  6  C{blend_func}, C{blend_equation}, and C{depth_range} (using 
  7  C{glDepthRangeArray} and C{glDepthRangeIndexed}). 
  8   
  9  @author: Stephan Wenger 
 10  @date: 2012-02-29 
 11  """ 
 12   
 13  import glitter.raw as _gl 
 14  from glitter.utils import ManagedObject, BindableObject, framebuffer_status 
15 16 -class Framebuffer(ManagedObject, BindableObject):
17 _generate_id = _gl.glGenFramebuffers 18 _delete_id = _gl.glDeleteBuffers 19 _db = "framebuffers" 20 _binding = "draw_framebuffer_binding" 21 _target = _gl.GL_DRAW_FRAMEBUFFER 22 23 framebuffer_status = framebuffer_status 24 _initialized = False 25
26 - def __init__(self, *attachments, **kwargs):
27 """Create a new framebuffer. 28 29 @param attachments: Textures to bind to color attachments. 30 @type attachments: C{list} of L{Texture}s 31 @param kwargs: Named arguments. 32 @type kwargs: C{dict} 33 @keyword context: The context in which to create the framebuffer. 34 @type context: L{Context} 35 @keyword depth: An optional depth buffer attachment. 36 @type depth: L{Texture} 37 @keyword stencil: An optional stencil buffer attachment. 38 @type stencil: L{Texture} 39 """ 40 41 super(Framebuffer, self).__init__(context=kwargs.pop("context", None)) 42 self._attachments = {} 43 44 if isinstance(attachments, dict): 45 attachments = dict(attachments) 46 else: 47 attachments = dict(enumerate(attachments)) 48 for i in range(self._context.max_color_attachments): 49 self[i] = attachments.pop(i, None) 50 if attachments: 51 raise ValueError("framebuffer has no attachment(s) %s" % ", ".join("'%s'" % x for x in attachments.keys())) 52 53 self.depth = kwargs.pop("depth", None) 54 self.stencil = kwargs.pop("stencil", None) 55 56 if kwargs: 57 raise TypeError("__init__() got an unexpected keyword argument '%s'" % kwargs.keys()[0]) 58 59 self._initialized = True
60
61 - def __getitem__(self, index):
62 return self._attachments[index]
63
64 - def __setitem__(self, index, value):
65 self.attach(index, value)
66
67 - def __delitem__(self, index):
68 self.attach(index, None)
69
70 - def _on_bind(self):
71 """Setup global framebuffer related state. 72 73 @todo: Setup C{color_writemasks}, C{depth_writemasks}, C{blend_funcs}, C{blend_equations}, and C{depth_ranges} after C{viewport}. 74 """ 75 76 if self._initialized: 77 self._stack.append(self._context.draw_buffers) 78 self._context.draw_buffers = [i if self[i] is not None else None for i in range(self._context.max_color_attachments)] 79 80 self._stack.append(self._context.viewport) 81 if self.shape is not None: 82 self._context.viewport = (0, 0) + self.shape
83
84 - def _on_release(self):
85 """Restore global framebuffer related state. 86 87 @todo: Restore C{depth_ranges}, C{blend_equations}, C{blend_funcs}, C{depth_writemasks}, and C{color_writemasks} before C{viewport}. 88 """ 89 90 if self._initialized: 91 self._context.viewport = self._stack.pop() 92 self._context.draw_buffers = self._stack.pop()
93
94 - def _attach(self, attachment, texture=None, layer=None, level=0):
95 """Attach a texture to an attachment. 96 97 C{texture} may be a (texture, layer) tuple generated by 98 L{Texture}C{.__getitem__()}. 99 """ 100 101 if type(texture) is tuple: 102 if layer is not None: 103 raise ValueError("cannot provide layer as both keyword and texture tuple") 104 texture, layer = texture 105 return self._attach(attachment, texture, layer, level) 106 107 with self: 108 if texture is None: 109 _gl.glFramebufferTextureLayer(self._target, attachment, 0, level, 0) 110 elif layer is None: 111 _gl.glFramebufferTexture(self._target, attachment, texture._id, level) 112 else: 113 _gl.glFramebufferTextureLayer(self._target, attachment, texture._id, level, layer)
114
115 - def attach(self, index, texture=None, layer=None, level=0):
116 """Attach a texture to color attachment C{index}. 117 118 C{texture} may be a (texture, layer) tuple generated by 119 L{Texture}C{.__getitem__()}. Otherwise, C{layer} specifies which 120 texture layer is to be bound. All layers are bound when C{layer} is 121 C{None}. 122 123 C{level} specifies which resolution level of the texture is to be 124 bound. 125 126 If C{texture} is C{None}, the attachment will be unbound. 127 """ 128 129 self._attach(_gl.GL_COLOR_ATTACHMENT0 + index, texture, layer, level) 130 self._attachments[index] = texture
131 132 @property
133 - def depth(self):
134 if not hasattr(self, "_depth"): 135 return None 136 return self._depth
137 138 @depth.setter
139 - def depth(self, depth):
140 self.attach_depth(depth)
141 142 @depth.deleter
143 - def depth(self):
144 self.attach_depth(None)
145
146 - def attach_depth(self, texture=None, layer=None, level=0):
147 """Attach a texture to the depth attachment. 148 149 C{texture} may be a (texture, layer) tuple generated by 150 L{Texture}C{.__getitem__()}. Otherwise, C{layer} specifies which 151 texture layer is to be bound. All layers are bound when C{layer} is 152 C{None}. 153 154 C{level} specifies which resolution level of the texture is to be 155 bound. 156 157 If C{texture} is C{None}, the attachment will be unbound. 158 """ 159 160 self._attach(_gl.GL_DEPTH_ATTACHMENT, texture, layer, level) 161 self._depth = texture
162 163 @property
164 - def stencil(self):
165 if not hasattr(self, "_stencil"): 166 return None 167 return self._stencil
168 169 @stencil.setter
170 - def stencil(self, stencil):
172 173 @stencil.deleter
174 - def stencil(self):
175 self.attach_stencil(None)
176
177 - def attach_stencil(self, texture=None, layer=None, level=0):
178 """Attach a texture to the stencil attachment. 179 180 C{texture} may be a (texture, layer) tuple generated by 181 L{Texture}C{.__getitem__()}. Otherwise, C{layer} specifies which 182 texture layer is to be bound. All layers are bound when C{layer} is 183 C{None}. 184 185 C{level} specifies which resolution level of the texture is to be 186 bound. 187 188 If C{texture} is C{None}, the attachment will be unbound. 189 """ 190 191 self._attach(_gl.GL_STENCIL_ATTACHMENT, texture, layer, level) 192 self._stencil = texture
193 194 @property
195 - def status(self):
196 """The framebuffer completeness status. 197 198 @rtype: L{Framebuffer.framebuffer_status} enum 199 """ 200 201 with self: 202 return self.framebuffer_status[_gl.glCheckFramebufferStatus(self._target)]
203 204 @property
205 - def shape(self):
206 shape = None 207 for i, attachment in sorted(self._attachments.items()): 208 if attachment is not None: 209 if type(attachment) is tuple: 210 texture, layer = attachment 211 shape = (min(shape[0], texture.shape[1]), min(shape[1], texture.shape[2])) if shape else texture.shape[1:3] 212 else: 213 shape = (min(shape[0], attachment.shape[0]), min(shape[1], attachment.shape[1])) if shape else attachment.shape[:2] 214 if self.depth is not None: 215 shape = (min(shape[0], self.depth.shape[0]), min(shape[1], self.depth.shape[1])) if shape else self.depth.shape[:2] 216 if self.stencil is not None: 217 shape = (min(shape[0], self.stencil.shape[0]), min(shape[1], self.stencil.shape[1])) if shape else self.stencil.shape[:2] 218 return shape
219
220 - def clear(self, color=None, depth=None, stencil=None):
221 """Clear the framebuffer. 222 223 @param color: Whether to clear the color buffer, and optionally, to which value. 224 @type color: C{bool} or C{numpy.ndarray}. 225 @param depth: Whether to clear the depth buffer, and optionally, to which value. 226 @type depth: C{bool} or C{numpy.ndarray}. 227 @param stencil: Whether to clear the stencil buffer, and optionally, to which value. 228 @type stencil: C{bool} or C{numpy.ndarray}. 229 230 If no parameters are given, color, depth and stencil are cleared with 231 the current clear values. 232 233 @todo: Use C{glClearBuffer} to clear selected attachments only. 234 """ 235 236 with self: 237 self._context._perform_gl_clear(color, depth, stencil)
238 239 __all__ = ["Framebuffer"] 240