playscii/framebuffer.py

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