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