From d50f94ca97913e4cab39534097db50e600d00d9d Mon Sep 17 00:00:00 2001 From: Laurent Gomila Date: Sat, 24 Aug 2013 17:27:23 +0200 Subject: [PATCH] Fixed render buffers not correctly resized on orientation changes --- include/SFML/Window/WindowStyle.hpp | 4 +- src/SFML/Window/iOS/EaglContext.hpp | 16 +++- src/SFML/Window/iOS/EaglContext.mm | 102 ++++++++++++++++--------- src/SFML/Window/iOS/SFView.hpp | 16 ++++ src/SFML/Window/iOS/SFView.mm | 46 +++++------ src/SFML/Window/iOS/WindowImplUIKit.mm | 3 +- 6 files changed, 119 insertions(+), 68 deletions(-) diff --git a/include/SFML/Window/WindowStyle.hpp b/include/SFML/Window/WindowStyle.hpp index 3423285d..41644e1c 100644 --- a/include/SFML/Window/WindowStyle.hpp +++ b/include/SFML/Window/WindowStyle.hpp @@ -39,8 +39,8 @@ namespace Style { None = 0, ///< No border / title bar (this flag and all others are mutually exclusive) Titlebar = 1 << 0, ///< Title bar + fixed border - Resize = 1 << 1, ///< Titlebar + resizable border + maximize button - Close = 1 << 2, ///< Titlebar + close button + Resize = 1 << 1, ///< Title bar + resizable border + maximize button + Close = 1 << 2, ///< Title bar + close button Fullscreen = 1 << 3, ///< Fullscreen mode (this flag and all others are mutually exclusive) Default = Titlebar | Resize | Close ///< Default window style diff --git a/src/SFML/Window/iOS/EaglContext.hpp b/src/SFML/Window/iOS/EaglContext.hpp index 99f58e6c..6018432e 100644 --- a/src/SFML/Window/iOS/EaglContext.hpp +++ b/src/SFML/Window/iOS/EaglContext.hpp @@ -35,6 +35,7 @@ SFML_DECLARE_OBJC_CLASS(EAGLContext); +SFML_DECLARE_OBJC_CLASS(SFView); namespace sf { @@ -87,7 +88,18 @@ public: /// //////////////////////////////////////////////////////////// ~EaglContext(); - + + //////////////////////////////////////////////////////////// + /// \brief Recreate the render buffers of the context + /// + /// This function must be called whenever the containing view + /// changes (typically after an orientation change) + /// + /// \param glView : Container of the context + /// + //////////////////////////////////////////////////////////// + void recreateRenderBuffers(SFView* glView); + //////////////////////////////////////////////////////////// /// \brief Display what has been rendered to the context so far /// @@ -125,14 +137,12 @@ private: /// /// \param shared Context to share the new one with (can be NULL) /// \param window Window to attach the context to (can be NULL) - /// \param size Size of the context's drawable /// \param bitsPerPixel Pixel depth, in bits per pixel /// \param settings Creation parameters /// //////////////////////////////////////////////////////////// void createContext(EaglContext* shared, const WindowImplUIKit* window, - Vector2u size, unsigned int bitsPerPixel, const ContextSettings& settings); diff --git a/src/SFML/Window/iOS/EaglContext.mm b/src/SFML/Window/iOS/EaglContext.mm index ca281632..791a6796 100644 --- a/src/SFML/Window/iOS/EaglContext.mm +++ b/src/SFML/Window/iOS/EaglContext.mm @@ -62,7 +62,7 @@ m_depthbuffer(0) { const WindowImplUIKit* window = static_cast(owner); - createContext(shared, window, window->getSize(), bitsPerPixel, settings); + createContext(shared, window, bitsPerPixel, settings); } @@ -105,6 +105,57 @@ EaglContext::~EaglContext() } +//////////////////////////////////////////////////////////// +void EaglContext::recreateRenderBuffers(SFView* glView) +{ + // Activate the context + EAGLContext* previousContext = [EAGLContext currentContext]; + [EAGLContext setCurrentContext:m_context]; + + // Bind the frame buffer + glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_framebuffer); + + // Destroy previous render-buffers + if (m_colorbuffer) + glDeleteRenderbuffersOES(1, &m_colorbuffer); + if (m_depthbuffer) + glDeleteRenderbuffersOES(1, &m_depthbuffer); + + // Create the color buffer + glGenRenderbuffersOES(1, &m_colorbuffer); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorbuffer); + if (glView) + [m_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:glView.layer]; + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, m_colorbuffer); + + // Create a depth buffer if requested + if (m_settings.depthBits > 0) + { + // Find the best internal format + GLenum format = m_settings.depthBits > 16 ? GL_DEPTH_COMPONENT24_OES : GL_DEPTH_COMPONENT16_OES; + + // Get the size of the color-buffer (which fits the current size of the GL view) + GLint width, height; + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &width); + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &height); + + // Create the depth buffer + glGenRenderbuffersOES(1, &m_depthbuffer); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_depthbuffer); + glRenderbufferStorageOES(GL_RENDERBUFFER_OES, format, width, height); + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, m_depthbuffer); + } + + // Make sure that everything's ok + GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); + if (status != GL_FRAMEBUFFER_COMPLETE_OES) + err() << "Failed to create a valid frame buffer (error code: " << status << ")" << std::endl; + + // Restore the previous context + [EAGLContext setCurrentContext:previousContext]; +} + + //////////////////////////////////////////////////////////// bool EaglContext::makeCurrent() { @@ -125,17 +176,22 @@ void EaglContext::setVerticalSyncEnabled(bool enabled) { } - + //////////////////////////////////////////////////////////// void EaglContext::createContext(EaglContext* shared, const WindowImplUIKit* window, - Vector2u size, unsigned int bitsPerPixel, const ContextSettings& settings) { // Save the settings m_settings = settings; - + + // Adjust the depth buffer format to those available + if (m_settings.depthBits > 16) + m_settings.depthBits = 24; + else if (m_settings.depthBits > 0) + m_settings.depthBits = 16; + // Create the context if (shared) m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 sharegroup:[shared->m_context sharegroup]]; @@ -147,42 +203,12 @@ void EaglContext::createContext(EaglContext* shared, // Create the framebuffer (this is the only allowed drawable on iOS) glGenFramebuffersOES(1, &m_framebuffer); - glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_framebuffer); - // Create the color buffer - glGenRenderbuffersOES(1, &m_colorbuffer); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorbuffer); - if (window) - [m_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:window->getGlView().layer]; - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, m_colorbuffer); + // Create the render buffers + recreateRenderBuffers(window->getGlView()); - // Create a depth buffer if requested - if (settings.depthBits > 0) - { - // Find the best internal format - GLenum format; - if (settings.depthBits > 16) - { - format = GL_DEPTH_COMPONENT24_OES; - m_settings.depthBits = 24; - } - else - { - format = GL_DEPTH_COMPONENT16_OES; - m_settings.depthBits = 16; - } - - // Create the depth buffer - glGenRenderbuffersOES(1, &m_depthbuffer); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_depthbuffer); - glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, size.x, size.y); - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, m_depthbuffer); - } - - // Make sure that everything's ok - GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); - if (status != GL_FRAMEBUFFER_COMPLETE_OES) - err() << "Failed to create a valid frame buffer (error code: " << status << ")" << std::endl; + // Attach the context to the GL view for future updates + window->getGlView().context = this; } } // namespace priv diff --git a/src/SFML/Window/iOS/SFView.hpp b/src/SFML/Window/iOS/SFView.hpp index 44c42e37..1720a609 100644 --- a/src/SFML/Window/iOS/SFView.hpp +++ b/src/SFML/Window/iOS/SFView.hpp @@ -28,6 +28,7 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// +#include #include @@ -38,6 +39,21 @@ //////////////////////////////////////////////////////////// @interface SFView : UIView +//////////////////////////////////////////////////////////// +/// \brief Construct the view with its initial size +/// +/// \param frame Dimensions of the view +/// +/// \return Id of the view +/// +//////////////////////////////////////////////////////////// +-(id)initWithFrame:(CGRect)frame; + +//////////////////////////////////////////////////////////// +// Member data +//////////////////////////////////////////////////////////// +@property (nonatomic) sf::priv::EaglContext* context; ///< The attached EAGL context + @end #endif // SFML_SFVIEW_HPP diff --git a/src/SFML/Window/iOS/SFView.mm b/src/SFML/Window/iOS/SFView.mm index c65a814b..4c88da05 100644 --- a/src/SFML/Window/iOS/SFView.mm +++ b/src/SFML/Window/iOS/SFView.mm @@ -34,6 +34,8 @@ @implementation SFView +@synthesize context; + //////////////////////////////////////////////////////////// -(BOOL)canBecomeFirstResponder @@ -111,6 +113,15 @@ } +//////////////////////////////////////////////////////////// +- (void)layoutSubviews +{ + // update the attached context's buffers + if (self.context) + self.context->recreateRenderBuffers(self); +} + + //////////////////////////////////////////////////////////// +(Class)layerClass { @@ -124,33 +135,22 @@ self = [super initWithFrame:frame]; if (self) { - if (![self initialize]) - { - [self release]; - self = nil; - } + self.context = NULL; + + // Configure the EAGL layer + CAEAGLLayer* eaglLayer = (CAEAGLLayer*)self.layer; + eaglLayer.opaque = YES; + eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, + kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, + nil]; + + // Enable user interactions on the view (touch events) + self.userInteractionEnabled = true; } return self; } -//////////////////////////////////////////////////////////// --(bool)initialize -{ - // Configure the EAGL layer - CAEAGLLayer* eaglLayer = (CAEAGLLayer*)self.layer; - eaglLayer.opaque = YES; - eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, - kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, - nil]; - - // Enable user interactions on the view (touch events) - self.userInteractionEnabled = true; - - return true; -} - - @end diff --git a/src/SFML/Window/iOS/WindowImplUIKit.mm b/src/SFML/Window/iOS/WindowImplUIKit.mm index 037b6bf1..975c461a 100644 --- a/src/SFML/Window/iOS/WindowImplUIKit.mm +++ b/src/SFML/Window/iOS/WindowImplUIKit.mm @@ -68,7 +68,6 @@ WindowImplUIKit::WindowImplUIKit(VideoMode mode, // Create the view m_view = [[SFView alloc] initWithFrame:frame]; - [m_window addSubview:m_view]; [m_view resignFirstResponder]; // Create the view controller @@ -91,7 +90,7 @@ WindowImplUIKit::~WindowImplUIKit() //////////////////////////////////////////////////////////// void WindowImplUIKit::processEvents() { - while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0001, TRUE) == kCFRunLoopRunHandledSource) + while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0001, true) == kCFRunLoopRunHandledSource) ; }