diff --git a/include/SFML/Graphics/RenderTexture.hpp b/include/SFML/Graphics/RenderTexture.hpp index 77647888..a26d94b6 100644 --- a/include/SFML/Graphics/RenderTexture.hpp +++ b/include/SFML/Graphics/RenderTexture.hpp @@ -31,6 +31,7 @@ #include #include #include +#include namespace sf @@ -82,8 +83,38 @@ public: /// /// \return True if creation has been successful /// + /// \deprecated Use create(unsigned int, unsigned int, const ContextSettings&) instead. + /// //////////////////////////////////////////////////////////// - bool create(unsigned int width, unsigned int height, bool depthBuffer = false); + SFML_DEPRECATED bool create(unsigned int width, unsigned int height, bool depthBuffer); + + //////////////////////////////////////////////////////////// + /// \brief Create the render-texture + /// + /// Before calling this function, the render-texture is in + /// an invalid state, thus it is mandatory to call it before + /// doing anything with the render-texture. + /// The last parameter, \a settings, is useful if you want to enable + /// multi-sampling or use the render-texture for OpenGL rendering that + /// requires a depth or stencil buffer. Otherwise it is unnecessary, and + /// you should leave this parameter at its default value. + /// + /// \param width Width of the render-texture + /// \param height Height of the render-texture + /// \param settings Additional settings for the underlying OpenGL texture and context + /// + /// \return True if creation has been successful + /// + //////////////////////////////////////////////////////////// + bool create(unsigned int width, unsigned int height, const ContextSettings& settings = ContextSettings()); + + //////////////////////////////////////////////////////////// + /// \brief Get the maximum anti-aliasing level supported by the system + /// + /// \return The maximum anti-aliasing level supported by the system + /// + //////////////////////////////////////////////////////////// + static unsigned int getMaximumAntialiasingLevel(); //////////////////////////////////////////////////////////// /// \brief Enable or disable texture smoothing diff --git a/src/SFML/Graphics/GLExtensions.hpp b/src/SFML/Graphics/GLExtensions.hpp index 0e0c8f51..687cf376 100644 --- a/src/SFML/Graphics/GLExtensions.hpp +++ b/src/SFML/Graphics/GLExtensions.hpp @@ -124,9 +124,15 @@ #define GLEXT_GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_OES #define GLEXT_GL_INVALID_FRAMEBUFFER_OPERATION GL_INVALID_FRAMEBUFFER_OPERATION_OES + // Core since 3.0 + #define GLEXT_packed_depth_stencil false + // Core since 3.0 #define GLEXT_framebuffer_blit false + // Core since 3.0 + #define GLEXT_framebuffer_multisample false + // Core since 3.0 - NV_copy_buffer #define GLEXT_copy_buffer false @@ -277,6 +283,11 @@ #define GLEXT_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_EXT #define GLEXT_GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_EXT #define GLEXT_GL_INVALID_FRAMEBUFFER_OPERATION GL_INVALID_FRAMEBUFFER_OPERATION_EXT + #define GLEXT_GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT_EXT + + // Core since 3.0 - EXT_packed_depth_stencil + #define GLEXT_packed_depth_stencil sfogl_ext_EXT_packed_depth_stencil + #define GLEXT_GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_EXT // Core since 3.0 - EXT_framebuffer_blit #define GLEXT_framebuffer_blit sfogl_ext_EXT_framebuffer_blit @@ -286,6 +297,11 @@ #define GLEXT_GL_DRAW_FRAMEBUFFER_BINDING GL_DRAW_FRAMEBUFFER_BINDING_EXT #define GLEXT_GL_READ_FRAMEBUFFER_BINDING GL_READ_FRAMEBUFFER_BINDING_EXT + // Core since 3.0 - EXT_framebuffer_multisample + #define GLEXT_framebuffer_multisample sfogl_ext_EXT_framebuffer_multisample + #define GLEXT_glRenderbufferStorageMultisample glRenderbufferStorageMultisampleEXT + #define GLEXT_GL_MAX_SAMPLES GL_MAX_SAMPLES_EXT + // Core since 3.1 - ARB_copy_buffer #define GLEXT_copy_buffer sfogl_ext_ARB_copy_buffer #define GLEXT_GL_COPY_READ_BUFFER GL_COPY_READ_BUFFER diff --git a/src/SFML/Graphics/GLExtensions.txt b/src/SFML/Graphics/GLExtensions.txt index fe65158c..e12e8093 100644 --- a/src/SFML/Graphics/GLExtensions.txt +++ b/src/SFML/Graphics/GLExtensions.txt @@ -16,6 +16,8 @@ ARB_texture_non_power_of_two EXT_blend_equation_separate EXT_texture_sRGB EXT_framebuffer_object +EXT_packed_depth_stencil EXT_framebuffer_blit +EXT_framebuffer_multisample ARB_copy_buffer ARB_geometry_shader4 diff --git a/src/SFML/Graphics/GLLoader.cpp b/src/SFML/Graphics/GLLoader.cpp index 4bb1a9bb..85f6d7e5 100644 --- a/src/SFML/Graphics/GLLoader.cpp +++ b/src/SFML/Graphics/GLLoader.cpp @@ -48,7 +48,9 @@ int sfogl_ext_ARB_texture_non_power_of_two = sfogl_LOAD_FAILED; int sfogl_ext_EXT_blend_equation_separate = sfogl_LOAD_FAILED; int sfogl_ext_EXT_texture_sRGB = sfogl_LOAD_FAILED; int sfogl_ext_EXT_framebuffer_object = sfogl_LOAD_FAILED; +int sfogl_ext_EXT_packed_depth_stencil = sfogl_LOAD_FAILED; int sfogl_ext_EXT_framebuffer_blit = sfogl_LOAD_FAILED; +int sfogl_ext_EXT_framebuffer_multisample = sfogl_LOAD_FAILED; int sfogl_ext_ARB_copy_buffer = sfogl_LOAD_FAILED; int sfogl_ext_ARB_geometry_shader4 = sfogl_LOAD_FAILED; @@ -879,6 +881,19 @@ static int Load_EXT_framebuffer_blit() return numFailed; } +void (GL_FUNCPTR *sf_ptrc_glRenderbufferStorageMultisampleEXT)(GLenum, GLsizei, GLenum, GLsizei, GLsizei) = NULL; + +static int Load_EXT_framebuffer_multisample() +{ + int numFailed = 0; + + sf_ptrc_glRenderbufferStorageMultisampleEXT = reinterpret_cast(glLoaderGetProcAddress("glRenderbufferStorageMultisampleEXT")); + if (!sf_ptrc_glRenderbufferStorageMultisampleEXT) + numFailed++; + + return numFailed; +} + void (GL_FUNCPTR *sf_ptrc_glCopyBufferSubData)(GLenum, GLenum, GLintptr, GLintptr, GLsizeiptr) = NULL; static int Load_ARB_copy_buffer() @@ -928,7 +943,7 @@ typedef struct sfogl_StrToExtMap_s PFN_LOADFUNCPOINTERS LoadExtension; } sfogl_StrToExtMap; -static sfogl_StrToExtMap ExtensionMap[18] = { +static sfogl_StrToExtMap ExtensionMap[20] = { {"GL_SGIS_texture_edge_clamp", &sfogl_ext_SGIS_texture_edge_clamp, NULL}, {"GL_EXT_texture_edge_clamp", &sfogl_ext_EXT_texture_edge_clamp, NULL}, {"GL_EXT_blend_minmax", &sfogl_ext_EXT_blend_minmax, Load_EXT_blend_minmax}, @@ -944,12 +959,14 @@ static sfogl_StrToExtMap ExtensionMap[18] = { {"GL_EXT_blend_equation_separate", &sfogl_ext_EXT_blend_equation_separate, Load_EXT_blend_equation_separate}, {"GL_EXT_texture_sRGB", &sfogl_ext_EXT_texture_sRGB, NULL}, {"GL_EXT_framebuffer_object", &sfogl_ext_EXT_framebuffer_object, Load_EXT_framebuffer_object}, + {"GL_EXT_packed_depth_stencil", &sfogl_ext_EXT_packed_depth_stencil, NULL}, {"GL_EXT_framebuffer_blit", &sfogl_ext_EXT_framebuffer_blit, Load_EXT_framebuffer_blit}, + {"GL_EXT_framebuffer_multisample", &sfogl_ext_EXT_framebuffer_multisample, Load_EXT_framebuffer_multisample}, {"GL_ARB_copy_buffer", &sfogl_ext_ARB_copy_buffer, Load_ARB_copy_buffer}, {"GL_ARB_geometry_shader4", &sfogl_ext_ARB_geometry_shader4, Load_ARB_geometry_shader4} }; -static int g_extensionMapSize = 18; +static int g_extensionMapSize = 20; static void ClearExtensionVars() @@ -969,7 +986,9 @@ static void ClearExtensionVars() sfogl_ext_EXT_blend_equation_separate = sfogl_LOAD_FAILED; sfogl_ext_EXT_texture_sRGB = sfogl_LOAD_FAILED; sfogl_ext_EXT_framebuffer_object = sfogl_LOAD_FAILED; + sfogl_ext_EXT_packed_depth_stencil = sfogl_LOAD_FAILED; sfogl_ext_EXT_framebuffer_blit = sfogl_LOAD_FAILED; + sfogl_ext_EXT_framebuffer_multisample = sfogl_LOAD_FAILED; sfogl_ext_ARB_copy_buffer = sfogl_LOAD_FAILED; sfogl_ext_ARB_geometry_shader4 = sfogl_LOAD_FAILED; } diff --git a/src/SFML/Graphics/GLLoader.hpp b/src/SFML/Graphics/GLLoader.hpp index d7920f90..9fe4adb1 100644 --- a/src/SFML/Graphics/GLLoader.hpp +++ b/src/SFML/Graphics/GLLoader.hpp @@ -185,7 +185,9 @@ extern int sfogl_ext_ARB_texture_non_power_of_two; extern int sfogl_ext_EXT_blend_equation_separate; extern int sfogl_ext_EXT_texture_sRGB; extern int sfogl_ext_EXT_framebuffer_object; +extern int sfogl_ext_EXT_packed_depth_stencil; extern int sfogl_ext_EXT_framebuffer_blit; +extern int sfogl_ext_EXT_framebuffer_multisample; extern int sfogl_ext_ARB_copy_buffer; extern int sfogl_ext_ARB_geometry_shader4; @@ -414,11 +416,20 @@ extern int sfogl_ext_ARB_geometry_shader4; #define GL_STENCIL_INDEX4_EXT 0x8D47 #define GL_STENCIL_INDEX8_EXT 0x8D48 +#define GL_DEPTH24_STENCIL8_EXT 0x88F0 +#define GL_DEPTH_STENCIL_EXT 0x84F9 +#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 +#define GL_UNSIGNED_INT_24_8_EXT 0x84FA + #define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6 #define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 #define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA #define GL_READ_FRAMEBUFFER_EXT 0x8CA8 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 +#define GL_MAX_SAMPLES_EXT 0x8D57 +#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB + #define GL_COPY_READ_BUFFER 0x8F36 #define GL_COPY_WRITE_BUFFER 0x8F37 @@ -1311,12 +1322,19 @@ extern void (GL_FUNCPTR *sf_ptrc_glRenderbufferStorageEXT)(GLenum, GLenum, GLsiz #define glRenderbufferStorageEXT sf_ptrc_glRenderbufferStorageEXT #endif // GL_EXT_framebuffer_object + #ifndef GL_EXT_framebuffer_blit #define GL_EXT_framebuffer_blit 1 extern void (GL_FUNCPTR *sf_ptrc_glBlitFramebufferEXT)(GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum); #define glBlitFramebufferEXT sf_ptrc_glBlitFramebufferEXT #endif // GL_EXT_framebuffer_blit +#ifndef GL_EXT_framebuffer_multisample +#define GL_EXT_framebuffer_multisample 1 +extern void (GL_FUNCPTR *sf_ptrc_glRenderbufferStorageMultisampleEXT)(GLenum, GLsizei, GLenum, GLsizei, GLsizei); +#define glRenderbufferStorageMultisampleEXT sf_ptrc_glRenderbufferStorageMultisampleEXT +#endif // GL_EXT_framebuffer_multisample + #ifndef GL_ARB_copy_buffer #define GL_ARB_copy_buffer 1 extern void (GL_FUNCPTR *sf_ptrc_glCopyBufferSubData)(GLenum, GLenum, GLintptr, GLintptr, GLsizeiptr); diff --git a/src/SFML/Graphics/RenderTexture.cpp b/src/SFML/Graphics/RenderTexture.cpp index b81a4091..a52e5063 100644 --- a/src/SFML/Graphics/RenderTexture.cpp +++ b/src/SFML/Graphics/RenderTexture.cpp @@ -50,6 +50,13 @@ RenderTexture::~RenderTexture() //////////////////////////////////////////////////////////// bool RenderTexture::create(unsigned int width, unsigned int height, bool depthBuffer) +{ + return create(width, height, ContextSettings(depthBuffer ? 32 : 0)); +} + + +//////////////////////////////////////////////////////////// +bool RenderTexture::create(unsigned int width, unsigned int height, const ContextSettings& settings) { // Create the texture if (!m_texture.create(width, height)) @@ -78,7 +85,7 @@ bool RenderTexture::create(unsigned int width, unsigned int height, bool depthBu } // Initialize the render texture - if (!m_impl->create(width, height, m_texture.m_texture, depthBuffer)) + if (!m_impl->create(width, height, m_texture.m_texture, settings)) return false; // We can now initialize the render target part @@ -88,6 +95,20 @@ bool RenderTexture::create(unsigned int width, unsigned int height, bool depthBu } +//////////////////////////////////////////////////////////// +unsigned int RenderTexture::getMaximumAntialiasingLevel() +{ + if (priv::RenderTextureImplFBO::isAvailable()) + { + return priv::RenderTextureImplFBO::getMaximumAntialiasingLevel(); + } + else + { + return priv::RenderTextureImplDefault::getMaximumAntialiasingLevel(); + } +} + + //////////////////////////////////////////////////////////// void RenderTexture::setSmooth(bool smooth) { diff --git a/src/SFML/Graphics/RenderTextureImpl.hpp b/src/SFML/Graphics/RenderTextureImpl.hpp index 9ad35b8d..5a357c72 100644 --- a/src/SFML/Graphics/RenderTextureImpl.hpp +++ b/src/SFML/Graphics/RenderTextureImpl.hpp @@ -33,6 +33,9 @@ namespace sf { + +struct ContextSettings; + namespace priv { //////////////////////////////////////////////////////////// @@ -52,15 +55,15 @@ public: //////////////////////////////////////////////////////////// /// \brief Create the render texture implementation /// - /// \param width Width of the texture to render to - /// \param height Height of the texture to render to - /// \param textureId OpenGL identifier of the target texture - /// \param depthBuffer Is a depth buffer requested? + /// \param width Width of the texture to render to + /// \param height Height of the texture to render to + /// \param textureId OpenGL identifier of the target texture + /// \param settings Context settings to create render-texture with /// /// \return True if creation has been successful /// //////////////////////////////////////////////////////////// - virtual bool create(unsigned int width, unsigned int height, unsigned int textureId, bool depthBuffer) = 0; + virtual bool create(unsigned int width, unsigned int height, unsigned int textureId, const ContextSettings& settings) = 0; //////////////////////////////////////////////////////////// /// \brief Activate or deactivate the render texture for rendering diff --git a/src/SFML/Graphics/RenderTextureImplDefault.cpp b/src/SFML/Graphics/RenderTextureImplDefault.cpp index e24978e9..29399d50 100644 --- a/src/SFML/Graphics/RenderTextureImplDefault.cpp +++ b/src/SFML/Graphics/RenderTextureImplDefault.cpp @@ -55,14 +55,24 @@ RenderTextureImplDefault::~RenderTextureImplDefault() //////////////////////////////////////////////////////////// -bool RenderTextureImplDefault::create(unsigned int width, unsigned int height, unsigned int, bool depthBuffer) +unsigned int RenderTextureImplDefault::getMaximumAntialiasingLevel() +{ + // If the system is so old that it doesn't support FBOs, chances are it is + // also using either a software renderer or some CPU emulated support for AA + // In order to not cripple performance in this rare case, we just return 0 here + return 0; +} + + +//////////////////////////////////////////////////////////// +bool RenderTextureImplDefault::create(unsigned int width, unsigned int height, unsigned int, const ContextSettings& settings) { // Store the dimensions m_width = width; m_height = height; // Create the in-memory OpenGL context - m_context = new Context(ContextSettings(depthBuffer ? 32 : 0), width, height); + m_context = new Context(settings, width, height); return true; } diff --git a/src/SFML/Graphics/RenderTextureImplDefault.hpp b/src/SFML/Graphics/RenderTextureImplDefault.hpp index 6f5d0f3e..c3b59aea 100644 --- a/src/SFML/Graphics/RenderTextureImplDefault.hpp +++ b/src/SFML/Graphics/RenderTextureImplDefault.hpp @@ -58,20 +58,28 @@ public: //////////////////////////////////////////////////////////// ~RenderTextureImplDefault(); + //////////////////////////////////////////////////////////// + /// \brief Get the maximum anti-aliasing level supported by the system + /// + /// \return The maximum anti-aliasing level supported by the system + /// + //////////////////////////////////////////////////////////// + static unsigned int getMaximumAntialiasingLevel(); + private: //////////////////////////////////////////////////////////// /// \brief Create the render texture implementation /// - /// \param width Width of the texture to render to - /// \param height Height of the texture to render to - /// \param textureId OpenGL identifier of the target texture - /// \param depthBuffer Is a depth buffer requested? + /// \param width Width of the texture to render to + /// \param height Height of the texture to render to + /// \param textureId OpenGL identifier of the target texture + /// \param settings Context settings to create render-texture with /// /// \return True if creation has been successful /// //////////////////////////////////////////////////////////// - virtual bool create(unsigned int width, unsigned int height, unsigned int textureId, bool depthBuffer); + virtual bool create(unsigned int width, unsigned int height, unsigned int textureId, const ContextSettings& settings); //////////////////////////////////////////////////////////// /// \brief Activate or deactivate the render texture for rendering diff --git a/src/SFML/Graphics/RenderTextureImplFBO.cpp b/src/SFML/Graphics/RenderTextureImplFBO.cpp index 95f94b3f..c424d33f 100644 --- a/src/SFML/Graphics/RenderTextureImplFBO.cpp +++ b/src/SFML/Graphics/RenderTextureImplFBO.cpp @@ -37,9 +37,13 @@ namespace priv { //////////////////////////////////////////////////////////// RenderTextureImplFBO::RenderTextureImplFBO() : -m_context (NULL), -m_frameBuffer(0), -m_depthBuffer(0) +m_context (NULL), +m_frameBuffer (0), +m_multisampleFrameBuffer(0), +m_depthStencilBuffer (0), +m_colorBuffer (0), +m_width (0), +m_height (0) { } @@ -50,11 +54,25 @@ RenderTextureImplFBO::~RenderTextureImplFBO() { m_context->setActive(true); - // Destroy the depth buffer - if (m_depthBuffer) + // Destroy the color buffer + if (m_colorBuffer) { - GLuint depthBuffer = static_cast(m_depthBuffer); - glCheck(GLEXT_glDeleteRenderbuffers(1, &depthBuffer)); + GLuint colorBuffer = static_cast(m_colorBuffer); + glCheck(GLEXT_glDeleteRenderbuffers(1, &colorBuffer)); + } + + // Destroy the depth/stencil buffer + if (m_depthStencilBuffer) + { + GLuint depthStencilBuffer = static_cast(m_depthStencilBuffer); + glCheck(GLEXT_glDeleteRenderbuffers(1, &depthStencilBuffer)); + } + + // Destroy the multisample frame buffer + if (m_multisampleFrameBuffer) + { + GLuint multisampleFrameBuffer = static_cast(m_multisampleFrameBuffer); + glCheck(GLEXT_glDeleteFramebuffers(1, &multisampleFrameBuffer)); } // Destroy the frame buffer @@ -82,52 +100,233 @@ bool RenderTextureImplFBO::isAvailable() //////////////////////////////////////////////////////////// -bool RenderTextureImplFBO::create(unsigned int width, unsigned int height, unsigned int textureId, bool depthBuffer) +unsigned int RenderTextureImplFBO::getMaximumAntialiasingLevel() { + GLint samples = 0; + +#ifndef SFML_OPENGL_ES + + glCheck(glGetIntegerv(GLEXT_GL_MAX_SAMPLES, &samples)); + +#endif + + return static_cast(samples); +} + + +//////////////////////////////////////////////////////////// +bool RenderTextureImplFBO::create(unsigned int width, unsigned int height, unsigned int textureId, const ContextSettings& settings) +{ + // Store the dimensions + m_width = width; + m_height = height; + + // Disable creation of depth/stencil surfaces in the context + ContextSettings contextSettings(settings); + contextSettings.depthBits = 0; + contextSettings.stencilBits = 0; + contextSettings.antialiasingLevel = 0; + contextSettings.sRgbCapable = false; + // Create the context - m_context = new Context; + m_context = new Context(contextSettings, 1, 1); - // Create the framebuffer object - GLuint frameBuffer = 0; - glCheck(GLEXT_glGenFramebuffers(1, &frameBuffer)); - m_frameBuffer = static_cast(frameBuffer); - if (!m_frameBuffer) - { - err() << "Impossible to create render texture (failed to create the frame buffer object)" << std::endl; + if (settings.antialiasingLevel && !(GLEXT_framebuffer_multisample && GLEXT_framebuffer_blit)) return false; - } - glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, m_frameBuffer)); - // Create the depth buffer if requested - if (depthBuffer) + if (settings.stencilBits && !GLEXT_packed_depth_stencil) + return false; + +#ifndef SFML_OPENGL_ES + + // Check if the requested anti-aliasing level is supported + if (settings.antialiasingLevel) { - GLuint depth = 0; - glCheck(GLEXT_glGenRenderbuffers(1, &depth)); - m_depthBuffer = static_cast(depth); - if (!m_depthBuffer) + GLint samples = 0; + glCheck(glGetIntegerv(GLEXT_GL_MAX_SAMPLES, &samples)); + + if (settings.antialiasingLevel > static_cast(samples)) { - err() << "Impossible to create render texture (failed to create the attached depth buffer)" << std::endl; + err() << "Impossible to create render texture (unsupported anti-aliasing level)"; + err() << " Requested: " << settings.antialiasingLevel << " Maximum supported: " << samples << std::endl; return false; } - glCheck(GLEXT_glBindRenderbuffer(GLEXT_GL_RENDERBUFFER, m_depthBuffer)); - glCheck(GLEXT_glRenderbufferStorage(GLEXT_GL_RENDERBUFFER, GLEXT_GL_DEPTH_COMPONENT, width, height)); - glCheck(GLEXT_glFramebufferRenderbuffer(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_DEPTH_ATTACHMENT, GLEXT_GL_RENDERBUFFER, m_depthBuffer)); } - // Link the texture to the frame buffer - glCheck(GLEXT_glFramebufferTexture2D(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0)); +#endif - // A final check, just to be sure... - GLenum status; - glCheck(status = GLEXT_glCheckFramebufferStatus(GLEXT_GL_FRAMEBUFFER)); - if (status != GLEXT_GL_FRAMEBUFFER_COMPLETE) + if (!settings.antialiasingLevel) { - glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, 0)); - err() << "Impossible to create render texture (failed to link the target texture to the frame buffer)" << std::endl; - return false; - } + // Create the framebuffer object + GLuint frameBuffer = 0; + glCheck(GLEXT_glGenFramebuffers(1, &frameBuffer)); + m_frameBuffer = static_cast(frameBuffer); + if (!m_frameBuffer) + { + err() << "Impossible to create render texture (failed to create the frame buffer object)" << std::endl; + return false; + } + glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, m_frameBuffer)); - return true; + // Create the depth/stencil buffer if requested + if (settings.stencilBits) + { + +#ifndef SFML_OPENGL_ES + + GLuint depthStencil = 0; + glCheck(GLEXT_glGenRenderbuffers(1, &depthStencil)); + m_depthStencilBuffer = static_cast(depthStencil); + if (!m_depthStencilBuffer) + { + err() << "Impossible to create render texture (failed to create the attached depth/stencil buffer)" << std::endl; + return false; + } + glCheck(GLEXT_glBindRenderbuffer(GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer)); + glCheck(GLEXT_glRenderbufferStorage(GLEXT_GL_RENDERBUFFER, GLEXT_GL_DEPTH24_STENCIL8, width, height)); + glCheck(GLEXT_glFramebufferRenderbuffer(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_DEPTH_ATTACHMENT, GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer)); + glCheck(GLEXT_glFramebufferRenderbuffer(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_STENCIL_ATTACHMENT, GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer)); +#else + + err() << "Impossible to create render texture (failed to create the attached depth/stencil buffer)" << std::endl; + return false; + +#endif // SFML_OPENGL_ES + + } + else if (settings.depthBits) + { + GLuint depthStencil = 0; + glCheck(GLEXT_glGenRenderbuffers(1, &depthStencil)); + m_depthStencilBuffer = static_cast(depthStencil); + if (!m_depthStencilBuffer) + { + err() << "Impossible to create render texture (failed to create the attached depth buffer)" << std::endl; + return false; + } + glCheck(GLEXT_glBindRenderbuffer(GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer)); + glCheck(GLEXT_glRenderbufferStorage(GLEXT_GL_RENDERBUFFER, GLEXT_GL_DEPTH_COMPONENT, width, height)); + glCheck(GLEXT_glFramebufferRenderbuffer(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_DEPTH_ATTACHMENT, GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer)); + } + + // Link the texture to the frame buffer + glCheck(GLEXT_glFramebufferTexture2D(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0)); + + // A final check, just to be sure... + GLenum status; + glCheck(status = GLEXT_glCheckFramebufferStatus(GLEXT_GL_FRAMEBUFFER)); + if (status != GLEXT_GL_FRAMEBUFFER_COMPLETE) + { + glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, 0)); + err() << "Impossible to create render texture (frame buffer incomplete)" << std::endl; + return false; + } + + return true; + } + else + { + +#ifndef SFML_OPENGL_ES + + // Create the framebuffer object + GLuint frameBuffer = 0; + glCheck(GLEXT_glGenFramebuffers(1, &frameBuffer)); + m_frameBuffer = static_cast(frameBuffer); + if (!m_frameBuffer) + { + err() << "Impossible to create render texture (failed to create the frame buffer object)" << std::endl; + return false; + } + glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, m_frameBuffer)); + + // Link the texture to the frame buffer + glCheck(GLEXT_glFramebufferTexture2D(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0)); + + // A final check, just to be sure... + GLenum status; + glCheck(status = GLEXT_glCheckFramebufferStatus(GLEXT_GL_FRAMEBUFFER)); + if (status != GLEXT_GL_FRAMEBUFFER_COMPLETE) + { + glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, 0)); + err() << "Impossible to create render texture (frame buffer incomplete)" << std::endl; + return false; + } + + // Create the multisample framebuffer object + frameBuffer = 0; + glCheck(GLEXT_glGenFramebuffers(1, &frameBuffer)); + m_multisampleFrameBuffer = static_cast(frameBuffer); + if (!m_multisampleFrameBuffer) + { + err() << "Impossible to create render texture (failed to create the multisample frame buffer object)" << std::endl; + return false; + } + glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, m_multisampleFrameBuffer)); + + // Create the multisample color buffer + GLuint color = 0; + glCheck(GLEXT_glGenRenderbuffers(1, &color)); + m_colorBuffer = static_cast(color); + if (!m_colorBuffer) + { + err() << "Impossible to create render texture (failed to create the attached multisample color buffer)" << std::endl; + return false; + } + glCheck(GLEXT_glBindRenderbuffer(GLEXT_GL_RENDERBUFFER, m_colorBuffer)); + glCheck(GLEXT_glRenderbufferStorageMultisample(GLEXT_GL_RENDERBUFFER, settings.antialiasingLevel, GL_RGBA, width, height)); + glCheck(GLEXT_glFramebufferRenderbuffer(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_COLOR_ATTACHMENT0, GLEXT_GL_RENDERBUFFER, m_colorBuffer)); + + // Create the multisample depth/stencil buffer if requested + if (settings.stencilBits) + { + GLuint depthStencil = 0; + glCheck(GLEXT_glGenRenderbuffers(1, &depthStencil)); + m_depthStencilBuffer = static_cast(depthStencil); + if (!m_depthStencilBuffer) + { + err() << "Impossible to create render texture (failed to create the attached multisample depth/stencil buffer)" << std::endl; + return false; + } + glCheck(GLEXT_glBindRenderbuffer(GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer)); + glCheck(GLEXT_glRenderbufferStorageMultisample(GLEXT_GL_RENDERBUFFER, settings.antialiasingLevel, GLEXT_GL_DEPTH24_STENCIL8, width, height)); + glCheck(GLEXT_glFramebufferRenderbuffer(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_DEPTH_ATTACHMENT, GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer)); + glCheck(GLEXT_glFramebufferRenderbuffer(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_STENCIL_ATTACHMENT, GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer)); + } + else if (settings.depthBits) + { + GLuint depthStencil = 0; + glCheck(GLEXT_glGenRenderbuffers(1, &depthStencil)); + m_depthStencilBuffer = static_cast(depthStencil); + if (!m_depthStencilBuffer) + { + err() << "Impossible to create render texture (failed to create the attached multisample depth buffer)" << std::endl; + return false; + } + glCheck(GLEXT_glBindRenderbuffer(GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer)); + glCheck(GLEXT_glRenderbufferStorageMultisample(GLEXT_GL_RENDERBUFFER, settings.antialiasingLevel, GLEXT_GL_DEPTH_COMPONENT, width, height)); + glCheck(GLEXT_glFramebufferRenderbuffer(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_DEPTH_ATTACHMENT, GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer)); + } + + // A final check, just to be sure... + glCheck(status = GLEXT_glCheckFramebufferStatus(GLEXT_GL_FRAMEBUFFER)); + if (status != GLEXT_GL_FRAMEBUFFER_COMPLETE) + { + glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, 0)); + err() << "Impossible to create render texture (multisample frame buffer incomplete)" << std::endl; + return false; + } + + return true; + +#else + + err() << "Impossible to create render texture (failed to create the multisample frame buffer object)" << std::endl; + return false; + +#endif // SFML_OPENGL_ES + + } } @@ -141,6 +340,18 @@ bool RenderTextureImplFBO::activate(bool active) //////////////////////////////////////////////////////////// void RenderTextureImplFBO::updateTexture(unsigned int) { + +#ifndef SFML_OPENGL_ES + + if (m_multisampleFrameBuffer) + { + glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_DRAW_FRAMEBUFFER, m_frameBuffer)); + glCheck(GLEXT_glBlitFramebuffer(0, 0, m_width, m_height, 0, 0, m_width, m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST)); + glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_DRAW_FRAMEBUFFER, m_multisampleFrameBuffer)); + } + +#endif // SFML_OPENGL_ES + glCheck(glFlush()); } diff --git a/src/SFML/Graphics/RenderTextureImplFBO.hpp b/src/SFML/Graphics/RenderTextureImplFBO.hpp index a72559f3..d2bb71c1 100644 --- a/src/SFML/Graphics/RenderTextureImplFBO.hpp +++ b/src/SFML/Graphics/RenderTextureImplFBO.hpp @@ -66,20 +66,28 @@ public: //////////////////////////////////////////////////////////// static bool isAvailable(); + //////////////////////////////////////////////////////////// + /// \brief Get the maximum anti-aliasing level supported by the system + /// + /// \return The maximum anti-aliasing level supported by the system + /// + //////////////////////////////////////////////////////////// + static unsigned int getMaximumAntialiasingLevel(); + private: //////////////////////////////////////////////////////////// /// \brief Create the render texture implementation /// - /// \param width Width of the texture to render to - /// \param height Height of the texture to render to - /// \param textureId OpenGL identifier of the target texture - /// \param depthBuffer Is a depth buffer requested? + /// \param width Width of the texture to render to + /// \param height Height of the texture to render to + /// \param textureId OpenGL identifier of the target texture + /// \param settings Context settings to create render-texture with /// /// \return True if creation has been successful /// //////////////////////////////////////////////////////////// - virtual bool create(unsigned int width, unsigned int height, unsigned int textureId, bool depthBuffer); + virtual bool create(unsigned int width, unsigned int height, unsigned int textureId, const ContextSettings& settings); //////////////////////////////////////////////////////////// /// \brief Activate or deactivate the render texture for rendering @@ -102,9 +110,13 @@ private: //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - Context* m_context; ///< Needs a separate OpenGL context for not messing up the other ones - unsigned int m_frameBuffer; ///< OpenGL frame buffer object - unsigned int m_depthBuffer; ///< Optional depth buffer attached to the frame buffer + Context* m_context; ///< Needs a separate OpenGL context for not messing up the other ones + unsigned int m_frameBuffer; ///< OpenGL frame buffer object + unsigned int m_multisampleFrameBuffer; ///< Optional OpenGL frame buffer object with multisample attachments + unsigned int m_depthStencilBuffer; ///< Optional depth/stencil buffer attached to the frame buffer + unsigned int m_colorBuffer; ///< Optional multisample color buffer attached to the frame buffer + unsigned int m_width; ///< Width of the attachments + unsigned int m_height; ///< Height of the attachments }; } // namespace priv