#include #include "client/rendering/wrapper/Framebuffer.h" Framebuffer::Framebuffer(const Size& size, int mode, bool texCompare) : size(size), mode(mode), textures(0), buffer(0), error(false) { glGenFramebuffers(1, &buffer); glBindFramebuffer(GL_FRAMEBUFFER, buffer); data[0] = {POSITION, GL_RGB16F, GL_RGB, GL_FLOAT}; data[1] = {NORMAL, GL_RGB16F, GL_RGB, GL_FLOAT}; data[2] = {COLOR, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}; data[3] = {RED, GL_R32F, GL_RGB, GL_FLOAT}; data[4] = {DEPTH, GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_FLOAT}; GLuint attachments[4]; int counter = 0; for(int i = 0; i < 4; i++) { if(mode & data[i].mask) { setupTexture(i, size.width, size.height, attachments, counter); } } if(mode & DEPTH) { genTexture(4, size.width, size.height); if(texCompare) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); } glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textures[4], 0); } glDrawBuffers(counter, attachments); GLenum glError = glCheckFramebufferStatus(GL_FRAMEBUFFER); if(glError != GL_FRAMEBUFFER_COMPLETE) { std::cout << "frame buffer error: " << getErrorString(error) << "\n"; error = true; } } Framebuffer::~Framebuffer() { glDeleteFramebuffers(1, &buffer); for(GLuint& texture : textures) { glDeleteTextures(1, &texture); } } bool Framebuffer::hasError() const { return error; } void Framebuffer::bind() const { glViewport(0, 0, size.width, size.height); glBindFramebuffer(GL_FRAMEBUFFER, buffer); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } void Framebuffer::resize(int width, int height) const { for(int i = 0; i < 5; i++) { if(mode & data[i].mask) { glBindTexture(GL_TEXTURE_2D, textures[i]); glTexImage2D(GL_TEXTURE_2D, 0, data[i].internalFormat, width, height, 0, data[i].format, data[i].type, nullptr); } } } void Framebuffer::bindTexture(int textureUnit, GLuint texture) const { glActiveTexture(GL_TEXTURE0 + textureUnit); glBindTexture(GL_TEXTURE_2D, texture); } void Framebuffer::bindPositionTexture(int textureUnit) const { bindTexture(textureUnit, textures[0]); } void Framebuffer::bindNormalTexture(int textureUnit) const { bindTexture(textureUnit, textures[1]); } void Framebuffer::bindColorTexture(int textureUnit) const { bindTexture(textureUnit, textures[2]); } void Framebuffer::bindRedTexture(int textureUnit) const { bindTexture(textureUnit, textures[3]); } void Framebuffer::bindDepthTexture(int textureUnit) const { bindTexture(textureUnit, textures[4]); } void Framebuffer::genTexture(int index, int width, int height) { glGenTextures(1, &(textures[index])); glBindTexture(GL_TEXTURE_2D, textures[index]); glTexImage2D(GL_TEXTURE_2D, 0, data[index].internalFormat, width, height, 0, data[index].format, data[index].type, nullptr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } void Framebuffer::setupTexture(int index, int width, int height, GLuint* attachments, int& counter) { genTexture(index, width, height); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + counter, GL_TEXTURE_2D, textures[index], 0); attachments[counter] = GL_COLOR_ATTACHMENT0 + counter; counter++; } const char* Framebuffer::getErrorString(GLenum error) const { switch(error) { case GL_FRAMEBUFFER_UNDEFINED: return "GL_FRAMEBUFFER_UNDEFINED"; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: return "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"; case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: return "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"; case GL_FRAMEBUFFER_UNSUPPORTED: return "GL_FRAMEBUFFER_UNSUPPORTED"; case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: return "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: return "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS"; } return "unknown error"; }