From 6d41597d1ddc815428c587c4eaa06e72bd60108f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 17 Apr 2018 09:40:29 +0200 Subject: [PATCH] Split the OpenGL layer out, pt 9: generic pixel formats. This is quite big, so: * There are new Magnum::PixelFormat and Magnum::CompressedPixelFormat enums, which contain generic API-independent formats. In particular, PixelFormat replaces GL::PixelFormat and GL::PixelType with a single value. * There's GL::pixelFormat(), GL::pixelType(), GL::compressedPixelFormat() to convert the generic enums to GL-specific. The mapping is only in one direction, done with a lookup table (generic enums are indices to that table). * GL classes taking the formats directly (such as GL::BufferImage) have overloads that take both the GL-specific and generic format. * The generic Image, CompressedImage, ImageView, CompressedImageView, and Trade::ImageData classes now accept the generic formats first-class. However, it's also possible to store an implementation-specific value to cover cases where a generic format enum doesn't have support for a particular format. This is done by wrapping the value using pixelFormatWrap() or compressedPixelFormatWrap(). Particular GPU APIs then assume it's their implementation-specific value and extract the value back using pixelFormatUnwrap() or compressedPixelFormatUnwrap(). There's also an isPixelFormatImplementationSpecific() and isCompressedPixelFormatImplementationSpecific() that distinguishes these values. * Many operations need pixel size and in order to have it even for implementation-specific formats, a corresponding pixelSize() overload is found via ADL on construction and the calculated size stored along the format. Previously the pixel size was only calculated on demand, but that's not possible now. In case such overload is not available, it's possible to pass pixel size manually as well. * In order to support the GL format+type pair, Image, ImageView and Trade::ImageData, there's now an additional untyped formatExtra() field that holds the second value. * The CompressedPixelStorage class is now unconditionally available on all targets, including OpenGL ES and WebGL. However, on OpenGL ES the GL APIs expect that it's all at default values. I attempted to preserve backwards compatibility as much as possible: * The PixelFormat and CompressedPixelFormat enum now contains generic API-independent values. The GL-specific formats are present there, but marked as deprecated. Use either the generic values or GL::PixelFormat (togehter with GL::PixelType) and GL::CompressedPixelFormat instead. There's a lot of ugliness caused by this, but seems to work well. * *Image::type() functions are deprecated as they were too GL-specific. Use formatExtra() and cast it to GL::PixelType instead. * Image constructors take templated format or format+extra arguments, so passing GL-specific values to them should still work. --- doc/changelog.dox | 58 +- doc/snippets/CMakeLists.txt | 8 + doc/snippets/Magnum.cpp | 179 +++ doc/snippets/MagnumGL.cpp | 54 + doc/snippets/MagnumTrade.cpp | 70 ++ src/Magnum/CMakeLists.txt | 66 +- src/Magnum/GL/AbstractFramebuffer.cpp | 5 +- src/Magnum/GL/AbstractTexture.cpp | 72 +- src/Magnum/GL/BufferImage.cpp | 66 +- src/Magnum/GL/BufferImage.h | 479 +++++-- src/Magnum/GL/CMakeLists.txt | 69 +- src/Magnum/GL/CubeMapTexture.cpp | 27 +- .../GL/Implementation/RendererState.cpp | 6 + .../compressedPixelFormatMapping.hpp | 32 + .../GL/Implementation/pixelFormatMapping.hpp | 140 +++ src/Magnum/GL/PixelFormat.cpp | 126 +- src/Magnum/GL/PixelFormat.h | 142 ++- src/Magnum/GL/Test/BufferImageGLTest.cpp | 20 +- src/Magnum/GL/Test/CMakeLists.txt | 4 +- src/Magnum/GL/Test/FormatTest.cpp | 74 -- src/Magnum/GL/Test/PixelFormatTest.cpp | 548 ++++++++ src/Magnum/GL/visibility.h | 2 +- src/Magnum/Image.cpp | 32 +- src/Magnum/Image.h | 505 ++++++-- src/Magnum/ImageView.cpp | 26 +- src/Magnum/ImageView.h | 579 +++++++-- src/Magnum/Magnum.h | 7 +- src/Magnum/PixelFormat.cpp | 369 ++++++ src/Magnum/PixelFormat.h | 1115 ++++++++++++++++- src/Magnum/PixelStorage.h | 39 +- src/Magnum/Test/CMakeLists.txt | 3 + src/Magnum/Test/PixelFormatTest.cpp | 216 ++++ src/Magnum/Trade/ImageData.cpp | 34 +- src/Magnum/Trade/ImageData.h | 251 +++- 34 files changed, 4761 insertions(+), 662 deletions(-) create mode 100644 doc/snippets/Magnum.cpp create mode 100644 doc/snippets/MagnumTrade.cpp create mode 100644 src/Magnum/GL/Implementation/compressedPixelFormatMapping.hpp create mode 100644 src/Magnum/GL/Implementation/pixelFormatMapping.hpp delete mode 100644 src/Magnum/GL/Test/FormatTest.cpp create mode 100644 src/Magnum/GL/Test/PixelFormatTest.cpp create mode 100644 src/Magnum/PixelFormat.cpp create mode 100644 src/Magnum/Test/PixelFormatTest.cpp diff --git a/doc/changelog.dox b/doc/changelog.dox index 01613ad7d..2133c17c6 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -48,6 +48,14 @@ See also: @subsection changelog-latest-new New features +- New @ref PixelFormat / @ref CompressedPixelFormat enums containing generic + API-independent pixel formats, together with @ref pixelSize(), + @ref pixelFormatWrap() / @ref pixelFormatUnwrap(), + @ref compressedPixelFormatWrap() / @ref compressedPixelFormatUnwrap() and @ref isPixelFormatImplementationSpecific() / + @ref isCompressedPixelFormatImplementationSpecific() utilities now used by + @ref Image / @ref CompressedImage and @ref ImageView / + @ref CompressedImageView instead of the GL-specific formats + @subsubsection changelog-latest-new-math Math library - Added @ref Math::isInf(), @ref Math::isNan() @@ -56,6 +64,11 @@ See also: - A new library that now contains wrappers for the OpenGL family of graphics APIs, separated from the core Magnum library +- New @ref GL::hasPixelFormat(), @ref GL::pixelFormat(), @ref GL::pixelType(), + @ref GL::hasCompressedPixelFormat(), @ref compressedPixelFormat() utilities + for converting generic @ref PixelFormat / @ref CompressedPixelFormat to + GL-specific @ref GL::PixelFormat, @ref GL::PixelType and + @ref GL::CompressedPixelFormat values - Initial support for OpenGL ES 3.2 and OpenGL 4.6 - New OpenGL extension support: - @extension{ARB,texture_filter_anisotropic} @@ -86,6 +99,13 @@ See also: - Debug output operator for @ref Trade::PhongMaterialData::Flag and @ref Trade::PhongMaterialData::Flags +@subsection changelog-latest-changes Changes and improvements + +- The @ref CompressedPixelStorage class and related APIs are now available + on all targets including OpenGL ES and WebGL, however at the moment, until + a compatibility code path is implemented, the @ref GL library expects that + all parameters are at their defaults. + @subsection changelog-latest-buildsystem Build system - All plugin interfaces now implement @@ -128,12 +148,20 @@ See also: @ref Magnum namespace were moved to @ref Magnum/GL directory and @ref Magnum::GL namespace. See their documentation for information about particular files, classes, enums, typedefs, values and functions. +- The @ref PixelFormat and @ref CompressedPixelFormat enum now contains + generic API-independent values. The GL-specific formats are present there, + but marked as deprecated. Use either the generic values or + @ref GL::PixelFormat (together with @ref GL::PixelType) and + @ref GL::CompressedPixelFormat instead. - @ref PixelStorage::pixelSize() was deprecated, use @ref GL::pixelSize() - instead + or @ref Magnum::pixelSize() instead - `PixelStorage::dataProperties(GL::PixelFormat, GL::PixelSize, const Vector3i&)` was deprecated for being too GL-specific, use @ref PixelStorage::dataProperties(std::size_t, const Vector3i&) const together with @ref GL::pixelSize() instead +- `Image*::type()` functions are deprecated as these are too GL-specific. The + second format specifier is now available through @ref Image::formatExtra(), + @ref ImageView::formatExtra() and @ref Trade::ImageData::formatExtra() - `Audio::Buffer::Format` is deprecated, use `Audio::BufferFormat` instead - `setData()` functions in the @ref Image and @ref CompressedImage classes are deprecated because they don't offer anything extra over simple @@ -185,6 +213,34 @@ See also: to the complexity of this change, no backwards compatibility is provided. - The `magnum-info` utility was renamed to @ref magnum-gl-info. No backwards compatibility symlinks or aliases are provided. +- @ref ImageView and @ref CompressedImageView methods are no longer + @cpp constexpr @ce. It might be possible to have them @cpp constexpr @ce in + C++14, but the resulting increase in maintenance costs and compile times is + not worth it. +- `PixelFormat` has been moved verbatim to @ref GL::PixelFormat and there's a + new @ref Magnum::PixelFormat enum for generic pixel formats. It contains + (deprecated) @ref GL::PixelFormat values for covering most of backwards + compatibility, but code that relies on these two types being the same may + break. In particular, @ref GL::BufferImage::format() now returns + @ref GL::PixelFormat instead of @ref Magnum::PixelFormat, code depending on + the return type being implicitly convertible to @ref Magnum::PixelFormat + may break. In all other cases, @ref Image::format() "Image*::format()" + returns @ref Magnum::PixelFormat. +- `CompressedPixelFormat` has been moved verbatim to + @ref GL::CompressedPixelFormat and there's a new + @ref Magnum::CompressedPixelFormat enum for generic pixel formats. It + contains (deprecated) @ref GL::CompressedPixelFormat values for covering + most of backwards compatibility, but code that relies on these two types + being the same may break. In particular, + @ref GL::CompressedBufferImage::format() now returns + @ref GL::CompressedPixelFormat instead of @ref Magnum::CompressedPixelFormat, + code depending on the return type being implicitly convertible to + @ref Magnum::CompressedPixelFormat may break. In all other cases, + @ref CompressedImage::format() "CompressedImage*::format()" + returns @ref Magnum::CompressedPixelFormat. +- The @ref Image::pixelSize(), @ref ImageView::pixelSize(), + @ref Trade::ImageData::pixelSize() and @ref BufferImage::pixelSize() + functions now return @ref UnsignedInt instead of @cpp std::size_t @ce. - Removed `PixelStorage::setSwapBytes()`, as every Magnum API dealing with images basically only asserted that it's not set. Use @ref Corrade::Utility::Endianness instead. diff --git a/doc/snippets/CMakeLists.txt b/doc/snippets/CMakeLists.txt index 1414128a0..ebda8947f 100644 --- a/doc/snippets/CMakeLists.txt +++ b/doc/snippets/CMakeLists.txt @@ -40,6 +40,7 @@ endif() add_library(snippets-Magnum STATIC plugins.cpp + Magnum.cpp MagnumMath.cpp) target_link_libraries(snippets-Magnum PRIVATE Magnum) set_target_properties(snippets-Magnum PROPERTIES FOLDER "Magnum/doc/snippets") @@ -54,6 +55,13 @@ if(WITH_GL) set_target_properties(snippets-MagnumGL PROPERTIES FOLDER "Magnum/doc/snippets") endif() +if(WITH_TRADE) + add_library(snippets-MagnumTrade STATIC + MagnumTrade.cpp) + target_link_libraries(snippets-MagnumTrade PRIVATE MagnumTrade) + set_target_properties(snippets-MagnumTrade PROPERTIES FOLDER "Magnum/doc/snippets") +endif() + find_package(Corrade COMPONENTS TestSuite) if(WITH_DEBUGTOOLS) diff --git a/doc/snippets/Magnum.cpp b/doc/snippets/Magnum.cpp new file mode 100644 index 000000000..fa1f1156f --- /dev/null +++ b/doc/snippets/Magnum.cpp @@ -0,0 +1,179 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Magnum/Image.h" +#include "Magnum/PixelFormat.h" +#ifdef MAGNUM_TARGET_GL +#include "Magnum/GL/PixelFormat.h" +#include "Magnum/GL/Texture.h" +#endif + +using namespace Magnum; +using namespace Magnum::Math::Literals; + +int main() { + +{ +char data[3]; +/* [ImageView-usage] */ +ImageView2D image{PixelFormat::RGBA8Unorm, {512, 256}, data}; +/* [ImageView-usage] */ +} + +{ +char evenFrameData[3], oddFrameData[3]; +/* [ImageView-usage-streaming] */ +ImageView2D frame{PixelFormat::RGBA8Unorm, {512, 256}}; + +frame.setData(evenFrameData); +// Use even frame data ... + +frame.setData(oddFrameData); +// Use odd frame data ... +/* [ImageView-usage-streaming] */ +} + +{ +char data[3]; +/* [ImageView-usage-storage] */ +ImageView2D image{ + PixelStorage{} + .setRowLength(75) + .setAlignment(4) + .setSkip({25, 25, 0}), + PixelFormat::RGBA8Unorm, {25, 25}, data}; +/* [ImageView-usage-storage] */ +} + +#ifdef MAGNUM_TARGET_GL +{ +char data[3]; +/* [ImageView-usage-gl] */ +ImageView2D image{GL::PixelFormat::DepthComponent, + GL::PixelType::UnsignedInt, {512, 256}, data}; +/* [ImageView-usage-gl] */ + +/* [ImageView-usage-gl-extract] */ +auto format = pixelFormatUnwrap(image.format()); +auto type = GLenum(image.formatExtra()); +/* [ImageView-usage-gl-extract] */ +static_cast(format); +static_cast(type); +} +#endif + +{ +char data[3]; +#define MTLPixelFormatRGBA8Unorm_sRGB 71 +/* [ImageView-usage-metal] */ +/* Default pixel storage, 8-bit sRGB + alpha, four bytes per pixel */ +ImageView2D view{{}, MTLPixelFormatRGBA8Unorm_sRGB, {}, 4, {256, 256}, data}; +/* [ImageView-usage-metal] */ +} + +{ +char data[3]; +/* [CompressedImageView-usage] */ +CompressedImageView2D image{CompressedPixelFormat::Bc1RGBUnorm, + {512, 256}, data}; +/* [CompressedImageView-usage] */ +} + +{ +char evenFrameData[3], oddFrameData[3]; +/* [CompressedImageView-usage-streaming] */ +CompressedImageView2D frame{CompressedPixelFormat::Bc1RGBUnorm, {512, 256}}; + +frame.setData(evenFrameData); +// Use even frame data ... + +frame.setData(oddFrameData); +// Use odd frame data ... +/* [CompressedImageView-usage-streaming] */ +} + +{ +char data[3]; +/* [CompressedImageView-usage-storage] */ +CompressedImageView2D image{ + CompressedPixelStorage{} + .setRowLength(64) + .setCompressedBlockSize({4, 4, 1}) + .setCompressedBlockDataSize(8) + .setSkip({32, 32, 0}), + CompressedPixelFormat::Bc1RGBUnorm, {32, 32}, data}; +/* [CompressedImageView-usage-storage] */ +} + +#if defined(MAGNUM_TARGET_GL) && !defined(MAGNUM_TARGET_GLES) +{ +char data[3]; +/* [CompressedImageView-usage-gl] */ +CompressedImageView2D image{GL::CompressedPixelFormat::SignedRGRgtc2, + {512, 256}, data}; +/* [CompressedImageView-usage-gl] */ + +/* [CompressedImageView-usage-gl-extract] */ +auto format = compressedPixelFormatUnwrap(image.format()); +/* [CompressedImageView-usage-gl-extract] */ +static_cast(format); +} +#endif + +{ +/* [Image-usage] */ +Containers::Array data; +Image2D image{PixelFormat::RGBA8Unorm, {512, 256}, std::move(data)}; +/* [Image-usage] */ +} + +#if defined(MAGNUM_TARGET_GL) && !defined(MAGNUM_TARGET_GLES) +{ +/* [Image-usage-query] */ +GL::Texture2D texture; +Image2D image = texture.image(0, {GL::PixelFormat::DepthComponent, + GL::PixelType::UnsignedInt}); +/* [Image-usage-query] */ +} +#endif + +{ +/* [CompressedImage-usage] */ +Containers::Array data; +CompressedImage2D image{CompressedPixelFormat::Bc1RGBUnorm, + {512, 256}, std::move(data)}; +/* [CompressedImage-usage] */ +} + +#if defined(MAGNUM_TARGET_GL) && !defined(MAGNUM_TARGET_GLES) +{ +/* [CompressedImage-usage-query] */ +GL::Texture2D texture; +CompressedImage2D image = texture.compressedImage(0, {}); +/* [CompressedImage-usage-query] */ +} +#endif + +} diff --git a/doc/snippets/MagnumGL.cpp b/doc/snippets/MagnumGL.cpp index 6e332eaaa..12373900b 100644 --- a/doc/snippets/MagnumGL.cpp +++ b/doc/snippets/MagnumGL.cpp @@ -475,6 +475,60 @@ Buffer vertices{Buffer::TargetHint::Array}, /* [Buffer-webgl] */ } +#ifndef MAGNUM_TARGET_GLES2 +{ +char data[3]; +/* [BufferImage-usage] */ +GL::BufferImage2D image{GL::PixelFormat::RGBA, GL::PixelType::UnsignedByte, + {512, 256}, data, GL::BufferUsage::StaticDraw}; +/* [BufferImage-usage] */ +} + +{ +/* [BufferImage-usage-wrap] */ +GL::Buffer buffer; +GL::BufferImage2D image{GL::PixelFormat::RGBA, GL::PixelType::UnsignedByte, + {512, 256}, std::move(buffer), 524288}; +/* [BufferImage-usage-wrap] */ +} + +#ifndef MAGNUM_TARGET_GLES +{ +/* [BufferImage-usage-query] */ +GL::Texture2D texture; +GL::BufferImage2D image = texture.image(0, {GL::PixelFormat::RGBA, + GL::PixelType::UnsignedByte}, GL::BufferUsage::StaticRead); +/* [BufferImage-usage-query] */ +} +#endif + +{ +char data[3]; +/* [CompressedBufferImage-usage] */ +GL::CompressedBufferImage2D image{GL::CompressedPixelFormat::RGBS3tcDxt1, + {512, 256}, data, GL::BufferUsage::StaticDraw}; +/* [CompressedBufferImage-usage] */ +} + +{ +/* [CompressedBufferImage-usage-wrap] */ +GL::Buffer buffer; +GL::CompressedBufferImage2D image{GL::CompressedPixelFormat::RGBS3tcDxt1, + {512, 256}, std::move(buffer), 65536}; +/* [CompressedBufferImage-usage-wrap] */ +} + +#ifndef MAGNUM_TARGET_GLES +{ +/* [CompressedBufferImage-usage-query] */ +GL::Texture2D texture; +GL::CompressedBufferImage2D image = texture.compressedImage(0, {}, + GL::BufferUsage::StaticRead); +/* [CompressedBufferImage-usage-query] */ +} +#endif +#endif + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) { /* [BufferTexture-usage] */ diff --git a/doc/snippets/MagnumTrade.cpp b/doc/snippets/MagnumTrade.cpp new file mode 100644 index 000000000..4cf0daaa9 --- /dev/null +++ b/doc/snippets/MagnumTrade.cpp @@ -0,0 +1,70 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Magnum/PixelFormat.h" +#include "Magnum/Trade/AbstractImporter.h" +#include "Magnum/Trade/ImageData.h" +#ifdef MAGNUM_TARGET_GL +#include "Magnum/GL/Texture.h" +#endif + +using namespace Magnum; +using namespace Magnum::Math::Literals; + +int main() { + +{ +/* [ImageData-construction] */ +Containers::Array data; +Trade::ImageData2D image{PixelFormat::RGB8Unorm, {32, 32}, std::move(data)}; +/* [ImageData-construction] */ +} + +{ +/* [ImageData-construction-compressed] */ +Containers::Array data; +Trade::ImageData2D image{CompressedPixelFormat::Bc1RGBUnorm, + {32, 32}, std::move(data)}; +/* [ImageData-construction-compressed] */ +} + +#ifdef MAGNUM_TARGET_GL +{ +/* [ImageData-usage] */ +std::unique_ptr importer; +Containers::Optional image = importer->image2D(0); +if(!image) Fatal{} << "Oopsie!"; + +GL::Texture2D texture; +// ... +if(!image->isCompressed()) + texture.setSubImage(0, {}, *image); +else + texture.setCompressedSubImage(0, {}, *image); +/* [ImageData-usage] */ +} +#endif + +} diff --git a/src/Magnum/CMakeLists.txt b/src/Magnum/CMakeLists.txt index c78899486..35529456e 100644 --- a/src/Magnum/CMakeLists.txt +++ b/src/Magnum/CMakeLists.txt @@ -28,10 +28,15 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake # Files shared between main library and unit test library set(Magnum_SRCS + Image.cpp + ImageView.cpp PixelStorage.cpp Resource.cpp Timeline.cpp) +set(Magnum_GracefulAssert_SRCS + PixelFormat.cpp) + set(Magnum_HEADERS AbstractResourceLoader.h Array.h @@ -39,6 +44,7 @@ set(Magnum_HEADERS Image.h ImageView.h Magnum.h + PixelFormat.h PixelStorage.h Resource.h ResourceManager.h @@ -65,7 +71,6 @@ if(WITH_GL AND BUILD_DEPRECATED) Mesh.h MeshView.h OpenGL.h - PixelFormat.h Renderbuffer.h RenderbufferFormat.h Renderer.h @@ -127,7 +132,7 @@ set(MagnumMath_SRCS Math/Packing.cpp Math/instantiation.cpp) -# Objects shared between main and test library +# Objects shared between main and math test library add_library(MagnumMathObjects OBJECT ${MagnumMath_SRCS}) target_include_directories(MagnumMathObjects PUBLIC ${PROJECT_SOURCE_DIR}/src @@ -141,11 +146,32 @@ if(NOT BUILD_STATIC OR BUILD_STATIC_PIC) endif() set_target_properties(MagnumMathObjects PROPERTIES FOLDER "Magnum/Math") -# Main library -add_library(Magnum ${SHARED_OR_STATIC} +# Objects shared between main and test library +add_library(MagnumObjects OBJECT ${Magnum_SRCS} ${Magnum_HEADERS} - $) + ${Magnum_PRIVATE_HEADERS}) +target_include_directories(MagnumObjects PUBLIC + ${PROJECT_SOURCE_DIR}/src + ${PROJECT_BINARY_DIR}/src + $) +if(BUILD_DEPRECATED AND TARGET_GL) # TODO: remove once compat gets dropped + target_include_directories(MagnumObjects PUBLIC + ${PROJECT_SOURCE_DIR}/src/MagnumExternal/OpenGL) +endif() +if(NOT BUILD_STATIC) + target_compile_definitions(MagnumObjects PRIVATE "MagnumObjects_EXPORTS") +endif() +if(NOT BUILD_STATIC OR BUILD_STATIC_PIC) + set_target_properties(MagnumObjects PROPERTIES POSITION_INDEPENDENT_CODE ON) +endif() +set_target_properties(MagnumObjects PROPERTIES FOLDER "Magnum") + +# Main library +add_library(Magnum ${SHARED_OR_STATIC} + $ + $ + ${Magnum_GracefulAssert_SRCS}) set_target_properties(Magnum PROPERTIES DEBUG_POSTFIX "-d" FOLDER "Magnum") @@ -157,6 +183,10 @@ endif() target_include_directories(Magnum PUBLIC ${PROJECT_SOURCE_DIR}/src ${PROJECT_BINARY_DIR}/src) +if(BUILD_DEPRECATED AND TARGET_GL) # TODO: remove once compat gets dropped + target_include_directories(Magnum PUBLIC + ${PROJECT_SOURCE_DIR}/src/MagnumExternal/OpenGL) +endif() target_link_libraries(Magnum PUBLIC Corrade::Utility) @@ -215,7 +245,7 @@ if(WITH_TRADE) endif() if(BUILD_TESTS) - # Library with graceful assert for testing + # Math library with graceful assert for testing add_library(MagnumMathTestLib ${SHARED_OR_STATIC} $ ${PROJECT_SOURCE_DIR}/src/dummy.cpp) # XCode workaround, see file comment for details @@ -228,10 +258,32 @@ if(BUILD_TESTS) FOLDER "Magnum/Math") target_link_libraries(MagnumMathTestLib Corrade::Utility) + # Library with graceful assert for testing + add_library(MagnumTestLib ${SHARED_OR_STATIC} + $ + $ + ${Magnum_GracefulAssert_SRCS}) + target_include_directories(MagnumTestLib PUBLIC + ${PROJECT_SOURCE_DIR}/src + ${PROJECT_BINARY_DIR}/src) + if(BUILD_DEPRECATED AND TARGET_GL) # TODO: remove once compat gets dropped + target_include_directories(MagnumTestLib PUBLIC + ${PROJECT_SOURCE_DIR}/src/MagnumExternal/OpenGL) + endif() + target_compile_definitions(MagnumTestLib PRIVATE + "CORRADE_GRACEFUL_ASSERT" "Magnum_EXPORTS") + set_target_properties(MagnumTestLib PROPERTIES + DEBUG_POSTFIX "-d" + FOLDER "Magnum") + if(BUILD_STATIC_PIC) + set_target_properties(MagnumTestLib PROPERTIES POSITION_INDEPENDENT_CODE ON) + endif() + target_link_libraries(MagnumTestLib PUBLIC Corrade::Utility) + # On Windows we need to install first and then run the tests to avoid "DLL # not found" hell, thus we need to install this too if(CORRADE_TARGET_WINDOWS AND NOT CMAKE_CROSSCOMPILING AND NOT BUILD_STATIC) - install(TARGETS MagnumMathTestLib + install(TARGETS MagnumMathTestLib MagnumTestLib RUNTIME DESTINATION ${MAGNUM_BINARY_INSTALL_DIR} LIBRARY DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR} ARCHIVE DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) diff --git a/src/Magnum/GL/AbstractFramebuffer.cpp b/src/Magnum/GL/AbstractFramebuffer.cpp index 6d8ca6ba9..d07fd2422 100644 --- a/src/Magnum/GL/AbstractFramebuffer.cpp +++ b/src/Magnum/GL/AbstractFramebuffer.cpp @@ -35,6 +35,7 @@ #include "Magnum/GL/CubeMapTextureArray.h" #endif #include "Magnum/GL/Extensions.h" +#include "Magnum/GL/PixelFormat.h" #ifndef MAGNUM_TARGET_GLES #include "Magnum/GL/RectangleTexture.h" #endif @@ -308,12 +309,12 @@ void AbstractFramebuffer::read(const Range2Di& rectangle, Image2D& image) { Buffer::unbindInternal(Buffer::TargetHint::PixelPack); #endif Context::current().state().renderer->applyPixelStoragePack(image.storage()); - (Context::current().state().framebuffer->readImplementation)(rectangle, image.format(), image.type(), data.size(), data + (Context::current().state().framebuffer->readImplementation)(rectangle, pixelFormat(image.format()), pixelType(image.format(), image.formatExtra()), data.size(), data #ifdef MAGNUM_TARGET_GLES2 + Magnum::Implementation::pixelStorageSkipOffsetFor(image, rectangle.size()) #endif ); - image = Image2D{image.storage(), image.format(), image.type(), rectangle.size(), std::move(data)}; + image = Image2D{image.storage(), image.format(), image.formatExtra(), image.pixelSize(), rectangle.size(), std::move(data)}; } Image2D AbstractFramebuffer::read(const Range2Di& rectangle, Image2D&& image) { diff --git a/src/Magnum/GL/AbstractTexture.cpp b/src/Magnum/GL/AbstractTexture.cpp index bd9d18492..638a6cd6c 100644 --- a/src/Magnum/GL/AbstractTexture.cpp +++ b/src/Magnum/GL/AbstractTexture.cpp @@ -1516,7 +1516,7 @@ void AbstractTexture::imageImplementationSvga3DSliceBySlice(const GLenum target, DSA cleanness is not worth it. */ /** @todo this will break when we support uploading from buffer offset (i.e. data != nullptr) */ if(target == GL_TEXTURE_1D_ARRAY && data && size.y() > 1) - subImageImplementationSvga3DSliceBySlice<&AbstractTexture::subImage2DImplementationDefault>(level, {0, 1}, {size.x(), size.y() - 1}, format, type, static_cast(data) + std::get<1>(storage.dataProperties(format, type, {size, 1})).x(), storage); + subImageImplementationSvga3DSliceBySlice<&AbstractTexture::subImage2DImplementationDefault>(level, {0, 1}, {size.x(), size.y() - 1}, format, type, static_cast(data) + std::get<1>(storage.dataProperties(pixelSize(format, type), {size, 1})).x(), storage); } #endif @@ -1531,7 +1531,7 @@ template(storage.dataProperties(format, type, {size, 1})).x(); + const std::size_t stride = std::get<1>(storage.dataProperties(pixelSize(format, type), {size, 1})).x(); for(Int i = 0; i != size.y(); ++i) (this->*original)(level, {offset.x(), offset.y() + i}, {size.x(), 1}, format, type, static_cast(data) + stride*i, storage); @@ -1599,7 +1599,7 @@ void AbstractTexture::imageImplementationSvga3DSliceBySlice(GLint level, Texture #endif ) && data && size.z() > 1) { - subImageImplementationSvga3DSliceBySlice<&AbstractTexture::subImage3DImplementationDefault>(level, {0, 0, 1}, {size.xy(), size.z() - 1}, format, type, static_cast(data) + std::get<1>(storage.dataProperties(format, type, size)).xy().product(), storage); + subImageImplementationSvga3DSliceBySlice<&AbstractTexture::subImage3DImplementationDefault>(level, {0, 0, 1}, {size.xy(), size.z() - 1}, format, type, static_cast(data) + std::get<1>(storage.dataProperties(pixelSize(format, type), size)).xy().product(), storage); } } #endif @@ -1626,7 +1626,7 @@ template(storage.dataProperties(format, type, size)).xy().product(); + const std::size_t stride = std::get<1>(storage.dataProperties(pixelSize(format, type), size)).xy().product(); for(Int i = 0; i != size.z(); ++i) (this->*original)(level, {offset.xy(), offset.z() + i}, {size.xy(), 1}, format, type, static_cast(data) + stride*i, storage); @@ -1701,8 +1701,8 @@ template void AbstractTexture::image(GLint level, Image< Buffer::unbindInternal(Buffer::TargetHint::PixelPack); Context::current().state().renderer->applyPixelStoragePack(image.storage()); - (this->*Context::current().state().texture->getImageImplementation)(level, image.format(), image.type(), data.size(), data); - image = Image{image.storage(), image.format(), image.type(), size, std::move(data)}; + (this->*Context::current().state().texture->getImageImplementation)(level, pixelFormat(image.format()), pixelType(image.format(), image.formatExtra()), data.size(), data); + image = Image{image.storage(), image.format(), image.formatExtra(), image.pixelSize(), size, std::move(data)}; } template void MAGNUM_GL_EXPORT AbstractTexture::image<1>(GLint, Image<1>&); @@ -1805,8 +1805,8 @@ template void AbstractTexture::subImage(const GLint leve Buffer::unbindInternal(Buffer::TargetHint::PixelPack); Context::current().state().renderer->applyPixelStoragePack(image.storage()); - glGetTextureSubImage(_id, level, paddedOffset.x(), paddedOffset.y(), paddedOffset.z(), paddedSize.x(), paddedSize.y(), paddedSize.z(), GLenum(image.format()), GLenum(image.type()), data.size(), data); - image = Image{image.storage(), image.format(), image.type(), size, std::move(data)}; + glGetTextureSubImage(_id, level, paddedOffset.x(), paddedOffset.y(), paddedOffset.z(), paddedSize.x(), paddedSize.y(), paddedSize.z(), GLenum(pixelFormat(image.format())), GLenum(pixelType(image.format(), image.formatExtra())), data.size(), data); + image = Image{image.storage(), image.format(), image.formatExtra(), image.pixelSize(), size, std::move(data)}; } template void MAGNUM_GL_EXPORT AbstractTexture::subImage<1>(GLint, const Range1Di&, Image<1>&); @@ -1995,7 +1995,7 @@ void AbstractTexture::DataHelper<1>::setImage(AbstractTexture& texture, const GL Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); texture.bindInternal(); - glTexImage1D(texture._target, level, GLint(internalFormat), image.size()[0], 0, GLenum(image.format()), GLenum(image.type()), image.data()); + glTexImage1D(texture._target, level, GLint(internalFormat), image.size()[0], 0, GLenum(pixelFormat(image.format())), GLenum(pixelType(image.format(), image.formatExtra())), image.data()); } void AbstractTexture::DataHelper<1>::setCompressedImage(AbstractTexture& texture, const GLint level, const CompressedImageView1D& image) { @@ -2022,13 +2022,13 @@ void AbstractTexture::DataHelper<1>::setCompressedImage(AbstractTexture& texture void AbstractTexture::DataHelper<1>::setSubImage(AbstractTexture& texture, const GLint level, const Math::Vector<1, GLint>& offset, const ImageView1D& image) { Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - (texture.*Context::current().state().texture->subImage1DImplementation)(level, offset, image.size(), image.format(), image.type(), image.data()); + (texture.*Context::current().state().texture->subImage1DImplementation)(level, offset, image.size(), pixelFormat(image.format()), pixelType(image.format(), image.formatExtra()), image.data()); } void AbstractTexture::DataHelper<1>::setCompressedSubImage(AbstractTexture& texture, const GLint level, const Math::Vector<1, GLint>& offset, const CompressedImageView1D& image) { Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - (texture.*Context::current().state().texture->compressedSubImage1DImplementation)(level, offset, image.size(), image.format(), image.data(), Magnum::Implementation::occupiedCompressedImageDataSize(image, image.data().size())); + (texture.*Context::current().state().texture->compressedSubImage1DImplementation)(level, offset, image.size(), compressedPixelFormat(image.format()), image.data(), Magnum::Implementation::occupiedCompressedImageDataSize(image, image.data().size())); } void AbstractTexture::DataHelper<1>::setSubImage(AbstractTexture& texture, const GLint level, const Math::Vector<1, GLint>& offset, BufferImage1D& image) { @@ -2049,7 +2049,7 @@ void AbstractTexture::DataHelper<2>::setImage(AbstractTexture& texture, const GL Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); #endif Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - (texture.*Context::current().state().texture->image2DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), image.data() + (texture.*Context::current().state().texture->image2DImplementation)(target, level, internalFormat, image.size(), pixelFormat(image.format()), pixelType(image.format(), image.formatExtra()), image.data() #ifdef MAGNUM_TARGET_GLES2 + Magnum::Implementation::pixelStorageSkipOffset(image) #endif @@ -2060,13 +2060,9 @@ void AbstractTexture::DataHelper<2>::setCompressedImage(AbstractTexture& texture #ifndef MAGNUM_TARGET_GLES2 Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); #endif - #ifndef MAGNUM_TARGET_GLES - /* Pixel storage is completely ignored for compressed images on ES, no need - to reset anything */ Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - #endif texture.bindInternal(); - glCompressedTexImage2D(target, level, GLenum(image.format()), image.size().x(), image.size().y(), 0, Magnum::Implementation::occupiedCompressedImageDataSize(image, image.data().size()), image.data()); + glCompressedTexImage2D(target, level, GLenum(compressedPixelFormat(image.format())), image.size().x(), image.size().y(), 0, Magnum::Implementation::occupiedCompressedImageDataSize(image, image.data().size()), image.data()); } #ifndef MAGNUM_TARGET_GLES2 @@ -2079,11 +2075,7 @@ void AbstractTexture::DataHelper<2>::setImage(AbstractTexture& texture, const GL void AbstractTexture::DataHelper<2>::setCompressedImage(AbstractTexture& texture, const GLenum target, const GLint level, CompressedBufferImage2D& image) { image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack); - #ifndef MAGNUM_TARGET_GLES - /* Pixel storage is completely ignored for compressed images on ES, no need - to reset anything */ Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - #endif texture.bindInternal(); glCompressedTexImage2D(target, level, GLenum(image.format()), image.size().x(), image.size().y(), 0, Magnum::Implementation::occupiedCompressedImageDataSize(image, image.dataSize()), nullptr); } @@ -2094,7 +2086,7 @@ void AbstractTexture::DataHelper<2>::setSubImage(AbstractTexture& texture, const Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); #endif Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - (texture.*Context::current().state().texture->subImage2DImplementation)(level, offset, image.size(), image.format(), image.type(), image.data() + (texture.*Context::current().state().texture->subImage2DImplementation)(level, offset, image.size(), pixelFormat(image.format()), pixelType(image.format(), image.formatExtra()), image.data() #ifdef MAGNUM_TARGET_GLES2 + Magnum::Implementation::pixelStorageSkipOffset(image) #endif @@ -2105,12 +2097,8 @@ void AbstractTexture::DataHelper<2>::setCompressedSubImage(AbstractTexture& text #ifndef MAGNUM_TARGET_GLES2 Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); #endif - #ifndef MAGNUM_TARGET_GLES - /* Pixel storage is completely ignored for compressed images on ES, no need - to reset anything */ Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - #endif - (texture.*Context::current().state().texture->compressedSubImage2DImplementation)(level, offset, image.size(), image.format(), image.data(), Magnum::Implementation::occupiedCompressedImageDataSize(image, image.data().size())); + (texture.*Context::current().state().texture->compressedSubImage2DImplementation)(level, offset, image.size(), compressedPixelFormat(image.format()), image.data(), Magnum::Implementation::occupiedCompressedImageDataSize(image, image.data().size())); } #ifndef MAGNUM_TARGET_GLES2 @@ -2122,11 +2110,7 @@ void AbstractTexture::DataHelper<2>::setSubImage(AbstractTexture& texture, const void AbstractTexture::DataHelper<2>::setCompressedSubImage(AbstractTexture& texture, const GLint level, const Vector2i& offset, CompressedBufferImage2D& image) { image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack); - #ifndef MAGNUM_TARGET_GLES - /* Pixel storage is completely ignored for compressed images on ES, no need - to reset anything */ Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - #endif (texture.*Context::current().state().texture->compressedSubImage2DImplementation)(level, offset, image.size(), image.format(), nullptr, Magnum::Implementation::occupiedCompressedImageDataSize(image, image.dataSize())); } #endif @@ -2137,7 +2121,7 @@ void AbstractTexture::DataHelper<3>::setImage(AbstractTexture& texture, const GL Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); #endif Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - (texture.*Context::current().state().texture->image3DImplementation)(level, internalFormat, image.size(), image.format(), image.type(), image.data() + (texture.*Context::current().state().texture->image3DImplementation)(level, internalFormat, image.size(), pixelFormat(image.format()), pixelType(image.format(), image.formatExtra()), image.data() #ifdef MAGNUM_TARGET_GLES2 + Magnum::Implementation::pixelStorageSkipOffset(image) #endif @@ -2148,16 +2132,12 @@ void AbstractTexture::DataHelper<3>::setCompressedImage(AbstractTexture& texture #ifndef MAGNUM_TARGET_GLES2 Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); #endif - #ifndef MAGNUM_TARGET_GLES - /* Pixel storage is completely ignored for compressed images on ES, no need - to reset anything */ Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - #endif texture.bindInternal(); #ifndef MAGNUM_TARGET_GLES2 - glCompressedTexImage3D(texture._target, level, GLenum(image.format()), image.size().x(), image.size().y(), image.size().z(), 0, Magnum::Implementation::occupiedCompressedImageDataSize(image, image.data().size()), image.data()); + glCompressedTexImage3D(texture._target, level, GLenum(compressedPixelFormat(image.format())), image.size().x(), image.size().y(), image.size().z(), 0, Magnum::Implementation::occupiedCompressedImageDataSize(image, image.data().size()), image.data()); #else - glCompressedTexImage3DOES(texture._target, level, GLenum(image.format()), image.size().x(), image.size().y(), image.size().z(), 0, Magnum::Implementation::occupiedCompressedImageDataSize(image, image.data().size()), image.data()); + glCompressedTexImage3DOES(texture._target, level, GLenum(compressedPixelFormat(image.format())), image.size().x(), image.size().y(), image.size().z(), 0, Magnum::Implementation::occupiedCompressedImageDataSize(image, image.data().size()), image.data()); #endif } #endif @@ -2172,11 +2152,7 @@ void AbstractTexture::DataHelper<3>::setImage(AbstractTexture& texture, const GL void AbstractTexture::DataHelper<3>::setCompressedImage(AbstractTexture& texture, const GLint level, CompressedBufferImage3D& image) { image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack); - #ifndef MAGNUM_TARGET_GLES - /* Pixel storage is completely ignored for compressed images on ES, no need - to reset anything */ Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - #endif texture.bindInternal(); glCompressedTexImage3D(texture._target, level, GLenum(image.format()), image.size().x(), image.size().y(), image.size().z(), 0, Magnum::Implementation::occupiedCompressedImageDataSize(image, image.dataSize()), nullptr); } @@ -2188,7 +2164,7 @@ void AbstractTexture::DataHelper<3>::setSubImage(AbstractTexture& texture, const Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); #endif Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - (texture.*Context::current().state().texture->subImage3DImplementation)(level, offset, image.size(), image.format(), image.type(), image.data() + (texture.*Context::current().state().texture->subImage3DImplementation)(level, offset, image.size(), pixelFormat(image.format()), pixelType(image.format(), image.formatExtra()), image.data() #ifdef MAGNUM_TARGET_GLES2 + Magnum::Implementation::pixelStorageSkipOffset(image) #endif @@ -2199,12 +2175,8 @@ void AbstractTexture::DataHelper<3>::setCompressedSubImage(AbstractTexture& text #ifndef MAGNUM_TARGET_GLES2 Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); #endif - #ifndef MAGNUM_TARGET_GLES - /* Pixel storage is completely ignored for compressed images on ES, no need - to reset anything */ Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - #endif - (texture.*Context::current().state().texture->compressedSubImage3DImplementation)(level, offset, image.size(), image.format(), image.data(), Magnum::Implementation::occupiedCompressedImageDataSize(image, image.data().size())); + (texture.*Context::current().state().texture->compressedSubImage3DImplementation)(level, offset, image.size(), compressedPixelFormat(image.format()), image.data(), Magnum::Implementation::occupiedCompressedImageDataSize(image, image.data().size())); } #endif @@ -2217,11 +2189,7 @@ void AbstractTexture::DataHelper<3>::setSubImage(AbstractTexture& texture, const void AbstractTexture::DataHelper<3>::setCompressedSubImage(AbstractTexture& texture, const GLint level, const Vector3i& offset, CompressedBufferImage3D& image) { image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack); - #ifndef MAGNUM_TARGET_GLES - /* Pixel storage is completely ignored for compressed images on ES, no need - to reset anything */ Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - #endif (texture.*Context::current().state().texture->compressedSubImage3DImplementation)(level, offset, image.size(), image.format(), nullptr, Magnum::Implementation::occupiedCompressedImageDataSize(image, image.dataSize())); } #endif diff --git a/src/Magnum/GL/BufferImage.cpp b/src/Magnum/GL/BufferImage.cpp index b1fc22eea..173227a40 100644 --- a/src/Magnum/GL/BufferImage.cpp +++ b/src/Magnum/GL/BufferImage.cpp @@ -30,19 +30,26 @@ namespace Magnum { namespace GL { #ifndef MAGNUM_TARGET_GLES2 -template BufferImage::BufferImage(const PixelStorage storage, const PixelFormat format, const PixelType type, const VectorTypeFor& size, Containers::ArrayView const data, const BufferUsage usage): _storage{storage}, _format{format}, _type{type}, _size{size}, _buffer{Buffer::TargetHint::PixelPack}, _dataSize{data.size()} { - CORRADE_ASSERT(Magnum::Implementation::imageDataSize(*this) <= data.size(), "GL::BufferImage::BufferImage(): bad image data size, got" << data.size() << "but expected at least" << Magnum::Implementation::imageDataSize(*this), ); +template BufferImage::BufferImage(const PixelStorage storage, const PixelFormat format, const PixelType type, const VectorTypeFor& size, Containers::ArrayView const data, const BufferUsage usage): BufferImage{storage, format, type, size, Buffer{Buffer::TargetHint::PixelPack}, data.size()} { _buffer.setData(data, usage); } +template BufferImage::BufferImage(const PixelStorage storage, const Magnum::PixelFormat format, const VectorTypeFor& size, Containers::ArrayView const data, const BufferUsage usage): BufferImage{storage, GL::pixelFormat(format), GL::pixelType(format), size, data, usage} {} + template BufferImage::BufferImage(const PixelStorage storage, const PixelFormat format, const PixelType type, const VectorTypeFor& size, Buffer&& buffer, const std::size_t dataSize) noexcept: _storage{storage}, _format{format}, _type{type}, _size{size}, _buffer{std::move(buffer)}, _dataSize{dataSize} { CORRADE_ASSERT(Magnum::Implementation::imageDataSize(*this) <= dataSize, "GL::BufferImage::BufferImage(): bad image data size, got" << dataSize << "but expected at least" << Magnum::Implementation::imageDataSize(*this), ); } +template BufferImage::BufferImage(const PixelStorage storage, const Magnum::PixelFormat format, const VectorTypeFor& size, Buffer&& buffer, const std::size_t dataSize) noexcept: BufferImage{storage, GL::pixelFormat(format), GL::pixelType(format), size, std::move(buffer), dataSize} {} + template BufferImage::BufferImage(const PixelStorage storage, const PixelFormat format, const PixelType type): _storage{storage}, _format{format}, _type{type}, _buffer{Buffer::TargetHint::PixelPack}, _dataSize{0} {} +template BufferImage::BufferImage(const PixelStorage storage, const Magnum::PixelFormat format): _storage{storage}, _format{GL::pixelFormat(format)}, _type{GL::pixelType(format)}, _buffer{Buffer::TargetHint::PixelPack}, _dataSize{0} {} + template BufferImage::BufferImage(NoCreateT) noexcept: _format{PixelFormat::RGBA}, _type{PixelType::UnsignedByte}, _buffer{NoCreate}, _dataSize{} {} +template UnsignedInt BufferImage::pixelSize() const { return GL::pixelSize(_format, _type); } + template void BufferImage::setData(const PixelStorage storage, const PixelFormat format, const PixelType type, const VectorTypeFor& size, Containers::ArrayView const data, const BufferUsage usage) { _storage = storage; _format = format; @@ -59,56 +66,37 @@ template void BufferImage::setData(const Pix } } -template CompressedBufferImage::CompressedBufferImage( - #ifndef MAGNUM_TARGET_GLES - const CompressedPixelStorage storage, - #endif - const CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data, const BufferUsage usage): - #ifndef MAGNUM_TARGET_GLES - _storage{storage}, - #endif - _format{format}, _size{size}, _buffer{Buffer::TargetHint::PixelPack}, _dataSize{data.size()} -{ +template void BufferImage::setData(const PixelStorage storage, const Magnum::PixelFormat format, const VectorTypeFor& size, Containers::ArrayView const data, const BufferUsage usage) { + setData(storage, GL::pixelFormat(format), GL::pixelType(format), size, data, usage); +} + +template CompressedBufferImage::CompressedBufferImage(const CompressedPixelStorage storage, const CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data, const BufferUsage usage): CompressedBufferImage{storage, format, size, Buffer{Buffer::TargetHint::PixelPack}, data.size()} { _buffer.setData(data, usage); } -template CompressedBufferImage::CompressedBufferImage( - #ifndef MAGNUM_TARGET_GLES - const CompressedPixelStorage storage, - #endif - const CompressedPixelFormat format, const VectorTypeFor& size, Buffer&& buffer, const std::size_t dataSize) noexcept: - #ifndef MAGNUM_TARGET_GLES - _storage{storage}, - #endif - _format{format}, _size{size}, _buffer{std::move(buffer)}, _dataSize{dataSize} {} - -template CompressedBufferImage::CompressedBufferImage( - #ifndef MAGNUM_TARGET_GLES - const CompressedPixelStorage storage - #endif - ): - #ifndef MAGNUM_TARGET_GLES - _storage{storage}, - #endif - _format{}, _buffer{Buffer::TargetHint::PixelPack}, _dataSize{} {} +template CompressedBufferImage::CompressedBufferImage(const CompressedPixelStorage storage, const Magnum::CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data, const BufferUsage usage): CompressedBufferImage{storage, compressedPixelFormat(format), size, data, usage} {} + +template CompressedBufferImage::CompressedBufferImage(const CompressedPixelStorage storage, const CompressedPixelFormat format, const VectorTypeFor& size, Buffer&& buffer, const std::size_t dataSize) noexcept: _storage{storage}, _format{format}, _size{size}, _buffer{std::move(buffer)}, _dataSize{dataSize} {} + +template CompressedBufferImage::CompressedBufferImage(const CompressedPixelStorage storage, const Magnum::CompressedPixelFormat format, const VectorTypeFor& size, Buffer&& buffer, const std::size_t dataSize) noexcept: CompressedBufferImage{storage, compressedPixelFormat(format), size, std::move(buffer), dataSize} {} + +template CompressedBufferImage::CompressedBufferImage(const CompressedPixelStorage storage): _storage{storage}, _format{}, _buffer{Buffer::TargetHint::PixelPack}, _dataSize{} {} template CompressedBufferImage::CompressedBufferImage(NoCreateT) noexcept: _format{}, _buffer{NoCreate}, _dataSize{} {} -template void CompressedBufferImage::setData( - #ifndef MAGNUM_TARGET_GLES - const CompressedPixelStorage storage, - #endif - const CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data, const BufferUsage usage) -{ - #ifndef MAGNUM_TARGET_GLES +template void CompressedBufferImage::setData(const CompressedPixelStorage storage, const CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data, const BufferUsage usage) { _storage = storage; - #endif _format = format; _size = size; _buffer.setData(data, usage); _dataSize = data.size(); } + +template void CompressedBufferImage::setData(const CompressedPixelStorage storage, const Magnum::CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data, const BufferUsage usage) { + setData(storage, compressedPixelFormat(format), size, data, usage); +} + template Buffer BufferImage::release() { _size = {}; _dataSize = {}; diff --git a/src/Magnum/GL/BufferImage.h b/src/Magnum/GL/BufferImage.h index 0b7bbd442..e5f825cea 100644 --- a/src/Magnum/GL/BufferImage.h +++ b/src/Magnum/GL/BufferImage.h @@ -42,10 +42,46 @@ namespace Magnum { namespace GL { /** @brief Buffer image -Stores image data in GPU memory. Interchangeable with @ref Image, -@ref ImageView or @ref Trade::ImageData. -@see @ref BufferImage1D, @ref BufferImage2D, @ref BufferImage3D, - @ref CompressedBufferImage, @ref Buffer +Stores multi-dimensional image data in GPU memory together with layout and +pixel format description. See @ref Image for the client memory counterpart. + +This class can act as a drop-in replacement for @ref Image, @ref ImageView and +@ref Trade::ImageData APIs. See also @ref CompressedBufferImage for equivalent +functionality targeted on compressed image formats. + +@section GL-BufferImage-usage Basic usage + +The image creates a @ref Buffer instance and fills it with passed data, storing +corresponding image size and pixel format properties. Because this is a +GL-centric class, it's common to specify the format using @ref GL::PixelFormat +and @link GL::PixelType @endlink: + +@snippet MagnumGL.cpp BufferImage-usage + +It's also possible to pass the generic @ref Magnum::PixelFormat to it, however +the @ref format() and @ref type() queries will always return the GL-specific +value. On construction, the image internally calculates pixel size +corresponding to given pixel format using either @ref GL::pixelSize() or +@ref Magnum::pixelSize(). This value is needed to check that the passed data +are large enough and also required by most of image manipulation operations. + +Besides creating and owning the buffer, you can also pass existing buffer to +it, for example to use buffer storage and other advanced functionality. The +image will take an ownership of the buffer, you can use @ref Buffer::wrap() to +make a non-owning copy. + +@snippet MagnumGL.cpp BufferImage-usage-wrap + +It's also possible to create just an image placeholder, storing only the image +properties without data or size. That is useful for example to specify desired +format of image queries in graphics APIs: + +@snippet MagnumGL.cpp BufferImage-usage-query + +Similarly to @ref ImageView, this class supports extra storage parameters. +See @ref ImageView-usage for more information. + +@see @ref BufferImage1D, @ref BufferImage2D, @ref BufferImage3D @requires_gles30 Pixel buffer objects are not available in OpenGL ES 2.0. @requires_webgl20 Pixel buffer objects are not available in WebGL 1.0. */ @@ -66,11 +102,62 @@ template class BufferImage { */ explicit BufferImage(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage); - /** @overload - * Similar to the above, but uses default @ref PixelStorage parameters. + /** + * @brief Constructor + * @param format Format of pixel data + * @param type Data type of pixel data + * @param size Image size + * @param data Image data + * @param usage Image buffer usage + * + * Equivalent to calling @ref BufferImage(PixelStorage, PixelFormat, PixelType, const VectorTypeFor&, Containers::ArrayView, BufferUsage) + * with default-constructed @ref PixelStorage. */ explicit BufferImage(PixelFormat format, PixelType type, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage): BufferImage{{}, format, type, size, data, usage} {} + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief Constructor + * @deprecated Use either @ref GL::PixelFormat together with + * @ref GL::PixelType or just @ref Magnum::PixelFormat instead + */ + explicit CORRADE_DEPRECATED("use either GL::PixelFormat together with GL::PixelType or just Magnum::PixelFormat instead") BufferImage(PixelStorage storage, Magnum::PixelFormat format, PixelType type, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage): BufferImage{storage, PixelFormat(UnsignedInt(format)), type, size, data, usage} {} + + /** + * @brief Constructor + * + * @deprecated Use either @ref GL::PixelFormat together with + * @ref GL::PixelType or just @ref Magnum::PixelFormat instead + */ + explicit CORRADE_DEPRECATED("use either GL::PixelFormat together with GL::PixelType or just Magnum::PixelFormat instead") BufferImage(Magnum::PixelFormat format, PixelType type, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage): BufferImage{PixelFormat(UnsignedInt(format)), type, size, data, usage} {} + #endif + + /** + * @brief Constructor + * @param storage Storage of pixel data + * @param format Format of pixel data + * @param size Image size + * @param data Image data + * @param usage Image buffer usage + * + * Converts @ref Magnum::PixelFormat to GL-specific values using + * @ref pixelFormat() and @ref pixelType() and then calls + * @ref BufferImage(PixelStorage, PixelFormat, PixelType, const VectorTypeFor&, Containers::ArrayView, BufferUsage). + */ + explicit BufferImage(PixelStorage storage, Magnum::PixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage); + + /** + * @brief Constructor + * @param format Format of pixel data + * @param size Image size + * @param data Image data + * @param usage Image buffer usage + * + * Equivalent to calling @ref BufferImage(PixelStorage, Magnum::PixelFormat, const VectorTypeFor&, Containers::ArrayView, BufferUsage) + * with default-constructed @ref PixelStorage. + */ + explicit BufferImage(Magnum::PixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage): BufferImage{{}, format, size, data, usage} {} + /** * @brief Construct from existing buffer * @param storage Storage of pixel data @@ -85,30 +172,118 @@ template class BufferImage { */ explicit BufferImage(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor& size, Buffer&& buffer, std::size_t dataSize) noexcept; - /** @overload - * Similar to the above, but uses default @ref PixelStorage parameters. + /** + * @brief Construct from existing buffer + * @param format Format of pixel data + * @param type Data type of pixel data + * @param size Image size + * @param buffer Buffer + * @param dataSize Buffer data size + * + * Equivalent to calling @ref BufferImage(PixelStorage, PixelFormat, PixelType, const VectorTypeFor&, Buffer&&, std::size_t) + * with default-constructed @ref PixelStorage. */ explicit BufferImage(PixelFormat format, PixelType type, const VectorTypeFor& size, Buffer&& buffer, std::size_t dataSize) noexcept: BufferImage{{}, format, type, size, std::move(buffer), dataSize} {} + #ifdef MAGNUM_BUILD_DEPRECATED /** - * @brief Constructor + * @brief Construct from existing buffer + * @deprecated Use either @ref GL::PixelFormat together with + * @ref GL::PixelType or just @ref Magnum::PixelFormat instead + */ + explicit CORRADE_DEPRECATED("use either GL::PixelFormat together with GL::PixelType or just Magnum::PixelFormat instead") BufferImage(PixelStorage storage, Magnum::PixelFormat format, PixelType type, const VectorTypeFor& size, Buffer&& buffer, std::size_t dataSize) noexcept: BufferImage{storage, PixelFormat(UnsignedInt(format)), type, size, std::move(buffer), dataSize} {} + + /** + * @brief Construct from existing buffer + * @deprecated Use either @ref GL::PixelFormat together with + * @ref GL::PixelType or just @ref Magnum::PixelFormat instead + */ + explicit CORRADE_DEPRECATED("use either GL::PixelFormat together with GL::PixelType or just Magnum::PixelFormat instead") BufferImage(Magnum::PixelFormat format, PixelType type, const VectorTypeFor& size, Buffer&& buffer, std::size_t dataSize) noexcept: BufferImage{PixelFormat(UnsignedInt(format)), type, size, std::move(buffer), dataSize} {} + #endif + + /** + * @brief Construct from existing buffer + * @param storage Storage of pixel data + * @param format Format of pixel data + * @param size Image size + * @param buffer Buffer + * @param dataSize Buffer data size + * + * Converts @ref Magnum::PixelFormat to GL-specific values using + * @ref pixelFormat() and @ref pixelType() and then calls + * @ref BufferImage(PixelStorage, PixelFormat, PixelType, const VectorTypeFor&, Buffer&&, std::size_t). + */ + explicit BufferImage(PixelStorage storage, Magnum::PixelFormat format, const VectorTypeFor& size, Buffer&& buffer, std::size_t dataSize) noexcept; + + /** + * @brief Construct from existing buffer + * @param format Format of pixel data + * @param size Image size + * @param buffer Buffer + * @param dataSize Buffer data size + * + * Equivalent to calling @ref BufferImage(PixelStorage, Magnum::PixelFormat, const VectorTypeFor&, Buffer&&, std::size_t) + * with default-constructed @ref PixelStorage. + */ + explicit BufferImage(Magnum::PixelFormat format, const VectorTypeFor& size, Buffer&& buffer, std::size_t dataSize) noexcept: BufferImage{{}, format, size, std::move(buffer), dataSize} {} + + /** + * @brief Construct an image placeholder * @param storage Storage of pixel data * @param format Format of pixel data * @param type Data type of pixel data * * Size is zero and buffer are empty, call @ref setData() to fill the - * image with data or use @ref Texture::image() "*Texture::image()"/ - * @ref Texture::subImage() "*Texture::subImage()"/ - * @ref AbstractFramebuffer::read() "*Framebuffer::read()" to fill the - * image with data using @p storage settings. + * image with data. */ /*implicit*/ BufferImage(PixelStorage storage, PixelFormat format, PixelType type); - /** @overload - * Similar to the above, but uses default @ref PixelStorage parameters. + /** + * @brief Construct an image placeholder + * @param format Format of pixel data + * @param type Data type of pixel data + * + * Equivalent to calling @ref BufferImage(PixelStorage, PixelFormat, PixelType) + * with default-constructed @ref PixelStorage. */ /*implicit*/ BufferImage(PixelFormat format, PixelType type): BufferImage{{}, format, type} {} + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief Construct an image placeholder + * @deprecated Use either @ref GL::PixelFormat together with + * @ref GL::PixelType or just @ref Magnum::PixelFormat instead + */ + /*implicit*/ CORRADE_DEPRECATED("use either GL::PixelFormat together with GL::PixelType or just Magnum::PixelFormat instead") BufferImage(PixelStorage storage, Magnum::PixelFormat format, PixelType type): BufferImage{storage, PixelFormat(UnsignedInt(format)), type} {} + + /** + * @brief Construct an image placeholder + * @deprecated Use either @ref GL::PixelFormat together with + * @ref GL::PixelType or just @ref Magnum::PixelFormat instead + */ + /*implicit*/ CORRADE_DEPRECATED("use either GL::PixelFormat together with GL::PixelType or just Magnum::PixelFormat instead") BufferImage(Magnum::PixelFormat format, PixelType type): BufferImage{PixelFormat(UnsignedInt(format)), type} {} + #endif + + /** + * @brief Construct an image placeholder + * @param storage Storage of pixel data + * @param format Format of pixel data + * + * Converts @ref Magnum::PixelFormat to GL-specific values using + * @ref pixelFormat() and @ref pixelType() and then calls + * @ref BufferImage(PixelStorage, PixelFormat, PixelType). + */ + /*implicit*/ BufferImage(PixelStorage storage, Magnum::PixelFormat format); + + /** + * @brief Construct an image placeholder + * @param format Format of pixel data + * + * Equivalent to calling @ref BufferImage(PixelStorage, Magnum::PixelFormat) + * with default-constructed @ref PixelStorage. + */ + /*implicit*/ BufferImage(Magnum::PixelFormat format): BufferImage{{}, format} {} + /** * @brief Construct without creating the underlying OpenGL object * @@ -149,7 +324,7 @@ template class BufferImage { * * @see @ref Magnum::pixelSize(), @ref GL::pixelSize() */ - std::size_t pixelSize() const { return PixelStorage::pixelSize(_format, _type); } + UnsignedInt pixelSize() const; /** @brief Image size */ VectorTypeFor size() const { return _size; } @@ -196,11 +371,59 @@ template class BufferImage { setData({}, format, type, size, data, usage); } + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief Set image data + * @deprecated Use either @ref GL::PixelFormat together with + * @ref GL::PixelType or just @ref Magnum::PixelFormat instead + */ + CORRADE_DEPRECATED("use either GL::PixelFormat together with GL::PixelType or just Magnum::PixelFormat instead") void setData(PixelStorage storage, Magnum::PixelFormat format, PixelType type, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage) { + setData(storage, PixelFormat(UnsignedInt(format)), type, size, data, usage); + } + + /** + * @brief Set image data + * @deprecated Use either @ref GL::PixelFormat together with + * @ref GL::PixelType or just @ref Magnum::PixelFormat instead + */ + CORRADE_DEPRECATED("use either GL::PixelFormat together with GL::PixelType or just Magnum::PixelFormat instead") void setData(Magnum::PixelFormat format, PixelType type, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage) { + setData({}, PixelFormat(UnsignedInt(format)), type, size, data, usage); + } + #endif + + /** + * @brief Set image data + * @param storage Storage of pixel data + * @param format Format of pixel data + * @param size Image size + * @param data Image data + * @param usage Image buffer usage + * + * Converts @ref Magnum::PixelFormat to GL-specific values using + * @ref pixelFormat() and @ref pixelType() and then calls + * @ref setData(PixelStorage, PixelFormat, PixelType, const VectorTypeFor&, Containers::ArrayView, BufferUsage). + */ + void setData(PixelStorage storage, Magnum::PixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage); + + /** + * @brief Set image data + * @param format Format of pixel data + * @param size Image size + * @param data Image data + * @param usage Image buffer usage + * + * Equivalent to calling @ref setData(PixelStorage, Magnum::PixelFormat, const VectorTypeFor&, Containers::ArrayView, BufferUsage) + * with default-constructed @ref PixelStorage. + */ + void setData(Magnum::PixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage) { + setData({}, format, size, data, usage); + } + /** * @brief Release the image buffer * - * Releases the ownership of the image buffer and resets internal state - * to default. + * Releases the ownership of the data array and resets @ref size() to + * zero. The state afterwards is equivalent to moved-from state. * @see @ref buffer() */ Buffer release(); @@ -226,10 +449,43 @@ typedef BufferImage<3> BufferImage3D; /** @brief Compressed buffer image -Stores image data in GPU memory. +Stores multi-dimensional compressed image data in GPU memory together with +layout and compressed block description. See @ref CompressedImage for the +client memory counterpart. + +This class can act as a drop-in replacement for @ref CompressedImage, +@ref CompressedImageView and @ref Trade::ImageData APIs. See also +@ref BufferImage for equivalent functionality targeted on non-compressed image +formats. + +@section GL-CompressedBufferImage-usage Basic usage + +The image creates a @ref Buffer instance and fills it with passed data, storing +corresponding image size and compression format properties. Because this is a +GL-centric class, it's common to specify the format using +@link GL::CompressedPixelFormat @endlink: + +@snippet MagnumGL.cpp CompressedBufferImage-usage + +It's also possible to pass the generic @ref Magnum::CompressedPixelFormat to +it, however the @ref format() query will always return the GL-specific value. + +Besides creating and owning the buffer, you can also pass existing buffer to +it, for example to use buffer storage and other advanced functionality. The +image will take an ownership of the buffer, you can use @ref Buffer::wrap() to +make a non-owning copy. + +@snippet MagnumGL.cpp CompressedBufferImage-usage-wrap + +It's also possible to create just an image placeholder, storing only the image +properties without data or size. That is useful for example to specify desired +format of image queries in graphics APIs: + +@snippet MagnumGL.cpp CompressedBufferImage-usage-query + +Similarly to @ref CompressedImageView, this class supports extra storage +parameters. See @ref CompressedImageView-usage for more information. -See @ref BufferImage for more information. Interchangeable with @ref CompressedImage, -@ref CompressedImageView or @ref Trade::ImageData. @see @ref CompressedBufferImage1D, @ref CompressedBufferImage2D, @ref CompressedBufferImage3D @requires_gles30 Pixel buffer objects are not available in OpenGL ES 2.0. @@ -241,7 +497,6 @@ template class CompressedBufferImage { Dimensions = dimensions /**< Image dimension count */ }; - #ifndef MAGNUM_TARGET_GLES /** * @brief Constructor * @param storage Storage of compressed pixel data @@ -251,11 +506,11 @@ template class CompressedBufferImage { * @param usage Image buffer usage * * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * for non-default compressed pixel storage * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and * WebGL. */ explicit CompressedBufferImage(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage); - #endif /** * @brief Constructor @@ -264,57 +519,112 @@ template class CompressedBufferImage { * @param data Image data * @param usage Image buffer usage * - * Similar the above, but uses default @ref CompressedPixelStorage - * parameters (or the hardcoded ones in OpenGL ES and WebGL). + * Equivalent to calling @ref CompressedBufferImage(CompressedPixelStorage, Magnum::CompressedPixelFormat, const VectorTypeFor&, Containers::ArrayView, BufferUsage) + * with default-constructed @ref CompressedPixelStorage. */ - explicit CompressedBufferImage(CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage); + explicit CompressedBufferImage(CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage): CompressedBufferImage{{}, format, size, data, usage} {} - #ifndef MAGNUM_TARGET_GLES /** * @brief Constructor * @param storage Storage of compressed pixel data * @param format Format of compressed pixel data * @param size Image size - * @param buffer Image data - * @param dataSize Image buffer usage + * @param data Image data + * @param usage Image buffer usage + * + * Converts @ref Magnum::CompressedPixelFormat to a GL-specific value + * using @ref compressedPixelFormat() and and then calls + * @ref CompressedBufferImage(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::ArrayView, BufferUsage). + */ + explicit CompressedBufferImage(CompressedPixelStorage storage, Magnum::CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage); + + /** + * @brief Constructor + * @param format Format of compressed pixel data + * @param size Image size + * @param data Image data + * @param usage Image buffer usage * + * Equivalent to calling @ref CompressedBufferImage(CompressedPixelStorage, Magnum::CompressedPixelFormat, const VectorTypeFor&, Containers::ArrayView, BufferUsage) + * with default-constructed @ref CompressedPixelStorage. + */ + explicit CompressedBufferImage(Magnum::CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage): CompressedBufferImage{{}, format, size, data, usage} {} + + /** + * @brief Constructor + * @param storage Storage of compressed pixel data + * @param format Format of compressed pixel data + * @param size Image size + * @param buffer Buffer + * @param dataSize Buffer data size + * + * If @p dataSize is @cpp 0 @ce, the buffer is unconditionally + * reallocated on the first call to @ref setData(). * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * for non-default compressed pixel storage * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and * WebGL. */ explicit CompressedBufferImage(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Buffer&& buffer, std::size_t dataSize) noexcept; - #endif - /** @overload - * Similar the above, but uses default @ref CompressedPixelStorage - * parameters (or the hardcoded ones in OpenGL ES and WebGL). + /** + * @brief Construct from existing buffer + * @param format Format of compressed pixel data + * @param size Image size + * @param buffer Buffer + * @param dataSize Buffer data size + * + * Equivalent to calling @ref CompressedBufferImage(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Buffer&&, std::size_t) + * with default-constructed @ref CompressedPixelStorage. */ - explicit CompressedBufferImage(CompressedPixelFormat format, const VectorTypeFor& size, Buffer&& buffer, std::size_t dataSize) noexcept; + explicit CompressedBufferImage(CompressedPixelFormat format, const VectorTypeFor& size, Buffer&& buffer, std::size_t dataSize) noexcept: CompressedBufferImage{{}, format, size, std::move(buffer), dataSize} {} - #ifndef MAGNUM_TARGET_GLES /** - * @brief Constructor + * @brief Construct from existing buffer + * @param storage Storage of compressed pixel data + * @param format Format of compressed pixel data + * @param size Image size + * @param buffer Buffer + * @param dataSize Buffer data size + * + * Converts @ref Magnum::CompressedPixelFormat to a GL-specific value + * using @ref compressedPixelFormat() and and then calls + * @ref CompressedBufferImage(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Buffer&&, std::size_t). + */ + explicit CompressedBufferImage(CompressedPixelStorage storage, Magnum::CompressedPixelFormat format, const VectorTypeFor& size, Buffer&& buffer, std::size_t dataSize) noexcept; + + /** + * @brief Construct from existing buffer + * @param format Format of compressed pixel data + * @param size Image size + * @param buffer Buffer + * @param dataSize Buffer data size + * + * Equivalent to calling @ref CompressedBufferImage(CompressedPixelStorage, Magnum::CompressedPixelFormat, const VectorTypeFor&, Buffer&&, std::size_t) + * with default-constructed @ref CompressedPixelStorage. + */ + explicit CompressedBufferImage(Magnum::CompressedPixelFormat format, const VectorTypeFor& size, Buffer&& buffer, std::size_t dataSize) noexcept: CompressedBufferImage{{}, format, size, std::move(buffer), dataSize} {} + + /** + * @brief Construct an image placeholder * @param storage Storage of compressed pixel data * * Format is undefined, size is zero and buffer is empty, call - * @ref setData() to fill the image with data or use - * @ref Texture::compressedImage() "*Texture::compressedImage()"/ - * @ref Texture::compressedSubImage() "*Texture::compressedSubImage()" - * to fill the image with data using @p storage settings. + * @ref setData() to fill the image with data. * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} + * for non-default compressed pixel storage * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and * WebGL. */ /*implicit*/ CompressedBufferImage(CompressedPixelStorage storage); - #endif /** - * @brief Constructor + * @brief Construct an image placeholder * - * Similar the above, but uses default @ref CompressedPixelStorage - * parameters (or the hardcoded ones in OpenGL ES and WebGL). + * Equivalent to calling @ref CompressedBufferImage(CompressedPixelStorage) + * with default-constructed @ref CompressedPixelStorage. */ - /*implicit*/ CompressedBufferImage(); + /*implicit*/ CompressedBufferImage(): CompressedBufferImage{CompressedPixelStorage{}} {} /** * @brief Construct without creating the underlying OpenGL object @@ -338,16 +648,8 @@ template class CompressedBufferImage { /** @brief Move assignment */ CompressedBufferImage& operator=(CompressedBufferImage&& other) noexcept; - #ifndef MAGNUM_TARGET_GLES - /** - * @brief Storage of compressed pixel data - * - * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} - * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and - * WebGL. - */ + /** @brief Storage of compressed pixel data */ CompressedPixelStorage storage() const { return _storage; } - #endif /** @brief Format of compressed pixel data */ CompressedPixelFormat format() const { return _format; } @@ -355,7 +657,6 @@ template class CompressedBufferImage { /** @brief Image size */ VectorTypeFor size() const { return _size; } - #ifndef MAGNUM_TARGET_GLES /** * @brief Compressed image data properties * @@ -368,7 +669,6 @@ template class CompressedBufferImage { std::tuple, VectorTypeFor, std::size_t> dataProperties() const { return Magnum::Implementation::compressedImageDataProperties(*this); } - #endif /** * @brief Image buffer @@ -380,7 +680,6 @@ template class CompressedBufferImage { /** @brief Raw data size */ std::size_t dataSize() const { return _dataSize; } - #ifndef MAGNUM_TARGET_GLES /** * @brief Set image data * @param storage Storage of compressed pixel data @@ -389,15 +688,13 @@ template class CompressedBufferImage { * @param data Image data * @param usage Image buffer usage * - * Updates the image buffer with given data. The data are *not* deleted - * after filling the buffer. + * Updates the image buffer with given data. * @see @ref Buffer::setData() * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and * WebGL. */ void setData(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage); - #endif /** * @brief Set image data @@ -406,24 +703,52 @@ template class CompressedBufferImage { * @param data Image data * @param usage Image buffer usage * - * Similar the above, but uses default @ref CompressedPixelStorage - * parameters (or the hardcoded ones in OpenGL ES and WebGL). + * Equivalent to calling @ref setData(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::ArrayView, BufferUsage) + * with default-constructed @ref CompressedPixelStorage. + */ + void setData(CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage) { + setData({}, format, size, data, usage); + } + + /** + * @brief Set image data + * @param storage Storage of compressed pixel data + * @param format Format of compressed pixel data + * @param size Image size + * @param data Image data + * @param usage Image buffer usage + * + * Converts @ref Magnum::CompressedPixelFormat to a GL-specific value + * using @ref compressedPixelFormat() and and then calls + * @ref setData(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::ArrayView, BufferUsage). + */ + void setData(CompressedPixelStorage storage, Magnum::CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage); + + /** + * @brief Set image data + * @param format Format of compressed pixel data + * @param size Image size + * @param data Image data + * @param usage Image buffer usage + * + * Equivalent to calling @ref setData(CompressedPixelStorage, Magnum::CompressedPixelFormat, const VectorTypeFor&, Containers::ArrayView, BufferUsage) + * with default-constructed @ref CompressedPixelStorage. */ - void setData(CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage); + void setData(Magnum::CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data, BufferUsage usage) { + setData({}, format, size, data, usage); + } /** * @brief Release the image buffer * - * Releases the ownership of the image buffer and resets internal state - * to default. + * Releases the ownership of the data array and resets @ref size() to + * zero. The state afterwards is equivalent to moved-from state. * @see @ref buffer() */ Buffer release(); private: - #ifndef MAGNUM_TARGET_GLES CompressedPixelStorage _storage; - #endif CompressedPixelFormat _format; Math::Vector _size; Buffer _buffer; @@ -443,11 +768,7 @@ template inline BufferImage::BufferImage(Buf other._size = {}; } -template inline CompressedBufferImage::CompressedBufferImage(CompressedBufferImage&& other) noexcept: - #ifndef MAGNUM_TARGET_GLES - _storage{std::move(other._storage)}, - #endif - _format{std::move(other._format)}, _size{std::move(other._size)}, _buffer{std::move(other._buffer)}, _dataSize{std::move(other._dataSize)} { +template inline CompressedBufferImage::CompressedBufferImage(CompressedBufferImage&& other) noexcept: _storage{std::move(other._storage)}, _format{std::move(other._format)}, _size{std::move(other._size)}, _buffer{std::move(other._buffer)}, _dataSize{std::move(other._dataSize)} { other._size = {}; other._dataSize = {}; } @@ -464,9 +785,7 @@ template inline BufferImage& BufferImage inline CompressedBufferImage& CompressedBufferImage::operator=(CompressedBufferImage&& other) noexcept { using std::swap; - #ifndef MAGNUM_TARGET_GLES swap(_storage, other._storage); - #endif swap(_format, other._format); swap(_size, other._size); swap(_buffer, other._buffer); @@ -474,18 +793,6 @@ template inline CompressedBufferImage& Compr return *this; } -#ifndef MAGNUM_TARGET_GLES -template inline CompressedBufferImage::CompressedBufferImage(const CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data, const BufferUsage usage): CompressedBufferImage{{}, format, size, data, usage} {} - -template inline CompressedBufferImage::CompressedBufferImage(const CompressedPixelFormat format, const VectorTypeFor& size, Buffer&& buffer, const std::size_t dataSize) noexcept: CompressedBufferImage{{}, format, size, std::move(buffer), dataSize} {} - -template inline CompressedBufferImage::CompressedBufferImage(): CompressedBufferImage{CompressedPixelStorage{}} {} - -template inline void CompressedBufferImage::setData(const CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data, const BufferUsage usage) { - setData({}, format, size, data, usage); -} -#endif - } #ifdef MAGNUM_BUILD_DEPRECATED diff --git a/src/Magnum/GL/CMakeLists.txt b/src/Magnum/GL/CMakeLists.txt index 9e2a9dabd..6e68d70c9 100644 --- a/src/Magnum/GL/CMakeLists.txt +++ b/src/Magnum/GL/CMakeLists.txt @@ -34,12 +34,9 @@ set(MagnumGL_SRCS Context.cpp DefaultFramebuffer.cpp Framebuffer.cpp - ../Image.cpp # temporary - ../ImageView.cpp # temporary Mesh.cpp MeshView.cpp OpenGL.cpp - PixelFormat.cpp Renderbuffer.cpp Renderer.cpp Sampler.cpp @@ -59,6 +56,9 @@ set(MagnumGL_SRCS Implementation/driverSpecific.cpp Implementation/maxTextureSize.cpp) +set(MagnumGL_GracefulAssert_SRCS + PixelFormat.cpp) + set(MagnumGL_HEADERS AbstractFramebuffer.h AbstractObject.h @@ -170,16 +170,35 @@ if(NOT (TARGET_WEBGL AND TARGET_GLES2)) Implementation/QueryState.h) endif() +# Objects shared between main and test library +add_library(MagnumGLObjects OBJECT + ${MagnumGL_SRCS} + ${MagnumGL_HEADERS} + ${MagnumGL_PRIVATE_HEADERS}) +# We can use both implicit include path (GLES2/gl2.h) where our headers can +# be overriden with system ones or explicit (MagnumExternal/OpenGL/GLES2/gl2ext.h) +# where only our headers will be used +target_include_directories(MagnumGLObjects PUBLIC + $ + ${PROJECT_SOURCE_DIR}/src/MagnumExternal/OpenGL) +if(NOT BUILD_STATIC) + target_compile_definitions(MagnumGLObjects PRIVATE "MagnumGLObjects_EXPORTS" "FlextGL_EXPORTS") +endif() +if(NOT BUILD_STATIC OR BUILD_STATIC_PIC) + set_target_properties(MagnumGLObjects PROPERTIES POSITION_INDEPENDENT_CODE ON) +endif() +set_target_properties(MagnumGLObjects PROPERTIES FOLDER "Magnum/GL") + # Link in GL function pointer variables on platforms that support it if(NOT CORRADE_TARGET_EMSCRIPTEN) - list(APPEND MagnumGL_SRCS $) + set(MagnumGL_FlextGL_SRCS $) endif() # GL library add_library(MagnumGL ${SHARED_OR_STATIC} - ${MagnumGL_SRCS} - ${MagnumGL_HEADERS} - ${MagnumGL_PRIVATE_HEADERS}) + $ + ${MagnumGL_FlextGL_SRCS} + ${MagnumGL_GracefulAssert_SRCS}) set_target_properties(MagnumGL PROPERTIES DEBUG_POSTFIX "-d" FOLDER "Magnum/GL") @@ -193,8 +212,6 @@ endif() # be overriden with system ones or explicit (MagnumExternal/OpenGL/GLES2/gl2ext.h) # where only our headers will be used target_include_directories(MagnumGL PUBLIC - ${PROJECT_SOURCE_DIR}/src - ${PROJECT_BINARY_DIR}/src ${PROJECT_SOURCE_DIR}/src/MagnumExternal/OpenGL) target_link_libraries(MagnumGL PUBLIC Magnum) if(NOT TARGET_GLES OR TARGET_DESKTOP_GLES) @@ -249,6 +266,40 @@ if(WITH_OPENGLTESTER) endif() if(BUILD_TESTS) + # Library with graceful assert for testing + add_library(MagnumGLTestLib ${SHARED_OR_STATIC} + $ + ${MagnumGL_FlextGL_SRCS} + ${MagnumGL_GracefulAssert_SRCS}) + target_include_directories(MagnumGLTestLib PUBLIC + ${PROJECT_SOURCE_DIR}/src/MagnumExternal/OpenGL) + set_target_properties(MagnumGLTestLib PROPERTIES + DEBUG_POSTFIX "-d" + FOLDER "Magnum/GL") + target_compile_definitions(MagnumGLTestLib PRIVATE + "CORRADE_GRACEFUL_ASSERT" "MagnumGL_EXPORTS" "FlextGL_EXPORTS") + if(BUILD_STATIC_PIC) + set_target_properties(MagnumGLTestLib PROPERTIES POSITION_INDEPENDENT_CODE ON) + endif() + target_link_libraries(MagnumGLTestLib PUBLIC + Magnum) + if(NOT TARGET_GLES OR TARGET_DESKTOP_GLES) + target_link_libraries(MagnumGLTestLib PUBLIC ${OPENGL_gl_LIBRARY}) + elseif(TARGET_GLES2) + target_link_libraries(MagnumGLTestLib PUBLIC OpenGLES2::OpenGLES2) + else() + target_link_libraries(MagnumGLTestLib PUBLIC OpenGLES3::OpenGLES3) + endif() + + # On Windows we need to install first and then run the tests to avoid "DLL + # not found" hell, thus we need to install this too + if(CORRADE_TARGET_WINDOWS AND NOT CMAKE_CROSSCOMPILING AND NOT BUILD_STATIC) + install(TARGETS MagnumGLTestLib + RUNTIME DESTINATION ${MAGNUM_BINARY_INSTALL_DIR} + LIBRARY DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR} + ARCHIVE DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) + endif() + add_subdirectory(Test) endif() diff --git a/src/Magnum/GL/CubeMapTexture.cpp b/src/Magnum/GL/CubeMapTexture.cpp index 6c9c2e26e..981f7c549 100644 --- a/src/Magnum/GL/CubeMapTexture.cpp +++ b/src/Magnum/GL/CubeMapTexture.cpp @@ -30,6 +30,7 @@ #include "Magnum/GL/BufferImage.h" #endif #include "Magnum/GL/Context.h" +#include "Magnum/GL/PixelFormat.h" #include "Magnum/GL/Implementation/maxTextureSize.h" #include "Magnum/GL/Implementation/RendererState.h" #include "Magnum/GL/Implementation/State.h" @@ -74,8 +75,8 @@ void CubeMapTexture::image(const Int level, Image3D& image) { Buffer::unbindInternal(Buffer::TargetHint::PixelPack); Context::current().state().renderer->applyPixelStoragePack(image.storage()); - glGetTextureImage(_id, level, GLenum(image.format()), GLenum(image.type()), data.size(), data); - image = Image3D{image.storage(), image.format(), image.type(), size, std::move(data)}; + glGetTextureImage(_id, level, GLenum(pixelFormat(image.format())), GLenum(pixelType(image.format(), image.formatExtra())), data.size(), data); + image = Image3D{image.storage(), image.format(), image.formatExtra(), image.pixelSize(), size, std::move(data)}; } Image3D CubeMapTexture::image(const Int level, Image3D&& image) { @@ -182,8 +183,8 @@ void CubeMapTexture::image(const CubeMapCoordinate coordinate, const Int level, Buffer::unbindInternal(Buffer::TargetHint::PixelPack); Context::current().state().renderer->applyPixelStoragePack(image.storage()); - (this->*Context::current().state().texture->getCubeImageImplementation)(coordinate, level, size, image.format(), image.type(), data.size(), data); - image = Image2D{image.storage(), image.format(), image.type(), size, std::move(data)}; + (this->*Context::current().state().texture->getCubeImageImplementation)(coordinate, level, size, pixelFormat(image.format()), pixelType(image.format(), image.formatExtra()), data.size(), data); + image = Image2D{image.storage(), image.format(), image.formatExtra(), image.pixelSize(), size, std::move(data)}; } Image2D CubeMapTexture::image(const CubeMapCoordinate coordinate, const Int level, Image2D&& image) { @@ -298,7 +299,7 @@ CubeMapTexture& CubeMapTexture::setSubImage(const Int level, const Vector3i& off Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - (this->*Context::current().state().texture->cubeSubImage3DImplementation)(level, offset, image.size(), image.format(), image.type(), image.data(), image.storage()); + (this->*Context::current().state().texture->cubeSubImage3DImplementation)(level, offset, image.size(), pixelFormat(image.format()), pixelType(image.format(), image.formatExtra()), image.data(), image.storage()); return *this; } @@ -316,7 +317,7 @@ CubeMapTexture& CubeMapTexture::setCompressedSubImage(const Int level, const Vec Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - glCompressedTextureSubImage3D(_id, level, offset.x(), offset.y(), offset.z(), image.size().x(), image.size().y(), image.size().z(), GLenum(image.format()), Magnum::Implementation::occupiedCompressedImageDataSize(image, image.data().size()), image.data()); + glCompressedTextureSubImage3D(_id, level, offset.x(), offset.y(), offset.z(), image.size().x(), image.size().y(), image.size().z(), GLenum(compressedPixelFormat(image.format())), Magnum::Implementation::occupiedCompressedImageDataSize(image, image.data().size()), image.data()); return *this; } @@ -335,7 +336,7 @@ CubeMapTexture& CubeMapTexture::setSubImage(const CubeMapCoordinate coordinate, Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); #endif Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - (this->*Context::current().state().texture->cubeSubImageImplementation)(coordinate, level, offset, image.size(), image.format(), image.type(), image.data() + (this->*Context::current().state().texture->cubeSubImageImplementation)(coordinate, level, offset, image.size(), pixelFormat(image.format()), pixelType(image.format(), image.formatExtra()), image.data() #ifdef MAGNUM_TARGET_GLES2 + Magnum::Implementation::pixelStorageSkipOffset(image) #endif @@ -356,23 +357,15 @@ CubeMapTexture& CubeMapTexture::setCompressedSubImage(const CubeMapCoordinate co #ifndef MAGNUM_TARGET_GLES2 Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); #endif - #ifndef MAGNUM_TARGET_GLES - /* Pixel storage is completely ignored for compressed images on ES, no need - to reset anything */ Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - #endif - (this->*Context::current().state().texture->cubeCompressedSubImageImplementation)(coordinate, level, offset, image.size(), image.format(), image.data(), Magnum::Implementation::occupiedCompressedImageDataSize(image, image.data().size())); + (this->*Context::current().state().texture->cubeCompressedSubImageImplementation)(coordinate, level, offset, image.size(), compressedPixelFormat(image.format()), image.data(), Magnum::Implementation::occupiedCompressedImageDataSize(image, image.data().size())); return *this; } #ifndef MAGNUM_TARGET_GLES2 CubeMapTexture& CubeMapTexture::setCompressedSubImage(const CubeMapCoordinate coordinate, const Int level, const Vector2i& offset, CompressedBufferImage2D& image) { image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack); - #ifndef MAGNUM_TARGET_GLES - /* Pixel storage is completely ignored for compressed images on ES, no need - to reset anything */ Context::current().state().renderer->applyPixelStorageUnpack(image.storage()); - #endif (this->*Context::current().state().texture->cubeCompressedSubImageImplementation)(coordinate, level, offset, image.size(), image.format(), nullptr, Magnum::Implementation::occupiedCompressedImageDataSize(image, image.dataSize())); return *this; } @@ -509,7 +502,7 @@ void CubeMapTexture::subImageImplementationDefault(const GLint level, const Vect } void CubeMapTexture::subImageImplementationSvga3DSliceBySlice(const GLint level, const Vector3i& offset, const Vector3i& size, const PixelFormat format, const PixelType type, const GLvoid* const data, const PixelStorage& storage) { - const std::size_t stride = std::get<1>(storage.dataProperties(format, type, size)).xy().product(); + const std::size_t stride = std::get<1>(storage.dataProperties(pixelSize(format, type), size)).xy().product(); for(Int i = 0; i != size.z(); ++i) subImageImplementationDefault(level, {offset.xy(), offset.z() + i}, {size.xy(), 1}, format, type, static_cast(data) + stride*i, storage); } diff --git a/src/Magnum/GL/Implementation/RendererState.cpp b/src/Magnum/GL/Implementation/RendererState.cpp index a70d6addb..82ab1f5e8 100644 --- a/src/Magnum/GL/Implementation/RendererState.cpp +++ b/src/Magnum/GL/Implementation/RendererState.cpp @@ -194,6 +194,11 @@ void RendererState::applyPixelStorageUnpack(const Magnum::PixelStorage& storage) } void RendererState::applyPixelStorageInternal(const CompressedPixelStorage& storage, const bool isUnpack) { + #ifdef MAGNUM_TARGET_GLES + CORRADE_ASSERT(storage == CompressedPixelStorage{}, + "GL: non-default CompressedPixelStorage parameters are not supported on OpenGLES or WebGL", ); + static_cast(isUnpack); + #else applyPixelStorageInternal(static_cast(storage), isUnpack); PixelStorage& state = isUnpack ? unpackPixelStorage : packPixelStorage; @@ -221,6 +226,7 @@ void RendererState::applyPixelStorageInternal(const CompressedPixelStorage& stor state.compressedBlockDataSize != storage.compressedBlockDataSize()) glPixelStorei(isUnpack ? GL_UNPACK_COMPRESSED_BLOCK_SIZE : GL_PACK_COMPRESSED_BLOCK_SIZE, state.compressedBlockDataSize = storage.compressedBlockDataSize()); + #endif } }}} diff --git a/src/Magnum/GL/Implementation/compressedPixelFormatMapping.hpp b/src/Magnum/GL/Implementation/compressedPixelFormatMapping.hpp new file mode 100644 index 000000000..dc917d082 --- /dev/null +++ b/src/Magnum/GL/Implementation/compressedPixelFormatMapping.hpp @@ -0,0 +1,32 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/* See Magnum/GL/PixelFormat.cpp and Magnum/GL/Test/PixelFormatTest.cpp */ +#ifdef _c +_c(Bc1RGBUnorm, RGBS3tcDxt1) +_c(Bc1RGBAUnorm, RGBAS3tcDxt1) +_c(Bc2RGBAUnorm, RGBAS3tcDxt3) +_c(Bc3RGBAUnorm, RGBAS3tcDxt5) +#endif diff --git a/src/Magnum/GL/Implementation/pixelFormatMapping.hpp b/src/Magnum/GL/Implementation/pixelFormatMapping.hpp new file mode 100644 index 000000000..507cb0506 --- /dev/null +++ b/src/Magnum/GL/Implementation/pixelFormatMapping.hpp @@ -0,0 +1,140 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/* See Magnum/GL/PixelFormat.cpp and Magnum/GL/Test/PixelFormatTest.cpp */ +#ifdef _c +#ifndef MAGNUM_TARGET_GLES2 +_c(R8Unorm, Red, UnsignedByte) +_c(RG8Unorm, RG, UnsignedByte) +#else +_c(R8Unorm, Luminance, UnsignedByte) +_c(RG8Unorm, LuminanceAlpha, UnsignedByte) +#endif +_c(RGB8Unorm, RGB, UnsignedByte) +_c(RGBA8Unorm, RGBA, UnsignedByte) +#ifndef MAGNUM_TARGET_GLES2 +_c(R8Snorm, Red, Byte) +_c(RG8Snorm, RG, Byte) +_c(RGB8Snorm, RGB, Byte) +_c(RGBA8Snorm, RGBA, Byte) +#else +_s(R8Snorm) +_s(RG8Snorm) +_s(RGB8Snorm) +_s(RGBA8Snorm) +#endif +#ifndef MAGNUM_TARGET_GLES2 +_c(R8UI, RedInteger, UnsignedByte) +_c(RG8UI, RGInteger, UnsignedByte) +_c(RGB8UI, RGBInteger, UnsignedByte) +_c(RGBA8UI, RGBAInteger, UnsignedByte) +_c(R8I, RedInteger, Byte) +_c(RG8I, RGInteger, Byte) +_c(RGB8I, RGBInteger, Byte) +_c(RGBA8I, RGBAInteger, Byte) +#else +_s(R8UI) +_s(RG8UI) +_s(RGB8UI) +_s(RGBA8UI) +_s(R8I) +_s(RG8I) +_s(RGB8I) +_s(RGBA8I) +#endif +#ifndef MAGNUM_TARGET_GLES2 +_c(R16Unorm, Red, UnsignedShort) +_c(RG16Unorm, RG, UnsignedShort) +#else +_c(R16Unorm, Luminance, UnsignedShort) +_c(RG16Unorm, LuminanceAlpha, UnsignedShort) +#endif +_c(RGB16Unorm, RGB, UnsignedShort) +_c(RGBA16Unorm, RGBA, UnsignedShort) +#ifndef MAGNUM_TARGET_GLES2 +_c(R16Snorm, Red, Short) +_c(RG16Snorm, RG, Short) +_c(RGB16Snorm, RGB, Short) +_c(RGBA16Snorm, RGBA, Short) +#else +_s(R16Snorm) +_s(RG16Snorm) +_s(RGB16Snorm) +_s(RGBA16Snorm) +#endif +#ifndef MAGNUM_TARGET_GLES2 +_c(R16UI, RedInteger, UnsignedShort) +_c(RG16UI, RGInteger, UnsignedShort) +_c(RGB16UI, RGBInteger, UnsignedShort) +_c(RGBA16UI, RGBAInteger, UnsignedShort) +_c(R16I, RedInteger, Short) +_c(RG16I, RGInteger, Short) +_c(RGB16I, RGBInteger, Short) +_c(RGBA16I, RGBAInteger, Short) +_c(R32UI, RedInteger, UnsignedInt) +_c(RG32UI, RGInteger, UnsignedInt) +_c(RGB32UI, RGBInteger, UnsignedInt) +_c(RGBA32UI, RGBAInteger, UnsignedInt) +_c(R32I, RedInteger, Int) +_c(RG32I, RGInteger, Int) +_c(RGB32I, RGBInteger, Int) +_c(RGBA32I, RGBAInteger, Int) +#else +_s(R16UI) +_s(RG16UI) +_s(RGB16UI) +_s(RGBA16UI) +_s(R16I) +_s(RG16I) +_s(RGB16I) +_s(RGBA16I) +_s(R32UI) +_s(RG32UI) +_s(RGB32UI) +_s(RGBA32UI) +_s(R32I) +_s(RG32I) +_s(RGB32I) +_s(RGBA32I) +#endif +#ifndef MAGNUM_TARGET_GLES2 +_c(R16F, Red, HalfFloat) +_c(RG16F, RG, HalfFloat) +#else +_c(R16F, Luminance, HalfFloat) +_c(RG16F, LuminanceAlpha, HalfFloat) +#endif +_c(RGB16F, RGB, HalfFloat) +_c(RGBA16F, RGBA, HalfFloat) +#ifndef MAGNUM_TARGET_GLES2 +_c(R32F, Red, Float) +_c(RG32F, RG, Float) +#else +_c(R32F, Luminance, Float) +_c(RG32F, LuminanceAlpha, Float) +#endif +_c(RGB32F, RGB, Float) +_c(RGBA32F, RGBA, Float) +#endif diff --git a/src/Magnum/GL/PixelFormat.cpp b/src/Magnum/GL/PixelFormat.cpp index 961197947..1a91a2a55 100644 --- a/src/Magnum/GL/PixelFormat.cpp +++ b/src/Magnum/GL/PixelFormat.cpp @@ -26,11 +26,85 @@ #include "PixelFormat.h" #include +#include #include +#include "Magnum/PixelFormat.h" + namespace Magnum { namespace GL { -std::size_t pixelSize(const PixelFormat format, const PixelType type) { +namespace { + +#ifndef DOXYGEN_GENERATING_OUTPUT /* It gets *really* confused */ +constexpr struct { + PixelFormat format; + PixelType type; +} FormatMapping[] { + #define _c(input, format, type) {PixelFormat::format, PixelType::type}, + #define _s(input) {PixelFormat{}, PixelType{}}, + #include "Magnum/GL/Implementation/pixelFormatMapping.hpp" + #undef _s + #undef _c +}; +#endif + +} + +bool hasPixelFormat(const Magnum::PixelFormat format) { + if(isPixelFormatImplementationSpecific(format)) + return true; + + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + /* See GL/Test/PixelFormatTest.cpp for more information. Returning true + unconditionally here as unsupported enum values shouldn't even be + compiled. */ + if(UnsignedInt(format) > 0x1000) return true; + #endif + + CORRADE_ASSERT(UnsignedInt(format) < Containers::arraySize(FormatMapping), + "GL::hasPixelFormat(): invalid format" << format, {}); + return UnsignedInt(FormatMapping[UnsignedInt(format)].format); +} + +PixelFormat pixelFormat(const Magnum::PixelFormat format) { + if(isPixelFormatImplementationSpecific(format)) + return pixelFormatUnwrap(format); + + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + /* See GL/Test/PixelFormatTest.cpp for more information */ + if(UnsignedInt(format) > 0x1000) + return PixelFormat(UnsignedInt(format)); + #endif + + CORRADE_ASSERT(UnsignedInt(format) < Containers::arraySize(FormatMapping), + "GL::pixelFormat(): invalid format" << format, {}); + const PixelFormat out = FormatMapping[UnsignedInt(format)].format; + CORRADE_ASSERT(UnsignedInt(out), + "GL::pixelFormat(): format" << format << "is not supported on this target", {}); + return out; +} + +PixelType pixelType(const Magnum::PixelFormat format, const UnsignedInt extra) { + if(isPixelFormatImplementationSpecific(format) + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + /* See GL/Test/PixelFormatTest.cpp for more information */ + || UnsignedInt(format) > 0x1000 + #endif + ) { + CORRADE_ASSERT(extra, + "GL::pixelType(): format is implementation-specific, but no additional type specifier was passed", {}); + return PixelType(extra); + } + + CORRADE_ASSERT(UnsignedInt(format) < Containers::arraySize(FormatMapping), + "GL::pixelType(): invalid format" << format, {}); + const PixelType out = FormatMapping[UnsignedInt(format)].type; + CORRADE_ASSERT(UnsignedInt(out), + "GL::pixelType(): format" << format << "is not supported on this target", {}); + return out; +} + +UnsignedInt pixelSize(const PixelFormat format, const PixelType type) { std::size_t size = 0; switch(type) { case PixelType::UnsignedByte: @@ -149,7 +223,7 @@ std::size_t pixelSize(const PixelFormat format, const PixelType type) { /* Handled above */ case PixelFormat::DepthStencil: - CORRADE_ASSERT(false, "GL::pixelSize(): invalid GL::PixelType specified for depth/stencil GL::PixelFormat", 0); + CORRADE_ASSERT(false, "GL::pixelSize(): invalid" << type << "specified for" << format, 0); } CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ @@ -271,6 +345,54 @@ Debug& operator<<(Debug& debug, const PixelType value) { return debug << "GL::PixelType(" << Debug::nospace << reinterpret_cast(GLenum(value)) << Debug::nospace << ")"; } +namespace { + +#ifndef DOXYGEN_GENERATING_OUTPUT /* It gets *really* confused */ +constexpr CompressedPixelFormat CompressedFormatMapping[] { + #define _c(input, format) GL::CompressedPixelFormat::format, + #define _s(input) GL::CompressedPixelFormat{}, + #include "Magnum/GL/Implementation/compressedPixelFormatMapping.hpp" + #undef _s + #undef _c +}; +#endif + +} + +bool hasCompressedPixelFormat(const Magnum::CompressedPixelFormat format) { + if(isCompressedPixelFormatImplementationSpecific(format)) + return true; + + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + /* See GL/Test/PixelFormatTest.cpp for more information. Returning true + unconditionally here as unsupported enum values shouldn't even be + compiled. */ + if(UnsignedInt(format) > 0x1000) return true; + #endif + + CORRADE_ASSERT(UnsignedInt(format) < Containers::arraySize(CompressedFormatMapping), + "GL::hasCompressedPixelFormat(): invalid format" << format, {}); + return UnsignedInt(CompressedFormatMapping[UnsignedInt(format)]); +} + +CompressedPixelFormat compressedPixelFormat(const Magnum::CompressedPixelFormat format) { + if(isCompressedPixelFormatImplementationSpecific(format)) + return compressedPixelFormatUnwrap(format); + + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + /* See GL/Test/PixelFormatTest.cpp for more information */ + if(UnsignedInt(format) > 0x1000) + return CompressedPixelFormat(UnsignedInt(format)); + #endif + + CORRADE_ASSERT(UnsignedInt(format) < Containers::arraySize(CompressedFormatMapping), + "GL::compressedPixelFormat(): invalid format" << format, {}); + const CompressedPixelFormat out = CompressedFormatMapping[UnsignedInt(format)]; + CORRADE_ASSERT(UnsignedInt(out), + "GL::compressedPixelFormat(): format" << format << "is not supported on this target", {}); + return out; +} + Debug& operator<<(Debug& debug, const CompressedPixelFormat value) { switch(value) { /* LCOV_EXCL_START */ diff --git a/src/Magnum/GL/PixelFormat.h b/src/Magnum/GL/PixelFormat.h index 502ac16ac..ee7153a00 100644 --- a/src/Magnum/GL/PixelFormat.h +++ b/src/Magnum/GL/PixelFormat.h @@ -26,9 +26,11 @@ */ /** @file - * @brief Enum @ref Magnum::GL::PixelFormat, @ref Magnum::GL::PixelType, @ref Magnum::GL::CompressedPixelFormat, function @ref Magnum::GL::pixelSize() + * @brief Enum @ref Magnum::GL::PixelFormat, @ref Magnum::GL::PixelType, @ref Magnum::GL::CompressedPixelFormat, function @ref Magnum::GL::hasPixelFormat(), @ref Magnum::GL::pixelFormat(), @ref Magnum::GL::pixelType(), @ref Magnum::GL::pixelSize(), @ref Magnum::GL::hasCompressedPixelFormat(), @ref Magnum::GL::compressedPixelFormat() */ +#include + #include "Magnum/Magnum.h" #include "Magnum/GL/OpenGL.h" #include "Magnum/GL/visibility.h" @@ -50,7 +52,8 @@ In most cases you may want to use @ref PixelFormat::Red (for grayscale images), See documentation of these values for possible limitations when using OpenGL ES 2.0 or WebGL. -@see @ref Image, @ref ImageView, @ref BufferImage, @ref Trade::ImageData +@see @ref Magnum::PixelFormat, @ref pixelFormat(), @ref hasPixelFormat(), + @ref Image, @ref ImageView, @ref BufferImage, @ref Trade::ImageData @m_enum_values_as_keywords */ enum class PixelFormat: GLenum { @@ -333,7 +336,8 @@ In most cases you may want to use @ref PixelType::UnsignedByte along with See documentation of these values for possible limitations when using OpenGL ES 2.0 or WebGL. -@see @ref Image, @ref ImageView, @ref BufferImage, @ref Trade::ImageData +@see @ref Magnum::PixelFormat, @ref pixelType(), @ref hasPixelFormat(), + @ref Image, @ref ImageView, @ref BufferImage, @ref Trade::ImageData @m_enum_values_as_keywords */ enum class PixelType: GLenum { @@ -595,13 +599,94 @@ enum class PixelType: GLenum { #endif }; +/** +@brief Check availability of a generic pixel format + +Some OpenGL targets don't support all generic pixel formats (for example WebGL +1.0 and OpenGL ES 2.0 don't support most of single- and two-component or +integer formats). Returns @cpp false @ce if current target can't support such +format, @cpp true @ce otherwise. Moreover, returns @cpp true @ce also for all +formats that are @ref isPixelFormatImplementationSpecific(). The @p format +value is expected to be valid. + +@note Support of some formats depends on presence of a particular OpenGL + extension. Such check is outside of the scope of this function and you are + expected to verify extension availability before using such format. + +@see @ref pixelFormat(), @ref pixelType() +*/ +MAGNUM_GL_EXPORT bool hasPixelFormat(Magnum::PixelFormat format); + +/** +@brief Convert a generic pixel format to OpenGL pixel format + +In case @ref isPixelFormatImplementationSpecific() returns @cpp false @ce for +@p format, maps it to a corresponding OpenGL pixel format. In case +@ref isPixelFormatImplementationSpecific() returns @cpp true @ce, assumes +@p format stores OpenGL-specific pixel format and returns +@ref pixelFormatUnwrap() cast to @ref GL::PixelFormat. + +Not all generic pixel formats may be available on all targets and this function +expects that given format is available on the target. Use @ref hasPixelFormat() +to query availability of given format. + +@note On OpenGL ES 2.0 and WebGL 1.0, one- and two-channel texture formats are + always translated to @ref PixelFormat::Luminance and + @ref PixelFormat::LuminanceAlpha, independently on the + @extension{EXT,texture_rg} being present or not. If you wish to use @ref PixelFormat::Red and @ref PixelFormat::RG instead, specify the GL-specific + pixel format directly instead of using the generic enum. + +@see @ref pixelType() +*/ +MAGNUM_GL_EXPORT PixelFormat pixelFormat(Magnum::PixelFormat format); + +/** +@brief Convert a generic pixel type to OpenGL pixel type + +In case @ref isPixelFormatImplementationSpecific() returns @cpp false @ce for +@p format, maps it to a corresponding OpenGL pixel type. In case +@ref isPixelFormatImplementationSpecific() returns @cpp true @ce, assumes +@p extra stores OpenGL-specific pixel type and returns it cast to +@ref GL::PixelType. + +Not all generic pixel formats may be available on all targets and this function +expects that given format is available on the target. Use @ref hasPixelFormat() +to query availability of given format. +@see @ref pixelFormat() +*/ +MAGNUM_GL_EXPORT PixelType pixelType(Magnum::PixelFormat format, UnsignedInt extra = 0); + +/** +@brief Pixel size for given format/type combination (in bytes) + +@see @ref Magnum::pixelSize(), @ref PixelStorage::dataProperties() +*/ +MAGNUM_GL_EXPORT UnsignedInt pixelSize(PixelFormat format, PixelType type); + +#ifdef MAGNUM_BUILD_DEPRECATED +/** @brief @copybrief pixelSize(PixelFormat, PixelType) + * @deprecated Use either @ref GL::PixelFormat together with + * @ref GL::PixelType or just @ref Magnum::PixelFormat instead + */ +inline CORRADE_DEPRECATED("use either GL::PixelFormat together with GL::PixelType or just Magnum::PixelFormat instead") UnsignedInt pixelSize(Magnum::PixelFormat format, PixelType type) { + return pixelSize(PixelFormat(UnsignedInt(format)), type); +} +#endif + +/** @debugoperatorenum{PixelFormat} */ +MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, PixelFormat value); + +/** @debugoperatorenum{PixelType} */ +MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, PixelType value); + /** @brief Format of compressed pixel data Equivalent to `Compressed*` values of @ref TextureFormat enum. -@see @ref CompressedImage, @ref CompressedImageView, @ref CompressedBufferImage, - @ref Trade::ImageData +@see @ref Magnum::CompressedPixelFormat, @ref compressedPixelFormat(), + @ref hasCompressedPixelFormat(), @ref CompressedImage, + @ref CompressedImageView, @ref CompressedBufferImage, @ref Trade::ImageData @m_enum_values_as_keywords */ enum class CompressedPixelFormat: GLenum { @@ -1235,17 +1320,38 @@ enum class CompressedPixelFormat: GLenum { }; /** -@brief Pixel size for given format/type combination (in bytes) +@brief Check availability of generic compressed pixel format -@see @ref PixelStorage::dataProperties() -*/ -MAGNUM_GL_EXPORT std::size_t pixelSize(PixelFormat format, PixelType type); +Some OpenGL targets don't support all generic pixel formats (for example ASTC +compression might not be available on WebGL 1.0). Returns @cpp false @ce if +current target can't support such format, @cpp true @ce otherwise. Moreover, +returns @cpp true @ce also for all formats that are +@ref isCompressedPixelFormatImplementationSpecific().The @p format value is +expected to be valid. -/** @debugoperatorenum{PixelFormat} */ -MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, PixelFormat value); +@note Support of some formats depends on presence of a particular OpenGL + extension. Such check is outside of the scope of this function and you are + expected to verify extension availability before using such format. -/** @debugoperatorenum{PixelType} */ -MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, PixelType value); +@see @ref pixelFormat(), @ref pixelType() +*/ +MAGNUM_GL_EXPORT bool hasCompressedPixelFormat(Magnum::CompressedPixelFormat format); + +/** +@brief Convert generic compressed pixel format to OpenGL compressed pixel format + +In case @ref isCompressedPixelFormatImplementationSpecific() returns +@cpp false @ce for @p format, maps it to a corresponding OpenGL pixel format. +In case @ref isCompressedPixelFormatImplementationSpecific() returns +@cpp true @ce, assumes @p format stores OpenGL-specific pixel format and +returns @ref compressedPixelFormatUnwrap() cast to @ref GL::CompressedPixelFormat. + +Not all generic pixel formats may be available on all targets and this function +expects that given format is available on the target. Use +@ref hasCompressedPixelFormat() to query availability of given format. +@see @ref pixelFormat() +*/ +MAGNUM_GL_EXPORT CompressedPixelFormat compressedPixelFormat(Magnum::CompressedPixelFormat format); /** @debugoperatorenum{CompressedPixelFormat} */ MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, CompressedPixelFormat value); @@ -1255,20 +1361,10 @@ MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, CompressedPixelFormat value); #ifdef MAGNUM_BUILD_DEPRECATED /* Note: needs to be prefixed with Magnum:: otherwise Doxygen can't find it */ -/** @brief @copybrief GL::PixelFormat - * @deprecated Use @ref GL::PixelFormat instead. - */ -typedef CORRADE_DEPRECATED("use GL::PixelFormat instead") Magnum::GL::PixelFormat PixelFormat; - /** @brief @copybrief GL::PixelType * @deprecated Use @ref GL::PixelType instead. */ typedef CORRADE_DEPRECATED("use GL::PixelType instead") Magnum::GL::PixelType PixelType; - -/** @brief @copybrief GL::CompressedPixelFormat - * @deprecated Use @ref GL::CompressedPixelFormat instead. - */ -typedef CORRADE_DEPRECATED("use GL::CompressedPixelFormat instead") Magnum::GL::CompressedPixelFormat CompressedPixelFormat; #endif } diff --git a/src/Magnum/GL/Test/BufferImageGLTest.cpp b/src/Magnum/GL/Test/BufferImageGLTest.cpp index 67fa7c0c2..3304f1f43 100644 --- a/src/Magnum/GL/Test/BufferImageGLTest.cpp +++ b/src/Magnum/GL/Test/BufferImageGLTest.cpp @@ -80,7 +80,7 @@ void BufferImageGLTest::construct() { MAGNUM_VERIFY_NO_ERROR(); CORRADE_COMPARE(a.storage().alignment(), 1); - CORRADE_COMPARE(a.format(), PixelFormat::Red); + CORRADE_COMPARE(a.format(), GL::PixelFormat::Red); CORRADE_COMPARE(a.type(), PixelType::UnsignedByte); CORRADE_COMPARE(a.size(), Vector2i(1, 3)); @@ -109,7 +109,7 @@ void BufferImageGLTest::constructCompressed() { #ifndef MAGNUM_TARGET_GLES CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); #endif - CORRADE_COMPARE(a.format(), CompressedPixelFormat::RGBAS3tcDxt1); + CORRADE_COMPARE(a.format(), GL::CompressedPixelFormat::RGBAS3tcDxt1); CORRADE_COMPARE(a.size(), Vector2i(4, 4)); CORRADE_COMPARE(a.dataSize(), 8); @@ -138,7 +138,7 @@ void BufferImageGLTest::constructBuffer() { CORRADE_VERIFY(!buffer.id()); CORRADE_COMPARE(a.buffer().id(), id); CORRADE_COMPARE(a.storage().alignment(), 1); - CORRADE_COMPARE(a.format(), PixelFormat::Red); + CORRADE_COMPARE(a.format(), GL::PixelFormat::Red); CORRADE_COMPARE(a.type(), PixelType::UnsignedByte); CORRADE_COMPARE(a.size(), Vector2i(1, 3)); @@ -173,7 +173,7 @@ void BufferImageGLTest::constructBufferCompressed() { #endif CORRADE_VERIFY(!buffer.id()); CORRADE_COMPARE(a.buffer().id(), id); - CORRADE_COMPARE(a.format(), CompressedPixelFormat::RGBAS3tcDxt1); + CORRADE_COMPARE(a.format(), GL::CompressedPixelFormat::RGBAS3tcDxt1); CORRADE_COMPARE(a.size(), Vector2i(4, 4)); CORRADE_COMPARE(a.dataSize(), 8); @@ -208,7 +208,7 @@ void BufferImageGLTest::constructMove() { CORRADE_COMPARE(a.size(), Vector2i()); CORRADE_COMPARE(b.storage().alignment(), 4); - CORRADE_COMPARE(b.format(), PixelFormat::Red); + CORRADE_COMPARE(b.format(), GL::PixelFormat::Red); CORRADE_COMPARE(b.type(), PixelType::UnsignedByte); CORRADE_COMPARE(b.size(), Vector2i(4, 1)); CORRADE_COMPARE(b.buffer().id(), id); @@ -226,7 +226,7 @@ void BufferImageGLTest::constructMove() { CORRADE_COMPARE(b.size(), Vector2i(1, 2)); CORRADE_COMPARE(c.storage().alignment(), 4); - CORRADE_COMPARE(c.format(), PixelFormat::Red); + CORRADE_COMPARE(c.format(), GL::PixelFormat::Red); CORRADE_COMPARE(c.type(), PixelType::UnsignedByte); CORRADE_COMPARE(c.size(), Vector2i(4, 1)); CORRADE_COMPARE(c.buffer().id(), id); @@ -249,7 +249,7 @@ void BufferImageGLTest::constructMoveCompressed() { #ifndef MAGNUM_TARGET_GLES CORRADE_COMPARE(b.storage().compressedBlockSize(), Vector3i{0}); #endif - CORRADE_COMPARE(b.format(), CompressedPixelFormat::RGBAS3tcDxt1); + CORRADE_COMPARE(b.format(), GL::CompressedPixelFormat::RGBAS3tcDxt1); CORRADE_COMPARE(b.size(), Vector2i(4, 4)); CORRADE_COMPARE(b.dataSize(), 8); CORRADE_COMPARE(b.buffer().id(), id); @@ -273,7 +273,7 @@ void BufferImageGLTest::constructMoveCompressed() { #ifndef MAGNUM_TARGET_GLES CORRADE_COMPARE(c.storage().compressedBlockSize(), Vector3i{0}); #endif - CORRADE_COMPARE(c.format(), CompressedPixelFormat::RGBAS3tcDxt1); + CORRADE_COMPARE(c.format(), GL::CompressedPixelFormat::RGBAS3tcDxt1); CORRADE_COMPARE(c.size(), Vector2i(4, 4)); CORRADE_COMPARE(c.dataSize(), 8); CORRADE_COMPARE(c.buffer().id(), id); @@ -294,7 +294,7 @@ void BufferImageGLTest::setData() { MAGNUM_VERIFY_NO_ERROR(); CORRADE_COMPARE(a.storage().alignment(), 4); - CORRADE_COMPARE(a.format(), PixelFormat::RGBA); + CORRADE_COMPARE(a.format(), GL::PixelFormat::RGBA); CORRADE_COMPARE(a.type(), PixelType::UnsignedShort); CORRADE_COMPARE(a.size(), Vector2i(1, 2)); @@ -326,7 +326,7 @@ void BufferImageGLTest::setDataCompressed() { #ifndef MAGNUM_TARGET_GLES CORRADE_COMPARE(a.storage().compressedBlockSize(), Vector3i{4}); #endif - CORRADE_COMPARE(a.format(), CompressedPixelFormat::RGBAS3tcDxt3); + CORRADE_COMPARE(a.format(), GL::CompressedPixelFormat::RGBAS3tcDxt3); CORRADE_COMPARE(a.size(), Vector2i(8, 4)); CORRADE_COMPARE(a.dataSize(), 16); diff --git a/src/Magnum/GL/Test/CMakeLists.txt b/src/Magnum/GL/Test/CMakeLists.txt index b32e23547..817dbeef4 100644 --- a/src/Magnum/GL/Test/CMakeLists.txt +++ b/src/Magnum/GL/Test/CMakeLists.txt @@ -26,7 +26,6 @@ corrade_add_test(GLAttributeTest AttributeTest.cpp LIBRARIES MagnumGL) corrade_add_test(GLAbstractShaderProgramTest AbstractShaderProgramTest.cpp LIBRARIES MagnumGL) corrade_add_test(GLBufferTest BufferTest.cpp LIBRARIES MagnumGL) -corrade_add_test(GLFormatTest FormatTest.cpp LIBRARIES MagnumGL) corrade_add_test(GLContextTest ContextTest.cpp LIBRARIES MagnumGL) corrade_add_test(GLCubeMapTextureTest CubeMapTextureTest.cpp LIBRARIES MagnumGL) corrade_add_test(GLDefaultFramebufferTest DefaultFramebufferTest.cpp LIBRARIES MagnumGL) @@ -34,6 +33,7 @@ corrade_add_test(GLFramebufferTest FramebufferTest.cpp LIBRARIES MagnumGL) corrade_add_test(GLImageTest ../../Test/ImageTest.cpp LIBRARIES MagnumGL) # temporary corrade_add_test(GLImageViewTest ../../Test/ImageViewTest.cpp LIBRARIES MagnumGL) # temporary corrade_add_test(GLMeshTest MeshTest.cpp LIBRARIES MagnumGL) +corrade_add_test(GLPixelFormatTest PixelFormatTest.cpp LIBRARIES MagnumGLTestLib) corrade_add_test(GLPixelStorageTest ../../Test/PixelStorageTest.cpp LIBRARIES MagnumGL) # temporary corrade_add_test(GLRendererTest RendererTest.cpp LIBRARIES MagnumGL) corrade_add_test(GLRenderbufferTest RenderbufferTest.cpp LIBRARIES MagnumGL) @@ -46,7 +46,6 @@ set_target_properties( GLAttributeTest GLAbstractShaderProgramTest GLBufferTest - GLFormatTest GLContextTest GLCubeMapTextureTest GLDefaultFramebufferTest @@ -55,6 +54,7 @@ set_target_properties( GLImageViewTest GLMeshTest GLPixelStorageTest + GLPixelFormatTest GLRendererTest GLRenderbufferTest GLSamplerTest diff --git a/src/Magnum/GL/Test/FormatTest.cpp b/src/Magnum/GL/Test/FormatTest.cpp deleted file mode 100644 index 1db478ab9..000000000 --- a/src/Magnum/GL/Test/FormatTest.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 - Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -#include -#include - -#include "Magnum/PixelFormat.h" - -namespace Magnum { namespace Test { - -struct FormatTest: TestSuite::Tester { - explicit FormatTest(); - - void debugPixelFormat(); - void debugPixelType(); - void debugCompressedPixelFormat(); -}; - -FormatTest::FormatTest() { - addTests({&FormatTest::debugPixelFormat, - &FormatTest::debugPixelType, - &FormatTest::debugCompressedPixelFormat}); -} - -void FormatTest::debugPixelFormat() { - std::ostringstream out; - - Debug(&out) << PixelFormat::RGBA << PixelFormat(0xdead); - CORRADE_COMPARE(out.str(), "GL::PixelFormat::RGBA GL::PixelFormat(0xdead)\n"); -} - -void FormatTest::debugPixelType() { - std::ostringstream out; - - Debug(&out) << PixelType::UnsignedByte << PixelType(0xdead); - CORRADE_COMPARE(out.str(), "GL::PixelType::UnsignedByte GL::PixelType(0xdead)\n"); -} - -void FormatTest::debugCompressedPixelFormat() { - #ifdef MAGNUM_TARGET_GLES - CORRADE_SKIP("No enum value available"); - #else - std::ostringstream out; - - Debug(&out) << CompressedPixelFormat::RGBBptcUnsignedFloat << CompressedPixelFormat(0xdead); - CORRADE_COMPARE(out.str(), "GL::CompressedPixelFormat::RGBBptcUnsignedFloat GL::CompressedPixelFormat(0xdead)\n"); - #endif -} - -}} - -CORRADE_TEST_MAIN(Magnum::Test::FormatTest) diff --git a/src/Magnum/GL/Test/PixelFormatTest.cpp b/src/Magnum/GL/Test/PixelFormatTest.cpp new file mode 100644 index 000000000..d18db102e --- /dev/null +++ b/src/Magnum/GL/Test/PixelFormatTest.cpp @@ -0,0 +1,548 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include + +#include "Magnum/PixelFormat.h" +#include "Magnum/GL/PixelFormat.h" + +#if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) +#include "Magnum/PixelStorage.h" +#endif + +namespace Magnum { namespace GL { namespace Test { + +struct PixelFormatTest: TestSuite::Tester { + explicit PixelFormatTest(); + + void mapFormatType(); + void mapFormatImplementationSpecific(); + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + void mapFormatDeprecated(); + #endif + void mapFormatUnsupported(); + void mapFormatInvalid(); + void mapTypeImplementationSpecific(); + void mapTypeImplementationSpecificZero(); + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + void mapTypeDeprecated(); + #endif + void mapTypeUnsupported(); + void mapTypeInvalid(); + + void size(); + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + void sizeDataPropertiesDeprecated(); + #endif + void sizeInvalid(); + + void mapCompressedFormat(); + void mapCompressedFormatImplementationSpecific(); + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + void mapCompressedFormatDeprecated(); + #endif + void mapCompressedFormatUnsupported(); + void mapCompressedFormatInvalid(); + + void debugPixelFormat(); + void debugPixelType(); + + void debugCompressedPixelFormat(); +}; + +PixelFormatTest::PixelFormatTest() { + addTests({&PixelFormatTest::mapFormatType, + &PixelFormatTest::mapFormatImplementationSpecific, + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + &PixelFormatTest::mapFormatDeprecated, + #endif + &PixelFormatTest::mapFormatUnsupported, + &PixelFormatTest::mapFormatInvalid, + &PixelFormatTest::mapTypeImplementationSpecific, + &PixelFormatTest::mapTypeImplementationSpecificZero, + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + &PixelFormatTest::mapTypeDeprecated, + #endif + &PixelFormatTest::mapTypeUnsupported, + &PixelFormatTest::mapTypeInvalid, + + &PixelFormatTest::size, + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + &PixelFormatTest::sizeDataPropertiesDeprecated, + #endif + &PixelFormatTest::sizeInvalid, + + &PixelFormatTest::mapCompressedFormat, + &PixelFormatTest::mapCompressedFormatImplementationSpecific, + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + &PixelFormatTest::mapCompressedFormatDeprecated, + #endif + &PixelFormatTest::mapCompressedFormatUnsupported, + &PixelFormatTest::mapCompressedFormatInvalid, + + &PixelFormatTest::debugPixelFormat, + &PixelFormatTest::debugPixelType, + &PixelFormatTest::debugCompressedPixelFormat}); +} + +void PixelFormatTest::mapFormatType() { + /* Touchstone verification */ + CORRADE_VERIFY(hasPixelFormat(Magnum::PixelFormat::RGBA8Unorm)); + CORRADE_COMPARE(pixelFormat(Magnum::PixelFormat::RGBA8Unorm), PixelFormat::RGBA); + CORRADE_COMPARE(pixelType(Magnum::PixelFormat::RGBA8Unorm), PixelType::UnsignedByte); + + /* This goes through the first 16 bits, which should be enough. Going + through 32 bits takes 8 seconds, too much. */ + UnsignedInt firstUnhandled = 0xffff; + UnsignedInt nextHandled = 0; + for(UnsignedInt i = 0; i <= 0xffff; ++i) { + const auto format = Magnum::PixelFormat(i); + /* Each case verifies: + - that the cases are ordered by number (so insertion here is done in + proper place) + - that there was no gap (unhandled value inside the range) + - that a particular pixel format maps to a particular GL format + - that a particular pixel type maps to a particular GL type */ + switch(format) { + #define _c(format, expectedFormat, expectedType) \ + case Magnum::PixelFormat::format: \ + CORRADE_COMPARE(nextHandled, i); \ + CORRADE_COMPARE(firstUnhandled, 0xffff); \ + CORRADE_VERIFY(hasPixelFormat(Magnum::PixelFormat::format)); \ + CORRADE_COMPARE(pixelFormat(Magnum::PixelFormat::format), Magnum::GL::PixelFormat::expectedFormat); \ + CORRADE_COMPARE(pixelType(Magnum::PixelFormat::format), Magnum::GL::PixelType::expectedType); \ + ++nextHandled; \ + continue; + #define _s(format) \ + case Magnum::PixelFormat::format: \ + CORRADE_COMPARE(nextHandled, i); \ + CORRADE_COMPARE(firstUnhandled, 0xffff); \ + CORRADE_VERIFY(!hasPixelFormat(Magnum::PixelFormat::format)); \ + pixelFormat(Magnum::PixelFormat::format); \ + pixelType(Magnum::PixelFormat::format); \ + ++nextHandled; \ + continue; + #include "Magnum/GL/Implementation/pixelFormatMapping.hpp" + #undef _s + #undef _c + + /* Here to silence unhandled value warnings and to verify that all + GL-specific formats are larger than a particular value. This + value is used in pixelFormat() and pixelType() to detect + deprecated GL-specific values and convert them properly. */ + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + #define _c(value) \ + case Magnum::PixelFormat::value: \ + CORRADE_VERIFY(UnsignedInt(Magnum::PixelFormat::value) >= 0x1000); \ + continue; + #ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" + #elif defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable: 4996) + #endif + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + _c(Red) + #endif + #ifndef MAGNUM_TARGET_GLES + _c(Green) + _c(Blue) + #endif + #ifdef MAGNUM_TARGET_GLES2 + _c(Luminance) + #endif + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + _c(RG) + #endif + #ifdef MAGNUM_TARGET_GLES2 + _c(LuminanceAlpha) + #endif + _c(RGB) + _c(RGBA) + #ifndef MAGNUM_TARGET_GLES + _c(BGR) + #endif + #ifndef MAGNUM_TARGET_WEBGL + _c(BGRA) + #endif + #ifdef MAGNUM_TARGET_GLES2 + _c(SRGB) + _c(SRGBAlpha) + #endif + #ifndef MAGNUM_TARGET_GLES2 + _c(RedInteger) + #ifndef MAGNUM_TARGET_GLES + _c(GreenInteger) + _c(BlueInteger) + #endif + _c(RGInteger) + _c(RGBInteger) + _c(RGBAInteger) + #ifndef MAGNUM_TARGET_GLES + _c(BGRInteger) + _c(BGRAInteger) + #endif + #endif + _c(DepthComponent) + #ifndef MAGNUM_TARGET_WEBGL + _c(StencilIndex) + #endif + _c(DepthStencil) + #undef _c + #ifdef __GNUC__ + #pragma GCC diagnostic pop + #elif defined(_MSC_VER) + #pragma warning(pop) + #endif + #endif + } + + /* Not handled by any value, remember -- we might either be at the end + of the enum range (which is okay) or some value might be unhandled + here */ + firstUnhandled = i; + } + + CORRADE_COMPARE(firstUnhandled, 0xffff); +} + +void PixelFormatTest::mapFormatImplementationSpecific() { + CORRADE_VERIFY(hasPixelFormat(Magnum::pixelFormatWrap(PixelFormat::RGBA))); + CORRADE_COMPARE(pixelFormat(Magnum::pixelFormatWrap(PixelFormat::RGBA)), + PixelFormat::RGBA); +} + +#if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) +void PixelFormatTest::mapFormatDeprecated() { + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE(pixelFormat(Magnum::PixelFormat::RGBA), + PixelFormat::RGBA); + CORRADE_IGNORE_DEPRECATED_POP +} +#endif + +void PixelFormatTest::mapFormatUnsupported() { + #ifndef MAGNUM_TARGET_GLES2 + CORRADE_SKIP("All pixel formats are supported on ES3+"); + #else + std::ostringstream out; + Error redirectError{&out}; + + pixelFormat(Magnum::PixelFormat::RGB16UI); + CORRADE_COMPARE(out.str(), "GL::pixelFormat(): format PixelFormat::RGB16UI is not supported on this target\n"); + #endif +} + +void PixelFormatTest::mapFormatInvalid() { + std::ostringstream out; + Error redirectError{&out}; + + hasPixelFormat(Magnum::PixelFormat(0x123)); + pixelFormat(Magnum::PixelFormat(0x123)); + CORRADE_COMPARE(out.str(), + "GL::hasPixelFormat(): invalid format PixelFormat(0x123)\n" + "GL::pixelFormat(): invalid format PixelFormat(0x123)\n"); +} + +void PixelFormatTest::mapTypeImplementationSpecific() { + CORRADE_COMPARE(pixelType(Magnum::pixelFormatWrap(PixelFormat::RGBA), GL_UNSIGNED_BYTE), + PixelType::UnsignedByte); +} + +void PixelFormatTest::mapTypeImplementationSpecificZero() { + std::ostringstream out; + Error redirectError{&out}; + + pixelType(Magnum::pixelFormatWrap(PixelFormat::RGBA)); + CORRADE_COMPARE(out.str(), "GL::pixelType(): format is implementation-specific, but no additional type specifier was passed\n"); +} + +#if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) +void PixelFormatTest::mapTypeDeprecated() { + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE(pixelType(Magnum::PixelFormat::RGBA, GL_UNSIGNED_BYTE), + PixelType::UnsignedByte); + CORRADE_IGNORE_DEPRECATED_POP +} +#endif + +void PixelFormatTest::mapTypeUnsupported() { + #ifndef MAGNUM_TARGET_GLES2 + CORRADE_SKIP("All pixel formats are supported on ES3+"); + #else + CORRADE_VERIFY(!hasPixelFormat(Magnum::PixelFormat::RGBA16UI)); + + std::ostringstream out; + Error redirectError{&out}; + pixelType(Magnum::PixelFormat::RGB16UI); + CORRADE_COMPARE(out.str(), "GL::pixelType(): format PixelFormat::RGB16UI is not supported on this target\n"); + #endif +} + +void PixelFormatTest::mapTypeInvalid() { + std::ostringstream out; + Error redirectError{&out}; + pixelType(Magnum::PixelFormat(0x123)); + CORRADE_COMPARE(out.str(), "GL::pixelType(): invalid format PixelFormat(0x123)\n"); +} + +void PixelFormatTest::size() { + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(pixelSize(PixelFormat::RGB, PixelType::UnsignedByte332), 1); + #endif + #ifndef MAGNUM_TARGET_WEBGL + CORRADE_COMPARE(pixelSize(PixelFormat::StencilIndex, PixelType::UnsignedByte), 1); + #endif + CORRADE_COMPARE(pixelSize(PixelFormat::DepthComponent, PixelType::UnsignedShort), 2); + CORRADE_COMPARE(pixelSize(PixelFormat::RGBA, PixelType::UnsignedShort4444), 2); + CORRADE_COMPARE(pixelSize(PixelFormat::DepthStencil, PixelType::UnsignedInt248), 4); + CORRADE_COMPARE(pixelSize(PixelFormat::RGBA, PixelType::UnsignedInt), 4*4); + #ifndef MAGNUM_TARGET_GLES2 + CORRADE_COMPARE(pixelSize(PixelFormat::DepthStencil, PixelType::Float32UnsignedInt248Rev), 8); + #endif +} + +#if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) +void PixelFormatTest::sizeDataPropertiesDeprecated() { + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE(PixelStorage::pixelSize(PixelFormat::RGBA, PixelType::UnsignedShort4444), 2); + CORRADE_IGNORE_DEPRECATED_POP + + PixelStorage storage; + storage.setAlignment(4) + .setRowLength(15) + .setSkip({3, 7, 0}); + + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE(storage.dataProperties(PixelFormat::RGBA, PixelType::UnsignedByte, Vector3i{1}), + (std::tuple, Math::Vector3, std::size_t>{{3*4, 7*15*4, 0}, {60, 1, 1}, 4})); + CORRADE_IGNORE_DEPRECATED_POP +} +#endif + +void PixelFormatTest::sizeInvalid() { + std::ostringstream out; + Error redirectError{&out}; + pixelSize(PixelFormat::DepthStencil, PixelType::Float); + CORRADE_COMPARE(out.str(), "GL::pixelSize(): invalid GL::PixelType::Float specified for GL::PixelFormat::DepthStencil\n"); +} + +void PixelFormatTest::mapCompressedFormat() { + /* Touchstone verification */ + CORRADE_VERIFY(hasCompressedPixelFormat(Magnum::CompressedPixelFormat::Bc1RGBAUnorm)); + CORRADE_COMPARE(compressedPixelFormat(Magnum::CompressedPixelFormat::Bc1RGBAUnorm), CompressedPixelFormat::RGBAS3tcDxt1); + + /* This goes through the first 16 bits, which should be enough. Going + through 32 bits takes 8 seconds, too much. */ + UnsignedInt firstUnhandled = 0xffff; + UnsignedInt nextHandled = 0; + for(UnsignedInt i = 0; i <= 0xffff; ++i) { + const auto format = Magnum::CompressedPixelFormat(i); + /* Each case verifies: + - that the cases are ordered by number (so insertion here is done in + proper place) + - that there was no gap (unhandled value inside the range) + - that a particular pixel format maps to a particular GL format + - that a particular pixel type maps to a particular GL type */ + switch(format) { + #define _c(format, expectedFormat) \ + case Magnum::CompressedPixelFormat::format: \ + CORRADE_COMPARE(nextHandled, i); \ + CORRADE_COMPARE(firstUnhandled, 0xffff); \ + CORRADE_VERIFY(hasCompressedPixelFormat(Magnum::CompressedPixelFormat::format)); \ + CORRADE_COMPARE(compressedPixelFormat(Magnum::CompressedPixelFormat::format), Magnum::GL::CompressedPixelFormat::expectedFormat); \ + ++nextHandled; \ + continue; + #define _s(format) \ + case Magnum::CompressedPixelFormat::format: \ + CORRADE_COMPARE(nextHandled, i); \ + CORRADE_COMPARE(firstUnhandled, 0xffff); \ + CORRADE_VERIFY(!hasCompressedPixelFormat(Magnum::CompressedPixelFormat::format)); \ + compressedPixelFormat(Magnum::CompressedPixelFormat::format); \ + ++nextHandled; \ + continue; + #include "Magnum/GL/Implementation/compressedPixelFormatMapping.hpp" + #undef _s + #undef _c + + /* Here to silence unhandled value warnings and to verify that all + GL-specific formats are larger than a particular value. This + value is used in compressedPixelFormat() to detect deprecated + GL-specific values and convert them properly. */ + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + #define _c(value) \ + case Magnum::CompressedPixelFormat::value: \ + CORRADE_VERIFY(UnsignedInt(Magnum::CompressedPixelFormat::value) >= 0x1000); \ + continue; + #ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" + #elif defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable: 4996) + #endif + #ifndef MAGNUM_TARGET_GLES + _c(Red) + _c(RG) + _c(RGB) + _c(RGBA) + _c(RedRgtc1) + _c(RGRgtc2) + _c(SignedRedRgtc1) + _c(SignedRGRgtc2) + _c(RGBBptcUnsignedFloat) + _c(RGBBptcSignedFloat) + _c(RGBABptcUnorm) + _c(SRGBAlphaBptcUnorm) + #endif + #ifndef MAGNUM_TARGET_GLES2 + _c(RGB8Etc2) + _c(SRGB8Etc2) + _c(RGB8PunchthroughAlpha1Etc2) + _c(SRGB8PunchthroughAlpha1Etc2) + _c(RGBA8Etc2Eac) + _c(SRGB8Alpha8Etc2Eac) + _c(R11Eac) + _c(SignedR11Eac) + _c(RG11Eac) + _c(SignedRG11Eac) + #endif + _c(RGBS3tcDxt1) + _c(RGBAS3tcDxt1) + _c(RGBAS3tcDxt3) + _c(RGBAS3tcDxt5) + #ifndef MAGNUM_TARGET_WEBGL + _c(RGBAAstc4x4) + _c(SRGB8Alpha8Astc4x4) + _c(RGBAAstc5x4) + _c(SRGB8Alpha8Astc5x4) + _c(RGBAAstc5x5) + _c(SRGB8Alpha8Astc5x5) + _c(RGBAAstc6x5) + _c(SRGB8Alpha8Astc6x5) + _c(RGBAAstc6x6) + _c(SRGB8Alpha8Astc6x6) + _c(RGBAAstc8x5) + _c(SRGB8Alpha8Astc8x5) + _c(RGBAAstc8x6) + _c(SRGB8Alpha8Astc8x6) + _c(RGBAAstc8x8) + _c(SRGB8Alpha8Astc8x8) + _c(RGBAAstc10x5) + _c(SRGB8Alpha8Astc10x5) + _c(RGBAAstc10x6) + _c(SRGB8Alpha8Astc10x6) + _c(RGBAAstc10x8) + _c(SRGB8Alpha8Astc10x8) + _c(RGBAAstc10x10) + _c(SRGB8Alpha8Astc10x10) + _c(RGBAAstc12x10) + _c(SRGB8Alpha8Astc12x10) + _c(RGBAAstc12x12) + _c(SRGB8Alpha8Astc12x12) + #endif + #undef _c + #ifdef __GNUC__ + #pragma GCC diagnostic pop + #elif defined(_MSC_VER) + #pragma warning(pop) + #endif + #endif + } + + /* Not handled by any value, remember -- we might either be at the end + of the enum range (which is okay) or some value might be unhandled + here */ + firstUnhandled = i; + } + + CORRADE_COMPARE(firstUnhandled, 0xffff); +} + +void PixelFormatTest::mapCompressedFormatImplementationSpecific() { + CORRADE_VERIFY(hasCompressedPixelFormat(Magnum::compressedPixelFormatWrap(CompressedPixelFormat::RGBAS3tcDxt1))); + CORRADE_COMPARE(compressedPixelFormat(Magnum::compressedPixelFormatWrap(CompressedPixelFormat::RGBAS3tcDxt1)), + CompressedPixelFormat::RGBAS3tcDxt1); +} + +#if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) +void PixelFormatTest::mapCompressedFormatDeprecated() { + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE(compressedPixelFormat(Magnum::CompressedPixelFormat::RGBAS3tcDxt1), + CompressedPixelFormat::RGBAS3tcDxt1); + CORRADE_IGNORE_DEPRECATED_POP +} +#endif + +void PixelFormatTest::mapCompressedFormatUnsupported() { + #if 1 + CORRADE_SKIP("All compressed pixel formats are currently supported everywhere"); + #else + CORRADE_VERIFY(!hasCompressedPixelFormat(Magnum::CompressedPixelFormat::Bc1RGBAUnorm)); + + std::ostringstream out; + Error redirectError{&out}; + compressedPixelFormat(Magnum::CompressedPixelFormat::Bc1RGBAUnorm); + CORRADE_COMPARE(out.str(), "GL::compressedPixelFormat(): format CompressedPixelFormat::Bc1RGBAUnorm is not supported on this target\n"); + #endif +} + +void PixelFormatTest::mapCompressedFormatInvalid() { + std::ostringstream out; + Error redirectError{&out}; + + hasCompressedPixelFormat(Magnum::CompressedPixelFormat(0x123)); + compressedPixelFormat(Magnum::CompressedPixelFormat(0x123)); + CORRADE_COMPARE(out.str(), + "GL::hasCompressedPixelFormat(): invalid format CompressedPixelFormat(0x123)\n" + "GL::compressedPixelFormat(): invalid format CompressedPixelFormat(0x123)\n"); +} + +void PixelFormatTest::debugPixelFormat() { + std::ostringstream out; + + Debug(&out) << PixelFormat::RGBA << PixelFormat(0xdead); + CORRADE_COMPARE(out.str(), "GL::PixelFormat::RGBA GL::PixelFormat(0xdead)\n"); +} + +void PixelFormatTest::debugPixelType() { + std::ostringstream out; + + Debug(&out) << PixelType::UnsignedByte << PixelType(0xdead); + CORRADE_COMPARE(out.str(), "GL::PixelType::UnsignedByte GL::PixelType(0xdead)\n"); +} + +void PixelFormatTest::debugCompressedPixelFormat() { + std::ostringstream out; + + Debug{&out} << CompressedPixelFormat::RGBS3tcDxt1 << CompressedPixelFormat(0xdead); + CORRADE_COMPARE(out.str(), "GL::CompressedPixelFormat::RGBS3tcDxt1 GL::CompressedPixelFormat(0xdead)\n"); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::GL::Test::PixelFormatTest) diff --git a/src/Magnum/GL/visibility.h b/src/Magnum/GL/visibility.h index 7fe402a8e..d9530b09b 100644 --- a/src/Magnum/GL/visibility.h +++ b/src/Magnum/GL/visibility.h @@ -31,7 +31,7 @@ #ifndef DOXYGEN_GENERATING_OUTPUT #ifndef MAGNUM_BUILD_STATIC - #ifdef MagnumGL_EXPORTS + #if defined(MagnumGL_EXPORTS) || defined(MagnumGLObjects_EXPORTS) #define MAGNUM_GL_EXPORT CORRADE_VISIBILITY_EXPORT #else #define MAGNUM_GL_EXPORT CORRADE_VISIBILITY_IMPORT diff --git a/src/Magnum/Image.cpp b/src/Magnum/Image.cpp index f72bf4490..70ff21b93 100644 --- a/src/Magnum/Image.cpp +++ b/src/Magnum/Image.cpp @@ -25,20 +25,38 @@ #include "Image.h" +#include "Magnum/PixelFormat.h" + namespace Magnum { -template Image::Image(PixelStorage storage, GL::PixelFormat format, GL::PixelType type, const VectorTypeFor& size, Containers::Array&& data) noexcept: _storage{storage}, _format{format}, _type{type}, _size{size}, _data{std::move(data)} { +template Image::Image(const PixelStorage storage, const PixelFormat format, const VectorTypeFor& size, Containers::Array&& data) noexcept: Image{storage, format, {}, Magnum::pixelSize(format), size, std::move(data)} {} + +template Image::Image(const PixelStorage storage, const UnsignedInt format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data) noexcept: Image{storage, pixelFormatWrap(format), formatExtra, pixelSize, size, std::move(data)} {} + +template Image::Image(const PixelStorage storage, const PixelFormat format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data) noexcept: _storage{storage}, _format{format}, _formatExtra{formatExtra}, _pixelSize{pixelSize}, _size{size}, _data{std::move(data)} { CORRADE_ASSERT(Implementation::imageDataSize(*this) <= _data.size(), "Image::Image(): bad image data size, got" << _data.size() << "but expected at least" << Implementation::imageDataSize(*this), ); } +template Image::Image(const PixelStorage storage, const PixelFormat format) noexcept: Image{storage, format, {}, Magnum::pixelSize(format)} {} + +template Image::Image(const PixelStorage storage, const UnsignedInt format, const UnsignedInt formatExtra, const UnsignedInt pixelSize) noexcept: Image{storage, pixelFormatWrap(format), formatExtra, pixelSize} {} + +template Image::Image(const PixelStorage storage, const PixelFormat format, const UnsignedInt formatExtra, const UnsignedInt pixelSize) noexcept: _storage{storage}, _format{format}, _formatExtra{formatExtra}, _pixelSize{pixelSize}, _data{} {} + +template CompressedImage::CompressedImage(const CompressedPixelStorage storage, const CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data) noexcept: _storage{storage}, _format{format}, _size{size}, _data{std::move(data)} {} + +template CompressedImage::CompressedImage(const CompressedPixelStorage storage, const UnsignedInt format, const VectorTypeFor& size, Containers::Array&& data) noexcept: CompressedImage{storage, compressedPixelFormatWrap(format), size, std::move(data)} {} + +template CompressedImage::CompressedImage(const CompressedPixelStorage storage) noexcept: _storage{storage}, _format{} {} + #ifndef DOXYGEN_GENERATING_OUTPUT -template class MAGNUM_GL_EXPORT Image<1>; -template class MAGNUM_GL_EXPORT Image<2>; -template class MAGNUM_GL_EXPORT Image<3>; +template class MAGNUM_EXPORT Image<1>; +template class MAGNUM_EXPORT Image<2>; +template class MAGNUM_EXPORT Image<3>; -template class MAGNUM_GL_EXPORT CompressedImage<1>; -template class MAGNUM_GL_EXPORT CompressedImage<2>; -template class MAGNUM_GL_EXPORT CompressedImage<3>; +template class MAGNUM_EXPORT CompressedImage<1>; +template class MAGNUM_EXPORT CompressedImage<2>; +template class MAGNUM_EXPORT CompressedImage<3>; #endif } diff --git a/src/Magnum/Image.h b/src/Magnum/Image.h index 1f22815df..4d776d5c5 100644 --- a/src/Magnum/Image.h +++ b/src/Magnum/Image.h @@ -38,8 +38,37 @@ namespace Magnum { /** @brief Image -Stores image data on client memory. Interchangeable with @ref ImageView, -@ref BufferImage or @ref Trade::ImageData. +Stores multi-dimensional image data together with layout and pixel format +description. See @ref ImageView for a non-owning alternative. + +This class can act as a drop-in replacement for @ref ImageView and +@ref Trade::ImageData APIs and is implicitly convertible to @ref ImageView. +Particular graphics API wrappers provide additional image classes, for example +@ref GL::BufferImage. See also @ref CompressedImage for equivalent +functionality targeted on compressed image formats. + +@section Image-usage Basic usage + +The image takes ownership of a passed @ref Corrade::Containers::Array, together +with storing image size and one of the generic @ref PixelFormat values: + +@snippet Magnum.cpp Image-usage + +On construction, the image internally calculates pixel size corresponding to +given pixel format using @ref pixelSize(). This value is needed to check that +the passed data array is large enough and is also required by most image +manipulation operations. + +It's also possible to create just an image placeholder, storing only the image +properties without data or size. That is useful for example to specify desired +format of image queries in graphics APIs: + +@snippet Magnum.cpp Image-usage-query + +As with @ref ImageView, this class supports extra storage parameters and +implementation-specific pixel format specification. See the @ref ImageView +documentation for more information. + @see @ref Image1D, @ref Image2D, @ref Image3D, @ref CompressedImage */ template class Image { @@ -52,39 +81,185 @@ template class Image { * @brief Constructor * @param storage Storage of pixel data * @param format Format of pixel data - * @param type Data type of pixel data * @param size Image size * @param data Image data * - * The data are expected to be of proper size for given @p storage + * The @p data array is expected to be of proper size for given + * parameters. + */ + explicit Image(PixelStorage storage, PixelFormat format, const VectorTypeFor& size, Containers::Array&& data) noexcept; + + /** + * @brief Constructor + * @param format Format of pixel data + * @param size Image size + * @param data Image data + * + * Equivalent to calling @ref Image(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::Array&&) + * with default-constructed @ref PixelStorage. + */ + explicit Image(PixelFormat format, const VectorTypeFor& size, Containers::Array&& data) noexcept: Image{{}, format, size, std::move(data)} {} + + /** + * @brief Construct an image placeholder + * @param storage Storage of pixel data + * @param format Format of pixel data + * + * Size is set to zero and data pointer to @cpp nullptr @ce. Move over + * a non-empty instance to make it useful. + */ + /*implicit*/ Image(PixelStorage storage, PixelFormat format) noexcept; + + /** + * @brief Construct an image placeholder + * @param format Format of pixel data + * + * Equivalent to calling @ref Image(PixelStorage, PixelFormat) + * with default-constructed @ref PixelStorage. + */ + /*implicit*/ Image(PixelFormat format) noexcept: Image{{}, format} {} + + /** + * @brief Construct an image with implementation-specific pixel format + * @param storage Storage of pixel data + * @param format Format of pixel data + * @param formatExtra Additional pixel format specifier + * @param pixelSize Size of a pixel in given format + * @param size Image size + * @param data Image data + * + * Unlike with @ref Image(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::Array&&), + * where pixel size is calculated automatically using + * @ref pixelSize(PixelFormat), this allows you to specify an + * implementation-specific pixel format and pixel size directly. Uses + * @ref pixelFormatWrap() internally to wrap @p format in + * @ref PixelFormat. + * + * The @p data array is expected to be of proper size for given * parameters. */ - explicit Image(PixelStorage storage, GL::PixelFormat format, GL::PixelType type, const VectorTypeFor& size, Containers::Array&& data) noexcept; + explicit Image(PixelStorage storage, UnsignedInt format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data) noexcept; /** @overload - * Similar to the above, but uses default @ref PixelStorage parameters. + * + * Equivalent to the above for @p format already wrapped with + * @ref pixelFormatWrap(). */ - explicit Image(GL::PixelFormat format, GL::PixelType type, const VectorTypeFor& size, Containers::Array&& data) noexcept: Image{{}, format, type, size, std::move(data)} {} + explicit Image(PixelStorage storage, PixelFormat format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data) noexcept; /** - * @brief Constructor + * @brief Construct an image placeholder with implementation-specific pixel format * @param storage Storage of pixel data * @param format Format of pixel data - * @param type Data type of pixel data + * @param formatExtra Additional pixel format specifier + * @param pixelSize Size of a pixel in given format * - * Dimensions are set to zero and data pointer to @cpp nullptr @ce, - * call @ref setData() to fill the image with data or use - * @ref Texture::image() "*Texture::image()"/ - * @ref Texture::subImage() "*Texture::subImage()"/ - * @ref AbstractFramebuffer::read() "*Framebuffer::read()" to fill the - * image with data using @p storage settings. + * Unlike with @ref Image(PixelStorage, PixelFormat), where pixel size + * is calculated automatically using @ref pixelSize(PixelFormat), this + * allows you to specify an implementation-specific pixel format and + * pixel size directly. Uses @ref pixelFormatWrap() internally to + * wrap @p format in @ref PixelFormat. */ - /*implicit*/ Image(PixelStorage storage, GL::PixelFormat format, GL::PixelType type) noexcept: _storage{storage}, _format{format}, _type{type}, _data{} {} + explicit Image(PixelStorage storage, UnsignedInt format, UnsignedInt formatExtra, UnsignedInt pixelSize) noexcept; /** @overload - * Similar to the above, but uses default @ref PixelStorage parameters. + * + * Equivalent to the above for @p format already wrapped with + * @ref pixelFormatWrap(). + */ + explicit Image(PixelStorage storage, PixelFormat format, UnsignedInt formatExtra, UnsignedInt pixelSize) noexcept; + + /** + * @brief Construct an image with implementation-specific pixel format + * @param storage Storage of pixel data + * @param format Format of pixel data + * @param formatExtra Additional pixel format specifier + * @param size Image size + * @param data Image data + * + * Uses ADL to find a corresponding @cpp pixelSize(T, U) @ce overload, + * then calls @ref Image(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::Array&&) + * with calculated pixel size. + */ + template explicit Image(PixelStorage storage, T format, U formatExtra, const VectorTypeFor& size, Containers::Array&& data) noexcept; + + /** + * @brief Construct an image with implementation-specific pixel format + * @param storage Storage of pixel data + * @param format Format of pixel data + * @param size Image size + * @param data Image data + * + * Uses ADL to find a corresponding @cpp pixelSize(T) @ce overload, + * then calls @ref Image(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::Array&&) + * with calculated pixel size and @p formatExtra set to @cpp 0 @ce. + */ + template explicit Image(PixelStorage storage, T format, const VectorTypeFor& size, Containers::Array&& data) noexcept; + + /** + * @brief Construct an image with implementation-specific pixel format + * @param format Format of pixel data + * @param formatExtra Additional pixel format specifier + * @param size Image size + * @param data Image data + * + * Equivalent to calling @ref Image(PixelStorage, T, U, const VectorTypeFor&, Containers::Array&&) + * with default-constructed @ref PixelStorage. + */ + template explicit Image(T format, U formatExtra, const VectorTypeFor& size, Containers::Array&& data) noexcept: Image{{}, format, formatExtra, size, std::move(data)} {} + + /** + * @brief Construct an image with implementation-specific pixel format + * @param format Format of pixel data + * @param size Image size + * @param data Image data + * + * Equivalent to calling @ref Image(PixelStorage, T, const VectorTypeFor&, Containers::Array&&) + * with default-constructed @ref PixelStorage. + */ + template explicit Image(T format, const VectorTypeFor& size, Containers::Array&& data) noexcept: Image{{}, format, size, std::move(data)} {} + + /** + * @brief Construct an image placeholder with implementation-specific pixel format + * @param storage Storage of pixel data + * @param format Format of pixel data + * @param formatExtra Additional pixel format specifier + * + * Uses ADL to find a corresponding @cpp pixelSize(T, U) @ce overload, + * then calls @ref Image(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt) + * with calculated pixel size. + */ + template /*implicit*/ Image(PixelStorage storage, T format, U formatExtra) noexcept; + + /** + * @brief Construct an image placeholder with implementation-specific pixel format + * @param format Format of pixel data + * @param formatExtra Additional pixel format specifier + * + * Equivalent to calling @ref Image(PixelStorage, T, U) with + * default-constructed @ref PixelStorage. + */ + template /*implicit*/ Image(T format, U formatExtra) noexcept: Image{{}, format, formatExtra} {} + + /** + * @brief Construct an image placeholder with implementation-specific pixel format + * @param storage Storage of pixel data + * @param format Format of pixel data + * + * Uses ADL to find a corresponding @cpp pixelSize(T) @ce overload, + * then calls @ref Image(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt) + * with calculated pixel size and @p formatExtra set to @cpp 0 @ce. + */ + template /*implicit*/ Image(PixelStorage storage, T format) noexcept; + + /** + * @brief Construct an image placeholder with implementation-specific pixel format + * @param format Format of pixel data + * + * Equivalent to calling @ref Image(PixelStorage, T) with + * default-constructed @ref PixelStorage. */ - /*implicit*/ Image(GL::PixelFormat format, GL::PixelType type) noexcept: Image{{}, format, type} {} + template /*implicit*/ Image(T format) noexcept: Image{{}, format} {} /** @brief Copying is not allowed */ Image(const Image&) = delete; @@ -106,18 +281,41 @@ template class Image { /** @brief Storage of pixel data */ PixelStorage storage() const { return _storage; } - /** @brief Format of pixel data */ - GL::PixelFormat format() const { return _format; } + /** + * @brief Format of pixel data + * + * Returns either a defined value from the @ref PixelFormat enum or a + * wrapped implementation-specific value. Use + * @ref isPixelFormatImplementationSpecific() to distinguish the case + * and @ref pixelFormatUnwrap() to extract an implementation-specific + * value, if needed. + * @see @ref formatExtra() + */ + PixelFormat format() const { return _format; } + + /** + * @brief Additional pixel format specifier + * + * Some implementations (such as OpenGL) define a pixel format using + * two values. This field contains the second implementation-specific + * value verbatim, if any. See @ref format() for more information. + */ + UnsignedInt formatExtra() const { return _formatExtra; } - /** @brief Data type of pixel data */ - GL::PixelType type() const { return _type; } + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + /** + * @brief Data type of pixel data + * @deprecated Cast @ref formatExtra() to @ref GL::PixelType instead. + */ + CORRADE_DEPRECATED("cast formatExtra() to GL::PixelType instead") GL::PixelType type() const { return GL::PixelType(_formatExtra); } + #endif /** * @brief Pixel size (in bytes) * - * @see @ref PixelStorage::pixelSize() + * @see @ref pixelSize(PixelFormat) */ - std::size_t pixelSize() const { return PixelStorage::pixelSize(_format, _type); } + UnsignedInt pixelSize() const { return _pixelSize; } /** @brief Image size */ VectorTypeFor size() const { return _size; } @@ -165,48 +363,56 @@ template class Image { return reinterpret_cast(_data.data()); } - #ifdef MAGNUM_BUILD_DEPRECATED + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) /** * @brief Set image data * @param storage Storage of pixel data * @param format Format of pixel data - * @param type Data type of pixel data + * @param formatExtra Additional pixel format specifier * @param size Image size * @param data Image data * * @deprecated Move-assign a new instance instead. * - * Deletes previous data and replaces them with new. The data are - * expected to be of proper size for given @p storage parameters. + * Deletes previous data and replaces them with new. The @p data array + * is expected to be of proper size for given parameters. * @see @ref release() */ - CORRADE_DEPRECATED("move-assign a new instance instead") void setData(PixelStorage storage, GL::PixelFormat format, GL::PixelType type, const VectorTypeFor& size, Containers::Array&& data) { - *this = Image{storage, format, type, size, std::move(data)}; + template CORRADE_DEPRECATED("move-assign a new instance instead") void setData(PixelStorage storage, T format, U formatExtra, const VectorTypeFor& size, Containers::Array&& data) { + *this = Image{storage, format, formatExtra, size, std::move(data)}; } - /** @overload - * Similar to the above, but uses default @ref PixelStorage parameters. + /** + * @brief Set image data + * @param format Format of pixel data + * @param formatExtra Additional pixel format specifier + * @param size Image size + * @param data Image data * * @deprecated Move-assign a new instance instead. + * + * Equivalent to calling @ref setData(PixelStorage, T, U, const VectorTypeFor&, Containers::Array&&) + * with default-constructed @ref PixelStorage. */ - CORRADE_DEPRECATED("move-assign a new instance instead") void setData(GL::PixelFormat format, GL::PixelType type, const VectorTypeFor& size, Containers::Array&& data) { - *this = Image{format, type, size, std::move(data)}; + template CORRADE_DEPRECATED("move-assign a new instance instead") void setData(T format, U formatExtra, const VectorTypeFor& size, Containers::Array&& data) { + *this = Image{format, formatExtra, size, std::move(data)}; } #endif /** * @brief Release data storage * - * Releases the ownership of the data array and resets internal state - * to default. + * Releases the ownership of the data array and resets @ref size() to + * zero. The state afterwards is equivalent to moved-from state. * @see @ref data() */ Containers::Array release(); private: PixelStorage _storage; - GL::PixelFormat _format; - GL::PixelType _type; + PixelFormat _format; + UnsignedInt _formatExtra; + UnsignedInt _pixelSize; Math::Vector _size; Containers::Array _data; }; @@ -223,10 +429,34 @@ typedef Image<3> Image3D; /** @brief Compressed image -Stores image data in client memory. +Stores multi-dimensional compressed image data together with layout and +compressed block format description. See @ref CompressedImageView for a +non-owning alternative. + +This class can act as a drop-in replacement for @ref CompressedImageView and +@ref Trade::ImageData APIs and is implicitly convertible to +@ref CompressedImageView. Particular graphics API wrappers provide additional +image classes, for example @ref GL::CompressedBufferImage. See also @ref Image +for equivalent functionality targeted on non-compressed image formats. + +@section CompressedImage-usage Basic usage + +The image takes ownership of a passed @ref Corrade::Containers::Array, together +with storing image size and one of the generic @ref CompressedPixelFormat +values: + +@snippet Magnum.cpp CompressedImage-usage + +It's also possible to create just an image placeholder, storing only the image +properties without data or size. That is useful for example to specify desired +format of image queries in graphics APIs: + +@snippet Magnum.cpp CompressedImage-usage-query + +As with @ref CompressedImageView, this class supports extra storage parameters +and implementation-specific compressed pixel format specification. See its +documentation for more information. -See @ref Image for more information. Interchangeable with -@ref CompressedImageView, @ref CompressedBufferImage or @ref Trade::ImageData. @see @ref CompressedImage1D, @ref CompressedImage2D, @ref CompressedImage3D */ template class CompressedImage { @@ -235,20 +465,14 @@ template class CompressedImage { Dimensions = dimensions /**< Image dimension count */ }; - #ifndef MAGNUM_TARGET_GLES /** * @brief Constructor * @param storage Storage of compressed pixel data * @param format Format of compressed pixel data * @param size Image size * @param data Image data - * - * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} - * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and - * WebGL. */ - explicit CompressedImage(CompressedPixelStorage storage, GL::CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data); - #endif + explicit CompressedImage(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data) noexcept; /** * @brief Constructor @@ -256,36 +480,50 @@ template class CompressedImage { * @param size Image size * @param data Image data * - * Similar the above, but uses default @ref CompressedPixelStorage - * parameters (or the hardcoded ones in OpenGL ES and WebGL). + * Equivalent to calling @ref CompressedImage(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::Array&&) + * with default-constructed @ref CompressedPixelStorage. */ - explicit CompressedImage(GL::CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data); + explicit CompressedImage(CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data) noexcept: CompressedImage{{}, format, size, std::move(data)} {} - #ifndef MAGNUM_TARGET_GLES /** - * @brief Constructor + * @brief Construct a compressed image with implementation-specific format * @param storage Storage of compressed pixel data + * @param format Format of compressed pixel data + * @param size Image size + * @param data Image data + * + * Uses @ref compressedPixelFormatWrap() internally to convert + * @p format to @ref CompressedPixelFormat. + */ + template explicit CompressedImage(CompressedPixelStorage storage, T format, const VectorTypeFor& size, Containers::Array&& data) noexcept; + + /** + * @brief Construct a compressed image with implementation-specific format + * @param format Format of compressed pixel data + * @param size Image size + * @param data Image data * - * Format is undefined, size is zero and data are empty, call - * @ref setData() to fill the image with data or use - * @ref Texture::compressedImage() "*Texture::compressedImage()"/ - * @ref Texture::compressedSubImage() "*Texture::compressedSubImage()" - * to fill the image with data using @p storage settings. + * Equivalent to calling @ref CompressedImage(CompressedPixelStorage, T, const VectorTypeFor&, Containers::Array&&) + * with default-constructed @ref CompressedPixelStorage. + */ + template explicit CompressedImage(T format, const VectorTypeFor& size, Containers::Array&& data) noexcept: CompressedImage{{}, format, size, std::move(data)} {} + + /** + * @brief Construct an image placeholder + * @param storage Storage of compressed pixel data * - * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} - * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and - * WebGL. + * Format is undefined, size is zero and data is @cpp nullptr @ce. Move + * over a non-empty instance to make it useful. */ - /*implicit*/ CompressedImage(CompressedPixelStorage storage); - #endif + /*implicit*/ CompressedImage(CompressedPixelStorage storage) noexcept; /** - * @brief Constructor + * @brief Construct an image placeholder * - * Similar the above, but uses default @ref CompressedPixelStorage - * parameters (or the hardcoded ones in OpenGL ES). + * Equivalent to calling @ref CompressedImage(CompressedPixelStorage) + * with default-constructed @ref CompressedPixelStorage. */ - /*implicit*/ CompressedImage(); + /*implicit*/ CompressedImage() noexcept: CompressedImage{{}} {} /** @brief Copying is not allowed */ CompressedImage(const CompressedImage&) = delete; @@ -302,37 +540,32 @@ template class CompressedImage { /** @brief Conversion to view */ /*implicit*/ operator CompressedImageView() const; - #ifndef MAGNUM_TARGET_GLES + /** @brief Storage of compressed pixel data */ + CompressedPixelStorage storage() const { return _storage; } + /** - * @brief Storage of compressed pixel data + * @brief Format of compressed pixel data * - * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} - * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and - * WebGL. + * Returns either a defined value from the @ref CompressedPixelFormat + * enum or a wrapped implementation-specific value. Use + * @ref isCompressedPixelFormatImplementationSpecific() to distinguish + * the case and @ref compressedPixelFormatUnwrap() to extract an + * implementation-specific value, if needed. */ - CompressedPixelStorage storage() const { return _storage; } - #endif - - /** @brief Format of compressed pixel data */ - GL::CompressedPixelFormat format() const { return _format; } + CompressedPixelFormat format() const { return _format; } /** @brief Image size */ VectorTypeFor size() const { return _size; } - #ifndef MAGNUM_TARGET_GLES /** * @brief Compressed image data properties * * See @ref CompressedPixelStorage::dataProperties() for more * information. - * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} - * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and - * WebGL. */ std::tuple, VectorTypeFor, std::size_t> dataProperties() const { return Implementation::compressedImageDataProperties(*this); } - #endif /** * @brief Raw data @@ -354,8 +587,7 @@ template class CompressedImage { return reinterpret_cast(_data.data()); } - #ifdef MAGNUM_BUILD_DEPRECATED - #ifndef MAGNUM_TARGET_GLES + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) /** * @brief Set image data * @param storage Storage of compressed pixel data @@ -365,17 +597,12 @@ template class CompressedImage { * * @deprecated Move-assign a new instance instead. * - * Deletes previous data and replaces them with new. Note that the - * data are not copied, but they are deleted on destruction. + * Deletes previous data and replaces it with @p data. * @see @ref release() - * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} - * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and - * WebGL. */ - CORRADE_DEPRECATED("move-assign a new instance instead") void setData(CompressedPixelStorage storage, GL::CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data) { - *this = CompressedImage{storage, format, size, std::move(data)}; + CORRADE_DEPRECATED("move-assign a new instance instead") void setData(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data) { + *this = CompressedImage{storage, GL::CompressedPixelFormat(format), size, std::move(data)}; } - #endif /** * @brief Set image data @@ -385,28 +612,30 @@ template class CompressedImage { * * @deprecated Move-assign a new instance instead. * - * Similar the above, but uses default @ref CompressedPixelStorage - * parameters (or the hardcoded ones in OpenGL ES and WebGL). + * Equivalent to calling @ref setData(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::Array&&) + * with default-constructed @ref CompressedPixelStorage. */ - CORRADE_DEPRECATED("move-assign a new instance instead") void setData(GL::CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data) { - *this = CompressedImage{format, size, std::move(data)}; + CORRADE_DEPRECATED("move-assign a new instance instead") void setData(CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data) { + *this = CompressedImage{GL::CompressedPixelFormat(format), size, std::move(data)}; } #endif /** * @brief Release data storage * - * Releases the ownership of the data array and resets internal state - * to default. - * @see @ref setData() + * Releases the ownership of the data array and resets @ref size() to + * zero. The state afterwards is equivalent to moved-from state. + * @see @ref data() */ Containers::Array release(); private: - #ifndef MAGNUM_TARGET_GLES + /* To be made public once block size and block data size are stored + together with the image */ + explicit CompressedImage(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor& size, Containers::Array&& data) noexcept; + CompressedPixelStorage _storage; - #endif - GL::CompressedPixelFormat _format; + CompressedPixelFormat _format; Math::Vector _size; Containers::Array _data; }; @@ -420,15 +649,11 @@ typedef CompressedImage<2> CompressedImage2D; /** @brief Three-dimensional compressed image */ typedef CompressedImage<3> CompressedImage3D; -template inline Image::Image(Image&& other) noexcept: _storage{std::move(other._storage)}, _format{std::move(other._format)}, _type{std::move(other._type)}, _size{std::move(other._size)}, _data{std::move(other._data)} { +template inline Image::Image(Image&& other) noexcept: _storage{std::move(other._storage)}, _format{std::move(other._format)}, _formatExtra{std::move(other._formatExtra)}, _pixelSize{std::move(other._pixelSize)}, _size{std::move(other._size)}, _data{std::move(other._data)} { other._size = {}; } -template inline CompressedImage::CompressedImage(CompressedImage&& other) noexcept: - #ifndef MAGNUM_TARGET_GLES - _storage{std::move(other._storage)}, - #endif - _format{std::move(other._format)}, _size{std::move(other._size)}, _data{std::move(other._data)} +template inline CompressedImage::CompressedImage(CompressedImage&& other) noexcept: _storage{std::move(other._storage)}, _format{std::move(other._format)}, _size{std::move(other._size)}, _data{std::move(other._data)} { other._size = {}; } @@ -437,7 +662,8 @@ template inline Image& Image::op using std::swap; swap(_storage, other._storage); swap(_format, other._format); - swap(_type, other._type); + swap(_formatExtra, other._formatExtra); + swap(_pixelSize, other._pixelSize); swap(_size, other._size); swap(_data, other._data); return *this; @@ -445,9 +671,7 @@ template inline Image& Image::op template inline CompressedImage& CompressedImage::operator=(CompressedImage&& other) noexcept { using std::swap; - #ifndef MAGNUM_TARGET_GLES swap(_storage, other._storage); - #endif swap(_format, other._format); swap(_size, other._size); swap(_data, other._data); @@ -456,16 +680,12 @@ template inline CompressedImage& CompressedI template inline Image::operator ImageView() const { - return ImageView{_storage, _format, _type, _size, _data}; + return ImageView{_storage, _format, _formatExtra, _pixelSize, _size, _data}; } template inline CompressedImage::operator CompressedImageView() const { - return CompressedImageView{ - #ifndef MAGNUM_TARGET_GLES - _storage, - #endif - _format, _size, _data}; + return CompressedImageView{_storage, _format, _size, _data}; } template inline Containers::Array Image::release() { @@ -480,31 +700,42 @@ template inline Containers::Array CompressedImage< return data; } -template inline CompressedImage::CompressedImage( - #ifndef MAGNUM_TARGET_GLES - const CompressedPixelStorage storage, +template template inline Image::Image(const PixelStorage storage, const T format, const U formatExtra, const VectorTypeFor& size, Containers::Array&& data) noexcept: Image{storage, + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + Implementation::wrapPixelFormatIfNotGLSpecific(format), + #else + UnsignedInt(format), #endif - const GL::CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data): - #ifndef MAGNUM_TARGET_GLES - _storage{storage}, - #endif - _format{format}, _size{size}, _data{std::move(data)} {} + UnsignedInt(formatExtra), Implementation::pixelSizeAdl(format, formatExtra), size, std::move(data)} { + static_assert(sizeof(T) <= 4 && sizeof(U) <= 4, + "format types larger than 32bits are not supported"); +} -template inline CompressedImage::CompressedImage( - #ifndef MAGNUM_TARGET_GLES - const CompressedPixelStorage storage - #endif - ) - #ifndef MAGNUM_TARGET_GLES - : _storage{storage} +template template inline Image::Image(const PixelStorage storage, const T format, const VectorTypeFor& size, Containers::Array&& data) noexcept: Image{storage, UnsignedInt(format), {}, Implementation::pixelSizeAdl(format), size, std::move(data)} { + static_assert(sizeof(T) <= 4, + "format types larger than 32bits are not supported"); +} + +template template inline Image::Image(const PixelStorage storage, const T format, const U formatExtra) noexcept: Image{storage, + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + Implementation::wrapPixelFormatIfNotGLSpecific(format), + #else + UnsignedInt(format), #endif - {} + UnsignedInt(formatExtra), Implementation::pixelSizeAdl(format, formatExtra)} { + static_assert(sizeof(T) <= 4 && sizeof(U) <= 4, + "format types larger than 32bits are not supported"); +} -#ifndef MAGNUM_TARGET_GLES -template inline CompressedImage::CompressedImage(const GL::CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data): CompressedImage{{}, format, size, std::move(data)} {} +template template inline Image::Image(const PixelStorage storage, const T format) noexcept: Image{storage, UnsignedInt(format), {}, Implementation::pixelSizeAdl(format)} { + static_assert(sizeof(T) <= 4, + "format types larger than 32bits are not supported"); +} -template inline CompressedImage::CompressedImage(): CompressedImage{CompressedPixelStorage{}} {} -#endif +template template inline CompressedImage::CompressedImage(const CompressedPixelStorage storage, const T format, const VectorTypeFor& size, Containers::Array&& data) noexcept: CompressedImage{storage, UnsignedInt(format), size, std::move(data)} { + static_assert(sizeof(T) <= 4, + "format types larger than 32bits are not supported"); +} } diff --git a/src/Magnum/ImageView.cpp b/src/Magnum/ImageView.cpp index 97d10ea8c..69f0f5a77 100644 --- a/src/Magnum/ImageView.cpp +++ b/src/Magnum/ImageView.cpp @@ -25,21 +25,45 @@ #include "ImageView.h" +#include "Magnum/PixelFormat.h" + namespace Magnum { -template ImageView::ImageView(PixelStorage storage, GL::PixelFormat format, GL::PixelType type, const VectorTypeFor& size, Containers::ArrayView data) noexcept: _storage{storage}, _format{format}, _type{type}, _size{size}, _data{reinterpret_cast(data.data()), data.size()} { +template ImageView::ImageView(const PixelStorage storage, const PixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: ImageView{storage, format, {}, Magnum::pixelSize(format), size, data} {} + +template ImageView::ImageView(const PixelStorage storage, const UnsignedInt format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: ImageView{storage, pixelFormatWrap(format), formatExtra, pixelSize, size, data} {} + +template ImageView::ImageView(const PixelStorage storage, const PixelFormat format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: _storage{storage}, _format{format}, _formatExtra{formatExtra}, _pixelSize{pixelSize}, _size{size}, _data{reinterpret_cast(data.data()), data.size()} { CORRADE_ASSERT(!_data || Implementation::imageDataSize(*this) <= _data.size(), "ImageView::ImageView(): bad image data size, got" << _data.size() << "but expected at least" << Implementation::imageDataSize(*this), ); } +template ImageView::ImageView(const PixelStorage storage, const PixelFormat format, const VectorTypeFor& size) noexcept: ImageView{storage, format, {}, Magnum::pixelSize(format), size} {} + +template ImageView::ImageView(const PixelStorage storage, const UnsignedInt format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size) noexcept: ImageView{storage, pixelFormatWrap(format), formatExtra, pixelSize, size} {} + +template ImageView::ImageView(const PixelStorage storage, const PixelFormat format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size) noexcept: _storage{storage}, _format{format}, _formatExtra{formatExtra}, _pixelSize{pixelSize}, _size{size}, _data{nullptr} {} + template void ImageView::setData(const Containers::ArrayView data) { CORRADE_ASSERT(Implementation::imageDataSize(*this) <= data.size(), "ImageView::setData(): bad image data size, got" << data.size() << "but expected at least" << Implementation::imageDataSize(*this), ); _data = {reinterpret_cast(data.data()), data.size()}; } +template CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: _storage{storage}, _format{format}, _size{size}, _data{reinterpret_cast(data.data()), data.size()} {} + +template CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const CompressedPixelFormat format, const VectorTypeFor& size) noexcept: _storage{storage}, _format{format}, _size{size} {} + +template CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const UnsignedInt format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: CompressedImageView{storage, compressedPixelFormatWrap(format), size, data} {} + +template CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const UnsignedInt format, const VectorTypeFor& size) noexcept: CompressedImageView{storage, compressedPixelFormatWrap(format), size} {} + #ifndef DOXYGEN_GENERATING_OUTPUT template class MAGNUM_EXPORT ImageView<1>; template class MAGNUM_EXPORT ImageView<2>; template class MAGNUM_EXPORT ImageView<3>; + +template class MAGNUM_EXPORT CompressedImageView<1>; +template class MAGNUM_EXPORT CompressedImageView<2>; +template class MAGNUM_EXPORT CompressedImageView<3>; #endif } diff --git a/src/Magnum/ImageView.h b/src/Magnum/ImageView.h index 020461c07..ca7e5fe36 100644 --- a/src/Magnum/ImageView.h +++ b/src/Magnum/ImageView.h @@ -33,25 +33,91 @@ #include "Magnum/DimensionTraits.h" #include "Magnum/PixelStorage.h" -#include "Magnum/Math/Vector4.h" +#include "Magnum/Math/Vector3.h" + +#if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) +#include "Magnum/PixelFormat.h" +#endif namespace Magnum { /** @brief Image view -Adds information about dimensions, color components and component type to some -data in memory. +Non-owning view on multi-dimensional image data together with layout and pixel +format description. Unlike @ref Image, this class doesn't take ownership of the +data, so it is targeted for wrapping data that is either stored in +stack/constant memory (and shouldn't be deleted) or is managed by something +else. + +This class can act as drop-in replacement for @ref Image or +@ref Trade::ImageData, these two are additionally implicitly convertible to it. +Particular graphics API wrappers provide additional image classes, for example +@ref GL::BufferImage. See also @ref CompressedImageView for equivalent +functionality targeted on compressed image formats. + +@section ImageView-usage Basic usage + +Usually, the view is created on some pre-existing data array in order to +describe its layout, with pixel format being one of the values from the generic +@link PixelFormat @endlink: + +@snippet Magnum.cpp ImageView-usage + +On construction, the image view internally calculates pixel size corresponding +to given pixel format using @ref pixelSize(). This value is needed to check +that the passed data array is large enough and is also required by most image +manipulation operations. + +It's also possible to create an empty view and assign the memory later. That is +useful for example in case of multi-buffered video streaming, where each frame +has the same properties but a different memory location: + +@snippet Magnum.cpp ImageView-usage-streaming + +It's possible to have views on image sub-rectangles, 3D texture slices or +images with over-aligned rows by passing a particular @ref PixelStorage as +first parameter. In the following snippet, the view is the center 25x25 +sub-rectangle of a 75x75 8-bit RGB image , with rows aligned to four bytes: + +@snippet Magnum.cpp ImageView-usage-storage + +@subsection ImageView-usage-implementation-specific Implementation-specific formats -Unlike @ref Image, this class doesn't delete the data on destruction, so it is -targeted for wrapping data which are either stored in stack/constant memory -(and shouldn't be deleted) or they are managed by someone else and have the -same properties for each frame, such as video stream. Thus it is not possible -to change image properties, only data pointer. +For known graphics APIs, there's a set of utility functions converting from +@ref PixelFormat to implementation-specific format identifiers and such +conversion is done implicitly when passing the view to a particular API. See +the enum documentation and documentation of its values for more information. -Interchangeable with @ref Image, @ref BufferImage or @ref Trade::ImageData. -@see @ref ImageView1D, @ref ImageView2D, @ref ImageView3D, - @ref CompressedImageView +In some cases, for example when there's no corresponding generic format +available, it's desirable to specify the pixel format using +implementation-specific identifiers directly. In case of OpenGL that would be +the @ref GL::PixelFormat and @ref GL::PixelType pair: + +@snippet Magnum.cpp ImageView-usage-gl + +In such cases, pixel size is calculated using either @cpp pixelSize(T, U) @ce +or @cpp pixelSize(T) @ce that is found using +[ADL](https://en.wikipedia.org/wiki/Argument-dependent_name_lookup), with +@cpp T @ce and @cpp U @ce corresponding to types of passed arguments. The +implementation-specific format is wrapped in @ref PixelFormat using +@ref pixelFormatWrap() and @ref format() returns the wrapped value. In order to +distinguish if the format is wrapped, use @ref isPixelFormatImplementationSpecific() +and then extract the implementation-specific identifier using @ref pixelFormatUnwrap(). +For APIs that have an additional format specifier (such as OpenGL), the second +value is stored verbatim in @ref formatExtra(): + +@snippet Magnum.cpp ImageView-usage-gl-extract + +As a final fallback, types for which the @cpp pixelSize() @ce overload is not +available can be specified directly together with pixel size. In particular, +pixel size of @cpp 0 @ce will cause the image to be treated as fully opaque +data, disabling all slicing operations. The following shows a image view using +Metal-specific format identifier: + +@snippet Magnum.cpp ImageView-usage-metal + +@see @ref ImageView1D, @ref ImageView2D, @ref ImageView3D */ template class ImageView { public: @@ -63,52 +129,241 @@ template class ImageView { * @brief Constructor * @param storage Storage of pixel data * @param format Format of pixel data - * @param type Data type of pixel data * @param size Image size * @param data Image data * - * The data are expected to be of proper size for given @p storage + * The @p data array is expected to be of proper size for given + * parameters. + */ + explicit ImageView(PixelStorage storage, PixelFormat format, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + + /** + * @brief Constructor + * @param format Format of pixel data + * @param size Image size + * @param data Image data + * + * Equivalent to calling @ref ImageView(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::ArrayView) + * with default-constructed @ref PixelStorage. + */ + explicit ImageView(PixelFormat format, const VectorTypeFor& size, Containers::ArrayView data) noexcept: ImageView{{}, format, size, data} {} + + /** + * @brief Construct an empty view + * @param storage Storage of pixel data + * @param format Format of pixel data + * @param size Image size + * + * Data pointer is set to @cpp nullptr @ce, call @ref setData() to + * assign a memory view to the image. + */ + explicit ImageView(PixelStorage storage, PixelFormat format, const VectorTypeFor& size) noexcept; + + /** + * @brief Construct an empty view + * @param format Format of pixel data + * @param size Image size + * + * Equivalent to calling @ref ImageView(PixelStorage, PixelFormat, const VectorTypeFor&) + * with default-constructed @ref PixelStorage. + */ + explicit ImageView(PixelFormat format, const VectorTypeFor& size) noexcept: ImageView{{}, format, size} {} + + /** + * @brief Construct an image view with implementation-specific pixel format + * @param storage Storage of pixel data + * @param format Format of pixel data + * @param formatExtra Additional pixel format specifier + * @param pixelSize Size of a pixel in given format + * @param size Image size + * @param data Image data + * + * Unlike with @ref ImageView(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::ArrayView), + * where pixel size is calculated automatically using + * @ref pixelSize(PixelFormat), this allows you to specify an + * implementation-specific pixel format and pixel size directly. Uses + * @ref pixelFormatWrap() internally to wrap @p format in + * @ref PixelFormat. + * + * The @p data array is expected to be of proper size for given * parameters. */ - explicit ImageView(PixelStorage storage, GL::PixelFormat format, GL::PixelType type, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + explicit ImageView(PixelStorage storage, UnsignedInt format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::ArrayView data) noexcept; /** @overload - * Similar to the above, but uses default @ref PixelStorage parameters. + * + * Equivalent to the above for @p format already wrapped with + * @ref pixelFormatWrap(). */ - explicit ImageView(GL::PixelFormat format, GL::PixelType type, const VectorTypeFor& size, Containers::ArrayView data) noexcept: ImageView{{}, format, type, size, data} {} + explicit ImageView(PixelStorage storage, PixelFormat format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::ArrayView data) noexcept; /** - * @brief Constructor + * @brief Construct an empty view with implementation-specific pixel format * @param storage Storage of pixel data * @param format Format of pixel data - * @param type Data type of pixel data + * @param formatExtra Additional pixel format specifier + * @param pixelSize Size of a pixel in given format * @param size Image size * - * Data pointer is set to @cpp nullptr @ce, call @ref setData() to fill - * the image with data. + * Unlike with @ref ImageView(PixelStorage, PixelFormat, const VectorTypeFor&), + * where pixel size is calculated automatically using + * @ref pixelSize(PixelFormat), this allows you to specify an + * implementation-specific pixel format and pixel size directly. Uses + * @ref pixelFormatWrap() internally to wrap @p format in + * @ref PixelFormat. + * + * Data pointer is set to @cpp nullptr @ce, call @ref setData() to + * assign a memory view to the image. */ - constexpr explicit ImageView(PixelStorage storage, GL::PixelFormat format, GL::PixelType type, const VectorTypeFor& size) noexcept: _storage{storage}, _format{format}, _type{type}, _size{size}, _data{nullptr} {} + explicit ImageView(PixelStorage storage, UnsignedInt format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size) noexcept; /** @overload - * Similar to the above, but uses default @ref PixelStorage parameters. + * + * Equivalent to the above for @p format already wrapped with + * @ref pixelFormatWrap(). + */ + explicit ImageView(PixelStorage storage, PixelFormat format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size) noexcept; + + /** + * @brief Construct an image view with implementation-specific pixel format + * @param storage Storage of pixel data + * @param format Format of pixel data + * @param formatExtra Additional pixel format specifier + * @param size Image size + * @param data Image data + * + * Uses ADL to find a corresponding @cpp pixelSize(T, U) @ce overload, + * then calls @ref ImageView(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::ArrayView) + * with calculated pixel size. + */ + template explicit ImageView(PixelStorage storage, T format, U formatExtra, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + + /** + * @brief Construct an image view with implementation-specific pixel format + * @param storage Storage of pixel data + * @param format Format of pixel data + * @param size Image size + * @param data Image data + * + * Uses ADL to find a corresponding @cpp pixelSize(T) @ce overload, + * then calls @ref ImageView(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::ArrayView) + * with calculated pixel size and @p formatExtra set to @cpp 0 @ce. */ - constexpr explicit ImageView(GL::PixelFormat format, GL::PixelType type, const VectorTypeFor& size) noexcept: ImageView{{}, format, type, size} {} + template explicit ImageView(PixelStorage storage, T format, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + + /** + * @brief Construct an image view with implementation-specific pixel format + * @param format Format of pixel data + * @param formatExtra Additional pixel format specifier + * @param size Image size + * @param data Image data + * + * Equivalent to calling @ref ImageView(PixelStorage, T, U, const VectorTypeFor&, Containers::ArrayView) + * with default-constructed @ref PixelStorage. + */ + template explicit ImageView(T format, U formatExtra, const VectorTypeFor& size, Containers::ArrayView data) noexcept: ImageView{{}, format, formatExtra, size, data} {} + + /** + * @brief Construct an image view with implementation-specific pixel format + * @param format Format of pixel data + * @param size Image size + * @param data Image data + * + * Equivalent to calling @ref ImageView(PixelStorage, T, const VectorTypeFor&, Containers::ArrayView) + * with default-constructed @ref PixelStorage. + */ + template explicit ImageView(T format, const VectorTypeFor& size, Containers::ArrayView data) noexcept: ImageView{{}, format, size, data} {} + + /** + * @brief Construct an empty view with implementation-specific pixel format + * @param storage Storage of pixel data + * @param format Format of pixel data + * @param formatExtra Additional pixel format specifier + * @param size Image size + * + * Uses ADL to find a corresponding @cpp pixelSize(T, U) @ce overload, + * then calls @ref ImageView(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&) + * with calculated pixel size. + * + * Data pointer is set to @cpp nullptr @ce, call @ref setData() to + * assign a memory view to the image. + */ + template explicit ImageView(PixelStorage storage, T format, U formatExtra, const VectorTypeFor& size) noexcept; + + /** + * @brief Construct an empty view with implementation-specific pixel format + * @param storage Storage of pixel data + * @param format Format of pixel data + * @param size Image size + * + * Uses ADL to find a corresponding @cpp pixelSize(T) @ce overload, + * then calls @ref ImageView(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&) + * with calculated pixel size and @p formatExtra set to @cpp 0 @ce. + * + * Data pointer is set to @cpp nullptr @ce, call @ref setData() to + * assign a memory view to the image. + */ + template explicit ImageView(PixelStorage storage, T format, const VectorTypeFor& size) noexcept; + + /** + * @brief Construct an empty view with implementation-specific pixel format + * @param format Format of pixel data + * @param formatExtra Additional pixel format specifier + * @param size Image size + * + * Equivalent to calling @ref ImageView(PixelStorage, T, U, const VectorTypeFor&, Containers::ArrayView) + * with default-constructed @ref PixelStorage. + */ + template explicit ImageView(T format, U formatExtra, const VectorTypeFor& size) noexcept: ImageView{{}, format, formatExtra, size} {} + + /** + * @brief Construct an empty view with implementation-specific pixel format + * @param format Format of pixel data + * @param size Image size + * + * Equivalent to calling @ref ImageView(PixelStorage, T, const VectorTypeFor&) + * with default-constructed @ref PixelStorage. + */ + template explicit ImageView(T format, const VectorTypeFor& size) noexcept: ImageView{{}, format, size} {} /** @brief Storage of pixel data */ PixelStorage storage() const { return _storage; } - /** @brief Format of pixel data */ - GL::PixelFormat format() const { return _format; } + /** + * @brief Format of pixel data + * + * Returns either a defined value from the @ref PixelFormat enum or a + * wrapped implementation-specific value. Use + * @ref isPixelFormatImplementationSpecific() to distinguish the case + * and @ref pixelFormatUnwrap() to extract an implementation-specific + * value, if needed. + * @see @ref formatExtra() + */ + PixelFormat format() const { return _format; } - /** @brief Data type of pixel data */ - GL::PixelType type() const { return _type; } + /** + * @brief Additional pixel format specifier + * + * Some implementations (such as OpenGL) define a pixel format using + * two values. This field contains the second implementation-specific + * value verbatim, if any. See @ref format() for more information. + */ + UnsignedInt formatExtra() const { return _formatExtra; } + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief Data type of pixel data + * @deprecated Cast @ref formatExtra() to @ref GL::PixelType instead. + */ + CORRADE_DEPRECATED("cast formatExtra() to GL::PixelType instead") GL::PixelType type() const { return GL::PixelType(_formatExtra); } + #endif /** * @brief Pixel size (in bytes) * - * @see @ref PixelStorage::pixelSize() + * @see @ref pixelSize(PixelFormat) */ - std::size_t pixelSize() const { return PixelStorage::pixelSize(_format, _type); } + UnsignedInt pixelSize() const { return _pixelSize; } /** @brief Image size */ constexpr VectorTypeFor size() const { return _size; } @@ -122,8 +377,8 @@ template class ImageView { return Implementation::imageDataProperties(*this); } - /** @brief Raw data */ - constexpr Containers::ArrayView data() const { return _data; } + /** @brief Image data */ + Containers::ArrayView data() const { return _data; } /** @overload */ template const T* data() const { @@ -132,18 +387,17 @@ template class ImageView { /** * @brief Set image data - * @param data Image data * - * Storage parameters, pixel format, type and size remain the same as - * passed in constructor. The data are expected to be of proper size - * for given @p storage parameters. + * The data array is expected to be of proper size for parameters + * specified in the constructor. */ void setData(Containers::ArrayView data); private: PixelStorage _storage; - GL::PixelFormat _format; - GL::PixelType _type; + PixelFormat _format; + UnsignedInt _formatExtra; + UnsignedInt _pixelSize; Math::Vector _size; Containers::ArrayView _data; }; @@ -160,10 +414,63 @@ typedef ImageView<3> ImageView3D; /** @brief Compressed image view -Adds information about dimensions and compression type to some data in memory. +Non-owning view on multi-dimensional compressed image data together with layout +and compressed block format description. Unlike @ref CompressedImage, this +class doesn't take ownership of the data, so it is targeted for wrapping data +that is either stored in stack/constant memory (and shouldn't be deleted) or is +managed by something else. + +This class can act as drop-in replacement for @ref CompressedImage or +@ref Trade::ImageData, these two are additionally implicitly convertible to it. +Particular graphics API wrappers provide additional image classes, for example +@ref GL::CompressedBufferImage. See also @ref ImageView for equivalent +functionality targeted on non-compressed image formats. + +@section CompressedImageView-usage Basic usage + +Usually, the view is created on some pre-existing data array in order to +describe its layout, with pixel format being one of the values from the generic +@link CompressedPixelFormat @endlink: + +@snippet Magnum.cpp CompressedImageView-usage + +It's also possible to create an empty view and assign the memory later. That is +useful for example in case of multi-buffered video streaming, where each frame +has the same properties but a different memory location: + +@snippet Magnum.cpp CompressedImageView-usage-streaming + +It's possible to have views on image sub-rectangles, 3D texture slices or +images with over-aligned rows by passing a particular @ref CompressedPixelStorage +as first parameter. In the following snippet, the view is the bottom-right +32x32 sub-rectangle of a 64x64 image: + +@snippet Magnum.cpp CompressedImageView-usage-storage + +@subsection CompressedImageView-usage-implementation-specific Implementation-specific formats + +For known graphics APIs, there's a set of utility functions converting from +@ref CompressedPixelFormat to implementation-specific format identifiers and +such conversion is done implicitly when passing the view to a particular API. +See the enum documentation and documentation of its values for more +information. + +In some cases, for example when there's no corresponding generic format +available, it's desirable to specify the pixel format using +implementation-specific identifiers directly. In case of OpenGL that would be +@link GL::CompressedPixelFormat @endlink: + +@snippet Magnum.cpp CompressedImageView-usage-gl + +In such cases, the implementation-specific format is wrapped in +@ref CompressedPixelFormat using @ref compressedPixelFormatWrap() and +@ref format() returns the wrapped value. In order to distinguish if the format +is wrapped, use @ref isCompressedPixelFormatImplementationSpecific() and then +extract the implementation-specific identifier using +@ref compressedPixelFormatUnwrap(): + +@snippet Magnum.cpp CompressedImageView-usage-gl-extract -See @ref ImageView for more information. Interchangeable with -@ref CompressedImage, @ref CompressedBufferImage or @ref Trade::ImageData. @see @ref CompressedImageView1D, @ref CompressedImageView2D, @ref CompressedImageView3D */ @@ -173,20 +480,14 @@ template class CompressedImageView { Dimensions = dimensions /**< Image dimension count */ }; - #ifndef MAGNUM_TARGET_GLES /** * @brief Constructor * @param storage Storage of compressed pixel data * @param format Format of compressed pixel data * @param size Image size * @param data Image data - * - * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} - * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and - * WebGL. */ - constexpr explicit CompressedImageView(CompressedPixelStorage storage, GL::CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data) noexcept; - #endif + explicit CompressedImageView(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data) noexcept; /** * @brief Constructor @@ -194,71 +495,107 @@ template class CompressedImageView { * @param size Image size * @param data Image data * - * Similar the above, but uses default @ref CompressedPixelStorage - * parameters (or the hardcoded ones in OpenGL ES and WebGL). + * Equivalent to calling @ref CompressedImageView(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::ArrayView) + * with default-constructed @ref CompressedPixelStorage. */ - constexpr explicit CompressedImageView(GL::CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + explicit CompressedImageView(CompressedPixelFormat format, const VectorTypeFor& size, Containers::ArrayView data) noexcept: CompressedImageView{{}, format, size, data} {} - #ifndef MAGNUM_TARGET_GLES /** - * @brief Constructor + * @brief Construct an empty view * @param storage Storage of compressed pixel data * @param format Format of compressed pixel data * @param size Image size * - * Data pointer is set to @cpp nullptr @ce, call @ref setData() to fill - * the image with data. - * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} - * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and - * WebGL. + * Data pointer is set to @cpp nullptr @ce, call @ref setData() to + * assign a memory view to the image. */ - constexpr explicit CompressedImageView(CompressedPixelStorage storage, GL::CompressedPixelFormat format, const VectorTypeFor& size) noexcept; - #endif + explicit CompressedImageView(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size) noexcept; /** - * @brief Constructor + * @brief Construct an empty view * @param format Format of compressed pixel data * @param size Image size * - * Similar the above, but uses default @ref CompressedPixelStorage - * parameters (or the hardcoded ones in OpenGL ES and WebGL). + * Equivalent to calling @ref CompressedImageView(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&) + * with default-constructed @ref CompressedPixelStorage. */ - constexpr explicit CompressedImageView(GL::CompressedPixelFormat format, const VectorTypeFor& size) noexcept; + explicit CompressedImageView(CompressedPixelFormat format, const VectorTypeFor& size) noexcept: CompressedImageView{{}, format, size} {} - #ifndef MAGNUM_TARGET_GLES /** - * @brief Storage of compressed pixel data + * @brief Construct an image view with implementation-specific format + * @param storage Storage of compressed pixel data + * @param format Format of compressed pixel data + * @param size Image size + * @param data Image data + * + * Uses @ref compressedPixelFormatWrap() internally to convert + * @p format to @ref CompressedPixelFormat. + */ + template explicit CompressedImageView(CompressedPixelStorage storage, T format, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + + /** + * @brief Construct an image view with implementation-specific format + * @param format Format of compressed pixel data + * @param size Image size + * @param data Image data + * + * Equivalent to calling @ref CompressedImageView(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::ArrayView) + * with default-constructed @ref CompressedPixelStorage. + */ + template explicit CompressedImageView(T format, const VectorTypeFor& size, Containers::ArrayView data) noexcept: CompressedImageView{{}, format, size, data} {} + + /** + * @brief Construct an empty view with implementation-specific format + * @param storage Storage of compressed pixel data + * @param format Format of compressed pixel data + * @param size Image size + * + * Uses @ref compressedPixelFormatWrap() internally to convert + * @p format to @ref CompressedPixelFormat. Data pointer is set to + * @cpp nullptr @ce, call @ref setData() to assign a memory view to the + * image. + */ + template explicit CompressedImageView(CompressedPixelStorage storage, T format, const VectorTypeFor& size) noexcept; + + /** + * @brief Construct an empty view with implementation-specific format + * @param format Format of compressed pixel data + * @param size Image size * - * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} - * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and - * WebGL. + * Equivalent to calling @ref CompressedImageView(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&) + * with default-constructed @ref CompressedPixelStorage. */ + template explicit CompressedImageView(T format, const VectorTypeFor& size) noexcept: CompressedImageView{{}, format, size} {} + + /** @brief Storage of compressed pixel data */ CompressedPixelStorage storage() const { return _storage; } - #endif - /** @brief Format of compressed data */ - GL::CompressedPixelFormat format() const { return _format; } + /** + * @brief Format of compressed pixel data + * + * Returns either a defined value from the @ref CompressedPixelFormat + * enum or a wrapped implementation-specific value. Use + * @ref isCompressedPixelFormatImplementationSpecific() to distinguish + * the case and @ref compressedPixelFormatUnwrap() to extract an + * implementation-specific value, if needed. + */ + CompressedPixelFormat format() const { return _format; } /** @brief Image size */ constexpr VectorTypeFor size() const { return _size; } - #ifndef MAGNUM_TARGET_GLES /** * @brief Compressed image data properties * * See @ref CompressedPixelStorage::dataProperties() for more * information. - * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} - * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and - * WebGL. */ std::tuple, VectorTypeFor, std::size_t> dataProperties() const { return Implementation::compressedImageDataProperties(*this); } - #endif - /** @brief Raw data */ - constexpr Containers::ArrayView data() const { return _data; } + /** @brief Image data */ + Containers::ArrayView data() const { return _data; } /** @overload */ template const T* data() const { @@ -267,21 +604,22 @@ template class CompressedImageView { /** * @brief Set image data - * @param data Image data * - * Dimensions, color compnents and data type remains the same as - * passed in constructor. The data are not copied nor deleted on - * destruction. + * The data array is expected to be of proper size for parameters + * specified in the constructor. */ void setData(Containers::ArrayView data) { _data = {reinterpret_cast(data.data()), data.size()}; } private: - #ifndef MAGNUM_TARGET_GLES + /* To be made public once block size and block data size are stored + together with the image */ + explicit CompressedImageView(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor& size, Containers::ArrayView data) noexcept; + explicit CompressedImageView(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor& size) noexcept; + CompressedPixelStorage _storage; - #endif - GL::CompressedPixelFormat _format; + CompressedPixelFormat _format; Math::Vector _size; Containers::ArrayView _data; }; @@ -295,31 +633,62 @@ typedef CompressedImageView<2> CompressedImageView2D; /** @brief Three-dimensional compressed image view */ typedef CompressedImageView<3> CompressedImageView3D; -template constexpr CompressedImageView::CompressedImageView( - #ifndef MAGNUM_TARGET_GLES - const CompressedPixelStorage storage, - #endif - const GL::CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: - #ifndef MAGNUM_TARGET_GLES - _storage{storage}, - #endif - _format{format}, _size{size}, _data{reinterpret_cast(data.data()), data.size()} {} +namespace Implementation { + template inline UnsignedInt pixelSizeAdl(T format) { + return pixelSize(format); + } + + template inline UnsignedInt pixelSizeAdl(T format, U formatExtra) { + /* So it doesn't warn when the deprecated + pixelSize(PixelFormat, GL::PixelType) overload is called + indirectly */ + CORRADE_IGNORE_DEPRECATED_PUSH + return pixelSize(format, formatExtra); + CORRADE_IGNORE_DEPRECATED_POP + } +} -template constexpr CompressedImageView::CompressedImageView( - #ifndef MAGNUM_TARGET_GLES - const CompressedPixelStorage storage, +template template inline ImageView::ImageView(const PixelStorage storage, const T format, const U formatExtra, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: ImageView{storage, + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + Implementation::wrapPixelFormatIfNotGLSpecific(format), + #else + UnsignedInt(format), #endif - const GL::CompressedPixelFormat format, const VectorTypeFor& size) noexcept: - #ifndef MAGNUM_TARGET_GLES - _storage{storage}, + UnsignedInt(formatExtra), Implementation::pixelSizeAdl(format, formatExtra), size, data} { + static_assert(sizeof(T) <= 4 && sizeof(U) <= 4, + "format types larger than 32bits are not supported"); +} + +template template inline ImageView::ImageView(const PixelStorage storage, const T format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: ImageView{storage, UnsignedInt(format), {}, Implementation::pixelSizeAdl(format), size, data} { + static_assert(sizeof(T) <= 4, + "format types larger than 32bits are not supported"); +} + +template template inline ImageView::ImageView(const PixelStorage storage, const T format, const U formatExtra, const VectorTypeFor& size) noexcept: ImageView{storage, + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + Implementation::wrapPixelFormatIfNotGLSpecific(format), + #else + UnsignedInt(format), #endif - _format{format}, _size{size} {} + UnsignedInt(formatExtra), Implementation::pixelSizeAdl(format, formatExtra), size} { + static_assert(sizeof(T) <= 4 && sizeof(U) <= 4, + "format types larger than 32bits are not supported"); +} -#ifndef MAGNUM_TARGET_GLES -template constexpr CompressedImageView::CompressedImageView(const GL::CompressedPixelFormat format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: CompressedImageView{{}, format, size, data} {} +template template inline ImageView::ImageView(const PixelStorage storage, const T format, const VectorTypeFor& size) noexcept: ImageView{storage, UnsignedInt(format), {}, Implementation::pixelSizeAdl(format), size} { + static_assert(sizeof(T) <= 4, + "format types larger than 32bits are not supported"); +} -template constexpr CompressedImageView::CompressedImageView(const GL::CompressedPixelFormat format, const VectorTypeFor& size) noexcept: CompressedImageView{{}, format, size} {} -#endif +template template inline CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const T format, const VectorTypeFor& size, const Containers::ArrayView data) noexcept: CompressedImageView{storage, UnsignedInt(format), size, data} { + static_assert(sizeof(T) <= 4, + "format types larger than 32bits are not supported"); +} + +template template inline CompressedImageView::CompressedImageView(const CompressedPixelStorage storage, const T format, const VectorTypeFor& size) noexcept: CompressedImageView{storage, UnsignedInt(format), size} { + static_assert(sizeof(T) <= 4, + "format types larger than 32bits are not supported"); +} } diff --git a/src/Magnum/Magnum.h b/src/Magnum/Magnum.h index 07b36203a..1bd37b7dd 100644 --- a/src/Magnum/Magnum.h +++ b/src/Magnum/Magnum.h @@ -698,10 +698,11 @@ typedef CompressedImageView<1> CompressedImageView1D; typedef CompressedImageView<2> CompressedImageView2D; typedef CompressedImageView<3> CompressedImageView3D; +enum class PixelFormat: UnsignedInt; +enum class CompressedPixelFormat: UnsignedInt; + class PixelStorage; -#ifndef MAGNUM_TARGET_GLES class CompressedPixelStorage; -#endif enum class ResourceState: UnsignedByte; enum class ResourceDataState: UnsignedByte; @@ -771,9 +772,7 @@ typedef CORRADE_DEPRECATED("use GL::MultisampleTexture2D instead") GL::Multisamp typedef CORRADE_DEPRECATED("use GL::MultisampleTexture2DArray instead") GL::MultisampleTexture2DArray MultisampleTexture2DArray; #endif -typedef CORRADE_DEPRECATED("use GL::PixelFormat instead") GL::PixelFormat PixelFormat; typedef CORRADE_DEPRECATED("use GL::PixelType instead") GL::PixelType PixelType; -typedef CORRADE_DEPRECATED("use GL::CompressedPixelFormat instead") GL::CompressedPixelFormat CompressedPixelFormat; typedef CORRADE_DEPRECATED("use GL::PrimitiveQuery instead") GL::PrimitiveQuery PrimitiveQuery; typedef CORRADE_DEPRECATED("use GL::SampleQuery instead") GL::SampleQuery SampleQuery; diff --git a/src/Magnum/PixelFormat.cpp b/src/Magnum/PixelFormat.cpp new file mode 100644 index 000000000..4a38e889d --- /dev/null +++ b/src/Magnum/PixelFormat.cpp @@ -0,0 +1,369 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Magnum/PixelFormat.h" + +#include +#include + +namespace Magnum { + +UnsignedInt pixelSize(const PixelFormat format) { + CORRADE_ASSERT(!(UnsignedInt(format) & (1 << 31)), + "pixelSize(): can't determine pixel size of an implementation-specific format", {}); + + switch(format) { + case PixelFormat::R8Unorm: + case PixelFormat::R8Snorm: + case PixelFormat::R8UI: + case PixelFormat::R8I: + return 1; + case PixelFormat::RG8Unorm: + case PixelFormat::RG8Snorm: + case PixelFormat::RG8UI: + case PixelFormat::RG8I: + case PixelFormat::R16Unorm: + case PixelFormat::R16Snorm: + case PixelFormat::R16UI: + case PixelFormat::R16I: + case PixelFormat::R16F: + return 2; + case PixelFormat::RGB8Unorm: + case PixelFormat::RGB8Snorm: + case PixelFormat::RGB8UI: + case PixelFormat::RGB8I: + return 3; + case PixelFormat::RGBA8Unorm: + case PixelFormat::RGBA8Snorm: + case PixelFormat::RGBA8UI: + case PixelFormat::RGBA8I: + case PixelFormat::RG16Unorm: + case PixelFormat::RG16Snorm: + case PixelFormat::RG16UI: + case PixelFormat::RG16I: + case PixelFormat::RG16F: + case PixelFormat::R32UI: + case PixelFormat::R32I: + case PixelFormat::R32F: + return 4; + case PixelFormat::RGB16Unorm: + case PixelFormat::RGB16Snorm: + case PixelFormat::RGB16UI: + case PixelFormat::RGB16I: + case PixelFormat::RGB16F: + return 6; + case PixelFormat::RGBA16Unorm: + case PixelFormat::RGBA16Snorm: + case PixelFormat::RGBA16UI: + case PixelFormat::RGBA16I: + case PixelFormat::RGBA16F: + case PixelFormat::RG32UI: + case PixelFormat::RG32I: + case PixelFormat::RG32F: + return 8; + case PixelFormat::RGB32UI: + case PixelFormat::RGB32I: + case PixelFormat::RGB32F: + return 12; + case PixelFormat::RGBA32UI: + case PixelFormat::RGBA32I: + case PixelFormat::RGBA32F: + return 16; + + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + CORRADE_IGNORE_DEPRECATED_PUSH + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + case PixelFormat::Red: + #endif + #ifndef MAGNUM_TARGET_GLES + case PixelFormat::Green: + case PixelFormat::Blue: + #endif + #ifdef MAGNUM_TARGET_GLES2 + case PixelFormat::Luminance: + #endif + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + case PixelFormat::RG: + #endif + #ifdef MAGNUM_TARGET_GLES2 + case PixelFormat::LuminanceAlpha: + #endif + case PixelFormat::RGB: + case PixelFormat::RGBA: + #ifndef MAGNUM_TARGET_GLES + case PixelFormat::BGR: + #endif + #ifndef MAGNUM_TARGET_WEBGL + case PixelFormat::BGRA: + #endif + #ifdef MAGNUM_TARGET_GLES2 + case PixelFormat::SRGB: + case PixelFormat::SRGBAlpha: + #endif + #ifndef MAGNUM_TARGET_GLES2 + case PixelFormat::RedInteger: + #ifndef MAGNUM_TARGET_GLES + case PixelFormat::GreenInteger: + case PixelFormat::BlueInteger: + #endif + case PixelFormat::RGInteger: + case PixelFormat::RGBInteger: + case PixelFormat::RGBAInteger: + #ifndef MAGNUM_TARGET_GLES + case PixelFormat::BGRInteger: + case PixelFormat::BGRAInteger: + #endif + #endif + case PixelFormat::DepthComponent: + #ifndef MAGNUM_TARGET_WEBGL + case PixelFormat::StencilIndex: + #endif + case PixelFormat::DepthStencil: + /** @todo CORRADE_ASSERT_UNREACHABLE() with message here */ + CORRADE_ASSERT(false, + "pixelSize(): called with deprecated GL-specific format, use GL::pixelSize() instead", {}); + CORRADE_IGNORE_DEPRECATED_POP + #endif + } + + CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ +} + +#ifndef DOXYGEN_GENERATING_OUTPUT +Debug& operator<<(Debug& debug, const PixelFormat value) { + if(isPixelFormatImplementationSpecific(value)) { + return debug << "PixelFormat::ImplementationSpecific(" << Debug::nospace << reinterpret_cast(pixelFormatUnwrap(value)) << Debug::nospace << ")"; + } + + switch(value) { + /* LCOV_EXCL_START */ + #define _c(value) case PixelFormat::value: return debug << "PixelFormat::" #value; + _c(R8Unorm) + _c(RG8Unorm) + _c(RGB8Unorm) + _c(RGBA8Unorm) + _c(R8Snorm) + _c(RG8Snorm) + _c(RGB8Snorm) + _c(RGBA8Snorm) + _c(R8UI) + _c(RG8UI) + _c(RGB8UI) + _c(RGBA8UI) + _c(R8I) + _c(RG8I) + _c(RGB8I) + _c(RGBA8I) + _c(R16Unorm) + _c(RG16Unorm) + _c(RGB16Unorm) + _c(RGBA16Unorm) + _c(R16Snorm) + _c(RG16Snorm) + _c(RGB16Snorm) + _c(RGBA16Snorm) + _c(R16UI) + _c(RG16UI) + _c(RGB16UI) + _c(RGBA16UI) + _c(R16I) + _c(RG16I) + _c(RGB16I) + _c(RGBA16I) + _c(R32UI) + _c(RG32UI) + _c(RGB32UI) + _c(RGBA32UI) + _c(R32I) + _c(RG32I) + _c(RGB32I) + _c(RGBA32I) + _c(R16F) + _c(RG16F) + _c(RGB16F) + _c(RGBA16F) + _c(R32F) + _c(RG32F) + _c(RGB32F) + _c(RGBA32F) + #undef _c + + /* Verbatim copy from GL/PixelFormat.cpp. Here mainly to suppress + compiler warnings about unhandled cases, to check that all values + from the original enum are present and also to check that there are + no accidentally conflicting values. */ + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + CORRADE_IGNORE_DEPRECATED_PUSH + #define _c(value) case PixelFormat::value: return debug << "GL::PixelFormat::" #value; + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + _c(Red) + #endif + #ifndef MAGNUM_TARGET_GLES + _c(Green) + _c(Blue) + #endif + #ifdef MAGNUM_TARGET_GLES2 + _c(Luminance) + #endif + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + _c(RG) + #endif + #ifdef MAGNUM_TARGET_GLES2 + _c(LuminanceAlpha) + #endif + _c(RGB) + _c(RGBA) + #ifndef MAGNUM_TARGET_GLES + _c(BGR) + #endif + #ifndef MAGNUM_TARGET_WEBGL + _c(BGRA) + #endif + #ifdef MAGNUM_TARGET_GLES2 + _c(SRGB) + _c(SRGBAlpha) + #endif + #ifndef MAGNUM_TARGET_GLES2 + _c(RedInteger) + #ifndef MAGNUM_TARGET_GLES + _c(GreenInteger) + _c(BlueInteger) + #endif + _c(RGInteger) + _c(RGBInteger) + _c(RGBAInteger) + #ifndef MAGNUM_TARGET_GLES + _c(BGRInteger) + _c(BGRAInteger) + #endif + #endif + _c(DepthComponent) + #ifndef MAGNUM_TARGET_WEBGL + _c(StencilIndex) + #endif + _c(DepthStencil) + #undef _c + CORRADE_IGNORE_DEPRECATED_POP + #endif + /* LCOV_EXCL_STOP */ + } + + return debug << "PixelFormat(" << Debug::nospace << reinterpret_cast(UnsignedInt(value)) << Debug::nospace << ")"; +} +#endif + +#ifndef DOXYGEN_GENERATING_OUTPUT +Debug& operator<<(Debug& debug, const CompressedPixelFormat value) { + if(isCompressedPixelFormatImplementationSpecific(value)) { + return debug << "CompressedPixelFormat::ImplementationSpecific(" << Debug::nospace << reinterpret_cast(compressedPixelFormatUnwrap(value)) << Debug::nospace << ")"; + } + + switch(value) { + /* LCOV_EXCL_START */ + #define _c(value) case CompressedPixelFormat::value: return debug << "CompressedPixelFormat::" #value; + _c(Bc1RGBUnorm) + _c(Bc1RGBAUnorm) + _c(Bc2RGBAUnorm) + _c(Bc3RGBAUnorm) + #undef _c + + /* Verbatim copy from GL/PixelFormat.cpp. Here mainly to suppress + compiler warnings about unhandled cases, to check that all values + from the original enum are present and also to check that there are + no accidentally conflicting values. */ + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + CORRADE_IGNORE_DEPRECATED_PUSH + #define _c(value) case CompressedPixelFormat::value: return debug << "GL::CompressedPixelFormat::" #value; + #ifndef MAGNUM_TARGET_GLES + _c(Red) + _c(RG) + _c(RGB) + _c(RGBA) + _c(RedRgtc1) + _c(RGRgtc2) + _c(SignedRedRgtc1) + _c(SignedRGRgtc2) + _c(RGBBptcUnsignedFloat) + _c(RGBBptcSignedFloat) + _c(RGBABptcUnorm) + _c(SRGBAlphaBptcUnorm) + #endif + #ifndef MAGNUM_TARGET_GLES2 + _c(RGB8Etc2) + _c(SRGB8Etc2) + _c(RGB8PunchthroughAlpha1Etc2) + _c(SRGB8PunchthroughAlpha1Etc2) + _c(RGBA8Etc2Eac) + _c(SRGB8Alpha8Etc2Eac) + _c(R11Eac) + _c(SignedR11Eac) + _c(RG11Eac) + _c(SignedRG11Eac) + #endif + _c(RGBS3tcDxt1) + _c(RGBAS3tcDxt1) + _c(RGBAS3tcDxt3) + _c(RGBAS3tcDxt5) + #ifndef MAGNUM_TARGET_WEBGL + _c(RGBAAstc4x4) + _c(SRGB8Alpha8Astc4x4) + _c(RGBAAstc5x4) + _c(SRGB8Alpha8Astc5x4) + _c(RGBAAstc5x5) + _c(SRGB8Alpha8Astc5x5) + _c(RGBAAstc6x5) + _c(SRGB8Alpha8Astc6x5) + _c(RGBAAstc6x6) + _c(SRGB8Alpha8Astc6x6) + _c(RGBAAstc8x5) + _c(SRGB8Alpha8Astc8x5) + _c(RGBAAstc8x6) + _c(SRGB8Alpha8Astc8x6) + _c(RGBAAstc8x8) + _c(SRGB8Alpha8Astc8x8) + _c(RGBAAstc10x5) + _c(SRGB8Alpha8Astc10x5) + _c(RGBAAstc10x6) + _c(SRGB8Alpha8Astc10x6) + _c(RGBAAstc10x8) + _c(SRGB8Alpha8Astc10x8) + _c(RGBAAstc10x10) + _c(SRGB8Alpha8Astc10x10) + _c(RGBAAstc12x10) + _c(SRGB8Alpha8Astc12x10) + _c(RGBAAstc12x12) + _c(SRGB8Alpha8Astc12x12) + #undef _c + #endif + CORRADE_IGNORE_DEPRECATED_POP + #endif + /* LCOV_EXCL_STOP */ + } + + return debug << "CompressedPixelFormat(" << Debug::nospace << reinterpret_cast(UnsignedInt(value)) << Debug::nospace << ")"; +} +#endif + +} diff --git a/src/Magnum/PixelFormat.h b/src/Magnum/PixelFormat.h index 763118e29..29d9cce8c 100644 --- a/src/Magnum/PixelFormat.h +++ b/src/Magnum/PixelFormat.h @@ -26,16 +26,1121 @@ */ /** @file - * @deprecated Use @ref Magnum/GL/PixelFormat.h instead. + * @brief Enum @ref Magnum::PixelFormat, @ref Magnum::CompressedPixelFormat, function @ref Magnum::pixelSize(), @ref Magnum::isPixelFormatImplementationSpecific(), @ref Magnum::pixelFormatWrap(), @ref Magnum::pixelFormatUnwrap(), @ref Magnum::isCompressedPixelFormatImplementationSpecific(), @ref Magnum::compressedPixelFormatWrap(), @ref Magnum::compressedPixelFormatUnwrap() */ -#include "Magnum/configure.h" +#include + +#include "Magnum/Magnum.h" +#include "Magnum/visibility.h" #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) #include "Magnum/GL/PixelFormat.h" -CORRADE_DEPRECATED_FILE("use Magnum/GL/PixelFormat.h instead") -#else -#error use Magnum/GL/PixelFormat.h instead #endif +namespace Magnum { + +/** +@brief Format of pixel data + +Can act also as a wrapper for implementation-specific pixel format values using +@ref pixelFormatWrap() and @ref pixelFormatUnwrap(). Distinction between +generic and implementation-specific formats can be done using +@ref isPixelFormatImplementationSpecific(). + +In case of OpenGL, corresponds to @ref GL::PixelFormat and @ref GL::PixelType +and is convertible to them using @ref GL::pixelFormat() and +@ref GL::pixelType(). See documentation of each value for more information +about the mapping. Note that not every format is available on all targets, use +@ref GL::hasPixelFormat() to check for its presence. + +@see @ref pixelSize(), @ref CompressedPixelFormat, @ref Image, @ref ImageView +*/ +enum class PixelFormat: UnsignedInt { + /** + * Red component, normalized unsigned byte. + * + * Corresponds to @ref GL::PixelFormat::Red and + * @ref GL::PixelType::UnsignedByte, @ref GL::TextureFormat::R8. + */ + R8Unorm, + + /** + * Red and green component, normalized unsigned byte. + * + * Corresponds to @ref GL::PixelFormat::RG and + * @ref GL::PixelType::UnsignedByte, @ref GL::TextureFormat::RG8. + */ + RG8Unorm, + + /** + * RGB, normalized unsigned byte. + * + * Corresponds to @ref GL::PixelFormat::RGB and + * @ref GL::PixelType::UnsignedByte, @ref GL::TextureFormat::RGB8. + */ + RGB8Unorm, + + /** + * RGBA, normalized unsigned byte. + * + * Corresponds to @ref GL::PixelFormat::RGBA and + * @ref GL::PixelType::UnsignedByte, @ref GL::TextureFormat::RGBA8. + */ + RGBA8Unorm, + + /** + * Red component, normalized signed byte. + * + * Corresponds to @ref GL::PixelFormat::Red and + * @ref GL::PixelType::Byte, @ref GL::TextureFormat::R8Snorm. + */ + R8Snorm, + + /** + * Red and green component, normalized signed byte. + * + * Corresponds to @ref GL::PixelFormat::RG and + * @ref GL::PixelType::Byte, @ref GL::TextureFormat::RG8Snorm. + */ + RG8Snorm, + + /** + * RGB, normalized signed byte. + * + * Corresponds to @ref GL::PixelFormat::RGB and + * @ref GL::PixelType::Byte, @ref GL::TextureFormat::RGB8Snorm. + */ + RGB8Snorm, + + /** + * RGBA, normalized signed byte. + * + * Corresponds to @ref GL::PixelFormat::RGBA and + * @ref GL::PixelType::Byte, @ref GL::TextureFormat::RGBA8Snorm. + */ + RGBA8Snorm, + + /** + * Red component, integral unsigned byte. + * + * Corresponds to @ref GL::PixelFormat::RedInteger and + * @ref GL::PixelType::UnsignedByte, @ref GL::TextureFormat::R8UI. + */ + R8UI, + + /** + * Red and green component, integral unsigned byte. + * + * Corresponds to @ref GL::PixelFormat::RGInteger and + * @ref GL::PixelType::UnsignedByte, @ref GL::TextureFormat::RG8UI. + */ + RG8UI, + + /** + * RGB, integral unsigned byte. + * + * Corresponds to @ref GL::PixelFormat::RGBInteger and + * @ref GL::PixelType::UnsignedByte, @ref GL::TextureFormat::RGB8UI. + */ + RGB8UI, + + /** + * RGBA, integral unsigned byte. + * + * Corresponds to @ref GL::PixelFormat::RGBAInteger and + * @ref GL::PixelType::UnsignedByte, @ref GL::TextureFormat::RGBA8UI. + */ + RGBA8UI, + + /** + * Red component, integral signed byte. + * + * Corresponds to @ref GL::PixelFormat::RedInteger and + * @ref GL::PixelType::Byte, @ref GL::TextureFormat::R8I. + */ + R8I, + + /** + * Red and green component, integral signed byte. + * + * Corresponds to @ref GL::PixelFormat::RGInteger and + * @ref GL::PixelType::Byte, @ref GL::TextureFormat::RG8I. + */ + RG8I, + + /** + * RGB, integral signed byte. + * + * Corresponds to @ref GL::PixelFormat::RGBInteger and + * @ref GL::PixelType::Byte, @ref GL::TextureFormat::RGB8I. + */ + RGB8I, + + /** + * RGBA, integral signed byte. + * + * Corresponds to @ref GL::PixelFormat::RGBAInteger and + * @ref GL::PixelType::Byte, @ref GL::TextureFormat::RGBA8I. + */ + RGBA8I, + + /** + * Red component, normalized unsigned short. + * + * Corresponds to @ref GL::PixelFormat::Red and + * @ref GL::PixelType::UnsignedShort, @ref GL::TextureFormat::R16. + */ + R16Unorm, + + /** + * Red and green component, normalized unsigned short. + * + * Corresponds to @ref GL::PixelFormat::RG and + * @ref GL::PixelType::UnsignedShort, @ref GL::TextureFormat::RG16. + */ + RG16Unorm, + + /** + * RGB, normalized unsigned short. + * + * Corresponds to @ref GL::PixelFormat::RGB and + * @ref GL::PixelType::UnsignedShort, @ref GL::TextureFormat::RGB16. + */ + RGB16Unorm, + + /** + * RGBA, normalized unsigned short. + * + * Corresponds to @ref GL::PixelFormat::RGBA and + * @ref GL::PixelType::UnsignedShort, @ref GL::TextureFormat::RGBA16. + */ + RGBA16Unorm, + + /** + * Red component, normalized signed short. + * + * Corresponds to @ref GL::PixelFormat::Red and + * @ref GL::PixelType::Short, @ref GL::TextureFormat::R16Snorm. + */ + R16Snorm, + + /** + * Red and green component, normalized signed short. + * + * Corresponds to @ref GL::PixelFormat::RG and + * @ref GL::PixelType::Short, @ref GL::TextureFormat::RG16Snorm. + */ + RG16Snorm, + + /** + * RGB, normalized signed short. + * + * Corresponds to @ref GL::PixelFormat::RGB and + * @ref GL::PixelType::Short, @ref GL::TextureFormat::RGB16Snorm. + */ + RGB16Snorm, + + /** + * RGBA, normalized signed short. + * + * Corresponds to @ref GL::PixelFormat::RGBA and + * @ref GL::PixelType::Short, @ref GL::TextureFormat::RGBA16Snorm. + */ + RGBA16Snorm, + + /** + * Red component, integral unsigned short. + * + * Corresponds to @ref GL::PixelFormat::RedInteger and + * @ref GL::PixelType::UnsignedShort, @ref GL::TextureFormat::R16UI. + */ + R16UI, + + /** + * Red and green component, integral unsigned short. + * + * Corresponds to @ref GL::PixelFormat::RGInteger and + * @ref GL::PixelType::UnsignedShort, @ref GL::TextureFormat::RG16UI. + */ + RG16UI, + + /** + * RGB, integral unsigned short. + * + * Corresponds to @ref GL::PixelFormat::RGBInteger and + * @ref GL::PixelType::UnsignedShort, @ref GL::TextureFormat::RGB16UI. + */ + RGB16UI, + + /** + * RGBA, integral unsigned short. + * + * Corresponds to @ref GL::PixelFormat::RGBAInteger and + * @ref GL::PixelType::UnsignedShort, @ref GL::TextureFormat::RGBA16UI. + */ + RGBA16UI, + + /** + * Red component, integral signed short. + * + * Corresponds to @ref GL::PixelFormat::RedInteger and + * @ref GL::PixelType::Short, @ref GL::TextureFormat::R16I. + */ + R16I, + + /** + * Red and green component, integral signed short. + * + * Corresponds to @ref GL::PixelFormat::RGInteger and + * @ref GL::PixelType::Short, @ref GL::TextureFormat::RG16I. + */ + RG16I, + + /** + * RGB, integral signed short. + * + * Corresponds to @ref GL::PixelFormat::RGBInteger and + * @ref GL::PixelType::Short, @ref GL::TextureFormat::RGB16I. + */ + RGB16I, + + /** + * RGBA, integral signed short. + * + * Corresponds to @ref GL::PixelFormat::RGBAInteger and + * @ref GL::PixelType::Short, @ref GL::TextureFormat::RGBA16I. + */ + RGBA16I, + + /** + * Red component, integral unsigned int. + * + * Corresponds to @ref GL::PixelFormat::RedInteger and + * @ref GL::PixelType::UnsignedInt, @ref GL::TextureFormat::R32UI. + */ + R32UI, + + /** + * Red and green component, integral unsigned int. + * + * Corresponds to @ref GL::PixelFormat::RGInteger and + * @ref GL::PixelType::UnsignedInt, @ref GL::TextureFormat::RG32UI. + */ + RG32UI, + + /** + * RGB, integral unsigned int. + * + * Corresponds to @ref GL::PixelFormat::RGBInteger and + * @ref GL::PixelType::UnsignedInt, @ref GL::TextureFormat::RGB32UI. + */ + RGB32UI, + + /** + * RGBA, integral unsigned int. + * + * Corresponds to @ref GL::PixelFormat::RGBAInteger and + * @ref GL::PixelType::UnsignedInt, @ref GL::TextureFormat::RGBA32UI. + */ + RGBA32UI, + + /** + * Red component, integral signed int. + * + * Corresponds to @ref GL::PixelFormat::RedInteger and + * @ref GL::PixelType::Int, @ref GL::TextureFormat::R32I. + */ + R32I, + + /** + * Red and green component, integral signed int. + * + * Corresponds to @ref GL::PixelFormat::RGInteger and + * @ref GL::PixelType::Int, @ref GL::TextureFormat::RG32I. + */ + RG32I, + + /** + * RGB, integral signed int. + * + * Corresponds to @ref GL::PixelFormat::RGBInteger and + * @ref GL::PixelType::Int, @ref GL::TextureFormat::RGB32I. + */ + RGB32I, + + /** + * RGBA, integral signed int. + * + * Corresponds to @ref GL::PixelFormat::RGBAInteger and + * @ref GL::PixelType::Int, @ref GL::TextureFormat::RGBA32I. + */ + RGBA32I, + + /** + * Red component, half float. + * + * Corresponds to @ref GL::PixelFormat::Red and + * @ref GL::PixelType::HalfFloat, @ref GL::TextureFormat::R16F. + * @see @ref Half, @ref Math::packHalf(), @ref Math::unpackHalf() + */ + R16F, + + /** + * Red and green component, half float. + * + * Corresponds to @ref GL::PixelFormat::RG and + * @ref GL::PixelType::HalfFloat, @ref GL::TextureFormat::RG16F. + * @see @ref Half, @ref Math::packHalf(), @ref Math::unpackHalf() + */ + RG16F, + + /** + * RGB, half float. + * + * Corresponds to @ref GL::PixelFormat::RGB and + * @ref GL::PixelType::HalfFloat, @ref GL::TextureFormat::RGB16F. + * @see @ref Half, @ref Math::packHalf(), @ref Math::unpackHalf() + */ + RGB16F, + + /** + * RGBA, half float. + * + * Corresponds to @ref GL::PixelFormat::RGBA and + * @ref GL::PixelType::HalfFloat, @ref GL::TextureFormat::RGBA16F. + * @see @ref Half, @ref Math::packHalf(), @ref Math::unpackHalf() + */ + RGBA16F, + + /** + * Red component, half float. + * + * Corresponds to @ref GL::PixelFormat::Red and + * @ref GL::PixelType::Float, @ref GL::TextureFormat::R32F. + */ + R32F, + + /** + * Red and green component, half float. + * + * Corresponds to @ref GL::PixelFormat::RG and + * @ref GL::PixelType::Float, @ref GL::TextureFormat::RG32F. + */ + RG32F, + + /** + * RGB, half float. + * + * Corresponds to @ref GL::PixelFormat::RGB and + * @ref GL::PixelType::Float, @ref GL::TextureFormat::RGB32F. + */ + RGB32F, + + /** + * RGBA, half float. + * + * Corresponds to @ref GL::PixelFormat::RGBA and + * @ref GL::PixelType::Float, @ref GL::TextureFormat::RGBA32F. + */ + RGBA32F, + + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + /** + * Floating-point red channel. + * @deprecated Use @ref GL::PixelFormat::Red or any of the complete + * single-channel formats instead. + */ + Red CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::Red or any of the complete single-channel formats instead") = UnsignedInt(GL::PixelFormat::Red), + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * Floating-point green channel. + * @deprecated Use @ref GL::PixelFormat::Green or any of the complete + * single-channel formats instead. + */ + Green CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::Green or any of the complete single-channel formats instead") = UnsignedInt(GL::PixelFormat::Green), + + /** + * Floating-point blue channel. + * @deprecated Use @ref GL::PixelFormat::Blue or any of the complete + * single-channel formats instead. + */ + Blue CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::Blue or any of the complete single-channel formats instead") = UnsignedInt(GL::PixelFormat::Blue), + #endif + + #if defined(MAGNUM_TARGET_GLES2) || defined(DOXYGEN_GENERATING_OUTPUT) + /** + * Floating-point luminance channel. The value is used for all RGB + * channels. + * @deprecated Use @ref GL::PixelFormat::Luminance or any of the complete + * single-channel formats instead. + */ + Luminance CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::Luminance or any of the complete single-channel formats instead") = UnsignedInt(GL::PixelFormat::Luminance), + #endif + + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + /** + * Floating-point red and green channel. + * @deprecated Use @ref GL::PixelFormat::RG or any of the complete + * two-channel formats instead. + */ + RG CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::RG or any of the complete two-channel formats instead") = UnsignedInt(GL::PixelFormat::RG), + #endif + + #if defined(MAGNUM_TARGET_GLES2) || defined(DOXYGEN_GENERATING_OUTPUT) + /** + * Floating-point luminance and alpha channel. First value is used for all + * RGB channels, second value is used for alpha channel. + * @deprecated Use @ref GL::PixelFormat::LuminanceAlpha or any of the + * complete two-channel formats instead. + */ + LuminanceAlpha CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::LuminanceAlpha or any of the complete two-channel formats instead") = UnsignedInt(GL::PixelFormat::LuminanceAlpha), + #endif + + /** + * Floating-point RGB. + * @deprecated Use @ref GL::PixelFormat::RGB or any of the complete + * three-channel formats instead. + */ + RGB CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::RGB or any of the complete three-channel formats instead") = UnsignedInt(GL::PixelFormat::RGB), + + /** + * Floating-point RGBA. + * @deprecated Use @ref GL::PixelFormat::RGBA or any of the complete + * four-channel formats instead. + */ + RGBA CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::RGBA or any of the complete four-channel formats instead") = UnsignedInt(GL::PixelFormat::RGBA), + + #ifndef MAGNUM_TARGET_GLES + /** + * Floating-point BGR. + * @deprecated Use @ref GL::PixelFormat::BGR or any of the complete + * three-channel formats instead. + */ + BGR CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::BGR or any of the complete three-channel formats instead") = UnsignedInt(GL::PixelFormat::BGR), + #endif + + #ifndef MAGNUM_TARGET_WEBGL + /** + * Floating-point BGRA. + * @deprecated Use @ref GL::PixelFormat::BGRA or any of the complete + * four-channel formats instead. + */ + BGRA CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::BGRA or any of the complete four-channel formats instead") = UnsignedInt(GL::PixelFormat::BGRA), + #endif + + #if defined(MAGNUM_TARGET_GLES2) || defined(DOXYGEN_GENERATING_OUTPUT) + /** + * Floating-point sRGB. + * @deprecated Use @ref GL::PixelFormat::SRGB or any of the complete + * three-channel formats instead. + */ + SRGB CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::SRGB or any of the complete three-channel formats instead") = UnsignedInt(GL::PixelFormat::SRGB), + + /** + * Floating-point sRGB + alpha. + * @deprecated Use @ref GL::PixelFormat::SRGBAlpha or any of the complete + * four-channel formats instead. + */ + SRGBAlpha CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::SRGBAlpha or any of the complete four-channel formats instead") = UnsignedInt(GL::PixelFormat::SRGBAlpha), + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * Integer red channel. + * @deprecated Use @ref GL::PixelFormat::RedInteger or any of the complete + * single-channel formats instead. + */ + RedInteger CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::RedInteger or any of the complete single-channel formats instead") = UnsignedInt(GL::PixelFormat::RedInteger), + + #ifndef MAGNUM_TARGET_GLES + /** + * Integer green channel. + * @deprecated Use @ref GL::PixelFormat::GreenInteger or any of the + * complete single-channel formats instead. + */ + GreenInteger CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::GreenInteger or any of the complete single-channel formats instead") = UnsignedInt(GL::PixelFormat::GreenInteger), + + /** + * Integer blue channel. + * @deprecated Use @ref GL::PixelFormat::BlueInteger or any of the complete + * single-channel formats instead. + */ + BlueInteger CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::BlueInteger or any of the complete single-channel formats instead") = UnsignedInt(GL::PixelFormat::BlueInteger), + #endif + + /** + * Integer red and green channel. + * @deprecated Use @ref GL::PixelFormat::RGInteger or any of the complete + * two-channel formats instead. + */ + RGInteger CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::RGInteger or any of the complete two-channel formats instead") = UnsignedInt(GL::PixelFormat::RGInteger), + + /** + * Integer RGB. + * @deprecated Use @ref GL::PixelFormat::RGBInteger or any of the complete + * three-channel formats instead. + */ + RGBInteger CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::RGBInteger or any of the complete three-channel formats instead") = UnsignedInt(GL::PixelFormat::RGBInteger), + + /** + * Integer RGBA. + * @deprecated Use @ref GL::PixelFormat::RGBAInteger or any of the complete + * four-channel formats instead. + */ + RGBAInteger CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::RGBAInteger or any of the complete four-channel formats instead") = UnsignedInt(GL::PixelFormat::RGBAInteger), + + #ifndef MAGNUM_TARGET_GLES + /** + * Integer BGR. + * @deprecated Use @ref GL::PixelFormat::BGRInteger or any of the complete + * three-channel formats instead. + */ + BGRInteger CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::BGRInteger or any of the complete three-channel formats instead") = UnsignedInt(GL::PixelFormat::BGRInteger), + + /** + * Integer BGRA. + * @deprecated Use @ref GL::PixelFormat::BGRAInteger or any of the complete + * four-channel formats instead. + */ + BGRAInteger CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::BGRAInteger or any of the complete four-channel formats instead") = UnsignedInt(GL::PixelFormat::BGRAInteger), + #endif + #endif + + /** + * Depth component. + * @deprecated Use @ref GL::PixelFormat::DepthComponent or any of the + * complete depth formats instead. + */ + DepthComponent CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::DepthComponent or any of the complete depth formats instead") = UnsignedInt(GL::PixelFormat::DepthComponent), + + #ifndef MAGNUM_TARGET_WEBGL + /** + * Stencil index. + * @deprecated Use @ref GL::PixelFormat::StencilIndex or any of the + * complete stencil formats instead. + */ + StencilIndex CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::StencilIndex or any of the complete stencil formats instead") = UnsignedInt(GL::PixelFormat::StencilIndex), + #endif + + /** + * Depth and stencil. + * @deprecated Use @ref GL::PixelFormat::DepthStencil or any of the + * complete depth+stencil formats instead. + */ + DepthStencil CORRADE_DEPRECATED_ENUM("use GL::PixelFormat::DepthStencil or any of the complete depth+stencil formats instead") = UnsignedInt(GL::PixelFormat::DepthStencil) + #endif +}; + +#ifdef MAGNUM_BUILD_DEPRECATED +/** @brief @copybrief GL::PixelType + * @deprecated Use @ref GL::PixelType instead. + */ +typedef CORRADE_DEPRECATED("use GL::PixelType instead") GL::PixelType PixelType; +#endif + +/** +@brief Pixel size + +Expects that the pixel format is *not* implementation-specific. +@see @ref isPixelFormatImplementationSpecific(), @ref GL::pixelSize() +*/ +MAGNUM_EXPORT UnsignedInt pixelSize(PixelFormat format); + +/** @debugoperatorenum{PixelFormat} */ +MAGNUM_EXPORT Debug& operator<<(Debug& debug, PixelFormat value); + +/** +@brief Whether a @ref PixelFormat value wraps an implementation-specific identifier + +Returns @cpp true @ce if value of @p format has its highest bit set, @cpp false @ce +otherwise. Use @ref pixelFormatWrap() and @ref pixelFormatUnwrap() to +wrap/unwrap an implementation-specific indentifier to/from @ref PixelFormat. +@see @ref isCompressedPixelFormatImplementationSpecific() +*/ +constexpr bool isPixelFormatImplementationSpecific(PixelFormat format) { + return UnsignedInt(format) & (1u << 31); +} + +/** +@brief Wrap an implementation-specific pixel format identifier in @ref PixelFormat + +Sets the highest bit on @p format to mark it as implementation-specific. +Expects that @p format fits into the remaining bits. Use @ref pixelFormatUnwrap() +for the inverse operation. +@see @ref isPixelFormatImplementationSpecific(), @ref compressedPixelFormatWrap() +*/ +template constexpr PixelFormat pixelFormatWrap(T implementationSpecific) { + static_assert(sizeof(T) <= 4, + "format types larger than 32bits are not supported"); + return CORRADE_CONSTEXPR_ASSERT(!(UnsignedInt(implementationSpecific) & (1u << 31)), + "pixelFormatWrap(): implementation-specific value already wrapped or too large"), + PixelFormat((1u << 31)|UnsignedInt(implementationSpecific)); +} + +/** +@brief Unwrap an implementation-specific pixel format identifier from @ref PixelFormat + +Unsets the highest bit from @p format to extract the implementation-specific +value. Expects that @p format has it set. Use @ref pixelFormatWrap() for the +inverse operation. +@see @ref isPixelFormatImplementationSpecific(), @ref compressedPixelFormatUnwrap() +*/ +template constexpr T pixelFormatUnwrap(PixelFormat format) { + return CORRADE_CONSTEXPR_ASSERT(UnsignedInt(format) & (1u << 31), + "pixelFormatUnwrap(): format doesn't contain a wrapped implementation-specific value"), + T(UnsignedInt(format) & ~(1u << 31)); +} + +/** +@brief Format of compressed pixel data + +Can act also as a wrapper for implementation-specific pixel format values using +@ref compressedPixelFormatWrap() and @ref compressedPixelFormatUnwrap(). +Distinction between generic and implementation-specific formats can be done +using @ref isCompressedPixelFormatImplementationSpecific(). + +In case of OpenGL, corresponds to @ref GL::CompressedPixelFormat and is +convertible to it using @ref GL::compressedPixelFormat(). See documentation of +each value for more information about the mapping. Note that not every format +is available on all targets, use @ref GL::hasCompressedPixelFormat() to check +for its presence. + +@see @ref PixelFormat, @ref CompressedImage, @ref CompressedImageView +*/ +enum class CompressedPixelFormat: UnsignedInt { + /** + * S3TC BC1 compressed RGB (DXT1). + * + * Corresponds to @ref GL::CompressedPixelFormat::RGBS3tcDxt1, + * @ref GL::TextureFormat::RGBS3tcDxt1. + */ + Bc1RGBUnorm, + + /** + * S3TC BC1 compressed RGBA (DXT1). + * + * Corresponds to @ref GL::CompressedPixelFormat::RGBAS3tcDxt1, + * @ref GL::TextureFormat::RGBAS3tcDxt1. + */ + Bc1RGBAUnorm, + + /** + * S3TC BC2 compressed RGBA (DXT3). + * + * Corresponds to @ref GL::CompressedPixelFormat::RGBAS3tcDxt3, + * @ref GL::TextureFormat::RGBAS3tcDxt3. + */ + Bc2RGBAUnorm, + + /** + * S3TC BC3 compressed RGBA (DXT5). + * + * Corresponds to @ref GL::CompressedPixelFormat::RGBAS3tcDxt5, + * @ref GL::TextureFormat::RGBAS3tcDxt5. + */ + Bc3RGBAUnorm, + + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + #ifndef MAGNUM_TARGET_GLES + /** + * Compressed red channel, normalized unsigned. + * @deprecated Use @ref GL::CompressedPixelFormat::Red instead. + */ + Red CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::Red instead") = UnsignedInt(GL::CompressedPixelFormat::Red), + + /** + * Compressed red and green channel, normalized unsigned. + * @deprecated Use @ref GL::CompressedPixelFormat::RG instead. + */ + RG CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RG instead") = UnsignedInt(GL::CompressedPixelFormat::RG), + + /** + * Compressed RGB, normalized unsigned. + * @deprecated Use @ref GL::CompressedPixelFormat::RGB instead. + */ + RGB CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGB instead") = UnsignedInt(GL::CompressedPixelFormat::RGB), + + /** + * Compressed RGBA, normalized unsigned. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBA instead. + */ + RGBA CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBA instead") = UnsignedInt(GL::CompressedPixelFormat::RGBA), + + /** + * RGTC compressed red channel, normalized unsigned. + * @deprecated Use @ref GL::CompressedPixelFormat::RedRgtc1 instead. + */ + RedRgtc1 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RedRgtc1 instead") = UnsignedInt(GL::CompressedPixelFormat::RedRgtc1), + + /** + * RGTC compressed red and green channel, normalized unsigned. + * @deprecated Use @ref GL::CompressedPixelFormat::RGRgtc2 instead. + */ + RGRgtc2 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGRgtc2 instead") = UnsignedInt(GL::CompressedPixelFormat::RGRgtc2), + + /** + * RGTC compressed red channel, normalized signed. + * @deprecated Use @ref GL::CompressedPixelFormat::SignedRedRgtc1 instead. + */ + SignedRedRgtc1 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SignedRedRgtc1 instead") = UnsignedInt(GL::CompressedPixelFormat::SignedRedRgtc1), + + /** + * RGTC compressed red and green channel, normalized signed. + * @deprecated Use @ref GL::CompressedPixelFormat::SignedRGRgtc2 instead. + */ + SignedRGRgtc2 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SignedRGRgtc2 instead") = UnsignedInt(GL::CompressedPixelFormat::SignedRGRgtc2), + + /** + * BPTC compressed RGB, unsigned float. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBBptcUnsignedFloat instead. + */ + RGBBptcUnsignedFloat CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBBptcUnsignedFloat instead") = UnsignedInt(GL::CompressedPixelFormat::RGBBptcUnsignedFloat), + + /** + * BPTC compressed RGB, signed float. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBBptcSignedFloat instead. + */ + RGBBptcSignedFloat CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBBptcSignedFloat instead") = UnsignedInt(GL::CompressedPixelFormat::RGBBptcSignedFloat), + + /** + * BPTC compressed RGBA, normalized unsigned. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBABptcUnorm instead. + */ + RGBABptcUnorm CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBABptcUnorm instead") = UnsignedInt(GL::CompressedPixelFormat::RGBABptcUnorm), + + /** + * BPTC compressed sRGBA, normalized unsigned. + * @deprecated Use @ref GL::CompressedPixelFormat::SRGBAlphaBptcUnorm instead. + */ + SRGBAlphaBptcUnorm CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SRGBAlphaBptcUnorm instead") = UnsignedInt(GL::CompressedPixelFormat::SRGBAlphaBptcUnorm), + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * ETC2 compressed RGB, normalized unsigned. + * @deprecated Use @ref GL::CompressedPixelFormat::RGB8Etc2 instead. + */ + RGB8Etc2 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGB8Etc2 instead") = UnsignedInt(GL::CompressedPixelFormat::RGB8Etc2), + + /** + * ETC2 compressed sRGB, normalized unsigned. + * @deprecated Use @ref GL::CompressedPixelFormat::SRGB8Etc2 instead. + */ + SRGB8Etc2 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SRGB8Etc2 instead") = UnsignedInt(GL::CompressedPixelFormat::SRGB8Etc2), + + /** + * ETC2 compressed RGB with punchthrough (single-bit) alpha, normalized + * unsigned. + * @deprecated Use @ref GL::CompressedPixelFormat::RGB8PunchthroughAlpha1Etc2 instead. + */ + RGB8PunchthroughAlpha1Etc2 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGB8PunchthroughAlpha1Etc2 instead") = UnsignedInt(GL::CompressedPixelFormat::RGB8PunchthroughAlpha1Etc2), + + /** + * ETC2 compressed sRGB with punchthrough (single-bit) alpha, normalized + * unsigned. + * @deprecated Use @ref GL::CompressedPixelFormat::SRGB8PunchthroughAlpha1Etc2 instead. + */ + SRGB8PunchthroughAlpha1Etc2 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SRGB8PunchthroughAlpha1Etc2 instead") = UnsignedInt(GL::CompressedPixelFormat::SRGB8PunchthroughAlpha1Etc2), + + /** + * ETC2/EAC compressed RGBA, normalized unsigned. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBA8Etc2Eac instead. + */ + RGBA8Etc2Eac CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBA8Etc2Eac instead") = UnsignedInt(GL::CompressedPixelFormat::RGBA8Etc2Eac), + + /** + * ETC2/EAC compressed sRGB with alpha, normalized unsigned. + * @deprecated Use @ref GL::CompressedPixelFormat::SRGB8Alpha8Etc2Eac instead. + */ + SRGB8Alpha8Etc2Eac CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SRGB8Alpha8Etc2Eac instead") = UnsignedInt(GL::CompressedPixelFormat::SRGB8Alpha8Etc2Eac), + + /** + * EAC compressed red channel, normalized unsigned. + * @deprecated Use @ref GL::CompressedPixelFormat::R11Eac instead. + */ + R11Eac CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::R11Eac instead") = UnsignedInt(GL::CompressedPixelFormat::R11Eac), + + /** + * EAC compressed red channel, normalized signed. + * @deprecated Use @ref GL::CompressedPixelFormat::SignedR11Eac instead. + */ + SignedR11Eac CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SignedR11Eac instead") = UnsignedInt(GL::CompressedPixelFormat::SignedR11Eac), + + /** + * EAC compressed red and green channel, normalized unsigned. + * @deprecated Use @ref GL::CompressedPixelFormat::RG11Eac instead. + */ + RG11Eac CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RG11Eac instead") = UnsignedInt(GL::CompressedPixelFormat::RG11Eac), + + /** + * EAC compressed red and green channel, normalized signed. + * @deprecated Use @ref GL::CompressedPixelFormat::SignedRG11Eac instead. + */ + SignedRG11Eac CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SignedRG11Eac instead") = UnsignedInt(GL::CompressedPixelFormat::SignedRG11Eac), + #endif + + /** + * S3TC DXT1 compressed RGB. + * @deprecated Use @ref CompressedPixelFormat::Bc1RGBUnorm or + * @ref GL::CompressedPixelFormat::RGBS3tcDxt1 instead. + */ + RGBS3tcDxt1 CORRADE_DEPRECATED_ENUM("use CompressedPixelFormat::Bc1RGBUnorm or GL::CompressedPixelFormat::RGBS3tcDxt1 instead") = UnsignedInt(GL::CompressedPixelFormat::RGBS3tcDxt1), + + /** + * S3TC DXT1 compressed RGBA. + * @deprecated Use @ref CompressedPixelFormat::Bc1RGBAUnorm or + * @ref GL::CompressedPixelFormat::RGBAS3tcDxt1 instead. + */ + RGBAS3tcDxt1 CORRADE_DEPRECATED_ENUM("use CompressedPixelFormat::Bc1RGBAUnorm or GL::CompressedPixelFormat::RGBAS3tcDxt1 instead") = UnsignedInt(GL::CompressedPixelFormat::RGBAS3tcDxt1), + + /** + * S3TC DXT3 compressed RGBA. + * @deprecated Use @ref CompressedPixelFormat::Bc2RGBAUnorm or + * @ref GL::CompressedPixelFormat::RGBAS3tcDxt3 instead. + */ + RGBAS3tcDxt3 CORRADE_DEPRECATED_ENUM("use CompressedPixelFormat::Bc2RGBAUnorm or GL::CompressedPixelFormat::RGBAS3tcDxt3 instead") = UnsignedInt(GL::CompressedPixelFormat::RGBAS3tcDxt3), + + /** + * S3TC DXT5 compressed RGBA. + * @deprecated Use @ref CompressedPixelFormat::Bc3RGBAUnorm or + * @ref GL::CompressedPixelFormat::RGBAS3tcDxt5 instead. + */ + RGBAS3tcDxt5 CORRADE_DEPRECATED_ENUM("use CompressedPixelFormat::Bc3RGBAUnorm or GL::CompressedPixelFormat::RGBAS3tcDxt5 instead") = UnsignedInt(GL::CompressedPixelFormat::RGBAS3tcDxt5), + + #ifndef MAGNUM_TARGET_WEBGL + /** + * ASTC compressed RGBA with 4x4 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBAAstc4x4 instead. + */ + RGBAAstc4x4 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBAAstc4x4 instead") = UnsignedInt(GL::CompressedPixelFormat::RGBAAstc4x4), + + /** + * ASTC compressed sRGB with alpha with 4x4 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::SRGB8Alpha8Astc4x4 instead. + */ + SRGB8Alpha8Astc4x4 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SRGB8Alpha8Astc4x4 instead") = UnsignedInt(GL::CompressedPixelFormat::SRGB8Alpha8Astc4x4), + + /** + * ASTC compressed RGBA with 5x4 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBAAstc5x4 instead. + */ + RGBAAstc5x4 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBAAstc5x4 instead") = UnsignedInt(GL::CompressedPixelFormat::RGBAAstc5x4), + + /** + * ASTC compressed sRGB with alpha with 5x4 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::SRGB8Alpha8Astc5x4 instead. + */ + SRGB8Alpha8Astc5x4 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SRGB8Alpha8Astc5x4 instead") = UnsignedInt(GL::CompressedPixelFormat::SRGB8Alpha8Astc5x4), + + /** + * ASTC compressed RGBA with 5x5 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBAAstc5x5 instead. + */ + RGBAAstc5x5 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBAAstc5x5 instead") = UnsignedInt(GL::CompressedPixelFormat::RGBAAstc5x5), + + /** + * ASTC compressed sRGB with alpha with 5x5 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::SRGB8Alpha8Astc5x5 instead. + */ + SRGB8Alpha8Astc5x5 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SRGB8Alpha8Astc5x5 instead") = UnsignedInt(GL::CompressedPixelFormat::SRGB8Alpha8Astc5x5), + + /** + * ASTC compressed RGBA with 6x5 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBAAstc6x5 instead. + */ + RGBAAstc6x5 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBAAstc6x5 instead") = UnsignedInt(GL::CompressedPixelFormat::RGBAAstc6x5), + + /** + * ASTC compressed sRGB with alpha with 6x5 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::SRGB8Alpha8Astc6x5 instead. + */ + SRGB8Alpha8Astc6x5 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SRGB8Alpha8Astc6x5 instead") = UnsignedInt(GL::CompressedPixelFormat::SRGB8Alpha8Astc6x5), + + /** + * ASTC compressed RGBA with 6x6 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBAAstc6x6 instead. + */ + RGBAAstc6x6 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBAAstc6x6 instead") = UnsignedInt(GL::CompressedPixelFormat::RGBAAstc6x6), + + /** + * ASTC compressed sRGB with alpha with 6x6 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::SRGB8Alpha8Astc6x6 instead. + */ + SRGB8Alpha8Astc6x6 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SRGB8Alpha8Astc6x6 instead") = UnsignedInt(GL::CompressedPixelFormat::SRGB8Alpha8Astc6x6), + + /** + * ASTC compressed RGBA with 8x5 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBAAstc8x5 instead. + */ + RGBAAstc8x5 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBAAstc8x5 instead") = UnsignedInt(GL::CompressedPixelFormat::RGBAAstc8x5), + + /** + * ASTC compressed sRGB with alpha with 8x5 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::SRGB8Alpha8Astc8x5 instead. + */ + SRGB8Alpha8Astc8x5 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SRGB8Alpha8Astc8x5 instead") = UnsignedInt(GL::CompressedPixelFormat::SRGB8Alpha8Astc8x5), + + /** + * ASTC compressed RGBA with 8x6 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBAAstc8x6 instead. + */ + RGBAAstc8x6 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBAAstc8x6 instead") = UnsignedInt(GL::CompressedPixelFormat::RGBAAstc8x6), + + /** + * ASTC compressed sRGB with alpha with 8x6 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::SRGB8Alpha8Astc8x6 instead. + */ + SRGB8Alpha8Astc8x6 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SRGB8Alpha8Astc8x6 instead") = UnsignedInt(GL::CompressedPixelFormat::SRGB8Alpha8Astc8x6), + + /** + * ASTC compressed RGBA with 8x8 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBAAstc8x8 instead. + */ + RGBAAstc8x8 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBAAstc8x8 instead") = UnsignedInt(GL::CompressedPixelFormat::RGBAAstc8x8), + + /** + * ASTC compressed sRGB with alpha with 8x8 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::SRGB8Alpha8Astc8x8 instead. + */ + SRGB8Alpha8Astc8x8 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SRGB8Alpha8Astc8x8 instead") = UnsignedInt(GL::CompressedPixelFormat::SRGB8Alpha8Astc8x8), + + /** + * ASTC compressed RGBA with 10x5 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBAAstc10x5 instead. + */ + RGBAAstc10x5 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBAAstc10x5 instead") = UnsignedInt(GL::CompressedPixelFormat::RGBAAstc10x5), + + /** + * ASTC compressed sRGB with alpha with 10x5 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::SRGB8Alpha8Astc10x5 instead. + */ + SRGB8Alpha8Astc10x5 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SRGB8Alpha8Astc10x5 instead") = UnsignedInt(GL::CompressedPixelFormat::SRGB8Alpha8Astc10x5), + + /** + * ASTC compressed RGBA with 10x6 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBAAstc10x6 instead. + */ + RGBAAstc10x6 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBAAstc10x6 instead") = UnsignedInt(GL::CompressedPixelFormat::RGBAAstc10x6), + + /** + * ASTC compressed sRGB with alpha with 10x6 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::SRGB8Alpha8Astc10x6 instead. + */ + SRGB8Alpha8Astc10x6 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SRGB8Alpha8Astc10x6 instead") = UnsignedInt(GL::CompressedPixelFormat::SRGB8Alpha8Astc10x6), + + /** + * ASTC compressed RGBA with 10x8 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBAAstc10x8 instead. + */ + RGBAAstc10x8 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBAAstc10x8 instead") = UnsignedInt(GL::CompressedPixelFormat::RGBAAstc10x8), + + /** + * ASTC compressed sRGB with alpha with 10x8 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::SRGB8Alpha8Astc10x8 instead. + */ + SRGB8Alpha8Astc10x8 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SRGB8Alpha8Astc10x8 instead") = UnsignedInt(GL::CompressedPixelFormat::SRGB8Alpha8Astc10x8), + + /** + * ASTC compressed RGBA with 10x10 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBAAstc10x10 instead. + */ + RGBAAstc10x10 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBAAstc10x10 instead") = UnsignedInt(GL::CompressedPixelFormat::RGBAAstc10x10), + + /** + * ASTC compressed sRGB with alpha with 10x10 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::SRGB8Alpha8Astc10x10 instead. + */ + SRGB8Alpha8Astc10x10 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SRGB8Alpha8Astc10x10 instead") = UnsignedInt(GL::CompressedPixelFormat::SRGB8Alpha8Astc10x10), + + /** + * ASTC compressed RGBA with 12x10 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBAAstc12x10 instead. + */ + RGBAAstc12x10 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBAAstc12x10 instead") = UnsignedInt(GL::CompressedPixelFormat::RGBAAstc12x10), + + /** + * ASTC compressed sRGB with alpha with 12x10 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::SRGB8Alpha8Astc12x10 instead. + */ + SRGB8Alpha8Astc12x10 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SRGB8Alpha8Astc12x10 instead") = UnsignedInt(GL::CompressedPixelFormat::SRGB8Alpha8Astc12x10), + + /** + * ASTC compressed RGBA with 12x12 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::RGBAAstc12x12 instead. + */ + RGBAAstc12x12 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::RGBAAstc12x12 instead") = UnsignedInt(GL::CompressedPixelFormat::RGBAAstc12x12), + + /** + * ASTC compressed sRGB with alpha with 12x12 blocks. + * @deprecated Use @ref GL::CompressedPixelFormat::SRGB8Alpha8Astc12x12 instead. + */ + SRGB8Alpha8Astc12x12 CORRADE_DEPRECATED_ENUM("use GL::CompressedPixelFormat::SRGB8Alpha8Astc12x12 instead") = UnsignedInt(GL::CompressedPixelFormat::SRGB8Alpha8Astc12x12) + #endif + #endif +}; + +/** @debugoperatorenum{CompressedPixelFormat} */ +MAGNUM_EXPORT Debug& operator<<(Debug& debug, CompressedPixelFormat value); + +/** +@brief Whether a @ref CompressedPixelFormat value wraps an implementation-specific identifier + +Returns @cpp true @ce if value of @p format has its highest bit set, @cpp false @ce +otherwise. Use @ref compressedPixelFormatWrap() and @ref compressedPixelFormatUnwrap() +to wrap/unwrap an implementation-specific indentifier to/from @ref CompressedPixelFormat. +@see @ref isPixelFormatImplementationSpecific() +*/ +constexpr bool isCompressedPixelFormatImplementationSpecific(CompressedPixelFormat format) { + return UnsignedInt(format) & (1u << 31); +} + +/** +@brief Wrap an implementation-specific pixel format identifier in a @ref CompressedPixelFormat + +Sets the highest bit on @p format to mark it as implementation-specific. +Expects that @p format fits into the remaining bits. Use @ref compressedPixelFormatUnwrap() +for the inverse operation. +@see @ref isCompressedPixelFormatImplementationSpecific(), @ref pixelFormatWrap() +*/ +template constexpr CompressedPixelFormat compressedPixelFormatWrap(T implementationSpecific) { + static_assert(sizeof(T) <= 4, + "format types larger than 32bits are not supported"); + return CORRADE_CONSTEXPR_ASSERT(!(UnsignedInt(implementationSpecific) & (1u << 31)), + "compressedPixelFormatWrap(): implementation-specific value already wrapped or too large"), + CompressedPixelFormat((1u << 31)|UnsignedInt(implementationSpecific)); +} + +/** +@brief Unwrap an implementation-specific pixel format identifier from a @ref CompressedPixelFormat + +Unsets the highest bit from @p format to extract the implementation-specific +value. Expects that @p format has it set. Use @ref compressedPixelFormatWrap() for the +inverse operation. +@see @ref isCompressedPixelFormatImplementationSpecific(), @ref pixelFormatUnwrap() +*/ +template constexpr T compressedPixelFormatUnwrap(CompressedPixelFormat format) { + return CORRADE_CONSTEXPR_ASSERT(UnsignedInt(format) & (1u << 31), + "compressedPixelFormatUnwrap(): format doesn't contain a wrapped implementation-specific value"), + T(UnsignedInt(format) & ~(1u << 31)); +} + +namespace Implementation { + +#if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) +template inline typename std::enable_if::value, UnsignedInt>::type wrapPixelFormatIfNotGLSpecific(T format) { + return UnsignedInt(format); +} +inline PixelFormat wrapPixelFormatIfNotGLSpecific(PixelFormat format) { + return format; +} +#endif + +} + +} + #endif diff --git a/src/Magnum/PixelStorage.h b/src/Magnum/PixelStorage.h index 6cfab21b1..519037c56 100644 --- a/src/Magnum/PixelStorage.h +++ b/src/Magnum/PixelStorage.h @@ -52,10 +52,21 @@ Descibes how to interpret data which are read from or stored into @ref Image, class MAGNUM_EXPORT PixelStorage { public: #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) - /** @brief @copybrief GL::pixelSize() - * @deprecated Use @ref GL::pixelSize() instead. + /** @brief Pixel size + * @deprecated Use @ref Magnum::pixelSize() or @ref GL::pixelSize() + * instead. */ static CORRADE_DEPRECATED("use GL::pixelSize() instead") std::size_t pixelSize(GL::PixelFormat format, GL::PixelType type); + + /** @brief Pixel size + * @deprecated Use @ref Magnum::pixelSize() or @ref GL::pixelSize() + * instead. + */ + static CORRADE_DEPRECATED("use GL::pixelSize() instead") std::size_t pixelSize(PixelFormat format, GL::PixelType type) { + CORRADE_IGNORE_DEPRECATED_PUSH + return pixelSize(GL::PixelFormat(format), type); + CORRADE_IGNORE_DEPRECATED_POP + } #endif /** @@ -153,6 +164,20 @@ class MAGNUM_EXPORT PixelStorage { * instead. */ CORRADE_DEPRECATED("use dataProperties(std::size_t, const Vector3i&) instead") std::tuple, Math::Vector3, std::size_t> dataProperties(GL::PixelFormat format, GL::PixelType type, const Vector3i& size) const; + + /** @brief @copybrief dataProperties(std::size_t, const Vector3i&) const + * + * Returns byte offset in each direction, (row length, row count, layer + * count) and pixel size for image of given @p size with current pixel + * storage parameters, @p format and @p type. + * @deprecated Use @ref dataProperties(std::size_t, const Vector3i&) const + * instead. + */ + CORRADE_DEPRECATED("use dataProperties(std::size_t, const Vector3i&) instead") std::tuple, Math::Vector3, std::size_t> dataProperties(PixelFormat format, GL::PixelType type, const Vector3i& size) const { + CORRADE_IGNORE_DEPRECATED_PUSH + return dataProperties(GL::PixelFormat(format), type, size); + CORRADE_IGNORE_DEPRECATED_POP + } #endif #ifndef DOXYGEN_GENERATING_OUTPUT @@ -287,9 +312,8 @@ namespace Implementation { /* Used in *Image::dataProperties() */ template std::tuple, Math::Vector, std::size_t> imageDataProperties(const T& image) { Math::Vector3 offset, dataSize; - std::size_t pixelSize; - std::tie(offset, dataSize, pixelSize) = image.storage().dataProperties(image.format(), image.type(), Vector3i::pad(image.size(), 1)); - return std::make_tuple(Math::Vector::pad(offset), Math::Vector::pad(dataSize), pixelSize); + std::tie(offset, dataSize) = image.storage().dataProperties(image.pixelSize(), Vector3i::pad(image.size(), 1)); + return std::make_tuple(Math::Vector::pad(offset), Math::Vector::pad(dataSize), image.pixelSize()); } /* Used in Compressed*Image::dataProperties() */ @@ -303,8 +327,7 @@ namespace Implementation { /* Used in image query functions */ template std::size_t imageDataSizeFor(const T& image, const Math::Vector& size) { Math::Vector3 offset, dataSize; - std::size_t pixelSize; - std::tie(offset, dataSize, pixelSize) = image.storage().dataProperties(image.format(), image.type(), Vector3i::pad(size, 1)); + std::tie(offset, dataSize) = image.storage().dataProperties(image.pixelSize(), Vector3i::pad(size, 1)); /* Smallest line/rectangle/cube that covers the area */ std::size_t dataOffset = 0; @@ -350,7 +373,7 @@ namespace Implementation { } template std::ptrdiff_t pixelStorageSkipOffsetFor(const T& image, const Math::Vector& size) { - return std::get<0>(image.storage().dataProperties(image.format(), image.type(), Vector3i::pad(size, 1))).sum(); + return std::get<0>(image.storage().dataProperties(image.pixelSize(), Vector3i::pad(size, 1))).sum(); } template std::ptrdiff_t pixelStorageSkipOffset(const T& image) { return pixelStorageSkipOffsetFor(image, image.size()); diff --git a/src/Magnum/Test/CMakeLists.txt b/src/Magnum/Test/CMakeLists.txt index 85d796327..8c98849ac 100644 --- a/src/Magnum/Test/CMakeLists.txt +++ b/src/Magnum/Test/CMakeLists.txt @@ -24,6 +24,8 @@ # corrade_add_test(ArrayTest ArrayTest.cpp LIBRARIES Magnum) +corrade_add_test(PixelFormatTest PixelFormatTest.cpp LIBRARIES MagnumTestLib) +target_compile_definitions(PixelFormatTest PRIVATE "CORRADE_GRACEFUL_ASSERT") corrade_add_test(ResourceManagerTest ResourceManagerTest.cpp LIBRARIES Magnum) target_compile_definitions(ResourceManagerTest PRIVATE "CORRADE_GRACEFUL_ASSERT") @@ -38,6 +40,7 @@ corrade_add_test(TagsTest TagsTest.cpp LIBRARIES Magnum) set_target_properties( ArrayTest + PixelFormatTest ResourceManagerTest ResourceManagerLocalInstanceTestLib ResourceManagerLocalInstanceTest diff --git a/src/Magnum/Test/PixelFormatTest.cpp b/src/Magnum/Test/PixelFormatTest.cpp new file mode 100644 index 000000000..323b2a9df --- /dev/null +++ b/src/Magnum/Test/PixelFormatTest.cpp @@ -0,0 +1,216 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include + +#include "Magnum/PixelFormat.h" + +namespace Magnum { namespace Test { + +struct PixelFormatTest: TestSuite::Tester { + explicit PixelFormatTest(); + + void size(); + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + void sizeDeprecated(); + #endif + void sizeImplementationSpecific(); + + void isImplementationSpecific(); + void wrap(); + void wrapInvalid(); + void unwrap(); + void unwrapInvalid(); + + void compressedIsImplementationSpecific(); + void compressedWrap(); + void compressedWrapInvalid(); + void compressedUnwrap(); + void compressedUnwrapInvalid(); + + void debug(); + void debugImplementationSpecific(); + + void compressedDebug(); + void compressedDebugImplementationSpecific(); +}; + +PixelFormatTest::PixelFormatTest() { + addTests({&PixelFormatTest::size, + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + &PixelFormatTest::sizeDeprecated, + #endif + &PixelFormatTest::sizeImplementationSpecific, + + &PixelFormatTest::isImplementationSpecific, + &PixelFormatTest::wrap, + &PixelFormatTest::wrapInvalid, + &PixelFormatTest::unwrap, + &PixelFormatTest::unwrapInvalid, + + &PixelFormatTest::compressedIsImplementationSpecific, + &PixelFormatTest::compressedWrap, + &PixelFormatTest::compressedWrapInvalid, + &PixelFormatTest::compressedUnwrap, + &PixelFormatTest::compressedUnwrapInvalid, + + &PixelFormatTest::debug, + &PixelFormatTest::debugImplementationSpecific, + + &PixelFormatTest::compressedDebug, + &PixelFormatTest::compressedDebugImplementationSpecific}); +} + +void PixelFormatTest::size() { + CORRADE_COMPARE(pixelSize(PixelFormat::R8I), 1); + CORRADE_COMPARE(pixelSize(PixelFormat::R16UI), 2); + CORRADE_COMPARE(pixelSize(PixelFormat::RGB8Unorm), 3); + CORRADE_COMPARE(pixelSize(PixelFormat::RGBA8Snorm), 4); + CORRADE_COMPARE(pixelSize(PixelFormat::RGB16I), 6); + CORRADE_COMPARE(pixelSize(PixelFormat::RGBA16F), 8); + CORRADE_COMPARE(pixelSize(PixelFormat::RGB32UI), 12); + CORRADE_COMPARE(pixelSize(PixelFormat::RGBA32F), 16); +} + +#if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) +void PixelFormatTest::sizeDeprecated() { + std::ostringstream out; + Error redirectError{&out}; + + CORRADE_IGNORE_DEPRECATED_PUSH + pixelSize(PixelFormat::RGBA); + CORRADE_IGNORE_DEPRECATED_POP + + CORRADE_COMPARE(out.str(), "pixelSize(): called with deprecated GL-specific format, use GL::pixelSize() instead\n"); +} +#endif + +void PixelFormatTest::sizeImplementationSpecific() { + std::ostringstream out; + Error redirectError{&out}; + + pixelSize(pixelFormatWrap(0xdead)); + + CORRADE_COMPARE(out.str(), "pixelSize(): can't determine pixel size of an implementation-specific format\n"); +} + +void PixelFormatTest::isImplementationSpecific() { + constexpr bool a = isPixelFormatImplementationSpecific(PixelFormat::RGBA8Unorm); + constexpr bool b = isPixelFormatImplementationSpecific(PixelFormat(0x8000dead)); + CORRADE_VERIFY(!a); + CORRADE_VERIFY(b); +} + +void PixelFormatTest::wrap() { + constexpr PixelFormat a = pixelFormatWrap(0xdead); + CORRADE_COMPARE(UnsignedInt(a), 0x8000dead); +} + +void PixelFormatTest::wrapInvalid() { + std::ostringstream out; + Error redirectError{&out}; + + pixelFormatWrap(0xdeadbeef); + + CORRADE_COMPARE(out.str(), "pixelFormatWrap(): implementation-specific value already wrapped or too large\n"); +} + +void PixelFormatTest::unwrap() { + constexpr UnsignedInt a = pixelFormatUnwrap(PixelFormat(0x8000dead)); + CORRADE_COMPARE(a, 0xdead); +} + +void PixelFormatTest::unwrapInvalid() { + std::ostringstream out; + Error redirectError{&out}; + + pixelFormatUnwrap(PixelFormat(0xdead)); + + CORRADE_COMPARE(out.str(), "pixelFormatUnwrap(): format doesn't contain a wrapped implementation-specific value\n"); +} + +void PixelFormatTest::compressedIsImplementationSpecific() { + CORRADE_VERIFY(!isPixelFormatImplementationSpecific(PixelFormat::RGBA8Unorm)); + CORRADE_VERIFY(isPixelFormatImplementationSpecific(pixelFormatWrap(0xdead))); +} + +void PixelFormatTest::compressedWrap() { + CORRADE_COMPARE(UnsignedInt(pixelFormatWrap(0xdead)), 0x8000dead); +} + +void PixelFormatTest::compressedWrapInvalid() { + std::ostringstream out; + Error redirectError{&out}; + + compressedPixelFormatWrap(0xdeadbeef); + + CORRADE_COMPARE(out.str(), "compressedPixelFormatWrap(): implementation-specific value already wrapped or too large\n"); +} + +void PixelFormatTest::compressedUnwrap() { + CORRADE_COMPARE(UnsignedInt(compressedPixelFormatUnwrap(CompressedPixelFormat(0x8000dead))), 0xdead); +} + +void PixelFormatTest::compressedUnwrapInvalid() { + std::ostringstream out; + Error redirectError{&out}; + + compressedPixelFormatUnwrap(CompressedPixelFormat(0xdead)); + + CORRADE_COMPARE(out.str(), "compressedPixelFormatUnwrap(): format doesn't contain a wrapped implementation-specific value\n"); +} + +void PixelFormatTest::debug() { + std::ostringstream out; + Debug{&out} << PixelFormat::RG16Snorm << PixelFormat(0xdead); + + CORRADE_COMPARE(out.str(), "PixelFormat::RG16Snorm PixelFormat(0xdead)\n"); +} + +void PixelFormatTest::debugImplementationSpecific() { + std::ostringstream out; + Debug{&out} << pixelFormatWrap(0xdead); + + CORRADE_COMPARE(out.str(), "PixelFormat::ImplementationSpecific(0xdead)\n"); +} + +void PixelFormatTest::compressedDebug() { + std::ostringstream out; + Debug{&out} << CompressedPixelFormat::Bc3RGBAUnorm << CompressedPixelFormat(0xdead); + + CORRADE_COMPARE(out.str(), "CompressedPixelFormat::Bc3RGBAUnorm CompressedPixelFormat(0xdead)\n"); +} + +void PixelFormatTest::compressedDebugImplementationSpecific() { + std::ostringstream out; + Debug{&out} << compressedPixelFormatWrap(0xdead); + + CORRADE_COMPARE(out.str(), "CompressedPixelFormat::ImplementationSpecific(0xdead)\n"); +} + +}} + +CORRADE_TEST_MAIN(Magnum::Test::PixelFormatTest) diff --git a/src/Magnum/Trade/ImageData.cpp b/src/Magnum/Trade/ImageData.cpp index ebad17613..ac8c5e619 100644 --- a/src/Magnum/Trade/ImageData.cpp +++ b/src/Magnum/Trade/ImageData.cpp @@ -25,12 +25,22 @@ #include "ImageData.h" +#include "Magnum/PixelFormat.h" + namespace Magnum { namespace Trade { -template ImageData::ImageData(const PixelStorage storage, const PixelFormat format, const PixelType type, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: _compressed{false}, _storage{storage}, _format{format}, _type{type}, _size{size}, _data{std::move(data)}, _importerState{importerState} { +template ImageData::ImageData(const PixelStorage storage, const PixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: ImageData{storage, format, {}, Magnum::pixelSize(format), size, std::move(data), importerState} {} + +template ImageData::ImageData(const PixelStorage storage, const UnsignedInt format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: ImageData{storage, pixelFormatWrap(format), formatExtra, pixelSize, size, std::move(data), importerState} {} + +template ImageData::ImageData(const PixelStorage storage, const PixelFormat format, const UnsignedInt formatExtra, const UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: _compressed{false}, _storage{storage}, _format{format}, _formatExtra{formatExtra}, _pixelSize{pixelSize}, _size{size}, _data{std::move(data)}, _importerState{importerState} { CORRADE_ASSERT(Implementation::imageDataSize(*this) <= _data.size(), "Trade::ImageData::ImageData(): bad image data size, got" << _data.size() << "but expected at least" << Implementation::imageDataSize(*this), ); } +template ImageData::ImageData(const CompressedPixelStorage storage, const CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: _compressed{true}, _compressedStorage{storage}, _compressedFormat{format}, _size{size}, _data{std::move(data)}, _importerState{importerState} {} + +template ImageData::ImageData(const CompressedPixelStorage storage, const UnsignedInt format, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: ImageData{storage, compressedPixelFormatWrap(format), size, std::move(data), importerState} {} + template PixelStorage ImageData::storage() const { CORRADE_ASSERT(!_compressed, "Trade::ImageData::storage(): the image is compressed", {}); return _storage; @@ -41,26 +51,24 @@ template PixelFormat ImageData::format() con return _format; } -template PixelType ImageData::type() const { - CORRADE_ASSERT(!_compressed, "Trade::ImageData::type(): the image is compressed", {}); - return _type; +template UnsignedInt ImageData::formatExtra() const { + CORRADE_ASSERT(!_compressed, "Trade::ImageData::formatExtra(): the image is compressed", {}); + return _formatExtra; } -#ifndef MAGNUM_TARGET_GLES template CompressedPixelStorage ImageData::compressedStorage() const { CORRADE_ASSERT(_compressed, "Trade::ImageData::compressedStorage(): the image is not compressed", {}); return _compressedStorage; } -#endif template CompressedPixelFormat ImageData::compressedFormat() const { CORRADE_ASSERT(_compressed, "Trade::ImageData::compressedFormat(): the image is not compressed", {}); return _compressedFormat; } -template std::size_t ImageData::pixelSize() const { +template UnsignedInt ImageData::pixelSize() const { CORRADE_ASSERT(!_compressed, "Trade::ImageData::pixelSize(): the image is compressed", {}); - return PixelStorage::pixelSize(_format, _type); + return _pixelSize; } template std::tuple, VectorTypeFor, std::size_t> ImageData::dataProperties() const { @@ -70,21 +78,15 @@ template std::tuple ImageData::operator ImageView() const { - CORRADE_ASSERT(!_compressed, "Trade::ImageData::type(): the image is compressed", (ImageView{_storage, _format, _type, _size})); - return ImageView{_storage, _format, _type, _size, _data}; + CORRADE_ASSERT(!_compressed, "Trade::ImageData::type(): the image is compressed", (ImageView{_storage, _format, _formatExtra, _pixelSize, _size})); + return ImageView{_storage, _format, _formatExtra, _pixelSize, _size, _data}; } template ImageData::operator CompressedImageView() const { - #ifndef MAGNUM_TARGET_GLES CORRADE_ASSERT(_compressed, "Trade::ImageData::type(): the image is not compressed", (CompressedImageView{_compressedStorage, _compressedFormat, _size})); - #else - CORRADE_ASSERT(_compressed, "Trade::ImageData::type(): the image is not compressed", (CompressedImageView{_compressedFormat, _size})); - #endif return CompressedImageView{ - #ifndef MAGNUM_TARGET_GLES _compressedStorage, - #endif _compressedFormat, _size, _data}; } diff --git a/src/Magnum/Trade/ImageData.h b/src/Magnum/Trade/ImageData.h index 351ce45ec..cb7d11275 100644 --- a/src/Magnum/Trade/ImageData.h +++ b/src/Magnum/Trade/ImageData.h @@ -39,16 +39,41 @@ namespace Magnum { namespace Trade { /** @brief Image data -Access to either uncompressed or compressed image data provided by -@ref AbstractImporter subclasses, the compression state is distinguished with -@ref isCompressed(). Uncompressed images have @ref format(), @ref type(), -@ref pixelSize() and @ref dataProperties() properties and are convertible to -@ref ImageView. Compressed images have just the @ref compressedFormat() -property and are convertible to @ref CompressedImageView. - -Uncompressed image is interchangeable with @ref Image, @ref ImageView or -@ref BufferImage, compressed with @ref CompressedImage, @ref CompressedImageView -or @ref CompressedBufferImage. +Used mainly by @ref AbstractImporter classes to store either compressed or +non-compressed multi-dimensional image data together with layout and pixel +format description. + +This class can act as a drop-in replacement for @ref Image or +@ref CompressedImage, @ref ImageView or @ref CompressedImageView and is +implicitly convertible to either @ref ImageView or @ref CompressedImageView. +Particular graphics API wrappers provide additional image classes, for example +@ref GL::BufferImage or @ref GL::CompressedBufferImage. + +@section Trade-ImageData-usage Basic usage + +The image usually comes out of @ref AbstractImporter::image1D(), +@ref AbstractImporter::image2D() "image2D()" or +@ref AbstractImporter::image3D() "image3D()" and, based on what format the +particular imported data is in, it stores either compressed or uncompressed +data. + +@snippet MagnumTrade.cpp ImageData-construction + +@snippet MagnumTrade.cpp ImageData-construction-compressed + +As with @ref Image / @ref ImageView, this class supports extra storage +parameters and implementation-specific format specification, if the importer +has a need for that. See the @ref ImageView documentation for more information. + +When using the image, its compression status can be distinguished using +@ref isCompressed(). Uncompressed image properties are available through +@ref storage(), @ref format(), @ref formatExtra() and @ref pixelSize(); +compressed properties through @ref compressedStorage() and +@ref compressedFormat(). Example of uploading the image to +@link GL::Texture @endlink: + +@snippet MagnumTrade.cpp ImageData-usage + @see @ref ImageData1D, @ref ImageData2D, @ref ImageData3D */ template class ImageData { @@ -61,22 +86,101 @@ template class ImageData { * @brief Construct uncompressed image data * @param storage Storage of pixel data * @param format Format of pixel data - * @param type Data type of pixel data * @param size Image size * @param data Image data * @param importerState Importer-specific state * - * The data are expected to be of proper size for given @p storage + * The @p data array is expected to be of proper size for given * parameters. */ - explicit ImageData(PixelStorage storage, PixelFormat format, PixelType type, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; + explicit ImageData(PixelStorage storage, PixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; + + /** + * @brief Construct uncompressed image data + * @param format Format of pixel data + * @param size Image size + * @param data Image data + * @param importerState Importer-specific state + * + * Equivalent to calling @ref ImageData(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::Array&&, const void*) + * with default-constructed @ref PixelStorage. + */ + explicit ImageData(PixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept: ImageData{{}, format, size, std::move(data), importerState} {} + + /** + * @brief Construct uncompressed image data with implementation-specific pixel format + * @param storage Storage of pixel data + * @param format Format of pixel data + * @param formatExtra Additional pixel format specifier + * @param pixelSize Size of a pixel in given format + * @param size Image size + * @param data Image data + * @param importerState Importer-specific state + * + * Unlike with @ref ImageData(PixelStorage, PixelFormat, const VectorTypeFor&, Containers::Array&&, const void*), + * where pixel size is calculated automatically using + * @ref pixelSize(PixelFormat), this allows you to specify an + * implementation-specific pixel format and pixel size directly. Uses + * @ref pixelFormatWrap() internally to wrap @p format in + * @ref Magnum::PixelFormat "PixelFormat". + * + * The @p data array is expected to be of proper size for given + * parameters. + */ + explicit ImageData(PixelStorage storage, UnsignedInt format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; /** @overload - * Similar to the above, but uses default @ref PixelStorage parameters. + * + * Equivalent to the above for @p format already wrapped with + * @ref pixelFormatWrap(). */ - explicit ImageData(PixelFormat format, PixelType type, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept: ImageData{{}, format, type, size, std::move(data), importerState} {} + explicit ImageData(PixelStorage storage, PixelFormat format, UnsignedInt formatExtra, UnsignedInt pixelSize, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; + + /** + * @brief Construct uncompressed image data with implementation-specific pixel format + * @param storage Storage of pixel data + * @param format Format of pixel data + * @param formatExtra Additional pixel format specifier + * @param size Image size + * @param data Image data + * @param importerState Importer-specific state + * + * Uses ADL to find a corresponding @cpp pixelSize(T, U) @ce overload, + * then calls @ref ImageData(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::Array&&, const void*) + * with calculated pixel size. + */ + template explicit ImageData(PixelStorage storage, T format, U formatExtra, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; + + /** + * @brief Construct uncompressed image data with implementation-specific pixel format + * @param storage Storage of pixel data + * @param format Format of pixel data + * @param size Image size + * @param data Image data + * @param importerState Importer-specific state + * + * Uses ADL to find a corresponding @cpp pixelSize(T) @ce overload, + * then calls @ref ImageData(PixelStorage, UnsignedInt, UnsignedInt, UnsignedInt, const VectorTypeFor&, Containers::Array&&, const void*) + * with calculated pixel size and @p formatExtra set to @cpp 0 @ce. + */ + template explicit ImageData(PixelStorage storage, T format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; + + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + /** + * @brief Construct uncompressed image data + * @param format Format of pixel data + * @param type Data type of pixel data + * @param size Image size + * @param data Image data + * @param importerState Importer-specific state + * + * @deprecated Use the generic @ref ImageData(PixelStorage, T, U, const VectorTypeFor&, Containers::Array&&, const void*) + * instead --- the pixel storage parameter is used to distinguish + * between compressed and uncompressed data. + */ + template explicit CORRADE_DEPRECATED("use Image(PixelStorage, T, U, const VectorTypeFor&, Containers::Array&&, const void*) instead") ImageData(PixelFormat format, GL::PixelType type, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; + #endif - #ifndef MAGNUM_TARGET_GLES /** * @brief Construct compressed image data * @param storage Storage of compressed pixel data @@ -84,15 +188,8 @@ template class ImageData { * @param size Image size * @param data Image data * @param importerState Importer-specific state - * - * Note that the image data are not copied on construction, but they - * are deleted on class destruction. - * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} - * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and - * WebGL. */ explicit ImageData(CompressedPixelStorage storage, CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; - #endif /** * @brief Construct compressed image data @@ -101,10 +198,23 @@ template class ImageData { * @param data Image data * @param importerState Importer-specific state * - * Similar the above, but uses default @ref CompressedPixelStorage - * parameters (or the hardcoded ones in OpenGL ES and WebGL). + * Equivalent to calling @ref ImageData(CompressedPixelStorage, CompressedPixelFormat, const VectorTypeFor&, Containers::Array&&, const void*) + * with default-constructed @ref CompressedPixelStorage. + */ + explicit ImageData(CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept: ImageData{{}, format, size, std::move(data), importerState} {} + + /** + * @brief Construct compressed image data + * @param storage Storage of compressed pixel data + * @param format Format of compressed pixel data + * @param size Image size + * @param data Image data + * @param importerState Importer-specific state + * + * Uses @ref compressedPixelFormatWrap() internally to convert + * @p format to @ref CompressedPixelFormat. */ - explicit ImageData(CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; + template explicit ImageData(CompressedPixelStorage storage, T format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; /** @brief Copying is not allowed */ ImageData(const ImageData&) = delete; @@ -152,35 +262,56 @@ template class ImageData { /** * @brief Format of pixel data * + * Returns either a defined value from the + * @ref Magnum::PixelFormat "PixelFormat" enum or a wrapped + * implementation-specific value. Use + * @ref isPixelFormatImplementationSpecific() to distinguish the case + * and @ref pixelFormatUnwrap() to extract an implementation-specific + * value, if needed. + * * The image is expected to be uncompressed. * @see @ref isCompressed(), @ref compressedFormat() */ PixelFormat format() const; /** - * @brief Data type of pixel data + * @brief Additional pixel format specifier + * + * Some implementations (such as OpenGL) define a pixel format using + * two values. This field contains the second implementation-specific + * value verbatim, if any. See @ref format() for more information. * * The image is expected to be uncompressed. * @see @ref isCompressed() */ - PixelType type() const; + UnsignedInt formatExtra() const; + + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + /** + * @brief Data type of pixel data + * + * @deprecated Cast @ref formatExtra() to @ref GL::PixelType instead. + */ + CORRADE_DEPRECATED("cast formatExtra() to GL::PixelType instead") GL::PixelType type() const { return GL::PixelType(formatExtra()); } + #endif - #ifndef MAGNUM_TARGET_GLES /** * @brief Storage of compressed pixel data * * The image is expected to be compressed. - * @see @ref isCompressed(), @ref storage()) - * @requires_gl42 Extension @extension{ARB,compressed_texture_pixel_storage} - * @requires_gl Compressed pixel storage is hardcoded in OpenGL ES and - * WebGL. + * @see @ref isCompressed(), @ref storage() */ CompressedPixelStorage compressedStorage() const; - #endif /** * @brief Format of compressed pixel data * + * Returns either a defined value from the @ref CompressedPixelFormat + * enum or a wrapped implementation-specific value. Use + * @ref isCompressedPixelFormatImplementationSpecific() to distinguish + * the case and @ref compressedPixelFormatUnwrap() to extract an + * implementation-specific value, if needed. + * * The image is expected to be compressed. * @see @ref isCompressed(), @ref format() */ @@ -192,7 +323,7 @@ template class ImageData { * The image is expected to be uncompressed. * @see @ref isCompressed(), @ref Magnum::pixelSize() */ - std::size_t pixelSize() const; + UnsignedInt pixelSize() const; /** @brief Image size */ VectorTypeFor size() const { return _size; } @@ -261,18 +392,19 @@ template class ImageData { const void* importerState() const { return _importerState; } private: + explicit ImageData(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState = nullptr) noexcept; + bool _compressed; union { PixelStorage _storage; - #ifndef MAGNUM_TARGET_GLES CompressedPixelStorage _compressedStorage; - #endif }; union { PixelFormat _format; CompressedPixelFormat _compressedFormat; }; - PixelType _type; + UnsignedInt _formatExtra; + UnsignedInt _pixelSize; Math::Vector _size; Containers::Array _data; const void* _importerState; @@ -287,31 +419,43 @@ typedef ImageData<2> ImageData2D; /** @brief Three-dimensional image */ typedef ImageData<3> ImageData3D; -template ImageData::ImageData( - #ifndef MAGNUM_TARGET_GLES - const CompressedPixelStorage storage, +template template ImageData::ImageData(const PixelStorage storage, const T format, const U formatExtra, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: ImageData{storage, + #if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) + Implementation::wrapPixelFormatIfNotGLSpecific(format), + #else + UnsignedInt(format), #endif - const CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* importerState) noexcept: _compressed{true}, - #ifndef MAGNUM_TARGET_GLES - _compressedStorage{storage}, - #endif - _compressedFormat{format}, _size{size}, _data{std::move(data)}, _importerState{importerState} {} + UnsignedInt(formatExtra), Implementation::pixelSizeAdl(format, formatExtra), size, std::move(data), importerState} { + static_assert(sizeof(T) <= 4 && sizeof(U) <= 4, + "format types larger than 32bits are not supported"); +} -#ifndef MAGNUM_TARGET_GLES -template inline ImageData::ImageData(const CompressedPixelFormat format, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: ImageData{{}, format, size, std::move(data), importerState} {} +#if defined(MAGNUM_BUILD_DEPRECATED) && defined(MAGNUM_TARGET_GL) +CORRADE_IGNORE_DEPRECATED_PUSH +template template inline ImageData::ImageData(const PixelFormat format, const GL::PixelType type, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: ImageData{PixelStorage{}, format, type, size, std::move(data), importerState} {} +CORRADE_IGNORE_DEPRECATED_POP #endif +template template ImageData::ImageData(const PixelStorage storage, const T format, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: ImageData{storage, UnsignedInt(format), {}, Implementation::pixelSizeAdl(format), size, std::move(data), importerState} { + static_assert(sizeof(T) <= 4, + "format types larger than 32bits are not supported"); +} + +template template ImageData::ImageData(const CompressedPixelStorage storage, const T format, const VectorTypeFor& size, Containers::Array&& data, const void* const importerState) noexcept: ImageData{storage, UnsignedInt(format), size, std::move(data), importerState} { + static_assert(sizeof(T) <= 4, + "format types larger than 32bits are not supported"); +} + template inline ImageData::ImageData(ImageData&& other) noexcept: _compressed{std::move(other._compressed)}, _size{std::move(other._size)}, _data{std::move(other._data)}, _importerState{std::move(other._importerState)} { if(_compressed) { - #ifndef MAGNUM_TARGET_GLES new(&_compressedStorage) CompressedPixelStorage{std::move(other._compressedStorage)}; - #endif _compressedFormat = std::move(other._compressedFormat); } else { new(&_storage) PixelStorage{std::move(other._storage)}; _format = std::move(other._format); - _type = std::move(other._type); + _formatExtra = std::move(other._formatExtra); + _pixelSize = std::move(other._pixelSize); } other._size = {}; @@ -321,16 +465,15 @@ template inline ImageData& ImageData