Mercurial > touhou
diff pytouhou/ui/opengl/framebuffer.pyx @ 586:4b0593da29d5
Simplify framebuffer rendering with glDrawArrays, and move it all to its own file.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Wed, 08 Oct 2014 16:34:24 +0200 |
parents | |
children | 6c9d8a3d853f |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/pytouhou/ui/opengl/framebuffer.pyx @@ -0,0 +1,121 @@ +# -*- encoding: utf-8 -*- +## +## Copyright (C) 2014 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published +## by the Free Software Foundation; version 3 only. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## + +from pytouhou.lib.opengl cimport \ + (glPushDebugGroup, glPopDebugGroup, GL_DEBUG_SOURCE_APPLICATION, + glGenTextures, glDeleteTextures, glBindTexture, glTexParameteri, + glTexImage2D, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_TEXTURE_MAG_FILTER, GL_LINEAR, GL_RGBA, GL_UNSIGNED_BYTE, + glGenRenderbuffers, glDeleteRenderbuffers, glBindRenderbuffer, + glRenderbufferStorage, GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, + glGenFramebuffers, glDeleteFramebuffers, glBindFramebuffer, + glFramebufferTexture2D, glFramebufferRenderbuffer, + glCheckFramebufferStatus, GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_COMPLETE, glGenBuffers, + glDeleteBuffers, glBindBuffer, glBufferData, GL_ARRAY_BUFFER, + GL_STATIC_DRAW, glGenVertexArrays, glDeleteVertexArrays, + glBindVertexArray, glVertexAttribPointer, GL_SHORT, GL_FLOAT, + glEnableVertexAttribArray, glDrawArrays, GL_TRIANGLE_STRIP) + +from .backend cimport use_debug_group, use_vao + +cdef class Framebuffer: + def __init__(self, int x, int y, int width, int height): + if use_debug_group: + glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, "Framebuffer creation") + + # This texture will receive the game area in native resolution. + glGenTextures(1, &self.texture) + glBindTexture(GL_TEXTURE_2D, self.texture) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + glTexImage2D(GL_TEXTURE_2D, 0, + GL_RGBA, + width, height, + 0, + GL_RGBA, GL_UNSIGNED_BYTE, + NULL) + glBindTexture(GL_TEXTURE_2D, 0) + + # We need a depth buffer, but don’t care about retrieving it. + glGenRenderbuffers(1, &self.rbo) + glBindRenderbuffer(GL_RENDERBUFFER, self.rbo) + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height) + glBindRenderbuffer(GL_RENDERBUFFER, 0) + + # The framebuffer is there as a rendering target. + glGenFramebuffers(1, &self.fbo) + glBindFramebuffer(GL_FRAMEBUFFER, self.fbo) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self.texture, 0) + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, self.rbo) + assert glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE + glBindFramebuffer(GL_FRAMEBUFFER, 0) + + # We’ll use only those vertices, everytime. + self.buf[0] = PassthroughVertex(x, y, 0, 1) + self.buf[1] = PassthroughVertex(x + width, y, 1, 1) + self.buf[2] = PassthroughVertex(x, y + height, 0, 0) + self.buf[3] = PassthroughVertex(x + width, y + height, 1, 0) + + # Now we upload those vertices into a static vbo. + glGenBuffers(1, &self.vbo) + glBindBuffer(GL_ARRAY_BUFFER, self.vbo) + glBufferData(GL_ARRAY_BUFFER, sizeof(self.buf), self.buf, GL_STATIC_DRAW) + + # As a performance optimisation, if supported, store the rendering state into a vao. + if use_vao: + glGenVertexArrays(1, &self.vao) + glBindVertexArray(self.vao) + self.set_state() + glBindVertexArray(0) + + glBindBuffer(GL_ARRAY_BUFFER, 0) + + if use_debug_group: + glPopDebugGroup() + + def __dealloc__(self): + if use_vao: + glDeleteVertexArrays(1, &self.vao) + glDeleteTextures(1, &self.texture) + glDeleteRenderbuffers(1, &self.rbo) + glDeleteFramebuffers(1, &self.fbo) + glDeleteBuffers(1, &self.vbo) + + cpdef bind(self): + glBindFramebuffer(GL_FRAMEBUFFER, self.fbo) + + cdef void set_state(self) nogil: + glBindBuffer(GL_ARRAY_BUFFER, self.vbo) + + #TODO: find a way to use offsetof() instead of those ugly hardcoded values. + glVertexAttribPointer(0, 2, GL_SHORT, False, sizeof(PassthroughVertex), <void*>0) + glEnableVertexAttribArray(0) + glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(PassthroughVertex), <void*>4) + glEnableVertexAttribArray(1) + + cdef void render(self) nogil: + if use_vao: + glBindVertexArray(self.vao) + else: + self.set_state() + + glBindTexture(GL_TEXTURE_2D, self.texture) + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4) + glBindTexture(GL_TEXTURE_2D, 0) + + if use_vao: + glBindVertexArray(0) + else: + glBindBuffer(GL_ARRAY_BUFFER, 0)