#include #include using namespace llmr; PrerenderedTexture::PrerenderedTexture(const RasterizedProperties &properties) : properties(properties) { } PrerenderedTexture::~PrerenderedTexture() { if (texture != 0) { glDeleteTextures(1, &texture); texture = 0; } if (fbo != 0) { glDeleteFramebuffers(1, &fbo); fbo = 0; } } void PrerenderedTexture::bindTexture() { if (texture == 0) { bindFramebuffer(); unbindFramebuffer(); } glBindTexture(GL_TEXTURE_2D, texture); } void PrerenderedTexture::bindFramebuffer() { glGetIntegerv(GL_FRAMEBUFFER_BINDING, &previous_fbo); if (texture == 0) { glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, properties.size, properties.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindTexture(GL_TEXTURE_2D, 0); } if (fbo == 0) { glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { fprintf(stderr, "Couldn't create framebuffer: "); switch (status) { case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: fprintf(stderr, "incomplete attachment\n"); break; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: fprintf(stderr, "incomplete missing attachment\n"); break; #ifdef GL_ES_VERSION_2_0 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: fprintf(stderr, "incomplete dimensions\n"); break; #else case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: fprintf(stderr, "incomplete draw buffer\n"); break; #endif case GL_FRAMEBUFFER_UNSUPPORTED: fprintf(stderr, "unsupported\n"); break; default: fprintf(stderr, "other\n"); break; } return; } } else { glBindFramebuffer(GL_FRAMEBUFFER, fbo); } } void PrerenderedTexture::unbindFramebuffer() { glBindFramebuffer(GL_FRAMEBUFFER, previous_fbo); if (fbo != 0) { glDeleteFramebuffers(1, &fbo); fbo = 0; } } void PrerenderedTexture::blur(Painter& painter, uint16_t passes) { const GLuint original_texture = texture; // Create a secondary texture GLuint secondary_texture; glGenTextures(1, &secondary_texture); glBindTexture(GL_TEXTURE_2D, secondary_texture); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, properties.size, properties.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindTexture(GL_TEXTURE_2D, 0); painter.useProgram(painter.gaussianShader->program); painter.gaussianShader->setMatrix(painter.flipMatrix); painter.gaussianShader->setImage(0); glActiveTexture(GL_TEXTURE0); for (int i = 0; i < passes; i++) { // Render horizontal glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, secondary_texture, 0); #if GL_EXT_discard_framebuffer const GLenum discards[] = { GL_COLOR_ATTACHMENT0 }; glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards); #endif glClear(GL_COLOR_BUFFER_BIT); painter.gaussianShader->setOffset({{ 1.0f / float(properties.size), 0 }}); glBindTexture(GL_TEXTURE_2D, original_texture); painter.coveringGaussianArray.bind(*painter.gaussianShader, painter.tileStencilBuffer, BUFFER_OFFSET(0)); glDrawArrays(GL_TRIANGLES, 0, (GLsizei)painter.tileStencilBuffer.index()); // Render vertical glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, original_texture, 0); #if GL_EXT_discard_framebuffer glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards); #endif glClear(GL_COLOR_BUFFER_BIT); painter.gaussianShader->setOffset({{ 0, 1.0f / float(properties.size) }}); glBindTexture(GL_TEXTURE_2D, secondary_texture); painter.coveringGaussianArray.bind(*painter.gaussianShader, painter.tileStencilBuffer, BUFFER_OFFSET(0)); glDrawArrays(GL_TRIANGLES, 0, (GLsizei)painter.tileStencilBuffer.index()); } glDeleteTextures(1, &secondary_texture); }