RenderTextureImplFBO::~RenderTextureImplFBO() { m_context->setActive(true); // Destroy the depth buffer if (m_depthBuffer) { GLuint depthBuffer = static_cast<GLuint>(m_depthBuffer); glCheck(GLEXT_glDeleteRenderbuffers(1, &depthBuffer)); } // Destroy the frame buffer if (m_frameBuffer) { GLuint frameBuffer = static_cast<GLuint>(m_frameBuffer); glCheck(GLEXT_glDeleteFramebuffers(1, &frameBuffer)); } // Delete the context delete m_context; }
Image Texture::copyToImage() const { // Easy case: empty texture if (!m_texture) return Image(); ensureGlContext(); // Make sure that the current texture binding will be preserved priv::TextureSaver save; // Create an array of pixels std::vector<Uint8> pixels(m_size.x * m_size.y * 4); #ifdef SFML_OPENGL_ES // OpenGL ES doesn't have the glGetTexImage function, the only way to read // from a texture is to bind it to a FBO and use glReadPixels GLuint frameBuffer = 0; glCheck(GLEXT_glGenFramebuffers(1, &frameBuffer)); if (frameBuffer) { GLint previousFrameBuffer; glCheck(glGetIntegerv(GLEXT_GL_FRAMEBUFFER_BINDING, &previousFrameBuffer)); glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, frameBuffer)); glCheck(GLEXT_glFramebufferTexture2D(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0)); glCheck(glReadPixels(0, 0, m_size.x, m_size.y, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0])); glCheck(GLEXT_glDeleteFramebuffers(1, &frameBuffer)); glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, previousFrameBuffer)); } #else if ((m_size == m_actualSize) && !m_pixelsFlipped) { // Texture is not padded nor flipped, we can use a direct copy glCheck(glBindTexture(GL_TEXTURE_2D, m_texture)); glCheck(glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0])); } else { // Texture is either padded or flipped, we have to use a slower algorithm // All the pixels will first be copied to a temporary array std::vector<Uint8> allPixels(m_actualSize.x * m_actualSize.y * 4); glCheck(glBindTexture(GL_TEXTURE_2D, m_texture)); glCheck(glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &allPixels[0])); // Then we copy the useful pixels from the temporary array to the final one const Uint8* src = &allPixels[0]; Uint8* dst = &pixels[0]; int srcPitch = m_actualSize.x * 4; int dstPitch = m_size.x * 4; // Handle the case where source pixels are flipped vertically if (m_pixelsFlipped) { src += srcPitch * (m_size.y - 1); srcPitch = -srcPitch; } for (unsigned int i = 0; i < m_size.y; ++i) { std::memcpy(dst, src, dstPitch); src += srcPitch; dst += dstPitch; } } #endif // SFML_OPENGL_ES // Create the image Image image; image.create(m_size.x, m_size.y, &pixels[0]); return image; }
void Texture::update(const Texture& texture, unsigned int x, unsigned int y) { assert(x + texture.m_size.x <= m_size.x); assert(y + texture.m_size.x <= m_size.y); if (!m_texture || !texture.m_texture) return; #ifndef SFML_OPENGL_ES { TransientContextLock lock; // Make sure that extensions are initialized priv::ensureExtensionsInit(); } if (GLEXT_framebuffer_object && GLEXT_framebuffer_blit) { TransientContextLock lock; // Save the current bindings so we can restore them after we are done GLint readFramebuffer = 0; GLint drawFramebuffer = 0; glCheck(glGetIntegerv(GLEXT_GL_READ_FRAMEBUFFER_BINDING, &readFramebuffer)); glCheck(glGetIntegerv(GLEXT_GL_DRAW_FRAMEBUFFER_BINDING, &drawFramebuffer)); // Create the framebuffers GLuint sourceFrameBuffer = 0; GLuint destFrameBuffer = 0; glCheck(GLEXT_glGenFramebuffers(1, &sourceFrameBuffer)); glCheck(GLEXT_glGenFramebuffers(1, &destFrameBuffer)); if (!sourceFrameBuffer || !destFrameBuffer) { err() << "Cannot copy texture, failed to create a frame buffer object" << std::endl; return; } // Link the source texture to the source frame buffer glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_READ_FRAMEBUFFER, sourceFrameBuffer)); glCheck(GLEXT_glFramebufferTexture2D(GLEXT_GL_READ_FRAMEBUFFER, GLEXT_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.m_texture, 0)); // Link the destination texture to the destination frame buffer glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_DRAW_FRAMEBUFFER, destFrameBuffer)); glCheck(GLEXT_glFramebufferTexture2D(GLEXT_GL_DRAW_FRAMEBUFFER, GLEXT_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0)); // A final check, just to be sure... GLenum sourceStatus; glCheck(sourceStatus = GLEXT_glCheckFramebufferStatus(GLEXT_GL_READ_FRAMEBUFFER)); GLenum destStatus; glCheck(destStatus = GLEXT_glCheckFramebufferStatus(GLEXT_GL_DRAW_FRAMEBUFFER)); if ((sourceStatus == GLEXT_GL_FRAMEBUFFER_COMPLETE) && (destStatus == GLEXT_GL_FRAMEBUFFER_COMPLETE)) { // Blit the texture contents from the source to the destination texture glCheck(GLEXT_glBlitFramebuffer(0, 0, texture.m_size.x, texture.m_size.y, x, y, x + texture.m_size.x, y + texture.m_size.y, GL_COLOR_BUFFER_BIT, GL_NEAREST)); } else { err() << "Cannot copy texture, failed to link texture to frame buffer" << std::endl; } // Restore previously bound framebuffers glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_READ_FRAMEBUFFER, readFramebuffer)); glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_DRAW_FRAMEBUFFER, drawFramebuffer)); // Delete the framebuffers glCheck(GLEXT_glDeleteFramebuffers(1, &sourceFrameBuffer)); glCheck(GLEXT_glDeleteFramebuffers(1, &destFrameBuffer)); return; } #endif // SFML_OPENGL_ES update(texture.copyToImage(), x, y); }