From d16b0f6aa186cafad287a85bfe6ac2c0e89da1b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Sun, 8 Oct 2017 04:18:11 -0300 Subject: [PATCH] Allow nested frame buffer binds. Allow windows with frame buffers. Allow resize frame buffers. --HG-- branch : dev --- include/eepp/graphics/framebuffer.hpp | 4 ++ include/eepp/ui/uicontrol.hpp | 4 ++ include/eepp/ui/uihelper.hpp | 7 +++- include/eepp/ui/uimanager.hpp | 4 ++ include/eepp/ui/uiwindow.hpp | 13 +++++++ src/eepp/graphics/framebuffer.cpp | 20 +++++++--- src/eepp/graphics/framebufferfbo.cpp | 34 ++++++++++++++++ src/eepp/graphics/framebufferfbo.hpp | 2 + src/eepp/graphics/texture.cpp | 2 +- src/eepp/ui/uicontrol.cpp | 17 ++++++++ src/eepp/ui/uimanager.cpp | 20 +++++++++- src/eepp/ui/uiwindow.cpp | 56 +++++++++++++++++++++++++++ src/eepp/window/engine.cpp | 4 +- 13 files changed, 174 insertions(+), 13 deletions(-) diff --git a/include/eepp/graphics/framebuffer.hpp b/include/eepp/graphics/framebuffer.hpp index 635e9c114..921d80b8a 100644 --- a/include/eepp/graphics/framebuffer.hpp +++ b/include/eepp/graphics/framebuffer.hpp @@ -41,6 +41,9 @@ class EE_API FrameBuffer { ** This is needed by the engine to recover any context lost. */ virtual void reload() = 0; + /** @brief Resizes the current Frame Buffer */ + virtual void resize( const Uint32& Width, const Uint32& Height ) = 0; + /** @return The frame buffer texture. Everything is rendered to this texture. ** To render the frame buffer you just need to draw the texture as any other texture. ** The frame buffer must be unbinded before any rendering is done outside the frame buffer. @@ -73,6 +76,7 @@ class EE_API FrameBuffer { bool mHasStencilBuffer; Texture * mTexture; ColorAf mClearColor; + View mView; View mPrevView; float mProjMat[16]; diff --git a/include/eepp/ui/uicontrol.hpp b/include/eepp/ui/uicontrol.hpp index 696bf8afe..ae71d4a2e 100644 --- a/include/eepp/ui/uicontrol.hpp +++ b/include/eepp/ui/uicontrol.hpp @@ -159,12 +159,16 @@ class EE_API UIControl { Uint32 isScaled(); + Uint32 isFrameBuffer(); + bool isMeOrParentTreeRotated(); bool isMeOrParentTreeScaled(); bool isMeOrParentTreeScaledOrRotated(); + bool isMeOrParentTreeScaledOrRotatedOrFrameBuffer(); + Uint32 addEventListener( const Uint32& EventType, const UIEventCallback& Callback ); void removeEventListener( const Uint32& CallbackId ); diff --git a/include/eepp/ui/uihelper.hpp b/include/eepp/ui/uihelper.hpp index 50a3d11c4..8dcc751b7 100644 --- a/include/eepp/ui/uihelper.hpp +++ b/include/eepp/ui/uihelper.hpp @@ -26,6 +26,7 @@ enum UI_CONTROL_FLAGS_VALUES { UI_CTRL_FLAG_OWNED_BY_WINDOW = (1<<17), UI_CTRL_FLAG_DRAWABLE_OWNER = (1<<18), UI_CTRL_FLAG_REVERSE_DRAW = (1<<19), + UI_CTRL_FLAG_FRAME_BUFFER = (1<<20), UI_CTRL_FLAG_FREE_USE = (1<<31) }; @@ -121,7 +122,8 @@ enum UI_MANAGER_FLAGS { UI_MANAGER_HIGHLIGHT_FOCUS = ( 1 << 0 ), UI_MANAGER_HIGHLIGHT_OVER = ( 1 << 1 ), UI_MANAGER_DRAW_DEBUG_DATA = ( 1 << 2 ), - UI_MANAGER_DRAW_BOXES = ( 1 << 3 ) + UI_MANAGER_DRAW_BOXES = ( 1 << 3 ), + UI_MANAGER_MAIN_CONTROL_IN_FRAME_BUFFER = ( 1 << 4 ) }; enum UI_WINDOW_FLAGS { @@ -134,7 +136,8 @@ enum UI_WINDOW_FLAGS { UI_WIN_DRAGABLE_CONTAINER = ( 1 << 6 ), UI_WIN_SHARE_ALPHA_WITH_CHILDS = ( 1 << 7 ), UI_WIN_MODAL = ( 1 << 8 ), - UI_WIN_SHADOW = ( 1 << 9 ) + UI_WIN_SHADOW = ( 1 << 9 ), + UI_WIN_FRAME_BUFFER = ( 1 << 10 ) }; enum UI_COMMON_DIALOG_FLAGS { diff --git a/include/eepp/ui/uimanager.hpp b/include/eepp/ui/uimanager.hpp index 07b3fa167..0fb70e4ff 100644 --- a/include/eepp/ui/uimanager.hpp +++ b/include/eepp/ui/uimanager.hpp @@ -83,6 +83,10 @@ class EE_API UIManager { void setHighlightOverColor( const Color& Color ); + void setMainControlInFrameBuffer( const bool& set ); + + bool isMainControlInFrameBuffer() const; + const Color& getHighlightOverColor() const; void sendMouseClick( UIControl * ToCtrl, const Vector2i& Pos, const Uint32 Flags ); diff --git a/include/eepp/ui/uiwindow.hpp b/include/eepp/ui/uiwindow.hpp index cc0121c14..b052aea4b 100644 --- a/include/eepp/ui/uiwindow.hpp +++ b/include/eepp/ui/uiwindow.hpp @@ -5,6 +5,10 @@ #include #include +namespace EE { namespace Graphics { +class FrameBuffer; +}} + namespace EE { namespace UI { class EE_API UIWindow : public UIWidget { @@ -95,6 +99,8 @@ class EE_API UIWindow : public UIWidget { const Sizei& getMinWindowSize(); + bool ownsFrameBuffer(); + virtual void loadFromXmlNode( const pugi::xml_node& node ); protected: class KeyboardShortcut { @@ -130,6 +136,7 @@ class EE_API UIWindow : public UIWidget { RESIZE_TOPRIGHT }; + FrameBuffer * mFrameBuffer; UIWindowStyleConfig mStyleConfig; UIControlAnim * mWindowDecoration; UIControlAnim * mBorderLeft; @@ -162,6 +169,10 @@ class EE_API UIWindow : public UIWidget { virtual Uint32 onKeyDown( const UIEventKey &Event ); + virtual void matrixSet(); + + virtual void matrixUnset(); + void onButtonCloseClick( const UIEvent * Event ); void onButtonMaximizeClick( const UIEvent * Event ); @@ -207,6 +218,8 @@ class EE_API UIWindow : public UIWidget { void applyMinWinSize(); void updateWinFlags(); + + void createFrameBuffer(); }; }} diff --git a/src/eepp/graphics/framebuffer.cpp b/src/eepp/graphics/framebuffer.cpp index c193d269d..022ebf81c 100644 --- a/src/eepp/graphics/framebuffer.cpp +++ b/src/eepp/graphics/framebuffer.cpp @@ -10,6 +10,8 @@ using namespace EE::Graphics::Private; namespace EE { namespace Graphics { +static std::list sFBOActiveViews; + FrameBuffer * FrameBuffer::New( const Uint32& Width, const Uint32& Height, bool StencilBuffer, bool DepthBuffer, EE::Window::Window * window ) { if ( FrameBufferFBO::isSupported() ) return eeNew( FrameBufferFBO, ( Width, Height, StencilBuffer, DepthBuffer, window ) ); @@ -34,9 +36,7 @@ FrameBuffer::FrameBuffer( EE::Window::Window * window ) : } FrameBuffer::~FrameBuffer() { - if ( NULL != mTexture ) { - eeSAFE_DELETE( mTexture ); - } + eeSAFE_DELETE( mTexture ); FrameBufferManager::instance()->remove( this ); } @@ -60,11 +60,12 @@ void FrameBuffer::clear() { } void FrameBuffer::setBufferView() { - mPrevView = mWindow->getView(); - // Get the user projection matrix GLi->getCurrentMatrix( GL_PROJECTION_MATRIX, mProjMat ); + mView.setSize( mWidth, mHeight ); + sFBOActiveViews.push_back(&mView); + GLi->viewport( 0, 0, mWidth, mHeight ); GLi->matrixMode( GL_PROJECTION ); GLi->loadIdentity(); @@ -76,7 +77,14 @@ void FrameBuffer::setBufferView() { void FrameBuffer::recoverView() { GlobalBatchRenderer::instance()->draw(); - mWindow->setView( mPrevView ); + sFBOActiveViews.remove(&mView); + + if ( sFBOActiveViews.empty() ) { + mWindow->setView( mWindow->getView() ); + } else { + const View* view = sFBOActiveViews.back(); + GLi->viewport( 0, 0, view->getView().getWidth(), view->getView().getHeight() ); + } // Recover the user projection matrix GLi->loadIdentity(); diff --git a/src/eepp/graphics/framebufferfbo.cpp b/src/eepp/graphics/framebufferfbo.cpp index b65751186..e49aef872 100644 --- a/src/eepp/graphics/framebufferfbo.cpp +++ b/src/eepp/graphics/framebufferfbo.cpp @@ -177,6 +177,40 @@ void FrameBufferFBO::reload() { create( mWidth, mHeight, mHasStencilBuffer, mHasDepthBuffer ); } +void FrameBufferFBO::resize( const Uint32& Width, const Uint32& Height ) { + mWidth = Width; + mHeight = Height; + + bindFrameBuffer(); + + if ( mHasDepthBuffer ) { + bindDepthBuffer(); + + GLi->renderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT, Width, Height ); + + GLi->framebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthBuffer ); + + GLi->bindRenderbuffer( GL_RENDERBUFFER, mLastDB ); + } + + if ( mHasStencilBuffer ) { + bindStencilBuffer(); + + GLi->renderbufferStorage( GL_RENDERBUFFER, GL_STENCIL_INDEX8, Width, Height ); + + GLi->framebufferRenderbuffer( GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER_EXT, mStencilBuffer ); + + GLi->bindRenderbuffer( GL_RENDERBUFFER, mLastSB ); + } + + if ( NULL != mTexture ) { + Image newImage( Width, Height, 4 ); + mTexture->replace( &newImage ); + } + + GLi->bindFramebuffer( GL_FRAMEBUFFER, mLastFB ); +} + void FrameBufferFBO::bindFrameBuffer() { int curFB; diff --git a/src/eepp/graphics/framebufferfbo.hpp b/src/eepp/graphics/framebufferfbo.hpp index e8c252538..a659f87c1 100644 --- a/src/eepp/graphics/framebufferfbo.hpp +++ b/src/eepp/graphics/framebufferfbo.hpp @@ -21,6 +21,8 @@ class EE_API FrameBufferFBO : public FrameBuffer { void reload(); + void resize( const Uint32& Width, const Uint32& Height ); + static bool isSupported(); protected: Int32 mFrameBuffer; diff --git a/src/eepp/graphics/texture.cpp b/src/eepp/graphics/texture.cpp index 6043abd2a..d600f49fb 100755 --- a/src/eepp/graphics/texture.cpp +++ b/src/eepp/graphics/texture.cpp @@ -453,7 +453,7 @@ void Texture::replace( Image * image ) { Uint32 flags = ( mFlags & TEX_FLAG_MIPMAP ) ? SOIL_FLAG_MIPMAPS : 0; flags = (mClampMode == CLAMP_REPEAT) ? (flags | SOIL_FLAG_TEXTURE_REPEATS) : flags; - TextureSaver TextureSaver; + TextureSaver textureSaver; Int32 width = (Int32)image->getWidth(); Int32 height = (Int32)image->getHeight(); diff --git a/src/eepp/ui/uicontrol.cpp b/src/eepp/ui/uicontrol.cpp index d2fe72654..9ebc9b6d3 100644 --- a/src/eepp/ui/uicontrol.cpp +++ b/src/eepp/ui/uicontrol.cpp @@ -1085,6 +1085,10 @@ Uint32 UIControl::isScaled() { return mControlFlags & UI_CTRL_FLAG_SCALED; } +Uint32 UIControl::isFrameBuffer() { + return mControlFlags & UI_CTRL_FLAG_FRAME_BUFFER; +} + bool UIControl::isMeOrParentTreeRotated() { UIControl * Ctrl = this; @@ -1124,6 +1128,19 @@ bool UIControl::isMeOrParentTreeScaledOrRotated() { return false; } +bool UIControl::isMeOrParentTreeScaledOrRotatedOrFrameBuffer() { + UIControl * Ctrl = this; + + while( NULL != Ctrl ) { + if ( Ctrl->isScaled() || Ctrl->isRotated() || Ctrl->isFrameBuffer() ) + return true; + + Ctrl = Ctrl->getParent(); + } + + return false; +} + Polygon2f& UIControl::getPolygon() { return mPoly; } diff --git a/src/eepp/ui/uimanager.cpp b/src/eepp/ui/uimanager.cpp index 51c4d7c30..61429727a 100644 --- a/src/eepp/ui/uimanager.cpp +++ b/src/eepp/ui/uimanager.cpp @@ -54,6 +54,10 @@ void UIManager::init( Uint32 Flags, EE::Window::Window * window ) { UIWindowStyleConfig windowStyleConfig; windowStyleConfig.WinFlags = UI_WIN_NO_BORDER | UI_WIN_RESIZEABLE; + + if ( isMainControlInFrameBuffer() ) + windowStyleConfig.WinFlags |= UI_WIN_FRAME_BUFFER; + windowStyleConfig.MinWindowSize = Sizei( 0, 0 ); windowStyleConfig.DecorationSize = Sizei( 0, 0 ); windowStyleConfig.DecorationAutoSize = false; @@ -288,7 +292,7 @@ const Uint32& UIManager::getLastPressTrigger() const { } void UIManager::clipSmartEnable(UIControl * ctrl, const Int32 & x, const Int32 & y, const Uint32 & Width, const Uint32 & Height) { - if ( ctrl->isMeOrParentTreeScaledOrRotated() ) { + if ( ctrl->isMeOrParentTreeScaledOrRotatedOrFrameBuffer() ) { GLi->getClippingMask()->clipPlaneEnable( x, y, Width, Height ); } else { GLi->getClippingMask()->clipEnable( x, y, Width, Height ); @@ -296,7 +300,7 @@ void UIManager::clipSmartEnable(UIControl * ctrl, const Int32 & x, const Int32 & } void UIManager::clipSmartDisable(UIControl * ctrl) { - if ( ctrl->isMeOrParentTreeScaledOrRotated() ) { + if ( ctrl->isMeOrParentTreeScaledOrRotatedOrFrameBuffer() ) { GLi->getClippingMask()->clipPlaneDisable(); } else { GLi->getClippingMask()->clipDisable(); @@ -347,6 +351,18 @@ void UIManager::setHighlightOverColor( const Color& Color ) { mHighlightOverColor = Color; } +void UIManager::setMainControlInFrameBuffer(const bool& set) { + BitOp::setBitFlagValue( &mFlags, UI_MANAGER_DRAW_BOXES, set ? 1 : 0 ); + + if ( NULL != mControl ) { + mControl->setWinFlags( mControl->getWinFlags() | ( set ? UI_WIN_FRAME_BUFFER : 0 ) ); + } +} + +bool UIManager::isMainControlInFrameBuffer() const { + return 0 != ( mFlags & UI_MANAGER_MAIN_CONTROL_IN_FRAME_BUFFER ); +} + const Color& UIManager::getHighlightOverColor() const { return mHighlightOverColor; } diff --git a/src/eepp/ui/uiwindow.cpp b/src/eepp/ui/uiwindow.cpp index 1d99a72f8..eed72076b 100644 --- a/src/eepp/ui/uiwindow.cpp +++ b/src/eepp/ui/uiwindow.cpp @@ -2,6 +2,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -14,6 +17,7 @@ UIWindow * UIWindow::New( UIWindow::WindowBaseContainerType type ) { UIWindow::UIWindow( UIWindow::WindowBaseContainerType type ) : UIWidget(), + mFrameBuffer( NULL ), mWindowDecoration( NULL ), mBorderLeft( NULL ), mBorderRight( NULL ), @@ -71,11 +75,21 @@ UIWindow::~UIWindow() { UIManager::instance()->setFocusLastWindow( this ); sendCommonEvent( UIEvent::EventOnWindowClose ); + + eeSAFE_DELETE( mFrameBuffer ); } void UIWindow::updateWinFlags() { bool needsUpdate = false; + writeCtrlFlag( UI_CTRL_FLAG_FRAME_BUFFER, ( mStyleConfig.WinFlags & UI_WIN_FRAME_BUFFER ) ? 1 : 0 ); + + if ( ( mStyleConfig.WinFlags & UI_WIN_FRAME_BUFFER ) && NULL == mFrameBuffer ) { + createFrameBuffer(); + } else { + eeSAFE_DELETE( mFrameBuffer ); + } + if ( !( mStyleConfig.WinFlags & UI_WIN_NO_BORDER ) ) { if ( NULL == mWindowDecoration ) { mWindowDecoration = UIControlAnim::New(); @@ -187,6 +201,11 @@ void UIWindow::updateWinFlags() { } } +void UIWindow::createFrameBuffer() { + eeSAFE_DELETE( mFrameBuffer ); + mFrameBuffer = FrameBuffer::New( Math::nextPowOfTwo( mRealSize.getWidth() ), Math::nextPowOfTwo( mRealSize.getHeight() ) ); +} + void UIWindow::createModalControl() { UIControl * Ctrl = UIManager::instance()->getMainControl(); @@ -386,6 +405,14 @@ void UIWindow::onSizeChange() { } else { fixChildsSize(); + if ( ownsFrameBuffer() && ( mFrameBuffer->getWidth() < mRealSize.getWidth() || mFrameBuffer->getHeight() < mRealSize.getHeight() ) ) { + if ( NULL == mFrameBuffer ) { + createFrameBuffer(); + } else { + mFrameBuffer->resize( Math::nextPowOfTwo( mRealSize.getWidth() ), Math::nextPowOfTwo( mRealSize.getHeight() ) ); + } + } + UIWidget::onSizeChange(); } } @@ -990,6 +1017,34 @@ Uint32 UIWindow::onKeyDown( const UIEventKey &Event ) { return UIWidget::onKeyDown( Event ); } +void UIWindow::matrixSet() { + if ( ownsFrameBuffer() ) { + mFrameBuffer->bind(); + mFrameBuffer->clear(); + + GLi->translatef( -mScreenPos.x , -mScreenPos.y, 0.f ); + } + + UIWidget::matrixSet(); +} + +void UIWindow::matrixUnset() { + UIWidget::matrixUnset(); + + if ( ownsFrameBuffer() ) { + GLi->translatef( mScreenPos.x , mScreenPos.y, 0.f ); + + mFrameBuffer->unbind(); + + SubTexture subTexture( mFrameBuffer->getTexture()->getId(), Rect( 0, 0, mRealSize.getWidth(), mRealSize.getHeight() ) ); + subTexture.draw( mScreenPosf.x, mScreenPosf.y ); + } +} + +bool UIWindow::ownsFrameBuffer() { + return ( ( mStyleConfig.WinFlags & UI_WIN_FRAME_BUFFER ) && NULL != mFrameBuffer ); +} + void UIWindow::checkShortcuts( const Uint32& KeyCode, const Uint32& Mod ) { for ( KeyboardShortcuts::iterator it = mKbShortcuts.begin(); it != mKbShortcuts.end(); it++ ) { KeyboardShortcut kb = (*it); @@ -1179,6 +1234,7 @@ void UIWindow::loadFromXmlNode(const pugi::xml_node & node) { else if ( "resizeable" == cur ) winflags |= UI_WIN_RESIZEABLE; else if ( "sharealpha" == cur ) winflags |= UI_WIN_SHARE_ALPHA_WITH_CHILDS; else if ( "buttonactions" == cur ) winflags |= UI_WIN_USE_DEFAULT_BUTTONS_ACTIONS; + else if ( "framebuffer"== cur ) winflags |= UI_WIN_FRAME_BUFFER; } setWinFlags( winflags ); diff --git a/src/eepp/window/engine.cpp b/src/eepp/window/engine.cpp index f9860e1df..c70b26d97 100755 --- a/src/eepp/window/engine.cpp +++ b/src/eepp/window/engine.cpp @@ -55,10 +55,10 @@ Engine::~Engine() { FontManager::destroySingleton(); - TextureFactory::destroySingleton(); - UI::UIManager::destroySingleton(); + TextureFactory::destroySingleton(); + Graphics::Renderer::destroySingleton(); ShaderProgramManager::destroySingleton();