/usr/share/pyshared/glitch/fbo.py is in python-glitch 0.6-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | "Framebuffer objects, for offscreen rendering."
from __future__ import with_statement
import OpenGL.GL as gl
import OpenGL.GL.EXT.framebuffer_object as fbo
from glitch.camera import Camera
from glitch.texture import Texture
from glitch.multicontext import MultiContext
class RenderBuffer(MultiContext):
"An abstract OpenGL render buffer."
_context_key = 'render_buffer'
def __init__(self, width, height):
MultiContext.__init__(self)
self.width = width
self.height = height
def _context_create(self, ctx):
return fbo.glGenRenderbuffersEXT(1)
def _context_delete(self, ctx, id):
fbo.glDeleteRenderbuffersEXT(1, [id])
def bind(self, ctx):
id = self.context_get(ctx)
fbo.glBindRenderbufferEXT(gl.GL_RENDERBUFFER_EXT, id)
#assert fbo.glIsRenderbufferEXT(id)
return id
def unbind(self, ctx):
fbo.glBindRenderbufferEXT(gl.GL_RENDERBUFFER_EXT, 0)
class DepthRenderBuffer(RenderBuffer):
"An OpenGL depth render buffer."
def _context_create(self, ctx):
id = RenderBuffer._context_create(self, ctx)
fbo.glBindRenderbufferEXT(gl.GL_RENDERBUFFER_EXT, id)
fbo.glRenderbufferStorageEXT(gl.GL_RENDERBUFFER_EXT,
gl.GL_DEPTH_COMPONENT, self.width, self.height)
return id
class ColorRenderBuffer(RenderBuffer):
"An OpenGL color render buffer."
format = gl.GL_RGBA8
def _context_create(self, ctx):
id = RenderBuffer._context_create(self, ctx)
fbo.glBindRenderbufferEXT(gl.GL_RENDERBUFFER_EXT, id)
fbo.glRenderbufferStorageEXT(gl.GL_RENDERBUFFER_EXT,
self.format, self.width, self.height)
return id
class FrameBuffer(MultiContext):
"An OpenGL frame buffer."
_context_key = 'framebuffer'
def __init__(self, color_buffer, depth_buffer=None):
MultiContext.__init__(self)
self.color_buffer = color_buffer
self.depth_buffer = depth_buffer
def _context_create(self, ctx):
id = fbo.glGenFramebuffersEXT(1)
fbo.glBindFramebufferEXT(gl.GL_FRAMEBUFFER_EXT, id)
if isinstance(self.color_buffer, Texture):
with self.color_buffer.bind(ctx, 0) as color_buffer_id:
# Attach texture to render to.
fbo.glFramebufferTexture2DEXT(gl.GL_FRAMEBUFFER_EXT,
gl.GL_COLOR_ATTACHMENT0_EXT, gl.GL_TEXTURE_2D,
color_buffer_id, 0)
else:
color_buffer_id = self.color_buffer.bind(ctx)
# Attach color buffer to render to.
fbo.glFramebufferRenderbufferEXT(gl.GL_FRAMEBUFFER_EXT,
gl.GL_COLOR_ATTACHMENT0_EXT, gl.GL_RENDERBUFFER_EXT,
color_buffer_id)
if self.depth_buffer is not None:
depth_buffer_id = self.depth_buffer.bind(ctx)
#self.depth_buffer.unbind(ctx)
fbo.glFramebufferRenderbufferEXT(gl.GL_FRAMEBUFFER_EXT,
gl.GL_DEPTH_ATTACHMENT_EXT, gl.GL_RENDERBUFFER_EXT,
depth_buffer_id)
self._check_status()
return id
def _context_delete(self, ctx, id):
fbo.glDeleteFramebuffersEXT([id])
def bind(self, ctx):
# XXX: Put this on a stack.
self.previous_binding = gl.glGetIntegerv(
fbo.GL_FRAMEBUFFER_BINDING_EXT)
id = self.context_get(ctx)
fbo.glBindFramebufferEXT(gl.GL_FRAMEBUFFER_EXT, id)
def _check_status(self):
status = fbo.glCheckFramebufferStatusEXT(gl.GL_FRAMEBUFFER_EXT)
if status != fbo.GL_FRAMEBUFFER_COMPLETE_EXT:
errors = dict((int(getattr(fbo, name)), getattr(fbo, name))
for name in dir(fbo) if 'INCOMPLETE' in name)
raise RuntimeError(errors[status])
def unbind(self, ctx):
fbo.glBindFramebufferEXT(gl.GL_FRAMEBUFFER_EXT, self.previous_binding)
class CameraTexture(Texture):
"""Render a scene to a texture.
A CameraTexture behaves like a Camera, in that it takes the same
parameters as a Camera, and it behaves like a Texture, in that it can be
passed to ApplyTexture.
"""
_context_key = 'camera_texture'
def __init__(self, width, height, **kw):
Texture.__init__(self, width, height, None)
# XXX: Should probably just take a camera as an argument, or have a
# texture as a property.
self.camera = Camera(**kw)
def _context_create(self, ctx):
depth_buffer = DepthRenderBuffer(self.width, self.height)
# Data is None: texture will be allocated but no texels loaded.
texture = Texture(self.width, self.height, None)
with texture.bind(ctx, 0):
pass
fbo = FrameBuffer(texture, depth_buffer)
self._context_update(ctx, fbo)
return fbo
def _context_update(self, ctx, fbo):
fbo.bind(ctx)
self.camera.context['w'] = self.width
self.camera.context['h'] = self.height
self.camera.render(ctx)
fbo.unbind(ctx)
return fbo
def _context_delete(self, ctx, fbo):
fbo.color_buffer.context_delete(ctx)
fbo.depth_buffer.context_delete(ctx)
fbo.context_delete(ctx)
def bind(self, ctx, unit):
fbo = self.context_get(ctx)
return fbo.color_buffer.bind(ctx, unit)
def refresh(self):
self.version += 1
class BufferCamera(Camera, MultiContext):
"A camera that renders to a ColorRenderBuffer."
_context_key = 'buffer_camera'
def __init__(self, width, height, **kw):
self.width = width
self.height = height
MultiContext.__init__(self)
Camera.__init__(self, **kw)
def _context_create(self, ctx):
color_buffer = ColorRenderBuffer(self.width, self.height)
depth_buffer = DepthRenderBuffer(self.width, self.height)
fbo = FrameBuffer(color_buffer, depth_buffer)
self._context_update(self, ctx, fbo)
return fbo
def _context_update(self, ctx, fbo):
fbo.bind(ctx)
self.context['w'] = self.width
self.context['h'] = self.height
Camera.render(self, ctx)
fbo.unbind(ctx)
return fbo
def render(self, parent_ctx=None):
self.context_get(self.context)
|