249 lines
9.2 KiB
Python
249 lines
9.2 KiB
Python
|
# ----------------------------------------------------------------------------
|
||
|
# pyglet
|
||
|
# Copyright (c) 2006-2008 Alex Holkner
|
||
|
# Copyright (c) 2008-2021 pyglet contributors
|
||
|
# All rights reserved.
|
||
|
#
|
||
|
# Redistribution and use in source and binary forms, with or without
|
||
|
# modification, are permitted provided that the following conditions
|
||
|
# are met:
|
||
|
#
|
||
|
# * Redistributions of source code must retain the above copyright
|
||
|
# notice, this list of conditions and the following disclaimer.
|
||
|
# * Redistributions in binary form must reproduce the above copyright
|
||
|
# notice, this list of conditions and the following disclaimer in
|
||
|
# the documentation and/or other materials provided with the
|
||
|
# distribution.
|
||
|
# * Neither the name of pyglet nor the names of its
|
||
|
# contributors may be used to endorse or promote products
|
||
|
# derived from this software without specific prior written
|
||
|
# permission.
|
||
|
#
|
||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||
|
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||
|
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||
|
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||
|
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||
|
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||
|
# POSSIBILITY OF SUCH DAMAGE.
|
||
|
# ----------------------------------------------------------------------------
|
||
|
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."""
|
||
|
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)
|
||
|
|
||
|
def __del__(self):
|
||
|
try:
|
||
|
glDeleteRenderbuffers(1, self._id)
|
||
|
# Python interpreter is shutting down:
|
||
|
except Exception:
|
||
|
pass
|
||
|
|
||
|
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
|
||
|
"""
|
||
|
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):
|
||
|
try:
|
||
|
glDeleteFramebuffers(1, self._id)
|
||
|
except Exception:
|
||
|
pass
|
||
|
|
||
|
@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 __del__(self):
|
||
|
try:
|
||
|
glDeleteFramebuffers(1, self._id)
|
||
|
# Python interpreter is shutting down:
|
||
|
except Exception:
|
||
|
pass
|
||
|
|
||
|
def __repr__(self):
|
||
|
return "{}(id={})".format(self.__class__.__name__, self._id.value)
|