122 lines
5.4 KiB
Python
122 lines
5.4 KiB
Python
import numpy as np
|
|
from OpenGL import GL
|
|
|
|
|
|
class Framebuffer:
|
|
|
|
start_crt_enabled = False
|
|
disable_crt = False
|
|
clear_color = (0, 0, 0, 1)
|
|
# declared as an option here in case people want to sub their own via CFG
|
|
crt_fragment_shader_filename = 'framebuffer_f_crt.glsl'
|
|
|
|
def __init__(self, app, width=None, height=None):
|
|
self.app = app
|
|
self.width, self.height = width or self.app.window_width, height or self.app.window_height
|
|
# bind vao before compiling shaders
|
|
if self.app.use_vao:
|
|
self.vao = GL.glGenVertexArrays(1)
|
|
GL.glBindVertexArray(self.vao)
|
|
self.vbo = GL.glGenBuffers(1)
|
|
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.vbo)
|
|
fb_verts = np.array([-1, -1, 1, -1, -1, 1, 1, 1], dtype=np.float32)
|
|
GL.glBufferData(GL.GL_ARRAY_BUFFER, fb_verts.nbytes, fb_verts,
|
|
GL.GL_STATIC_DRAW)
|
|
# texture, depth buffer, framebuffer
|
|
self.texture = GL.glGenTextures(1)
|
|
self.depth_buffer = GL.glGenRenderbuffers(1)
|
|
self.framebuffer = GL.glGenFramebuffers(1)
|
|
self.setup_texture_and_buffers()
|
|
# shaders
|
|
self.plain_shader = self.app.sl.new_shader('framebuffer_v.glsl', 'framebuffer_f.glsl')
|
|
if not self.disable_crt:
|
|
self.crt_shader = self.app.sl.new_shader('framebuffer_v.glsl', self.crt_fragment_shader_filename)
|
|
self.crt = self.get_crt_enabled()
|
|
# shader uniforms and attributes
|
|
self.plain_tex_uniform = self.plain_shader.get_uniform_location('fbo_texture')
|
|
self.plain_attrib = self.plain_shader.get_attrib_location('v_coord')
|
|
GL.glEnableVertexAttribArray(self.plain_attrib)
|
|
GL.glVertexAttribPointer(self.plain_attrib, 2, GL.GL_FLOAT, GL.GL_FALSE, 0, None)
|
|
if not self.disable_crt:
|
|
self.crt_tex_uniform = self.crt_shader.get_uniform_location('fbo_texture')
|
|
self.crt_time_uniform = self.crt_shader.get_uniform_location('elapsed_time')
|
|
self.crt_res_uniform = self.crt_shader.get_uniform_location('resolution')
|
|
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, 0)
|
|
if self.app.use_vao:
|
|
GL.glBindVertexArray(0)
|
|
|
|
def get_crt_enabled(self):
|
|
return self.disable_crt or self.start_crt_enabled
|
|
|
|
def setup_texture_and_buffers(self):
|
|
GL.glBindTexture(GL.GL_TEXTURE_2D, self.texture)
|
|
GL.glTexParameterf(GL.GL_TEXTURE_2D,
|
|
GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR)
|
|
GL.glTexParameterf(GL.GL_TEXTURE_2D,
|
|
GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR)
|
|
GL.glTexParameterf(GL.GL_TEXTURE_2D,
|
|
GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE)
|
|
GL.glTexParameterf(GL.GL_TEXTURE_2D,
|
|
GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE)
|
|
GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA,
|
|
self.width, self.height, 0,
|
|
GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, None)
|
|
GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, self.depth_buffer)
|
|
GL.glRenderbufferStorage(GL.GL_RENDERBUFFER, GL.GL_DEPTH_COMPONENT16,
|
|
self.width, self.height)
|
|
GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, 0)
|
|
GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, self.framebuffer)
|
|
GL.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0,
|
|
GL.GL_TEXTURE_2D, self.texture, 0)
|
|
GL.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT,
|
|
GL.GL_RENDERBUFFER, self.depth_buffer)
|
|
GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0)
|
|
|
|
def resize(self, new_width, new_height):
|
|
self.width, self.height = new_width, new_height
|
|
self.setup_texture_and_buffers()
|
|
|
|
def toggle_crt(self):
|
|
self.crt = not self.crt
|
|
|
|
def destroy(self):
|
|
if self.app.use_vao:
|
|
GL.glDeleteVertexArrays(1, [self.vao])
|
|
GL.glDeleteBuffers(1, [self.vbo])
|
|
GL.glDeleteRenderbuffers(1, [self.depth_buffer])
|
|
GL.glDeleteTextures([self.texture])
|
|
GL.glDeleteFramebuffers(1, [self.framebuffer])
|
|
|
|
def render(self):
|
|
if self.crt and not self.disable_crt:
|
|
GL.glUseProgram(self.crt_shader.program)
|
|
GL.glUniform1i(self.crt_tex_uniform, 0)
|
|
GL.glUniform2f(self.crt_res_uniform, self.width, self.height)
|
|
GL.glUniform1f(self.crt_time_uniform, self.app.get_elapsed_time())
|
|
else:
|
|
GL.glUseProgram(self.plain_shader.program)
|
|
GL.glUniform1i(self.plain_tex_uniform, 0)
|
|
GL.glBindTexture(GL.GL_TEXTURE_2D, self.texture)
|
|
GL.glClearColor(*self.clear_color)
|
|
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
|
|
# VAO vs non-VAO paths
|
|
if self.app.use_vao:
|
|
GL.glBindVertexArray(self.vao)
|
|
else:
|
|
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.vbo)
|
|
GL.glVertexAttribPointer(self.plain_attrib, 2, GL.GL_FLOAT, GL.GL_FALSE, 0, None)
|
|
GL.glEnableVertexAttribArray(self.plain_attrib)
|
|
GL.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4)
|
|
if self.app.use_vao:
|
|
GL.glBindVertexArray(0)
|
|
GL.glUseProgram(0)
|
|
|
|
|
|
class ExportFramebuffer(Framebuffer):
|
|
clear_color = (0, 0, 0, 0)
|
|
def get_crt_enabled(self): return True
|
|
|
|
|
|
class ExportFramebufferNoCRT(Framebuffer):
|
|
clear_color = (0, 0, 0, 0)
|
|
def get_crt_enabled(self): return False
|