diff --git a/src/AbstractFramebuffer.cpp b/src/AbstractFramebuffer.cpp new file mode 100644 index 000000000..5e8099db0 --- /dev/null +++ b/src/AbstractFramebuffer.cpp @@ -0,0 +1,43 @@ +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include "AbstractFramebuffer.h" + +#include "BufferImage.h" +#include "Image.h" + +namespace Magnum { + +void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, Image2D* image) { + bind(Target::ReadDraw); + char* data = new char[AbstractImage::pixelSize(format, type)*size.product()]; + glReadPixels(offset.x(), offset.y(), size.x(), size.y(), static_cast(format), static_cast(type), data); + image->setData(size, format, type, data); +} + +#ifndef MAGNUM_TARGET_GLES2 +void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, BufferImage2D* image, Buffer::Usage usage) { + bind(Target::ReadDraw); + /* If the buffer doesn't have sufficient size, resize it */ + /** @todo Explicitly reset also when buffer usage changes */ + if(image->size() != size || image->format() != format || image->type() != type) + image->setData(size, format, type, nullptr, usage); + + image->buffer()->bind(Buffer::Target::PixelPack); + glReadPixels(offset.x(), offset.y(), size.x(), size.y(), static_cast(format), static_cast(type), nullptr); +} +#endif + +} diff --git a/src/AbstractFramebuffer.h b/src/AbstractFramebuffer.h new file mode 100644 index 000000000..d0774aefa --- /dev/null +++ b/src/AbstractFramebuffer.h @@ -0,0 +1,270 @@ +#ifndef Magnum_AbstractFramebuffer_h +#define Magnum_AbstractFramebuffer_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Class Magnum::AbstractFramebuffer + */ + +#include + +#include "Math/Vector2.h" +#include "AbstractImage.h" +#include "Buffer.h" + +namespace Magnum { + +/** +@brief Base for default and named framebuffers + +See DefaultFramebuffer and Framebuffer for more information. +@todo @extension{ARB,viewport_array} +*/ +class MAGNUM_EXPORT AbstractFramebuffer { + AbstractFramebuffer(const AbstractFramebuffer& other) = delete; + AbstractFramebuffer(AbstractFramebuffer&& other) = delete; + AbstractFramebuffer& operator=(const AbstractFramebuffer& other) = delete; + AbstractFramebuffer& operator=(AbstractFramebuffer&& other) = delete; + + public: + /** + * @brief Mask for clearing + * + * @see ClearMask + */ + enum class Clear: GLbitfield { + Color = GL_COLOR_BUFFER_BIT, /**< Color */ + Depth = GL_DEPTH_BUFFER_BIT, /**< Depth value */ + Stencil = GL_STENCIL_BUFFER_BIT /**< Stencil value */ + }; + + /** + * @brief Mask for clearing + * + * @see clear() + */ + typedef Corrade::Containers::EnumSet ClearMask; + + /** + * @brief Mask for blitting + * + * @see BlitMask + * @requires_gl30 %Extension @extension{EXT,framebuffer_object} + * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} + */ + enum class Blit: GLbitfield { + ColorBuffer = GL_COLOR_BUFFER_BIT, /**< Color buffer */ + DepthBuffer = GL_DEPTH_BUFFER_BIT, /**< Depth buffer */ + StencilBuffer = GL_STENCIL_BUFFER_BIT /**< Stencil buffer */ + }; + + /** + * @brief Mask for blitting + * + * @see blit() + * @requires_gl30 %Extension @extension{EXT,framebuffer_object} + * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} + */ + typedef Corrade::Containers::EnumSet BlitMask; + + /** + * @brief Blit filtering + * + * @see blit() + */ + enum class BlitFilter: GLenum { + NearestNeighbor = GL_NEAREST, /**< Nearest neighbor filtering */ + LinearInterpolation = GL_LINEAR /**< Linear interpolation filtering */ + }; + + /** + * @brief Target for binding framebuffer + * + * @see DefaultFramebuffer::bind(), Framebuffer::bind() + * @requires_gl30 %Extension @extension{EXT,framebuffer_object} + */ + enum class Target: GLenum { + /** + * For reading only. + * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} + * @requires_gles30 %Extension @es_extension{APPLE,framebuffer_multisample} + * or @es_extension{ANGLE,framebuffer_blit} + */ + #ifndef MAGNUM_TARGET_GLES2 + Read = GL_READ_FRAMEBUFFER, + #else + Read = GL_READ_FRAMEBUFFER_APPLE, + #endif + + /** + * For drawing only. + * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} + * @requires_gles30 %Extension @es_extension{APPLE,framebuffer_multisample} + * or @es_extension{ANGLE,framebuffer_blit} + */ + #ifndef MAGNUM_TARGET_GLES2 + Draw = GL_DRAW_FRAMEBUFFER, + #else + Draw = GL_DRAW_FRAMEBUFFER_APPLE, + #endif + + ReadDraw = GL_FRAMEBUFFER /**< For both reading and drawing. */ + }; + + /** + * @brief Copy block of pixels + * @param source Source framebuffer + * @param destination Destination framebuffer + * @param sourceBottomLeft Bottom left coordinates of source rectangle + * @param sourceTopRight Top right coordinates of source rectangle + * @param destinationBottomLeft Bottom left coordinates of destination rectangle + * @param destinationTopRight Top right coordinates of destination + * rectangle + * @param mask Which buffers to perform blit operation on + * @param filter Interpolation filter + * + * Binds @p source framebuffer to @ref Target "Target::Read" and + * @p destination framebuffer to @ref Target "Target::Draw" and + * performs blitting operation. See DefaultFramebuffer::mapForRead(), + * Framebuffer::mapForRead(), DefaultFramebuffer::mapForDraw() and + * Framebuffer::mapForDraw() for specifying particular buffers for + * blitting operation. + * @see @fn_gl{BlitFramebuffer} + * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} + * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} + */ + inline static void blit(AbstractFramebuffer& source, AbstractFramebuffer& destination, const Vector2i& sourceBottomLeft, const Vector2i& sourceTopRight, const Vector2i& destinationBottomLeft, const Vector2i& destinationTopRight, BlitMask mask, BlitFilter filter) { + source.bind(AbstractFramebuffer::Target::Read); + destination.bind(AbstractFramebuffer::Target::Draw); + /** @todo Get some extension wrangler instead to avoid undeclared glBlitFramebuffer() on ES2 */ + #ifndef MAGNUM_TARGET_GLES2 + glBlitFramebuffer(sourceBottomLeft.x(), sourceBottomLeft.y(), sourceTopRight.x(), sourceTopRight.y(), destinationBottomLeft.x(), destinationBottomLeft.y(), destinationTopRight.x(), destinationTopRight.y(), static_cast(mask), static_cast(filter)); + #else + static_cast(sourceBottomLeft); + static_cast(sourceTopRight); + static_cast(destinationBottomLeft); + static_cast(destinationTopRight); + static_cast(mask); + static_cast(filter); + #endif + } + + /** + * @brief Copy block of pixels + * @param source Source framebuffer + * @param destination Destination framebuffer + * @param bottomLeft Bottom left coordinates of source and + * destination rectangle + * @param topRight Top right coordinates of source and + * destination rectangle + * @param mask Which buffers to perform blit operation on + * + * Convenience alternative to above function when source rectangle is + * the same as destination rectangle. As the image is copied + * pixel-by-pixel, no interpolation is needed and thus + * @ref BlitFilter "BlitFilter::NearestNeighbor" filtering is used by + * default. + * @see @fn_gl{BlitFramebuffer} + * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} + * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} + */ + inline static void blit(AbstractFramebuffer& source, AbstractFramebuffer& destination, const Vector2i& bottomLeft, const Vector2i& topRight, BlitMask mask) { + blit(source, destination, bottomLeft, topRight, bottomLeft, topRight, mask, BlitFilter::NearestNeighbor); + } + + AbstractFramebuffer() = default; + virtual ~AbstractFramebuffer() = 0; + + /** + * @brief Bind framebuffer + * + * @see DefaultFramebuffer::mapForRead(), Framebuffer::mapForRead(), + * DefaultFramebuffer::mapForDraw(), Framebuffer::mapForDraw(), + * @fn_gl{BindFramebuffer} + */ + inline void bind(Target target) { + glBindFramebuffer(static_cast(target), _id); + } + + /** + * @brief Set viewport size + * + * Call when window size changes. + * @see @fn_gl{Viewport} + */ + inline void setViewport(const Vector2i& position, const Vector2i& size) { + bind(Target::ReadDraw); + glViewport(position.x(), position.y(), size.x(), size.y()); + } + + /** + * @brief Clear specified buffers in framebuffer + * @param mask Which buffers to clear + * + * @see Renderer::setClearColor(), Renderer::setClearDepth(), + * Renderer::setClearStencil(), @fn_gl{Clear} + */ + inline void clear(ClearMask mask) { + bind(Target::ReadDraw); + glClear(static_cast(mask)); + } + + /** + * @brief Read block of pixels from framebuffer to image + * @param offset Offset in the framebuffer + * @param size %Image size + * @param format Format of pixel data + * @param type Data type of pixel data + * @param image %Image where to put the data + * + * @see @fn_gl{ReadPixels} + */ + void read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, Image2D* image); + + #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Read block of pixels from framebuffer to buffer image + * @param offset Offset in the framebuffer + * @param size %Image size + * @param format Format of pixel data + * @param type Data type of pixel data + * @param image %Buffer image where to put the data + * @param usage %Buffer usage + * + * @see Buffer::bind(Target), @fn_gl{ReadPixels} + * @requires_gles30 Pixel buffer objects are not available in OpenGL ES 2.0. + */ + void read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, BufferImage2D* image, Buffer::Usage usage); + #endif + + #ifndef DOXYGEN_GENERATING_OUTPUT + protected: + GLuint _id; + #endif +}; + +inline AbstractFramebuffer::~AbstractFramebuffer() {} + +CORRADE_ENUMSET_OPERATORS(AbstractFramebuffer::ClearMask) +#ifndef MAGNUM_TARGET_GLES +CORRADE_ENUMSET_OPERATORS(AbstractFramebuffer::BlitMask) +#endif + +} + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c521a9e31..eb5732e97 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,12 +11,14 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CO # Files shared between main library and unit test library set(Magnum_SRCS + AbstractFramebuffer.cpp AbstractImage.cpp AbstractTexture.cpp AbstractShaderProgram.cpp Buffer.cpp Context.cpp DebugMarker.cpp + DefaultFramebuffer.cpp Framebuffer.cpp Image.cpp IndexedMesh.cpp @@ -50,6 +52,7 @@ if(NOT TARGET_GLES2) endif() set(Magnum_HEADERS + AbstractFramebuffer.h AbstractImage.h AbstractResourceLoader.h AbstractShaderProgram.h @@ -60,6 +63,7 @@ set(Magnum_HEADERS Context.h CubeMapTexture.h DebugMarker.h + DefaultFramebuffer.h DimensionTraits.h Extensions.h Framebuffer.h diff --git a/src/DefaultFramebuffer.cpp b/src/DefaultFramebuffer.cpp new file mode 100644 index 000000000..7d12c9715 --- /dev/null +++ b/src/DefaultFramebuffer.cpp @@ -0,0 +1,36 @@ +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include "DefaultFramebuffer.h" + +namespace Magnum { + +DefaultFramebuffer defaultFramebuffer; + +DefaultFramebuffer::DefaultFramebuffer() { _id = 0; } + +#ifndef MAGNUM_TARGET_GLES2 +void DefaultFramebuffer::mapForDraw(std::initializer_list attachments) { + GLenum* _attachments = new GLenum[attachments.size()]; + for(auto it = attachments.begin(); it != attachments.end(); ++it) + _attachments[it-attachments.begin()] = static_cast(*it); + + bind(Target::Draw); + glDrawBuffers(attachments.size(), _attachments); + delete[] _attachments; +} +#endif + +} diff --git a/src/DefaultFramebuffer.h b/src/DefaultFramebuffer.h new file mode 100644 index 000000000..0afa8e432 --- /dev/null +++ b/src/DefaultFramebuffer.h @@ -0,0 +1,204 @@ +#ifndef Magnum_DefaultFramebuffer_h +#define Magnum_DefaultFramebuffer_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Class Magnum::DefaultFramebuffer + */ + +#include "AbstractFramebuffer.h" + +namespace Magnum { + +/** +@brief Default framebuffer + +@see @ref defaultFramebuffer, Framebuffer +*/ +class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { + public: + #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Draw attachment + * + * @see mapForDraw() + * @requires_gles30 Draw attachments for default framebuffer are + * available only in OpenGL ES 3.0. + */ + enum class DrawAttachment: GLenum { + /** Don't use the output. */ + None = GL_NONE, + + #ifndef MAGNUM_TARGET_GLES + /** + * Write output to back left framebuffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + BackLeft = GL_BACK_LEFT, + + /** + * Write output to back right framebuffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + BackRight = GL_BACK_RIGHT, + + /** + * Write output to front left framebuffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + FrontLeft = GL_FRONT_LEFT, + + /** + * Write output to front right framebuffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + FrontRight = GL_FRONT_RIGHT, + #endif + + /** + * Write output to back framebuffer. + * + * On desktop OpenGL, this is equal to @ref DrawAttachment "DrawAttachment::BackLeft". + */ + #ifdef MAGNUM_TARGET_GLES + Back = GL_BACK, + #else + Back = GL_BACK_LEFT, + #endif + + /** + * Write output to front framebuffer. + * + * On desktop OpenGL, this is equal to @ref DrawAttachment "DrawAttachment::FrontLeft". + */ + #ifdef MAGNUM_TARGET_GLES + Front = GL_FRONT + #else + Front = GL_FRONT_LEFT + #endif + }; + #endif + + /** + * @brief Read attachment + * + * @see mapForRead() + * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} + */ + enum class ReadAttachment: GLenum { + /** Don't read from any framebuffer */ + None = GL_NONE, + + #ifndef MAGNUM_TARGET_GLES + /** + * Read from back left framebuffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + BackLeft = GL_BACK_LEFT, + + /** + * Read from back right framebuffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + BackRight = GL_BACK_RIGHT, + + /** + * Read from front left framebuffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + FrontLeft = GL_FRONT_LEFT, + + /** + * Read from front right framebuffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + FrontRight = GL_FRONT_RIGHT, + + /** + * Read from left framebuffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + Left = GL_LEFT, + + /** + * Read from right framebuffer. + * @requires_gl Stereo rendering is not available in OpenGL ES. + */ + Right = GL_RIGHT, + #endif + + /** Read from back framebuffer. */ + Back = GL_BACK, + + /** + * Read from front framebuffer. + * @requires_es_extension %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} + */ + Front = GL_FRONT + + #ifndef MAGNUM_TARGET_GLES + , + + /** + * Read from front and back framebuffer. + * @requires_gl In OpenGL ES you must specify either + * @ref Magnum::DefaultFramebuffer::ReadAttachment "ReadAttachment::Front" + * or @ref Magnum::DefaultFramebuffer::ReadAttachment "ReadAttachment::Back". + */ + FrontAndBack = GL_FRONT_AND_BACK + #endif + }; + + MAGNUM_LOCAL DefaultFramebuffer(); + + #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Map given attachments for drawing + * @param attachments Attachments. If any value is + * @ref DrawAttachment "Attachment::None", given output is not + * used. + * + * @see mapForRead(), bind(), @fn_gl{DrawBuffers} + * @requires_gles30 Draw attachments for default framebuffer are + * available only in OpenGL ES 3.0. + */ + void mapForDraw(std::initializer_list attachments); + #endif + + /** + * @brief Map given attachment for reading + * @param attachment Attachment + * + * @see mapForDraw(), bind(), @fn_gl{ReadBuffer} + * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} + */ + inline void mapForRead(ReadAttachment attachment) { + bind(Target::Read); + /** @todo Get some extension wrangler instead to avoid undeclared glReadBuffer() on ES2 */ + #ifndef MAGNUM_TARGET_GLES2 + glReadBuffer(static_cast(attachment)); + #else + static_cast(attachment); + #endif + } +}; + +/** @brief Default framebuffer instance */ +extern DefaultFramebuffer MAGNUM_EXPORT defaultFramebuffer; + +} + +#endif diff --git a/src/Framebuffer.cpp b/src/Framebuffer.cpp index 238c2f7a1..d37dbe064 100644 --- a/src/Framebuffer.cpp +++ b/src/Framebuffer.cpp @@ -20,18 +20,6 @@ namespace Magnum { -#ifndef MAGNUM_TARGET_GLES2 -void Framebuffer::mapDefaultForDraw(std::initializer_list attachments) { - GLenum* _attachments = new GLenum[attachments.size()]; - for(auto it = attachments.begin(); it != attachments.end(); ++it) - _attachments[it-attachments.begin()] = static_cast(*it); - - bindDefault(Target::Draw); - glDrawBuffers(attachments.size(), _attachments); - delete[] _attachments; -} -#endif - void Framebuffer::mapForDraw(std::initializer_list colorAttachments) { GLenum* attachments = new GLenum[colorAttachments.size()]; for(auto it = colorAttachments.begin(); it != colorAttachments.end(); ++it) @@ -45,22 +33,4 @@ void Framebuffer::mapForDraw(std::initializer_list colorAttachments delete[] attachments; } -void Framebuffer::read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, Image2D* image) { - char* data = new char[AbstractImage::pixelSize(format, type)*size.product()]; - glReadPixels(offset.x(), offset.y(), size.x(), size.y(), static_cast(format), static_cast(type), data); - image->setData(size, format, type, data); -} - -#ifndef MAGNUM_TARGET_GLES2 -void Framebuffer::read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, BufferImage2D* image, Buffer::Usage usage) { - /* If the buffer doesn't have sufficient size, resize it */ - /** @todo Explicitly reset also when buffer usage changes */ - if(image->size() != size || image->format() != format || image->type() != type) - image->setData(size, format, type, nullptr, usage); - - image->buffer()->bind(Buffer::Target::PixelPack); - glReadPixels(offset.x(), offset.y(), size.x(), size.y(), static_cast(format), static_cast(type), nullptr); -} -#endif - } diff --git a/src/Framebuffer.h b/src/Framebuffer.h index 18664f319..54167b9ee 100644 --- a/src/Framebuffer.h +++ b/src/Framebuffer.h @@ -19,242 +19,26 @@ * @brief Class Magnum::Framebuffer */ -#include - -#include "AbstractImage.h" -#include "Buffer.h" +#include "AbstractFramebuffer.h" #include "CubeMapTexture.h" #include "Texture.h" #include "Renderbuffer.h" namespace Magnum { -/** @nosubgrouping +/** @brief %Framebuffer -Provides operations with framebuffers (configuring, clearing, blitting...) and -creation and attaching of named framebuffers. -@todo @extension{ARB,viewport_array} +@see DefaultFramebuffer +@requires_gl30 %Extension @extension{EXT,framebuffer_object} */ -class MAGNUM_EXPORT Framebuffer { - Framebuffer(const Framebuffer& other) = delete; - Framebuffer(Framebuffer&& other) = delete; - Framebuffer& operator=(const Framebuffer& other) = delete; - Framebuffer& operator=(Framebuffer&& other) = delete; - +class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { public: - /** - * @brief Set viewport size - * - * Call when window size changes. - * @see @fn_gl{Viewport} - */ - inline static void setViewport(const Vector2i& position, const Vector2i& size) { - glViewport(position.x(), position.y(), size.x(), size.y()); - } - - /** - * @brief Mask for clearing - * - * @see ClearMask, clear(), clear(ClearMask) - */ - enum class Clear: GLbitfield { - Color = GL_COLOR_BUFFER_BIT, /**< Color */ - Depth = GL_DEPTH_BUFFER_BIT, /**< Depth value */ - Stencil = GL_STENCIL_BUFFER_BIT /**< Stencil value */ - }; - - /** @brief Mask for clearing */ - typedef Corrade::Containers::EnumSet ClearMask; - - /** - * @brief Clear specified buffers in framebuffer - * - * @see clear(), Renderer::setClearColor(), Renderer::setClearDepth(), - * Renderer::setClearStencil(), @fn_gl{Clear} - * @todo Clearing only given draw buffer - */ - inline static void clear(ClearMask mask) { glClear(static_cast(mask)); } - - /** @{ @name Framebuffer creation and binding */ - - /** - * @brief %Framebuffer target - * - * @see bind(), bindDefault() - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - */ - enum class Target: GLenum { - /** - * For reading only. - * @requires_gl30 Extension @extension{EXT,framebuffer_blit} - * @requires_gles30 %Extension @es_extension{APPLE,framebuffer_multisample} - * or @es_extension{ANGLE,framebuffer_blit} - */ - #ifndef MAGNUM_TARGET_GLES2 - Read = GL_READ_FRAMEBUFFER, - #else - Read = GL_READ_FRAMEBUFFER_APPLE, - #endif - - /** - * For drawing only. - * @requires_gl30 Extension @extension{EXT,framebuffer_blit} - * @requires_gles30 %Extension @es_extension{APPLE,framebuffer_multisample} - * or @es_extension{ANGLE,framebuffer_blit} - */ - #ifndef MAGNUM_TARGET_GLES2 - Draw = GL_DRAW_FRAMEBUFFER, - #else - Draw = GL_DRAW_FRAMEBUFFER_APPLE, - #endif - - ReadDraw = GL_FRAMEBUFFER /**< For both reading and drawing. */ - }; - - #ifndef MAGNUM_TARGET_GLES2 - /** - * @brief Draw attachment for default framebuffer - * - * @see mapDefaultForDraw() - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - * @requires_gles30 Draw attachments for default framebuffer are - * available only in OpenGL ES 3.0. - */ - enum class DefaultDrawAttachment: GLenum { - /** Don't use the output. */ - None = GL_NONE, - - #ifndef MAGNUM_TARGET_GLES - /** - * Write output to back left framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - BackLeft = GL_BACK_LEFT, - - /** - * Write output to back right framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - BackRight = GL_BACK_RIGHT, - - /** - * Write output to front left framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - FrontLeft = GL_FRONT_LEFT, - - /** - * Write output to front right framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - FrontRight = GL_FRONT_RIGHT, - #endif - - /** - * Write output to back framebuffer. - * - * On desktop OpenGL, this is equal to - * @ref Magnum::Framebuffer::DefaultDrawAttachment "DefaultDrawAttachment::BackLeft". - */ - #ifdef MAGNUM_TARGET_GLES - Back = GL_BACK, - #else - Back = GL_BACK_LEFT, - #endif - - /** - * Write output to front framebuffer. - * - * On desktop OpenGL, this is equal to - * @ref Magnum::Framebuffer::DefaultDrawAttachment "DefaultDrawAttachment::FrontLeft". - */ - #ifdef MAGNUM_TARGET_GLES - Front = GL_FRONT - #else - Front = GL_FRONT_LEFT - #endif - }; - #endif - - /** - * @brief Read attachment for default framebuffer - * - * @see mapDefaultForRead() - * @requires_gl30 %Extension @extension{EXT,framebuffer_object} - * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} - */ - enum class DefaultReadAttachment: GLenum { - /** Don't read from any framebuffer */ - None = GL_NONE, - - #ifndef MAGNUM_TARGET_GLES - /** - * Read from back left framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - BackLeft = GL_BACK_LEFT, - - /** - * Read from back right framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - BackRight = GL_BACK_RIGHT, - - /** - * Read from front left framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - FrontLeft = GL_FRONT_LEFT, - - /** - * Read from front right framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - FrontRight = GL_FRONT_RIGHT, - - /** - * Read from left framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - Left = GL_LEFT, - - /** - * Read from right framebuffer. - * @requires_gl Stereo rendering is not available in OpenGL ES. - */ - Right = GL_RIGHT, - #endif - - /** Read from back framebuffer. */ - Back = GL_BACK, - - /** - * Read from front framebuffer. - * @requires_es_extension %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} - */ - Front = GL_FRONT - - #ifndef MAGNUM_TARGET_GLES - , - - /** - * Read from front and back framebuffer. - * @requires_gl In OpenGL ES you must specify either - * @ref Magnum::Framebuffer::DefaultReadAttachment "DefaultReadAttachment::Front" - * or @ref Magnum::Framebuffer::DefaultReadAttachment "DefaultReadAttachment::Back". - */ - FrontAndBack = GL_FRONT_AND_BACK - #endif - }; - /** * @brief Constructor * * Generates new OpenGL framebuffer. * @see @fn_gl{GenFramebuffers} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} */ inline Framebuffer() { glGenFramebuffers(1, &_id); } @@ -263,94 +47,24 @@ class MAGNUM_EXPORT Framebuffer { * * Deletes associated OpenGL framebuffer. * @see @fn_gl{DeleteFramebuffers} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} */ inline ~Framebuffer() { glDeleteFramebuffers(1, &_id); } - /** - * @brief Bind default framebuffer to given target - * @param target %Target - * - * @see @fn_gl{BindFramebuffer} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - */ - inline static void bindDefault(Target target) { - glBindFramebuffer(static_cast(target), 0); - } - - /** - * @brief Bind framebuffer - * - * @see @fn_gl{BindFramebuffer} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - */ - inline void bind(Target target) { - glBindFramebuffer(static_cast(target), _id); - } - - #ifndef MAGNUM_TARGET_GLES2 - /** - * @brief Map given attachments of default framebuffer for drawing - * @param attachments Default attachments. If any value is - * DefaultAttachment::None, given output is not used. - * - * If used for mapping output of fragment shader, the order must be as - * specified by the shader (see AbstractShaderProgram documentation). - * If used for blit(), the order is not important. Each used attachment - * should have either renderbuffer or texture attached for writing to - * work properly. - * @see mapForDraw(), mapDefaultForRead(), bindDefault(), @fn_gl{DrawBuffers} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - * @requires_gles30 Draw attachments for default framebuffer are - * available only in OpenGL ES 3.0. - */ - static void mapDefaultForDraw(std::initializer_list attachments); - #endif - /** * @brief Map given color attachments of current framebuffer for drawing * @param colorAttachments Color attachment IDs. If any value is -1, * given output is not used. * - * If used for mapping output of fragment shader, the order must be as - * specified by the shader (see AbstractShaderProgram documentation). - * If used for blit(), the order is not important. Each used attachment - * should have either renderbuffer or texture attached for writing to - * work properly. - * @see mapDefaultForDraw(), mapForRead(), bind(), @fn_gl{DrawBuffers} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} + * @see mapForRead(), bind(), @fn_gl{DrawBuffers} * @requires_gles30 %Extension @es_extension2{NV,draw_buffers,GL_NV_draw_buffers} */ void mapForDraw(std::initializer_list colorAttachments); - /** - * @brief Map given attachment of default framebuffer for reading - * @param attachment Default attachment - * - * Each used attachment should have either renderbuffer or texture - * attached to work properly. - * @see mapForRead(), mapDefaultForDraw(), bindDefault(), @fn_gl{ReadBuffer} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} - */ - inline static void mapDefaultForRead(DefaultReadAttachment attachment) { - bindDefault(Target::Read); - /** @todo Get some extension wrangler instead to avoid undeclared glReadBuffer() on ES2 */ - #ifndef MAGNUM_TARGET_GLES2 - glReadBuffer(static_cast(attachment)); - #else - static_cast(attachment); - #endif - } - /** * @brief Map given color attachment of current framebuffer for reading * @param colorAttachment Color attachment ID * - * The color attachment should have either renderbuffer or texture - * attached for reading to work properly. - * @see mapDefaultForRead(), mapForDraw(), bind(), @fn_gl{ReadBuffer} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} + * @see mapForDraw(), bind(), @fn_gl{ReadBuffer} * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} */ inline void mapForRead(std::uint8_t colorAttachment) { @@ -363,19 +77,11 @@ class MAGNUM_EXPORT Framebuffer { #endif } - /*@}*/ - - /** @{ @name Attaching textures and renderbuffers */ - /** * @brief Attachment for depth/stencil part of fragment shader output * - * @see attachRenderbuffer(Target, DepthStencilAttachment, Renderbuffer*), - * attachTexture1D(Target, DepthStencilAttachment, Texture1D*, GLint), - * attachTexture2D(Target, DepthStencilAttachment, Texture2D*, GLint), - * attachCubeMapTexture(Target, DepthStencilAttachment, CubeMapTexture*, CubeMapTexture::Coordinate, GLint), - * attachTexture3D(Target, DepthStencilAttachment, Texture3D*, GLint, GLint) - * @requires_gl30 Extension @extension{EXT,framebuffer_object} + * @see attachRenderbuffer(), attachTexture1D(), attachTexture2D(), + * attachCubeMapTexture(), attachTexture3D() */ enum class DepthStencilAttachment: GLenum { Depth = GL_DEPTH_ATTACHMENT, /**< Depth output only. */ @@ -400,10 +106,8 @@ class MAGNUM_EXPORT Framebuffer { * @param renderbuffer %Renderbuffer * * @see bind(), @fn_gl{FramebufferRenderbuffer} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} */ inline void attachRenderbuffer(Target target, DepthStencilAttachment depthStencilAttachment, Renderbuffer* renderbuffer) { - /** @todo Check for internal format compatibility */ bind(target); glFramebufferRenderbuffer(static_cast(target), static_cast(depthStencilAttachment), GL_RENDERBUFFER, renderbuffer->id()); } @@ -415,10 +119,8 @@ class MAGNUM_EXPORT Framebuffer { * @param renderbuffer %Renderbuffer * * @see bind(), @fn_gl{FramebufferRenderbuffer} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} */ inline void attachRenderbuffer(Target target, std::uint8_t colorAttachment, Renderbuffer* renderbuffer) { - /** @todo Check for internal format compatibility */ bind(target); glFramebufferRenderbuffer(static_cast(target), GL_COLOR_ATTACHMENT0 + colorAttachment, GL_RENDERBUFFER, renderbuffer->id()); } @@ -432,11 +134,9 @@ class MAGNUM_EXPORT Framebuffer { * @param mipLevel Mip level * * @see bind(), @fn_gl{FramebufferTexture} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} * @requires_gl Only 2D and 3D textures are available in OpenGL ES. */ inline void attachTexture1D(Target target, DepthStencilAttachment depthStencilAttachment, Texture1D* texture, GLint mipLevel) { - /** @todo Check for internal format compatibility */ /** @todo Check for texture target compatibility */ bind(target); glFramebufferTexture1D(static_cast(target), static_cast(depthStencilAttachment), static_cast(texture->target()), texture->id(), mipLevel); @@ -450,11 +150,9 @@ class MAGNUM_EXPORT Framebuffer { * @param mipLevel Mip level * * @see bind(), @fn_gl{FramebufferTexture} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} * @requires_gl Only 2D and 3D textures are available in OpenGL ES. */ inline void attachTexture1D(Target target, std::uint8_t colorAttachment, Texture1D* texture, GLint mipLevel) { - /** @todo Check for internal format compatibility */ /** @todo Check for texture target compatibility */ bind(target); glFramebufferTexture1D(static_cast(target), GL_COLOR_ATTACHMENT0 + colorAttachment, static_cast(texture->target()), texture->id(), mipLevel); @@ -470,10 +168,8 @@ class MAGNUM_EXPORT Framebuffer { * should be always 0. * * @see attachCubeMapTexture(), bind(), @fn_gl{FramebufferTexture} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} */ inline void attachTexture2D(Target target, DepthStencilAttachment depthStencilAttachment, Texture2D* texture, GLint mipLevel) { - /** @todo Check for internal format compatibility */ /** @todo Check for texture target compatibility */ bind(target); glFramebufferTexture2D(static_cast(target), static_cast(depthStencilAttachment), static_cast(texture->target()), texture->id(), mipLevel); @@ -488,10 +184,8 @@ class MAGNUM_EXPORT Framebuffer { * should be always 0. * * @see attachCubeMapTexture(), bind(), @fn_gl{FramebufferTexture} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} */ inline void attachTexture2D(Target target, std::uint8_t colorAttachment, Texture2D* texture, GLint mipLevel) { - /** @todo Check for internal format compatibility */ /** @todo Check for texture target compatibility */ bind(target); glFramebufferTexture2D(static_cast(target), GL_COLOR_ATTACHMENT0 + colorAttachment, static_cast(texture->target()), texture->id(), mipLevel); @@ -506,7 +200,6 @@ class MAGNUM_EXPORT Framebuffer { * @param mipLevel Mip level * * @see attachTexture2D(), bind(), @fn_gl{FramebufferTexture} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} */ inline void attachCubeMapTexture(Target target, DepthStencilAttachment depthStencilAttachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, GLint mipLevel) { /** @todo Check for internal format compatibility */ @@ -523,7 +216,6 @@ class MAGNUM_EXPORT Framebuffer { * @param mipLevel Mip level * * @see attachTexture2D(), bind(), @fn_gl{FramebufferTexture} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} */ inline void attachCubeMapTexture(Target target, std::uint8_t colorAttachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, GLint mipLevel) { /** @todo Check for internal format compatibility */ @@ -540,11 +232,9 @@ class MAGNUM_EXPORT Framebuffer { * @param layer Layer of 2D image within a 3D texture * * @see bind(), @fn_gl{FramebufferTexture} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} * @requires_es_extension %Extension @es_extension{OES,texture_3D} */ inline void attachTexture3D(Target target, DepthStencilAttachment depthStencilAttachment, Texture3D* texture, GLint mipLevel, GLint layer) { - /** @todo Check for internal format compatibility */ /** @todo Check for texture target compatibility */ bind(target); /** @todo Get some extension wrangler for glFramebufferTexture3D() (extension only) */ @@ -567,11 +257,9 @@ class MAGNUM_EXPORT Framebuffer { * @param layer Layer of 2D image within a 3D texture. * * @see bind(), @fn_gl{FramebufferTexture} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} * @requires_es_extension %Extension @es_extension{OES,texture_3D} */ inline void attachTexture3D(Target target, std::uint8_t colorAttachment, Texture3D* texture, GLint mipLevel, GLint layer) { - /** @todo Check for internal format compatibility */ /** @todo Check for texture target compatibility */ bind(target); /** @todo Get some extension wrangler for glFramebufferTexture3D() (extension only) */ @@ -584,136 +272,8 @@ class MAGNUM_EXPORT Framebuffer { static_cast(layer); #endif } - - /*@}*/ - - /** @{ @name Framebuffer blitting and reading */ - - /** - * @brief Output mask for blitting - * - * Specifies which data are copied when performing blit operation - * using blit(). - * @see BlitMask - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} - */ - enum class Blit: GLbitfield { - Color = GL_COLOR_BUFFER_BIT, /**< Color */ - Depth = GL_DEPTH_BUFFER_BIT, /**< Depth value */ - Stencil = GL_STENCIL_BUFFER_BIT /**< Stencil value */ - }; - - /** - * @brief Output mask for blitting - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} - */ - typedef Corrade::Containers::EnumSet BlitMask; - - /** - * @brief Copy block of pixels from read to draw framebuffer - * @param bottomLeft Bottom left coordinates of source rectangle - * @param topRight Top right coordinates of source rectangle - * @param destinationBottomLeft Bottom left coordinates of destination rectangle - * @param destinationTopRight Top right coordinates of destination - * rectangle - * @param blitMask Blit mask - * @param filter Interpolation applied if the image is - * stretched - * - * See mapForRead() / mapDefaultForRead() and mapForDraw() / - * mapDefaultForDraw() for binding particular framebuffer for reading - * and drawing. If multiple attachments are specified in mapForDraw() - * / mapDefaultForDraw(), the data are written to each of them. - * @see @fn_gl{BlitFramebuffer} - * @requires_gl30 Extension @extension{EXT,framebuffer_blit} - * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} - */ - inline static void blit(const Vector2i& bottomLeft, const Vector2i& topRight, const Vector2i& destinationBottomLeft, const Vector2i& destinationTopRight, BlitMask blitMask, AbstractTexture::Filter filter) { - /** @todo Get some extension wrangler instead to avoid undeclared glBlitFramebuffer() on ES2 */ - #ifndef MAGNUM_TARGET_GLES2 - glBlitFramebuffer(bottomLeft.x(), bottomLeft.y(), topRight.x(), topRight.y(), destinationBottomLeft.x(), destinationBottomLeft.y(), destinationTopRight.x(), destinationTopRight.y(), static_cast(blitMask), static_cast(filter)); - #else - static_cast(bottomLeft); - static_cast(topRight); - static_cast(destinationBottomLeft); - static_cast(destinationTopRight); - static_cast(blitMask); - static_cast(filter); - #endif - } - - /** - * @brief Copy block of pixels from read to draw framebuffer - * @param bottomLeft Bottom left coordinates of source and - * destination rectangle - * @param topRight Top right coordinates of source and - * destination rectangle - * @param blitMask Blit mask - * - * Convenience function when source rectangle is the same as - * destination rectangle. As the image is copied pixel-by-pixel, - * no interpolation is needed and thus - * AbstractTexture::Filter::NearestNeighbor filtering is used by - * default. - * @see @fn_gl{BlitFramebuffer} - * @requires_gl30 Extension @extension{EXT,framebuffer_blit} - * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} - */ - inline static void blit(const Vector2i& bottomLeft, const Vector2i& topRight, BlitMask blitMask) { - /** @todo Get some extension wrangler instead to avoid undeclared glBlitFramebuffer() on ES2 */ - #ifndef MAGNUM_TARGET_GLES2 - glBlitFramebuffer(bottomLeft.x(), bottomLeft.y(), topRight.x(), topRight.y(), bottomLeft.x(), bottomLeft.y(), topRight.x(), topRight.y(), static_cast(blitMask), static_cast(AbstractTexture::Filter::NearestNeighbor)); - #else - static_cast(bottomLeft); - static_cast(topRight); - static_cast(blitMask); - #endif - } - - /** - * @brief Read block of pixels from framebuffer to image - * @param offset Offset in the framebuffer - * @param size %Image size - * @param format Format of pixel data - * @param type Data type of pixel data - * @param image %Image where to put the data - * - * @see @fn_gl{ReadPixels} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - */ - static void read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, Image2D* image); - - #ifndef MAGNUM_TARGET_GLES2 - /** - * @brief Read block of pixels from framebuffer to buffered image - * @param offset Offset in the framebuffer - * @param size %Image size - * @param format Format of pixel data - * @param type Data type of pixel data - * @param image Buffered image where to put the data - * @param usage %Buffer usage - * - * @see Buffer::bind(Target), @fn_gl{ReadPixels} - * @requires_gl30 Extension @extension{EXT,framebuffer_object} - * @requires_gles30 Pixel buffer objects are not available in OpenGL ES 2.0. - */ - static void read(const Vector2i& offset, const Vector2i& size, AbstractImage::Format format, AbstractImage::Type type, BufferImage2D* image, Buffer::Usage usage); - #endif - - /*@}*/ - - private: - GLuint _id; }; -CORRADE_ENUMSET_OPERATORS(Framebuffer::ClearMask) -#ifndef MAGNUM_TARGET_GLES -CORRADE_ENUMSET_OPERATORS(Framebuffer::BlitMask) -#endif - } #endif diff --git a/src/Magnum.h b/src/Magnum.h index 41010a193..6e4cf7ee2 100644 --- a/src/Magnum.h +++ b/src/Magnum.h @@ -122,6 +122,7 @@ using Math::deg; using Math::rad; /* Forward declarations for all types in root namespace */ +class AbstractFramebuffer; class AbstractImage; class AbstractShaderProgram; class AbstractTexture; @@ -156,6 +157,7 @@ class CubeMapTextureArray; #endif /* DebugMarker forward declaration is not needed */ +/* DefaultFramebuffer is available only through global instance */ /* DimensionTraits forward declaration is not needed */ class Extension; diff --git a/src/Renderbuffer.h b/src/Renderbuffer.h index 42bd27bac..0d687fe48 100644 --- a/src/Renderbuffer.h +++ b/src/Renderbuffer.h @@ -31,7 +31,7 @@ namespace Magnum { Attachable to Framebuffer as render target. -@requires_gl30 Extension @extension{EXT,framebuffer_object} +@requires_gl30 %Extension @extension{EXT,framebuffer_object} */ class Renderbuffer { Renderbuffer(const Renderbuffer& other) = delete;