2021-09-23 06:34:23 +08:00
|
|
|
from pyglet.gl import *
|
|
|
|
|
|
|
|
|
|
|
|
def get_max_color_attachments():
|
|
|
|
"""Get the maximum allow Framebuffer Color attachements"""
|
|
|
|
number = GLint()
|
|
|
|
glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, number)
|
|
|
|
return number.value
|
|
|
|
|
|
|
|
|
|
|
|
class Renderbuffer:
|
|
|
|
"""OpenGL Renderbuffer Object"""
|
|
|
|
|
|
|
|
def __init__(self, width, height, internal_format, samples=1):
|
|
|
|
"""Create an instance of a Renderbuffer object."""
|
2023-10-14 15:36:43 +08:00
|
|
|
self._context = pyglet.gl.current_context
|
2021-09-23 06:34:23 +08:00
|
|
|
self._id = GLuint()
|
|
|
|
self._width = width
|
|
|
|
self._height = height
|
|
|
|
self._internal_format = internal_format
|
|
|
|
|
|
|
|
glGenRenderbuffers(1, self._id)
|
|
|
|
glBindRenderbuffer(GL_RENDERBUFFER, self._id)
|
|
|
|
|
|
|
|
if samples > 1:
|
|
|
|
glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, internal_format, width, height)
|
|
|
|
else:
|
|
|
|
glRenderbufferStorage(GL_RENDERBUFFER, internal_format, width, height)
|
|
|
|
|
|
|
|
glBindRenderbuffer(GL_RENDERBUFFER, 0)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def id(self):
|
|
|
|
return self._id.value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def width(self):
|
|
|
|
return self._width
|
|
|
|
|
|
|
|
@property
|
|
|
|
def height(self):
|
|
|
|
return self._height
|
|
|
|
|
|
|
|
def bind(self):
|
|
|
|
glBindRenderbuffer(GL_RENDERBUFFER, self._id)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def unbind():
|
|
|
|
glBindRenderbuffer(GL_RENDERBUFFER, 0)
|
|
|
|
|
|
|
|
def delete(self):
|
|
|
|
glDeleteRenderbuffers(1, self._id)
|
2023-10-14 15:36:43 +08:00
|
|
|
self._id = None
|
2021-09-23 06:34:23 +08:00
|
|
|
|
|
|
|
def __del__(self):
|
2023-10-14 15:36:43 +08:00
|
|
|
if self._id is not None:
|
|
|
|
try:
|
|
|
|
self._context.delete_renderbuffer(self._id.value)
|
|
|
|
self._id = None
|
|
|
|
except (AttributeError, ImportError):
|
|
|
|
pass # Interpreter is shutting down
|
2021-09-23 06:34:23 +08:00
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return "{}(id={})".format(self.__class__.__name__, self._id.value)
|
|
|
|
|
|
|
|
|
|
|
|
class Framebuffer:
|
|
|
|
"""OpenGL Framebuffer Object"""
|
|
|
|
|
|
|
|
def __init__(self, target=GL_FRAMEBUFFER):
|
|
|
|
"""Create an OpenGL Framebuffer object.
|
|
|
|
|
|
|
|
:rtype: :py:class:`~pyglet.image.Framebuffer`
|
|
|
|
|
|
|
|
.. versionadded:: 2.0
|
|
|
|
"""
|
2023-10-14 15:36:43 +08:00
|
|
|
self._context = pyglet.gl.current_context
|
2021-09-23 06:34:23 +08:00
|
|
|
self._id = GLuint()
|
|
|
|
glGenFramebuffers(1, self._id)
|
|
|
|
self._attachment_types = 0
|
|
|
|
self._width = 0
|
|
|
|
self._height = 0
|
|
|
|
self.target = target
|
|
|
|
|
|
|
|
@property
|
|
|
|
def id(self):
|
|
|
|
return self._id.value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def width(self):
|
|
|
|
"""The width of the widest attachment."""
|
|
|
|
return self._width
|
|
|
|
|
|
|
|
@property
|
|
|
|
def height(self):
|
|
|
|
"""The width of the widest attachment."""
|
|
|
|
return self._height
|
|
|
|
|
|
|
|
def bind(self):
|
|
|
|
glBindFramebuffer(self.target, self._id)
|
|
|
|
|
|
|
|
def unbind(self):
|
|
|
|
glBindFramebuffer(self.target, 0)
|
|
|
|
|
|
|
|
def clear(self):
|
|
|
|
if self._attachment_types:
|
|
|
|
self.bind()
|
|
|
|
glClear(self._attachment_types)
|
|
|
|
self.unbind()
|
|
|
|
|
|
|
|
def delete(self):
|
2023-10-14 15:36:43 +08:00
|
|
|
glDeleteFramebuffers(1, self._id)
|
|
|
|
self._id = None
|
|
|
|
|
|
|
|
def __del__(self):
|
|
|
|
if self._id is not None:
|
|
|
|
try:
|
|
|
|
self._context.delete_framebuffer(self._id.value)
|
|
|
|
self._id = None
|
|
|
|
except (AttributeError, ImportError):
|
|
|
|
pass # Interpreter is shutting down
|
2021-09-23 06:34:23 +08:00
|
|
|
|
|
|
|
@property
|
|
|
|
def is_complete(self):
|
|
|
|
return glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def get_status():
|
|
|
|
states = {GL_FRAMEBUFFER_UNSUPPORTED: "Framebuffer unsupported. Try another format.",
|
|
|
|
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: "Framebuffer incomplete attachment.",
|
|
|
|
GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: "Framebuffer missing attachment.",
|
|
|
|
GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: "Framebuffer unsupported dimension.",
|
|
|
|
GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: "Framebuffer incomplete formats.",
|
|
|
|
GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: "Framebuffer incomplete draw buffer.",
|
|
|
|
GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: "Framebuffer incomplete read buffer.",
|
|
|
|
GL_FRAMEBUFFER_COMPLETE: "Framebuffer is complete."}
|
|
|
|
|
|
|
|
gl_status = glCheckFramebufferStatus(GL_FRAMEBUFFER)
|
|
|
|
|
|
|
|
return states.get(gl_status, "Unknown error")
|
|
|
|
|
|
|
|
def attach_texture(self, texture, target=GL_FRAMEBUFFER, attachment=GL_COLOR_ATTACHMENT0):
|
|
|
|
"""Attach a Texture to the Framebuffer
|
|
|
|
|
|
|
|
:Parameters:
|
|
|
|
`texture` : pyglet.image.Texture
|
|
|
|
Specifies the texture object to attach to the framebuffer attachment
|
|
|
|
point named by attachment.
|
|
|
|
`target` : int
|
|
|
|
Specifies the framebuffer target. target must be GL_DRAW_FRAMEBUFFER,
|
|
|
|
GL_READ_FRAMEBUFFER, or GL_FRAMEBUFFER. GL_FRAMEBUFFER is equivalent
|
|
|
|
to GL_DRAW_FRAMEBUFFER.
|
|
|
|
`attachment` : int
|
|
|
|
Specifies the attachment point of the framebuffer. attachment must be
|
|
|
|
GL_COLOR_ATTACHMENTi, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT or
|
|
|
|
GL_DEPTH_STENCIL_ATTACHMENT.
|
|
|
|
"""
|
|
|
|
self.bind()
|
|
|
|
glFramebufferTexture(target, attachment, texture.id, texture.level)
|
|
|
|
# glFramebufferTexture2D(target, attachment, texture.target, texture.id, texture.level)
|
|
|
|
self._attachment_types |= attachment
|
|
|
|
self._width = max(texture.width, self._width)
|
|
|
|
self._height = max(texture.height, self._height)
|
|
|
|
self.unbind()
|
|
|
|
|
|
|
|
def attach_texture_layer(self, texture, layer, level, target=GL_FRAMEBUFFER, attachment=GL_COLOR_ATTACHMENT0):
|
|
|
|
"""Attach a Texture layer to the Framebuffer
|
|
|
|
|
|
|
|
:Parameters:
|
|
|
|
`texture` : pyglet.image.TextureArray
|
|
|
|
Specifies the texture object to attach to the framebuffer attachment
|
|
|
|
point named by attachment.
|
|
|
|
`layer` : int
|
|
|
|
Specifies the layer of texture to attach.
|
|
|
|
`level` : int
|
|
|
|
Specifies the mipmap level of texture to attach.
|
|
|
|
`target` : int
|
|
|
|
Specifies the framebuffer target. target must be GL_DRAW_FRAMEBUFFER,
|
|
|
|
GL_READ_FRAMEBUFFER, or GL_FRAMEBUFFER. GL_FRAMEBUFFER is equivalent
|
|
|
|
to GL_DRAW_FRAMEBUFFER.
|
|
|
|
`attachment` : int
|
|
|
|
Specifies the attachment point of the framebuffer. attachment must be
|
|
|
|
GL_COLOR_ATTACHMENTi, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT or
|
|
|
|
GL_DEPTH_STENCIL_ATTACHMENT.
|
|
|
|
"""
|
|
|
|
self.bind()
|
|
|
|
glFramebufferTextureLayer(target, attachment, texture.id, level, layer)
|
|
|
|
self._attachment_types |= attachment
|
|
|
|
self._width = max(texture.width, self._width)
|
|
|
|
self._height = max(texture.height, self._height)
|
|
|
|
self.unbind()
|
|
|
|
|
|
|
|
def attach_renderbuffer(self, renderbuffer, target=GL_FRAMEBUFFER, attachment=GL_COLOR_ATTACHMENT0):
|
|
|
|
""""Attach a Renderbuffer to the Framebuffer
|
|
|
|
|
|
|
|
:Parameters:
|
|
|
|
`renderbuffer` : pyglet.image.Renderbuffer
|
|
|
|
Specifies the Renderbuffer to attach to the framebuffer attachment
|
|
|
|
point named by attachment.
|
|
|
|
`target` : int
|
|
|
|
Specifies the framebuffer target. target must be GL_DRAW_FRAMEBUFFER,
|
|
|
|
GL_READ_FRAMEBUFFER, or GL_FRAMEBUFFER. GL_FRAMEBUFFER is equivalent
|
|
|
|
to GL_DRAW_FRAMEBUFFER.
|
|
|
|
`attachment` : int
|
|
|
|
Specifies the attachment point of the framebuffer. attachment must be
|
|
|
|
GL_COLOR_ATTACHMENTi, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT or
|
|
|
|
GL_DEPTH_STENCIL_ATTACHMENT.
|
|
|
|
"""
|
|
|
|
self.bind()
|
|
|
|
glFramebufferRenderbuffer(target, attachment, GL_RENDERBUFFER, renderbuffer.id)
|
|
|
|
self._attachment_types |= attachment
|
|
|
|
self._width = max(renderbuffer.width, self._width)
|
|
|
|
self._height = max(renderbuffer.height, self._height)
|
|
|
|
self.unbind()
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return "{}(id={})".format(self.__class__.__name__, self._id.value)
|