diff --git a/Doxyfile b/Doxyfile
index c6ab1a574..257379fc2 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -220,6 +220,7 @@ ALIASES = \
"extension{2}=\1_\2" \
"requires_gles30=@xrefitem requires-gles30 \"Requires OpenGL ES 3.0\" \"Functionality requiring OpenGL ES 3.0\"" \
"requires_gl=@xrefitem requires-gl \"Requires desktop OpenGL\" \"Functionality requiring desktop OpenGL (not available in OpenGL ES)\"" \
+ "requires_gles20=@xrefitem requires-gles20 \"Requires OpenGL ES 2.0\" \"Functionality requiring OpenGL ES 2.0 (not available in ES 3.0 and desktop OpenGL)\"" \
"requires_es_extension=@xrefitem requires-es-extension \"Requires OpenGL ES extension\" \"Functionality requiring specific OpenGL ES extension\"" \
"es_extension{2}=\1_\2" \
"es_extension2{3}=\1_\2"
diff --git a/PKGBUILD-es2 b/PKGBUILD-es2
index e4c937d64..5372804da 100644
--- a/PKGBUILD-es2
+++ b/PKGBUILD-es2
@@ -26,8 +26,6 @@ build() {
-DBUILD_TESTS=ON \
-DTARGET_GLES=ON \
-DTARGET_GLES2=ON \
- -DWITH_TEXT=OFF \
- -DWITH_TEXTURETOOLS=OFF \
-DWITH_MAGNUMINFO=OFF \
-DWITH_XEGLAPPLICATION=ON
make
diff --git a/PKGBUILD-es2desktop b/PKGBUILD-es2desktop
index 55fa9ccb9..8467066d9 100644
--- a/PKGBUILD-es2desktop
+++ b/PKGBUILD-es2desktop
@@ -27,10 +27,9 @@ build() {
-DTARGET_GLES=ON \
-DTARGET_GLES2=ON \
-DTARGET_DESKTOP_GLES=ON \
- -DWITH_TEXT=OFF \
- -DWITH_TEXTURETOOLS=OFF \
- -DWITH_MAGNUMINFO=OFF \
- -DWITH_XEGLAPPLICATION=ON
+ -DWITH_MAGNUMINFO=ON \
+ -DWITH_GLXAPPLICATION=ON \
+ -DWITH_WINDOWLESSGLXAPPLICATION=ON
make
}
diff --git a/PKGBUILD-es3 b/PKGBUILD-es3
index e567c82a8..6c8a8aef6 100644
--- a/PKGBUILD-es3
+++ b/PKGBUILD-es3
@@ -26,8 +26,6 @@ build() {
-DBUILD_TESTS=ON \
-DTARGET_GLES=ON \
-DTARGET_GLES2=OFF \
- -DWITH_TEXT=OFF \
- -DWITH_TEXTURETOOLS=OFF \
-DWITH_MAGNUMINFO=OFF \
-DWITH_XEGLAPPLICATION=ON
make
diff --git a/doc/required-extensions.dox b/doc/required-extensions.dox
index 610e4542b..2d56cfa65 100644
--- a/doc/required-extensions.dox
+++ b/doc/required-extensions.dox
@@ -48,13 +48,11 @@ supported on Intel GPUs even if they are capable of OpenGL 2.1 only).
- @subpage requires-gl43
- @subpage requires-extension
- @subpage requires-gl
+- @subpage requires-gles20
- @subpage requires-gles30
- @subpage requires-es-extension
- @subpage unsupported
-@page requires-gl Functionality requiring desktop OpenGL (not available on OpenGL ES)
-@see @ref MAGNUM_TARGET_GLES_ "MAGNUM_TARGET_GLES"
-
@page requires-gl30 Functionality requiring OpenGL 3.0
@page requires-gl31 Functionality requiring OpenGL 3.1
@page requires-gl32 Functionality requiring OpenGL 3.2
@@ -66,9 +64,15 @@ supported on Intel GPUs even if they are capable of OpenGL 2.1 only).
@page requires-extension Functionality requiring specific OpenGL extension
-@page requires-gles30 Functionality requiring OpenGL ES 3.0
+@page requires-gl Functionality requiring desktop OpenGL (not available on OpenGL ES)
+@see @ref MAGNUM_TARGET_GLES_ "MAGNUM_TARGET_GLES"
+
+@page requires-gles20 Functionality requiring OpenGL ES 2.0 (not available in ES 3.0 and desktop OpenGL)
@see @ref MAGNUM_TARGET_GLES2_ "MAGNUM_TARGET_GLES2"
+@page requires-gles30 Functionality requiring OpenGL ES 3.0
+@see @ref MAGNUM_TARGET_GLES3_ "MAGNUM_TARGET_GLES3"
+
@page requires-es-extension Functionality requiring specific OpenGL ES extension
@see @ref MAGNUM_TARGET_GLES2_ "MAGNUM_TARGET_GLES2"
diff --git a/doc/unsupported.dox b/doc/unsupported.dox
index 85a52c830..0c6efc4ec 100644
--- a/doc/unsupported.dox
+++ b/doc/unsupported.dox
@@ -29,8 +29,6 @@ add any performance gains, is not supported in %Magnum.
@section unsupported-features Unsupported features
-- Luminance texture formats (OpenGL ES) are not supported, as they are
- deprecated in OpenGL ES 3.0 and not present in core desktop OpenGL.
- Fixed precision data types (OpenGL ES) are not supported, as they occupy the
same memory as floats and they aren't faster than floats on current hardware
anymore.
diff --git a/src/AbstractFramebuffer.cpp b/src/AbstractFramebuffer.cpp
index bc9b20eb5..c410aac91 100644
--- a/src/AbstractFramebuffer.cpp
+++ b/src/AbstractFramebuffer.cpp
@@ -34,16 +34,18 @@
namespace Magnum {
+AbstractFramebuffer::CheckStatusImplementation AbstractFramebuffer::checkStatusImplementation = &AbstractFramebuffer::checkStatusImplementationDefault;
+
AbstractFramebuffer::ReadImplementation AbstractFramebuffer::readImplementation = &AbstractFramebuffer::readImplementationDefault;
AbstractFramebuffer::DrawBuffersImplementation AbstractFramebuffer::drawBuffersImplementation = &AbstractFramebuffer::drawBuffersImplementationDefault;
AbstractFramebuffer::DrawBufferImplementation AbstractFramebuffer::drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDefault;
AbstractFramebuffer::ReadBufferImplementation AbstractFramebuffer::readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDefault;
+#ifdef MAGNUM_TARGET_GLES2
FramebufferTarget AbstractFramebuffer::readTarget = FramebufferTarget::ReadDraw;
FramebufferTarget AbstractFramebuffer::drawTarget = FramebufferTarget::ReadDraw;
-
-AbstractFramebuffer::~AbstractFramebuffer() {}
+#endif
void AbstractFramebuffer::bind(FramebufferTarget target) {
bindInternal(target);
@@ -81,10 +83,15 @@ FramebufferTarget AbstractFramebuffer::bindInternal() {
/* Or bind it, if not already */
state->readBinding = _id;
- if(readTarget == FramebufferTarget::ReadDraw) state->drawBinding = _id;
+ #ifndef MAGNUM_TARGET_GLES2
+ glBindFramebuffer(GLenum(FramebufferTarget::Read), _id);
+ return FramebufferTarget::Read;
+ #else
+ if(readTarget == FramebufferTarget::ReadDraw) state->drawBinding = _id;
glBindFramebuffer(GLenum(readTarget), _id);
return readTarget;
+ #endif
}
void AbstractFramebuffer::blit(AbstractFramebuffer& source, AbstractFramebuffer& destination, const Rectanglei& sourceRectangle, const Rectanglei& destinationRectangle, FramebufferBlitMask mask, FramebufferBlitFilter filter) {
@@ -126,12 +133,20 @@ void AbstractFramebuffer::setViewportInternal() {
}
void AbstractFramebuffer::clear(FramebufferClearMask mask) {
+ #ifndef MAGNUM_TARGET_GLES2
+ bindInternal(FramebufferTarget::Draw);
+ #else
bindInternal(drawTarget);
+ #endif
glClear(static_cast(mask));
}
void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, Image2D* image) {
+ #ifndef MAGNUM_TARGET_GLES2
+ bindInternal(FramebufferTarget::Read);
+ #else
bindInternal(readTarget);
+ #endif
const std::size_t dataSize = image->pixelSize()*size.product();
char* const data = new char[dataSize];
readImplementation(offset, size, image->format(), image->type(), dataSize, data);
@@ -140,7 +155,11 @@ void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, Ima
#ifndef MAGNUM_TARGET_GLES2
void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, BufferImage2D* image, Buffer::Usage usage) {
+ #ifndef MAGNUM_TARGET_GLES2
+ bindInternal(FramebufferTarget::Read);
+ #else
bindInternal(readTarget);
+ #endif
/* If the buffer doesn't have sufficient size, resize it */
/** @todo Explicitly reset also when buffer usage changes */
if(image->size() != size)
@@ -177,22 +196,42 @@ void AbstractFramebuffer::invalidateImplementation(GLsizei count, GLenum* attach
void AbstractFramebuffer::initializeContextBasedFunctionality(Context* context) {
#ifndef MAGNUM_TARGET_GLES
- if(context->isExtensionSupported()) {
- Debug() << "AbstractFramebuffer: using" << Extensions::GL::EXT::framebuffer_blit::string() << "features";
-
- readTarget = FramebufferTarget::Read;
- drawTarget = FramebufferTarget::Draw;
- }
-
if(context->isExtensionSupported()) {
Debug() << "AbstractFramebuffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features";
+ checkStatusImplementation = &AbstractFramebuffer::checkStatusImplementationDSA;
drawBuffersImplementation = &AbstractFramebuffer::drawBuffersImplementationDSA;
drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDSA;
readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDSA;
}
#endif
+ #ifdef MAGNUM_TARGET_GLES2
+ /* Optimistically set separate binding targets and check if one of the
+ extensions providing them is available */
+ readTarget = FramebufferTarget::Read;
+ drawTarget = FramebufferTarget::Draw;
+
+ if(context->isExtensionSupported())
+ Debug() << "AbstractFramebuffer: using" << Extensions::GL::ANGLE::framebuffer_blit::string() << "features";
+
+ else if(context->isExtensionSupported())
+ Debug() << "AbstractFramebuffer: using" << Extensions::GL::APPLE::framebuffer_multisample::string() << "features";
+
+ else if(context->isExtensionSupported())
+ Debug() << "AbstractFramebuffer: using" << Extensions::GL::NV::framebuffer_blit::string() << "features";
+
+ /* NV_framebuffer_multisample requires NV_framebuffer_blit, which has these
+ enums. However, on my system only NV_framebuffer_multisample is
+ supported, but NV_framebuffer_blit isn't. I will hold my breath and
+ assume these enums are available. */
+ else if(context->isExtensionSupported())
+ Debug() << "AbstractFramebuffer: using" << Extensions::GL::NV::framebuffer_multisample::string() << "features";
+
+ /* If no such extension is available, reset back to unified target */
+ else readTarget = drawTarget = FramebufferTarget::ReadDraw;
+ #endif
+
#ifndef MAGNUM_TARGET_GLES3
#ifndef MAGNUM_TARGET_GLES
if(context->isExtensionSupported())
@@ -216,10 +255,25 @@ void AbstractFramebuffer::initializeContextBasedFunctionality(Context* context)
#endif
}
+GLenum AbstractFramebuffer::checkStatusImplementationDefault(const FramebufferTarget target) {
+ bindInternal(target);
+ return glCheckFramebufferStatus(GLenum(target));
+}
+
+#ifndef MAGNUM_TARGET_GLES
+GLenum AbstractFramebuffer::checkStatusImplementationDSA(const FramebufferTarget target) {
+ return glCheckNamedFramebufferStatusEXT(_id, GLenum(target));
+}
+#endif
+
void AbstractFramebuffer::drawBuffersImplementationDefault(GLsizei count, const GLenum* buffers) {
/** @todo Re-enable when extension wrangler is available for ES2 */
#ifndef MAGNUM_TARGET_GLES2
+ #ifndef MAGNUM_TARGET_GLES2
+ bindInternal(FramebufferTarget::Draw);
+ #else
bindInternal(drawTarget);
+ #endif
glDrawBuffers(count, buffers);
#else
static_cast(count);
@@ -236,7 +290,11 @@ void AbstractFramebuffer::drawBuffersImplementationDSA(GLsizei count, const GLen
void AbstractFramebuffer::drawBufferImplementationDefault(GLenum buffer) {
/** @todo Re-enable when extension wrangler is available for ES2 */
#ifndef MAGNUM_TARGET_GLES2
+ #ifndef MAGNUM_TARGET_GLES2
+ bindInternal(FramebufferTarget::Draw);
+ #else
bindInternal(drawTarget);
+ #endif
#ifndef MAGNUM_TARGET_GLES3
glDrawBuffer(buffer);
#else
@@ -256,7 +314,11 @@ void AbstractFramebuffer::drawBufferImplementationDSA(GLenum buffer) {
void AbstractFramebuffer::readBufferImplementationDefault(GLenum buffer) {
/** @todo Get some extension wrangler instead to avoid undeclared glReadBuffer() on ES2 */
#ifndef MAGNUM_TARGET_GLES2
+ #ifndef MAGNUM_TARGET_GLES2
+ bindInternal(FramebufferTarget::Read);
+ #else
bindInternal(readTarget);
+ #endif
glReadBuffer(buffer);
#else
static_cast(buffer);
diff --git a/src/AbstractFramebuffer.h b/src/AbstractFramebuffer.h
index 792ffa182..f9e486ff1 100644
--- a/src/AbstractFramebuffer.h
+++ b/src/AbstractFramebuffer.h
@@ -40,10 +40,10 @@
namespace Magnum {
/**
- * @brief Mask for framebuffer clearing
- *
- * @see AbstractFramebuffer, FramebufferClearMask
- */
+@brief Mask for framebuffer clearing
+
+@see AbstractFramebuffer, FramebufferClearMask
+*/
enum class FramebufferClear: GLbitfield {
Color = GL_COLOR_BUFFER_BIT, /**< Color */
Depth = GL_DEPTH_BUFFER_BIT, /**< Depth value */
@@ -51,21 +51,21 @@ enum class FramebufferClear: GLbitfield {
};
/**
- * @brief Mask for clearing
- *
- * @see AbstractFramebuffer::clear()
- */
+@brief Mask for clearing
+
+@see AbstractFramebuffer::clear()
+*/
typedef Containers::EnumSet FramebufferClearMask;
/**
- * @brief Mask for framebuffer blitting
- *
- * @see AbstractFramebuffer, FramebufferBlitMask
- * @requires_gl30 %Extension @extension{EXT,framebuffer_object}
- * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or
- * @es_extension{NV,framebuffer_blit}
- */
+@brief Mask for framebuffer blitting
+
+@see AbstractFramebuffer, FramebufferBlitMask
+@requires_gl30 %Extension @extension{ARB,framebuffer_object}
+@requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or
+ @es_extension{NV,framebuffer_blit}
+*/
enum class FramebufferBlit: GLbitfield {
ColorBuffer = GL_COLOR_BUFFER_BIT, /**< Color buffer */
DepthBuffer = GL_DEPTH_BUFFER_BIT, /**< Depth buffer */
@@ -73,36 +73,38 @@ enum class FramebufferBlit: GLbitfield {
};
/**
- * @brief Mask for framebuffer blitting
- *
- * @see AbstractFramebuffer::blit()
- * @requires_gl30 %Extension @extension{EXT,framebuffer_object}
- * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or
- * @es_extension{NV,framebuffer_blit}
- */
+@brief Mask for framebuffer blitting
+
+@see AbstractFramebuffer::blit()
+@requires_gl30 %Extension @extension{ARB,framebuffer_object}
+@requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or
+ @es_extension{NV,framebuffer_blit}
+*/
typedef Containers::EnumSet FramebufferBlitMask;
/**
- * @brief %Framebuffer blit filtering
- *
- * @see AbstractFramebuffer::blit()
- */
+@brief %Framebuffer blit filtering
+
+@see AbstractFramebuffer::blit()
+@requires_gl30 %Extension @extension{ARB,framebuffer_object}
+@requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or
+ @es_extension{NV,framebuffer_blit}
+*/
enum class FramebufferBlitFilter: GLenum {
Nearest = GL_NEAREST, /**< Nearest neighbor filtering */
Linear = GL_LINEAR /**< Linear interpolation filtering */
};
/**
- * @brief Target for binding framebuffer
- *
- * @see DefaultFramebuffer::bind(), Framebuffer::bind()
- * @requires_gl30 %Extension @extension{EXT,framebuffer_object}
- */
+@brief Target for binding framebuffer
+
+@see DefaultFramebuffer::bind(), Framebuffer::bind()
+@requires_gl30 %Extension @extension{ARB,framebuffer_object}
+*/
enum class FramebufferTarget: GLenum {
/**
* For reading only.
- * @requires_gl30 %Extension @extension{EXT,framebuffer_blit}
* @requires_gles30 %Extension @es_extension{APPLE,framebuffer_multisample},
* @es_extension{ANGLE,framebuffer_blit} or @es_extension{NV,framebuffer_blit}
*/
@@ -114,7 +116,6 @@ enum class FramebufferTarget: GLenum {
/**
* For drawing only.
- * @requires_gl30 %Extension @extension{EXT,framebuffer_blit}
* @requires_gles30 %Extension @es_extension{APPLE,framebuffer_multisample},
* @es_extension{ANGLE,framebuffer_blit} or @es_extension{NV,framebuffer_blit}
*/
@@ -167,7 +168,6 @@ class MAGNUM_EXPORT AbstractFramebuffer {
* Framebuffer::mapForDraw() for specifying particular buffers for
* blitting operation.
* @see @fn_gl{BlitFramebuffer}
- * @requires_gl30 %Extension @extension{EXT,framebuffer_blit}
* @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or
* @es_extension{NV,framebuffer_blit}
*/
@@ -186,7 +186,6 @@ class MAGNUM_EXPORT AbstractFramebuffer {
* @ref FramebufferBlitFilter "FramebufferBlitFilter::Nearest"
* filtering is used by default.
* @see @fn_gl{BlitFramebuffer}
- * @requires_gl30 %Extension @extension{EXT,framebuffer_blit}
* @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or
* @es_extension{NV,framebuffer_blit}
*/
@@ -195,7 +194,6 @@ class MAGNUM_EXPORT AbstractFramebuffer {
}
explicit AbstractFramebuffer();
- virtual ~AbstractFramebuffer() = 0;
/**
* @brief Bind framebuffer for rendering
@@ -205,6 +203,8 @@ class MAGNUM_EXPORT AbstractFramebuffer {
* Framebuffer::mapForRead(), DefaultFramebuffer::mapForDraw(),
* Framebuffer::mapForDraw(), @fn_gl{BindFramebuffer},
* @fn_gl{Viewport}
+ * @todo Bind internally to ReadDraw if separate binding points are not
+ * supported
*/
void bind(FramebufferTarget target);
@@ -272,12 +272,19 @@ class MAGNUM_EXPORT AbstractFramebuffer {
#else
protected:
#endif
+ ~AbstractFramebuffer() = default;
+
void MAGNUM_LOCAL bindInternal(FramebufferTarget target);
FramebufferTarget MAGNUM_LOCAL bindInternal();
void MAGNUM_LOCAL setViewportInternal();
+ #ifdef MAGNUM_TARGET_GLES2
static MAGNUM_LOCAL FramebufferTarget readTarget;
static MAGNUM_LOCAL FramebufferTarget drawTarget;
+ #endif
+
+ typedef GLenum(AbstractFramebuffer::*CheckStatusImplementation)(FramebufferTarget);
+ static CheckStatusImplementation checkStatusImplementation;
typedef void(AbstractFramebuffer::*DrawBuffersImplementation)(GLsizei, const GLenum*);
static MAGNUM_LOCAL DrawBuffersImplementation drawBuffersImplementation;
@@ -297,6 +304,11 @@ class MAGNUM_EXPORT AbstractFramebuffer {
private:
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
+ GLenum MAGNUM_LOCAL checkStatusImplementationDefault(FramebufferTarget target);
+ #ifndef MAGNUM_TARGET_GLES
+ GLenum MAGNUM_LOCAL checkStatusImplementationDSA(FramebufferTarget target);
+ #endif
+
void MAGNUM_LOCAL drawBuffersImplementationDefault(GLsizei count, const GLenum* buffers);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL drawBuffersImplementationDSA(GLsizei count, const GLenum* buffers);
diff --git a/src/AbstractImage.cpp b/src/AbstractImage.cpp
index 253f2ec37..0e3af2904 100644
--- a/src/AbstractImage.cpp
+++ b/src/AbstractImage.cpp
@@ -99,11 +99,17 @@ std::size_t AbstractImage::pixelSize(ImageFormat format, ImageType type) {
case ImageFormat::Blue:
case ImageFormat::GreenInteger:
case ImageFormat::BlueInteger:
+ #endif
+ #ifdef MAGNUM_TARGET_GLES2
+ case ImageFormat::Luminance:
#endif
return 1*size;
case ImageFormat::RG:
#ifndef MAGNUM_TARGET_GLES2
case ImageFormat::RGInteger:
+ #endif
+ #ifdef MAGNUM_TARGET_GLES2
+ case ImageFormat::LuminanceAlpha:
#endif
return 2*size;
case ImageFormat::RGB:
diff --git a/src/AbstractShaderProgram.cpp b/src/AbstractShaderProgram.cpp
index af7e6a218..6e892d7e8 100644
--- a/src/AbstractShaderProgram.cpp
+++ b/src/AbstractShaderProgram.cpp
@@ -116,10 +116,9 @@ std::pair AbstractShaderProgram::validate() {
/* Error or warning message. The string is returned null-terminated, scrap
the \0 at the end afterwards */
std::string message(logLength, '\n');
- if(!message.empty()) {
+ if(message.size() > 1)
glGetProgramInfoLog(_id, message.size(), nullptr, &message[0]);
- message.resize(logLength-1);
- }
+ message.resize(std::max(logLength, 1)-1);
return {success, std::move(message)};
}
@@ -159,10 +158,9 @@ bool AbstractShaderProgram::link() {
/* Error or warning message. The string is returned null-terminated, scrap
the \0 at the end afterwards */
std::string message(logLength, '\n');
- if(!message.empty()) {
+ if(message.size() > 1)
glGetProgramInfoLog(_id, message.size(), nullptr, &message[0]);
- message.resize(logLength-1);
- }
+ message.resize(std::max(logLength, 1)-1);
/* Show error log and delete shader */
if(!success) {
diff --git a/src/AbstractTexture.cpp b/src/AbstractTexture.cpp
index 315cdd811..e96b931be 100644
--- a/src/AbstractTexture.cpp
+++ b/src/AbstractTexture.cpp
@@ -29,6 +29,8 @@
#include "Context.h"
#include "Extensions.h"
#include "Image.h"
+#include "ImageFormat.h"
+#include "TextureFormat.h"
#include "Implementation/State.h"
#include "Implementation/TextureState.h"
@@ -50,12 +52,12 @@ AbstractTexture::MipmapImplementation AbstractTexture::mipmapImplementation =
&AbstractTexture::mipmapImplementationDefault;
#ifndef MAGNUM_TARGET_GLES
AbstractTexture::Storage1DImplementation AbstractTexture::storage1DImplementation =
- &AbstractTexture::storageImplementationDefault;
+ &AbstractTexture::storageImplementationFallback;
#endif
AbstractTexture::Storage2DImplementation AbstractTexture::storage2DImplementation =
- &AbstractTexture::storageImplementationDefault;
+ &AbstractTexture::storageImplementationFallback;
AbstractTexture::Storage3DImplementation AbstractTexture::storage3DImplementation =
- &AbstractTexture::storageImplementationDefault;
+ &AbstractTexture::storageImplementationFallback;
#ifndef MAGNUM_TARGET_GLES
AbstractTexture::GetImageImplementation AbstractTexture::getImageImplementation =
&AbstractTexture::getImageImplementationDefault;
@@ -205,9 +207,6 @@ void AbstractTexture::initializeContextBasedFunctionality(Context* context) {
parameterfvImplementation = &AbstractTexture::parameterImplementationDSA;
getLevelParameterivImplementation = &AbstractTexture::getLevelParameterImplementationDSA;
mipmapImplementation = &AbstractTexture::mipmapImplementationDSA;
- storage1DImplementation = &AbstractTexture::storageImplementationDSA;
- storage2DImplementation = &AbstractTexture::storageImplementationDSA;
- storage3DImplementation = &AbstractTexture::storageImplementationDSA;
getImageImplementation = &AbstractTexture::getImageImplementationDSA;
image1DImplementation = &AbstractTexture::imageImplementationDSA;
image2DImplementation = &AbstractTexture::imageImplementationDSA;
@@ -230,9 +229,396 @@ void AbstractTexture::initializeContextBasedFunctionality(Context* context) {
getImageImplementation = &AbstractTexture::getImageImplementationRobustness;
}
+
+ if(context->isExtensionSupported()) {
+ Debug() << "AbstractTexture: using" << Extensions::GL::ARB::texture_storage::string() << "features";
+
+ if(context->isExtensionSupported()) {
+ storage1DImplementation = &AbstractTexture::storageImplementationDSA;
+ storage2DImplementation = &AbstractTexture::storageImplementationDSA;
+ storage3DImplementation = &AbstractTexture::storageImplementationDSA;
+ } else {
+ storage1DImplementation = &AbstractTexture::storageImplementationDefault;
+ storage2DImplementation = &AbstractTexture::storageImplementationDefault;
+ storage3DImplementation = &AbstractTexture::storageImplementationDefault;
+ }
+ }
#endif
}
+ImageFormat AbstractTexture::imageFormatForInternalFormat(const TextureFormat internalFormat) {
+ switch(internalFormat) {
+ case TextureFormat::Red:
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::R8:
+ case TextureFormat::R8Snorm:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::R16:
+ case TextureFormat::R16Snorm:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::R16F:
+ case TextureFormat::R32F:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::CompressedRed:
+ case TextureFormat::CompressedRedRtgc1:
+ case TextureFormat::CompressedSignedRedRgtc1:
+ #endif
+ return ImageFormat::Red;
+
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::R8UI:
+ case TextureFormat::R8I:
+ case TextureFormat::R16UI:
+ case TextureFormat::R16I:
+ case TextureFormat::R32UI:
+ case TextureFormat::R32I:
+ return ImageFormat::RedInteger;
+ #endif
+
+ case TextureFormat::RG:
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::RG8:
+ case TextureFormat::RG8Snorm:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::RG16:
+ case TextureFormat::RG16Snorm:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::RG16F:
+ case TextureFormat::RG32F:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::CompressedRG:
+ case TextureFormat::CompressedRGRgtc2:
+ case TextureFormat::CompressedSignedRGRgtc2:
+ #endif
+ return ImageFormat::RG;
+
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::RG8UI:
+ case TextureFormat::RG8I:
+ case TextureFormat::RG16UI:
+ case TextureFormat::RG16I:
+ case TextureFormat::RG32UI:
+ case TextureFormat::RG32I:
+ return ImageFormat::RGInteger;
+ #endif
+
+ case TextureFormat::RGB:
+ case TextureFormat::RGB8:
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::RGB8Snorm:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::RGB16:
+ case TextureFormat::RGB16Snorm:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::RGB16F:
+ case TextureFormat::RGB32F:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::R3B3G2:
+ case TextureFormat::RGB4:
+ case TextureFormat::RGB5:
+ #endif
+ case TextureFormat::RGB565:
+ #ifndef MAGNUM_TARGET_GLES3
+ case TextureFormat::RGB10:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::RGB12:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::R11FG11FB10F:
+ case TextureFormat::RGB9E5:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES3
+ case TextureFormat::SRGB:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::SRGB8:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::CompressedRGB:
+ case TextureFormat::CompressedRGBBptcUnsignedFloat:
+ case TextureFormat::CompressedRGBBptcSignedFloat:
+ #endif
+ return ImageFormat::RGB;
+
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::RGB8UI:
+ case TextureFormat::RGB8I:
+ case TextureFormat::RGB16UI:
+ case TextureFormat::RGB16I:
+ case TextureFormat::RGB32UI:
+ case TextureFormat::RGB32I:
+ return ImageFormat::RGBInteger;
+ #endif
+
+ case TextureFormat::RGBA:
+ case TextureFormat::RGBA8:
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::RGBA8Snorm:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::RGBA16:
+ case TextureFormat::RGBA16Snorm:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::RGBA16F:
+ case TextureFormat::RGBA32F:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::RGBA2:
+ #endif
+ case TextureFormat::RGBA4:
+ case TextureFormat::RGB5A1:
+ case TextureFormat::RGB10A2:
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::RGBA12:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES3
+ case TextureFormat::SRGBAlpha:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::SRGB8Alpha8:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::CompressedRGBA:
+ case TextureFormat::CompressedRGBABptcUnorm:
+ case TextureFormat::CompressedSRGBAlphaBptcUnorm:
+ #endif
+ return ImageFormat::RGBA;
+
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::RGBA8UI:
+ case TextureFormat::RGBA8I:
+ case TextureFormat::RGBA16UI:
+ case TextureFormat::RGBA16I:
+ case TextureFormat::RGBA32UI:
+ case TextureFormat::RGBA32I:
+ case TextureFormat::RGB10A2UI:
+ return ImageFormat::RGBAInteger;
+ #endif
+
+ #ifdef MAGNUM_TARGET_GLES2
+ case TextureFormat::Luminance:
+ return ImageFormat::Luminance;
+ case TextureFormat::LuminanceAlpha:
+ return ImageFormat::LuminanceAlpha;
+ #endif
+
+ case TextureFormat::DepthComponent:
+ case TextureFormat::DepthComponent16:
+ case TextureFormat::DepthComponent24:
+ #ifndef MAGNUM_TARGET_GLES3
+ case TextureFormat::DepthComponent32:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::DepthComponent32F:
+ #endif
+ return ImageFormat::DepthComponent;
+
+ case TextureFormat::DepthStencil:
+ case TextureFormat::Depth24Stencil8:
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::Depth32FStencil8:
+ #endif
+ return ImageFormat::DepthStencil;
+ }
+
+ CORRADE_ASSERT_UNREACHABLE();
+}
+
+ImageType AbstractTexture::imageTypeForInternalFormat(const TextureFormat internalFormat) {
+ switch(internalFormat) {
+ case TextureFormat::Red:
+ case TextureFormat::RG:
+ case TextureFormat::RGB:
+ case TextureFormat::RGBA:
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::R8:
+ case TextureFormat::RG8:
+ #endif
+ case TextureFormat::RGB8:
+ case TextureFormat::RGBA8:
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::R8UI:
+ case TextureFormat::RG8UI:
+ case TextureFormat::RGB8UI:
+ case TextureFormat::RGBA8UI:
+ #endif
+ #ifdef MAGNUM_TARGET_GLES2
+ case TextureFormat::Luminance:
+ case TextureFormat::LuminanceAlpha:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES3
+ case TextureFormat::SRGB:
+ case TextureFormat::SRGBAlpha:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::SRGB8:
+ case TextureFormat::SRGB8Alpha8:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::RGBA2: /**< @todo really? */
+ case TextureFormat::CompressedRed:
+ case TextureFormat::CompressedRG:
+ case TextureFormat::CompressedRGB:
+ case TextureFormat::CompressedRGBA:
+ case TextureFormat::CompressedRedRtgc1:
+ case TextureFormat::CompressedRGRgtc2:
+ case TextureFormat::CompressedRGBABptcUnorm:
+ case TextureFormat::CompressedSRGBAlphaBptcUnorm:
+ #endif
+ return ImageType::UnsignedByte;
+
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::R8Snorm:
+ case TextureFormat::RG8Snorm:
+ case TextureFormat::RGB8Snorm:
+ case TextureFormat::RGBA8Snorm:
+ case TextureFormat::R8I:
+ case TextureFormat::RG8I:
+ case TextureFormat::RGB8I:
+ case TextureFormat::RGBA8I:
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::CompressedSignedRedRgtc1:
+ case TextureFormat::CompressedSignedRGRgtc2:
+ #endif
+ return ImageType::Byte;
+ #endif
+
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::R16:
+ case TextureFormat::RG16:
+ case TextureFormat::RGB16:
+ case TextureFormat::RGBA16:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::R16UI:
+ case TextureFormat::RG16UI:
+ case TextureFormat::RGB16UI:
+ case TextureFormat::RGBA16UI:
+ #endif
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::RGB12: /**< @todo really? */
+ #endif
+ case TextureFormat::RGBA4: /**< @todo really? */
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::RGBA12: /**< @todo really? */
+ #endif
+ return ImageType::UnsignedShort;
+
+ #ifndef MAGNUM_TARGET_GLES2
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::R16Snorm:
+ case TextureFormat::RG16Snorm:
+ case TextureFormat::RGB16Snorm:
+ case TextureFormat::RGBA16Snorm:
+ #endif
+ case TextureFormat::R16I:
+ case TextureFormat::RG16I:
+ case TextureFormat::RGB16I:
+ case TextureFormat::RGBA16I:
+ return ImageType::Short;
+ #endif
+
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::R16F:
+ case TextureFormat::RG16F:
+ case TextureFormat::RGB16F:
+ case TextureFormat::RGBA16F:
+ return ImageType::HalfFloat;
+
+ case TextureFormat::R32UI:
+ case TextureFormat::RG32UI:
+ case TextureFormat::RGB32UI:
+ case TextureFormat::RGBA32UI:
+ return ImageType::UnsignedInt;
+
+ case TextureFormat::R32I:
+ case TextureFormat::RG32I:
+ case TextureFormat::RGB32I:
+ case TextureFormat::RGBA32I:
+ return ImageType::Int;
+
+ case TextureFormat::R32F:
+ case TextureFormat::RG32F:
+ case TextureFormat::RGB32F:
+ case TextureFormat::RGBA32F:
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::CompressedRGBBptcUnsignedFloat:
+ case TextureFormat::CompressedRGBBptcSignedFloat:
+ #endif
+ return ImageType::Float;
+ #endif
+
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::R3B3G2:
+ return ImageType::UnsignedByte332;
+ case TextureFormat::RGB4:
+ return ImageType::UnsignedShort4444;
+ #endif
+
+ #ifndef MAGNUM_TARGET_GLES
+ case TextureFormat::RGB5:
+ #endif
+ case TextureFormat::RGB5A1:
+ return ImageType::UnsignedShort5551;
+
+ case TextureFormat::RGB565:
+ return ImageType::UnsignedShort565;
+
+ #ifndef MAGNUM_TARGET_GLES3
+ case TextureFormat::RGB10:
+ #endif
+ case TextureFormat::RGB10A2:
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::RGB10A2UI:
+ #endif
+ return ImageType::UnsignedInt2101010Rev; /**< @todo Rev for all? */
+
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::R11FG11FB10F:
+ return ImageType::UnsignedInt10F11F11FRev;
+ case TextureFormat::RGB9E5:
+ return ImageType::UnsignedInt5999Rev;
+ #endif
+
+ case TextureFormat::DepthComponent16:
+ return ImageType::UnsignedShort;
+
+ case TextureFormat::DepthComponent:
+ case TextureFormat::DepthComponent24:
+ #ifndef MAGNUM_TARGET_GLES3
+ case TextureFormat::DepthComponent32:
+ #endif
+ return ImageType::UnsignedInt;
+
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::DepthComponent32F:
+ return ImageType::Float;
+ #endif
+
+ case TextureFormat::DepthStencil:
+ case TextureFormat::Depth24Stencil8:
+ return ImageType::UnsignedInt248;
+
+ #ifndef MAGNUM_TARGET_GLES2
+ case TextureFormat::Depth32FStencil8:
+ return ImageType::Float32UnsignedInt248Rev;
+ #endif
+ }
+
+ CORRADE_ASSERT_UNREACHABLE();
+}
+
void AbstractTexture::parameterImplementationDefault(GLenum parameter, GLint value) {
bindInternal();
glTexParameteri(_target, parameter, value);
@@ -278,7 +664,20 @@ void AbstractTexture::getLevelParameterImplementationDSA(GLenum target, GLint le
#endif
#ifndef MAGNUM_TARGET_GLES
-void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector< 1, GLsizei >& size) {
+void AbstractTexture::storageImplementationFallback(const GLenum target, const GLsizei levels, const TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size) {
+ CORRADE_INTERNAL_ASSERT(target == GL_TEXTURE_1D);
+
+ const ImageFormat format = imageFormatForInternalFormat(internalFormat);
+ const ImageType type = imageTypeForInternalFormat(internalFormat);
+
+ auto levelSize = size;
+ for(GLsizei level = 0; level != levels; ++level) {
+ (this->*image1DImplementation)(target, level, internalFormat, levelSize, format, type, nullptr);
+ levelSize = Math::max(Math::Vector<1, GLsizei>(1), levelSize/2);
+ }
+}
+
+void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size) {
bindInternal();
/** @todo Re-enable when extension wrangler is available for ES2 */
#ifndef MAGNUM_TARGET_GLES2
@@ -292,11 +691,56 @@ void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels
#endif
}
-void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector< 1, GLsizei >& size) {
+void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size) {
glTextureStorage1DEXT(_id, target, levels, GLenum(internalFormat), size[0]);
}
#endif
+void AbstractTexture::storageImplementationFallback(const GLenum target, const GLsizei levels, const TextureFormat internalFormat, const Vector2i& size) {
+ const ImageFormat format = imageFormatForInternalFormat(internalFormat);
+ const ImageType type = imageTypeForInternalFormat(internalFormat);
+
+ /* Common code for classic types */
+ #ifndef MAGNUM_TARGET_GLES
+ if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE)
+ #else
+ if(target == GL_TEXTURE_2D)
+ #endif
+ {
+ Vector2i levelSize = size;
+ for(GLsizei level = 0; level != levels; ++level) {
+ (this->*image2DImplementation)(target, level, internalFormat, levelSize, format, type, nullptr);
+ levelSize = Math::max(Vector2i(1), levelSize/2);
+ }
+
+ /* Cube map additionaly needs to specify all faces */
+ } else if(target == GL_TEXTURE_CUBE_MAP) {
+ Vector2i levelSize = size;
+ for(GLsizei level = 0; level != levels; ++level) {
+ for(GLenum face: {GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z})
+ (this->*image2DImplementation)(face, level, internalFormat, levelSize, format, type, nullptr);
+ levelSize = Math::max(Vector2i(1), levelSize/2);
+ }
+
+ #ifndef MAGNUM_TARGET_GLES
+ /* Array texture is not scaled in "layer" dimension */
+ } else if(target == GL_TEXTURE_1D_ARRAY) {
+ Vector2i levelSize = size;
+ for(GLsizei level = 0; level != levels; ++level) {
+ (this->*image2DImplementation)(target, level, internalFormat, levelSize, format, type, nullptr);
+ levelSize.x() = Math::max(1, levelSize.x()/2);
+ }
+ #endif
+
+ /* No other targets are available */
+ } else CORRADE_ASSERT_UNREACHABLE();
+}
+
void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size) {
bindInternal();
/** @todo Re-enable when extension wrangler is available for ES2 */
@@ -317,6 +761,43 @@ void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, Te
}
#endif
+void AbstractTexture::storageImplementationFallback(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size) {
+ const ImageFormat format = imageFormatForInternalFormat(internalFormat);
+ const ImageType type = imageTypeForInternalFormat(internalFormat);
+
+ /* Common code for classic type */
+ #ifndef MAGNUM_TARGET_GLES2
+ if(target == GL_TEXTURE_3D)
+ #else
+ if(target == GL_TEXTURE_3D_OES)
+ #endif
+ {
+ Vector3i levelSize = size;
+ for(GLsizei level = 0; level != levels; ++level) {
+ (this->*image3DImplementation)(target, level, internalFormat, levelSize, format, type, nullptr);
+ levelSize = Math::max(Vector3i(1), levelSize/2);
+ }
+
+ #ifndef MAGNUM_TARGET_GLES2
+ /* Array texture is not scaled in "layer" dimension */
+ }
+ #ifndef MAGNUM_TARGET_GLES
+ else if(target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_CUBE_MAP_ARRAY)
+ #else
+ else if(target == GL_TEXTURE_2D_ARRAY)
+ #endif
+ {
+ Vector3i levelSize = size;
+ for(GLsizei level = 0; level != levels; ++level) {
+ (this->*image3DImplementation)(target, level, internalFormat, levelSize, format, type, nullptr);
+ levelSize.xy() = Math::max(Vector2i(1), levelSize.xy()/2);
+ }
+ #endif
+
+ /* No other targets are available */
+ } else CORRADE_ASSERT_UNREACHABLE();
+}
+
void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size) {
bindInternal();
/** @todo Re-enable when extension wrangler is available for ES2 */
diff --git a/src/AbstractTexture.h b/src/AbstractTexture.h
index 44292becc..018b2b228 100644
--- a/src/AbstractTexture.h
+++ b/src/AbstractTexture.h
@@ -77,6 +77,13 @@ avoid redundant consistency checks and memory reallocations when updating
texture data, set texture storage at once using @ref Texture::setStorage() "setStorage()"
and then set data using @ref Texture::setSubImage() "setSubImage()".
+Function @ref Texture::setStorage() "setStorage()" creates immutable texture
+storage, removing the need for additional consistency checks and memory
+reallocations when updating the data later. If OpenGL 4.2, @extension{ARB,texture_storage},
+OpenGL ES 3.0 or @es_extension{EXT,texture_storage} in OpenGL ES 2.0 is not
+available, the feature is emulated with sequence of @ref Texture::setImage() "setImage()"
+calls.
+
You can use functions invalidateImage() and @ref Texture::invalidateSubImage() "invalidateSubImage()"
if you don't need texture data anymore to avoid unnecessary memory operations
performed by OpenGL in order to preserve the data. If running on OpenGL ES or
@@ -251,7 +258,7 @@ class MAGNUM_EXPORT AbstractTexture {
* @see setMinificationFilter(), @fn_gl{ActiveTexture},
* @fn_gl{BindTexture} and @fn_gl{GenerateMipmap} or
* @fn_gl_extension{GenerateTextureMipmap,EXT,direct_state_access}
- * @requires_gl30 %Extension @extension{EXT,framebuffer_object}
+ * @requires_gl30 %Extension @extension{ARB,framebuffer_object}
*/
AbstractTexture* generateMipmap();
@@ -319,12 +326,14 @@ class MAGNUM_EXPORT AbstractTexture {
#ifndef MAGNUM_TARGET_GLES
typedef void(AbstractTexture::*Storage1DImplementation)(GLenum, GLsizei, TextureFormat, const Math::Vector<1, GLsizei>&);
+ void MAGNUM_LOCAL storageImplementationFallback(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size);
void MAGNUM_LOCAL storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size);
void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size);
static Storage1DImplementation storage1DImplementation;
#endif
typedef void(AbstractTexture::*Storage2DImplementation)(GLenum, GLsizei, TextureFormat, const Vector2i&);
+ void MAGNUM_LOCAL storageImplementationFallback(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size);
void MAGNUM_LOCAL storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size);
@@ -332,6 +341,7 @@ class MAGNUM_EXPORT AbstractTexture {
static Storage2DImplementation storage2DImplementation;
typedef void(AbstractTexture::*Storage3DImplementation)(GLenum, GLsizei, TextureFormat, const Vector3i&);
+ void MAGNUM_LOCAL storageImplementationFallback(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size);
void MAGNUM_LOCAL storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size);
@@ -404,6 +414,8 @@ class MAGNUM_EXPORT AbstractTexture {
void MAGNUM_LOCAL destroy();
void MAGNUM_LOCAL move();
+ ImageFormat MAGNUM_LOCAL imageFormatForInternalFormat(TextureFormat internalFormat);
+ ImageType MAGNUM_LOCAL imageTypeForInternalFormat(TextureFormat internalFormat);
GLuint _id;
};
diff --git a/src/Context.cpp b/src/Context.cpp
index c91bf90a5..25014c222 100644
--- a/src/Context.cpp
+++ b/src/Context.cpp
@@ -97,14 +97,7 @@ const std::vector& Extension::extensions(Version version) {
_extension(GL,ARB,texture_float), // done
_extension(GL,ARB,depth_buffer_float), // done
_extension(GL,ARB,texture_rg), // done
- /**
- * @todo Remove as it doesn't have the same functionality present in
- * GL 3.0 and replace with ARB_framebuffer_object?
- */
- _extension(GL,EXT,framebuffer_object),
- _extension(GL,EXT,packed_depth_stencil), // done
- _extension(GL,EXT,framebuffer_blit), // done
- _extension(GL,EXT,framebuffer_multisample),
+ _extension(GL,ARB,framebuffer_object),
_extension(GL,EXT,gpu_shader4),
_extension(GL,EXT,packed_float), // done
_extension(GL,EXT,texture_array),
@@ -213,7 +206,13 @@ const std::vector& Extension::extensions(Version version) {
_extension(GL,EXT,disjoint_timer_query),
_extension(GL,EXT,separate_shader_objects),
_extension(GL,EXT,sRGB),
+ /**
+ * @todo Support also IMG_multisampled_render_to_texture? It has
+ * different enum values (!)
+ */
+ _extension(GL,EXT,multisampled_render_to_texture),
_extension(GL,EXT,robustness),
+ _extension(GL,KHR,debug),
_extension(GL,NV,read_buffer_front),
_extension(GL,NV,read_stencil),
_extension(GL,NV,texture_border_clamp), // done
@@ -253,7 +252,8 @@ const std::vector& Extension::extensions(Version version) {
_extension(GL,OES,depth_texture),
_extension(GL,OES,standard_derivatives), // done
_extension(GL,OES,vertex_array_object),
- _extension(GL,OES,required_internalformat)};
+ _extension(GL,OES,required_internalformat),
+ _extension(GL,OES,surfaceless_context)}; // done
#endif
switch(version) {
@@ -292,6 +292,14 @@ Context::Context() {
#endif
_version = static_cast(_majorVersion*100+_minorVersion*10);
+ #ifndef MAGNUM_TARGET_GLES
+ CORRADE_ASSERT(isVersionSupported(Version::GL210), "Context: unsupported OpenGL version" << Int(_version), );
+ #elif defined(MAGNUM_TARGET_GLES2)
+ CORRADE_ASSERT(isVersionSupported(Version::GLES200), "Context: unsupported OpenGL ES version" << Int(_version), );
+ #else
+ CORRADE_ASSERT(isVersionSupported(Version::GLES300), "Context: unsupported OpenGL ES version" << Int(_version), );
+ #endif
+
/* Context flags are supported since GL 3.0 */
#ifndef MAGNUM_TARGET_GLES
/**
diff --git a/src/Context.h b/src/Context.h
index 5e42b8620..1ee1dad67 100644
--- a/src/Context.h
+++ b/src/Context.h
@@ -382,8 +382,8 @@ class MAGNUM_EXPORT Context {
Useful for initial checks on availability of required features.
By default, if assertion fails, an message is printed to error output and the
-application exits with value `-3`. If `CORRADE_NO_ASSERT` is defined, this
-macro does nothing. Example usage:
+application aborts. If `CORRADE_NO_ASSERT` is defined, this macro does nothing.
+Example usage:
@code
MAGNUM_ASSERT_VERSION_SUPPORTED(Version::GL330);
@endcode
@@ -399,7 +399,7 @@ MAGNUM_ASSERT_VERSION_SUPPORTED(Version::GL330);
do { \
if(!Magnum::Context::current()->isVersionSupported(version)) { \
Corrade::Utility::Error() << "Magnum: required version" << version << "is not supported"; \
- std::exit(-3); \
+ std::abort(); \
} \
} while(0)
#endif
@@ -412,8 +412,8 @@ MAGNUM_ASSERT_VERSION_SUPPORTED(Version::GL330);
Useful for initial checks on availability of required features.
By default, if assertion fails, an message is printed to error output and the
-application exits with value `-3`. If `CORRADE_NO_ASSERT` is defined, this
-macro does nothing. Example usage:
+application aborts. If `CORRADE_NO_ASSERT` is defined, this macro does nothing.
+Example usage:
@code
MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::geometry_shader4);
@endcode
@@ -429,7 +429,7 @@ MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::geometry_shader4);
do { \
if(!Magnum::Context::current()->isExtensionSupported()) { \
Corrade::Utility::Error() << "Magnum: required extension" << extension::string() << "is not supported"; \
- std::exit(-3); \
+ std::abort(); \
} \
} while(0)
#endif
diff --git a/src/DefaultFramebuffer.cpp b/src/DefaultFramebuffer.cpp
index 5e1c9e021..346bd6ad5 100644
--- a/src/DefaultFramebuffer.cpp
+++ b/src/DefaultFramebuffer.cpp
@@ -90,4 +90,17 @@ void DefaultFramebuffer::initializeContextBasedFunctionality(Context* context) {
#endif
}
+#ifndef DOXYGEN_GENERATING_OUTPUT
+Debug operator<<(Debug debug, const DefaultFramebuffer::Status value) {
+ switch(value) {
+ #define _c(value) case DefaultFramebuffer::Status::value: return debug << "DefaultFramebuffer::Status::" #value;
+ _c(Complete)
+ _c(Undefined)
+ #undef _c
+ }
+
+ return debug << "DefaultFramebuffer::Status::(invalid)";
+}
+#endif
+
}
diff --git a/src/DefaultFramebuffer.h b/src/DefaultFramebuffer.h
index 8f0a38148..a7e4bb7c0 100644
--- a/src/DefaultFramebuffer.h
+++ b/src/DefaultFramebuffer.h
@@ -80,6 +80,27 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer {
friend class Context;
public:
+ /**
+ * @brief Status
+ *
+ * @see checkStatus()
+ * @requires_gl30 %Extension @extension{ARB,framebuffer_object}
+ */
+ enum class Status: GLenum {
+ /** The framebuffer is complete */
+ Complete = GL_FRAMEBUFFER_COMPLETE,
+
+ /**
+ * The default framebuffer does not exist.
+ * @requires_es_extension %Extension @es_extension{OES,surfaceless_context}
+ */
+ #ifndef MAGNUM_TARGET_GLES2
+ Undefined = GL_FRAMEBUFFER_UNDEFINED
+ #else
+ Undefined = GL_FRAMEBUFFER_UNDEFINED_OES
+ #endif
+ };
+
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Draw attachment
@@ -270,6 +291,21 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer {
explicit MAGNUM_LOCAL DefaultFramebuffer();
+ /**
+ * @brief Check framebuffer status
+ * @param target Target for which to check the status
+ *
+ * If @extension{EXT,direct_state_access} is not available and the
+ * framebuffer is not currently bound, it is bound before the
+ * operation.
+ * @see @fn_gl{BindFramebuffer}, @fn_gl{CheckFramebufferStatus} or
+ * @fn_gl_extension{CheckNamedFramebufferStatus,EXT,direct_state_access}
+ * @requires_gl30 %Extension @extension{ARB,framebuffer_object}
+ */
+ Status checkStatus(FramebufferTarget target) {
+ return Status((this->*checkStatusImplementation)(target));
+ }
+
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Map shader outputs to buffer attachment
@@ -285,7 +321,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer {
* @endcode
*
* If @extension{EXT,direct_state_access} is not available and the
- * framebufferbuffer is not currently bound, it is bound before the
+ * framebuffer is not currently bound, it is bound before the
* operation.
* @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffers} or
* @fn_gl_extension{FramebufferDrawBuffers,EXT,direct_state_access}
@@ -303,7 +339,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer {
* only one (unnamed) output.
*
* If @extension{EXT,direct_state_access} is not available and the
- * framebufferbuffer is not currently bound, it is bound before the
+ * framebuffer is not currently bound, it is bound before the
* operation.
* @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffer} or
* @fn_gl_extension{FramebufferDrawBuffer,EXT,direct_state_access},
@@ -323,7 +359,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer {
* @return Pointer to self (for method chaining)
*
* If @extension{EXT,direct_state_access} is not available and the
- * framebufferbuffer is not currently bound, it is bound before the
+ * framebuffer is not currently bound, it is bound before the
* operation.
* @see mapForDraw(), @fn_gl{BindFramebuffer}, @fn_gl{ReadBuffer} or
* @fn_gl_extension{FramebufferReadBuffer,EXT,direct_state_access}
@@ -380,6 +416,9 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer {
/** @brief Default framebuffer instance */
extern DefaultFramebuffer MAGNUM_EXPORT defaultFramebuffer;
+/** @debugoperator{DefaultFramebuffer} */
+Debug MAGNUM_EXPORT operator<<(Debug debug, DefaultFramebuffer::Status value);
+
}
#endif
diff --git a/src/Extensions.h b/src/Extensions.h
index ea74900da..f1582d657 100644
--- a/src/Extensions.h
+++ b/src/Extensions.h
@@ -76,6 +76,7 @@ namespace GL {
_extension(GL,ARB,texture_float, GL210, GL300) // #41
_extension(GL,ARB,depth_buffer_float, GL210, GL300) // #43
_extension(GL,ARB,draw_instanced, GL210, GL310) // #44
+ _extension(GL,ARB,framebuffer_object, GL210, GL300) // #45
_extension(GL,ARB,geometry_shader4, GL210, GL320) // #47
_extension(GL,ARB,instanced_arrays, GL210, GL330) // #49
_extension(GL,ARB,map_buffer_range, GL210, GL300) // #50
@@ -154,10 +155,8 @@ namespace GL {
_extension(GL,ARB,texture_storage_multisample, GL210, GL430) // #141
} namespace EXT {
_extension(GL,EXT,texture_filter_anisotropic, GL210, None) // #187
- _extension(GL,EXT,framebuffer_object, GL210, GL300) // #310
- _extension(GL,EXT,packed_depth_stencil, GL210, GL300) // #312
- _extension(GL,EXT,framebuffer_blit, GL210, GL300) // #316
- _extension(GL,EXT,framebuffer_multisample, GL210, GL300) // #317
+ /* EXT_framebuffer_object, EXT_packed_depth_stencil, EXT_framebuffer_blit,
+ EXT_framebuffer_multisample replaced with ARB_framebuffer_object */
_extension(GL,EXT,gpu_shader4, GL210, GL300) // #326
_extension(GL,EXT,packed_float, GL210, GL300) // #328
_extension(GL,EXT,texture_array, GL210, GL300) // #329
@@ -206,10 +205,13 @@ namespace GL {
_extension(GL,EXT,separate_shader_objects, GLES200, None) // #101
_extension(GL,EXT,texture_rg, GLES200, GLES300) // #103
_extension(GL,EXT,sRGB, GLES200, None) // #105
- _extension(GL,EXT,robustness, GLES200, None) // #105
+ _extension(GL,EXT,multisampled_render_to_texture, GLES200, None) // #106
+ _extension(GL,EXT,robustness, GLES200, None) // #107
_extension(GL,EXT,texture_storage, GLES200, GLES300) // #108
_extension(GL,EXT,map_buffer_range, GLES200, GLES300) // #121
_extension(GL,EXT,disjoint_timer_query, GLES200, None) // #150
+ } namespace KHR {
+ _extension(GL,KHR,debug, GLES200, None) // #118
} namespace NV {
_extension(GL,NV,draw_buffers, GLES200, GLES300) // #91
_extension(GL,NV,read_buffer, GLES200, GLES300) // #93
@@ -238,7 +240,8 @@ namespace GL {
_extension(GL,OES,depth_texture, GLES200, GLES300) // #44
_extension(GL,OES,standard_derivatives, GLES200, GLES300) // #45
_extension(GL,OES,vertex_array_object, GLES200, GLES300) // #71
- _extension(GL,OES,required_internalformat, GLES200, GLES300) // #?
+ _extension(GL,OES,required_internalformat, GLES200, GLES300) // #115
+ _extension(GL,OES,surfaceless_context, GLES200, GLES300) // #116
}
#endif
}
diff --git a/src/Framebuffer.cpp b/src/Framebuffer.cpp
index ba3c1ddc6..3e320306a 100644
--- a/src/Framebuffer.cpp
+++ b/src/Framebuffer.cpp
@@ -172,4 +172,27 @@ void Framebuffer::texture3DImplementationDSA(BufferAttachment attachment, Textur
}
#endif
+#ifndef DOXYGEN_GENERATING_OUTPUT
+Debug operator<<(Debug debug, const Framebuffer::Status value) {
+ switch(value) {
+ #define _c(value) case Framebuffer::Status::value: return debug << "Framebuffer::Status::" #value;
+ _c(Complete)
+ _c(IncompleteAttachment)
+ _c(IncompleteMissingAttachment)
+ #ifndef MAGNUM_TARGET_GLES
+ _c(IncompleteDrawBuffer)
+ _c(IncompleteReadBuffer)
+ #endif
+ _c(Unsupported)
+ _c(IncompleteMultisample)
+ #ifndef MAGNUM_TARGET_GLES
+ _c(IncompleteLayerTargets)
+ #endif
+ #undef _c
+ }
+
+ return debug << "Framebuffer::Status::(invalid)";
+}
+#endif
+
}
diff --git a/src/Framebuffer.h b/src/Framebuffer.h
index 7991cc029..6941e3ec0 100644
--- a/src/Framebuffer.h
+++ b/src/Framebuffer.h
@@ -94,7 +94,7 @@ attachTexture2D(), attachCubeMapTexture() and attachTexture3D() use DSA
to avoid unnecessary calls to @fn_gl{BindFramebuffer}. See their respective
documentation for more information.
-@requires_gl30 %Extension @extension{EXT,framebuffer_object}
+@requires_gl30 %Extension @extension{ARB,framebuffer_object}
*/
class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
friend class Context;
@@ -228,6 +228,66 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
GLenum attachment;
};
+ /**
+ * @brief Status
+ *
+ * @see checkStatus()
+ */
+ enum class Status: GLenum {
+ /** The framebuffer is complete */
+ Complete = GL_FRAMEBUFFER_COMPLETE,
+
+ /** Any of the attachment points are incomplete */
+ IncompleteAttachment = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
+
+ /** The framebuffer does not have at least one image attached to it */
+ IncompleteMissingAttachment = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT,
+
+ #ifndef MAGNUM_TARGET_GLES
+ /** @todo Why exactly this is not needed? */
+ /**
+ * No object attached to any draw color attachment points
+ * @requires_gl Not available in OpenGL ES.
+ */
+ IncompleteDrawBuffer = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER,
+
+ /**
+ * No object attached to read color attachment point
+ * @requires_gl Not available in OpenGL ES.
+ */
+ IncompleteReadBuffer = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER,
+ #endif
+
+ /**
+ * Combination of internal formats of the attached images violates
+ * an implementation-dependent set of restrictions.
+ */
+ Unsupported = GL_FRAMEBUFFER_UNSUPPORTED,
+
+ /**
+ * Sample count or locations are not the same for all attached
+ * images.
+ * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_multisample},
+ * @es_extension{APPLE,framebuffer_multisample},
+ * @es_extension{EXT,multisampled_render_to_texture} or
+ * @es_extension{NV,framebuffer_multisample}
+ */
+ #ifndef MAGNUM_TARGET_GLES2
+ IncompleteMultisample = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
+ #else
+ IncompleteMultisample = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE,
+ #endif
+
+ #ifndef MAGNUM_TARGET_GLES
+ /** @todo Why exactly this is not needed? */
+ /**
+ * Mismatched layered color attachments
+ * @requires_gl Not available in OpenGL ES.
+ */
+ IncompleteLayerTargets = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS
+ #endif
+ };
+
/**
* @brief Constructor
*
@@ -244,6 +304,20 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
*/
~Framebuffer();
+ /**
+ * @brief Check framebuffer status
+ * @param target Target for which check the status
+ *
+ * If @extension{EXT,direct_state_access} is not available and the
+ * framebuffer is not currently bound, it is bound before the
+ * operation.
+ * @see @fn_gl{BindFramebuffer}, @fn_gl{CheckFramebufferStatus} or
+ * @fn_gl_extension{CheckNamedFramebufferStatus,EXT,direct_state_access}
+ */
+ Status checkStatus(FramebufferTarget target) {
+ return Status((this->*checkStatusImplementation)(target));
+ }
+
/**
* @brief Map shader output to attachments
* @return Pointer to self (for method chaining)
@@ -468,6 +542,9 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer {
static Texture3DImplementation texture3DImplementation;
};
+/** @debugoperator{DefaultFramebuffer} */
+Debug MAGNUM_EXPORT operator<<(Debug debug, Framebuffer::Status value);
+
}
#endif
diff --git a/src/ImageFormat.cpp b/src/ImageFormat.cpp
index 014cf25eb..0d8d1fb88 100644
--- a/src/ImageFormat.cpp
+++ b/src/ImageFormat.cpp
@@ -37,7 +37,13 @@ Debug operator<<(Debug debug, ImageFormat value) {
_c(Green)
_c(Blue)
#endif
+ #ifdef MAGNUM_TARGET_GLES2
+ _c(Luminance)
+ #endif
_c(RG)
+ #ifdef MAGNUM_TARGET_GLES2
+ _c(LuminanceAlpha)
+ #endif
_c(RGB)
_c(RGBA)
#ifndef MAGNUM_TARGET_GLES
diff --git a/src/ImageFormat.h b/src/ImageFormat.h
index 23b2a58f8..2a358eca7 100644
--- a/src/ImageFormat.h
+++ b/src/ImageFormat.h
@@ -68,8 +68,18 @@ enum class ImageFormat: GLenum {
* available in OpenGL ES.
*/
Blue = GL_BLUE,
+ #endif
- /** @todo GL_ALPHA? */
+ #if defined(MAGNUM_TARGET_GLES2) || defined(DOXYGEN_GENERATING_OUTPUT)
+ /**
+ * Floating-point luminance channel. The value is used for all RGB
+ * channels.
+ * @deprecated Included for compatibility reasons only, use
+ * @ref Magnum::ImageFormat "ImageFormat::Red" instead.
+ * @requires_gles20 Not available in ES 3.0 or desktop OpenGL. Use
+ * @ref Magnum::ImageFormat "ImageFormat::Red" instead.
+ */
+ Luminance = GL_LUMINANCE,
#endif
/**
@@ -84,6 +94,18 @@ enum class ImageFormat: GLenum {
RG = GL_RG_EXT,
#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 Included for compatibility reasons only, use
+ * @ref Magnum::ImageFormat "ImageFormat::RG" instead.
+ * @requires_gles20 Not available in ES 3.0 or desktop OpenGL. Use
+ * @ref Magnum::ImageFormat "ImageFormat::RG" instead.
+ */
+ LuminanceAlpha = GL_LUMINANCE_ALPHA,
+ #endif
+
/**
* Floating-point RGB.
* @requires_gl Can't be used for framebuffer reading in OpenGL ES.
@@ -214,7 +236,7 @@ enum class ImageFormat: GLenum {
/**
* Depth and stencil.
- * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil}
+ * @requires_gl30 %Extension @extension{ARB,framebuffer_object}
* @requires_gles30 For texture data only, extension @es_extension{OES,packed_depth_stencil}.
* @requires_es_extension For framebuffer reading only, extension
* @es_extension2{NV,read_depth_stencil,GL_NV_read_depth_stencil}.
@@ -424,14 +446,16 @@ enum class ImageType: GLenum {
/**
* Unsigned int, depth component 24bit, stencil index 8bit.
- * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil}
+ * @requires_gl30 %Extension @extension{ARB,framebuffer_object}
* @requires_gles30 For texture data only, extension @es_extension{OES,packed_depth_stencil}.
*/
- #ifdef MAGNUM_TARGET_GLES2
- UnsignedInt248 = GL_UNSIGNED_INT_24_8_OES
- #else
+ #ifndef MAGNUM_TARGET_GLES2
UnsignedInt248 = GL_UNSIGNED_INT_24_8,
+ #else
+ UnsignedInt248 = GL_UNSIGNED_INT_24_8_OES,
+ #endif
+ #ifndef MAGNUM_TARGET_GLES2
/**
* Float + unsigned int, depth component 32bit float, 24bit gap, stencil
* index 8bit.
diff --git a/src/Platform/AbstractXApplication.h b/src/Platform/AbstractXApplication.h
index ac0710785..ba5bb5680 100644
--- a/src/Platform/AbstractXApplication.h
+++ b/src/Platform/AbstractXApplication.h
@@ -35,6 +35,7 @@
#include
#include
/* undef Xlib nonsense to avoid conflicts */
+#undef Complex
#undef None
#undef Always
diff --git a/src/Renderbuffer.h b/src/Renderbuffer.h
index cd41fb3fd..281a780f6 100644
--- a/src/Renderbuffer.h
+++ b/src/Renderbuffer.h
@@ -53,7 +53,7 @@ If extension @extension{EXT,direct_state_access} is available, function
setStorage() uses DSA to avoid unnecessary calls to @fn_gl{BindFramebuffer}.
See its documentation for more information.
-@requires_gl30 %Extension @extension{EXT,framebuffer_object}
+@requires_gl30 %Extension @extension{ARB,framebuffer_object}
*/
class MAGNUM_EXPORT Renderbuffer {
friend class Context;
@@ -109,7 +109,6 @@ class MAGNUM_EXPORT Renderbuffer {
* operation.
* @see @fn_gl{BindRenderbuffer}, @fn_gl{RenderbufferStorage} or
* @fn_gl_extension{NamedRenderbufferStorage,EXT,direct_state_access}
- * @requires_gl30 %Extension @extension{EXT,framebuffer_multisample}
* @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_multisample}
* or @es_extension{NV,framebuffer_multisample}
* @todo How about @es_extension{APPLE,framebuffer_multisample}?
diff --git a/src/RenderbufferFormat.h b/src/RenderbufferFormat.h
index f0d3de92f..fdb935ba1 100644
--- a/src/RenderbufferFormat.h
+++ b/src/RenderbufferFormat.h
@@ -36,6 +36,7 @@ namespace Magnum {
@brief Internal renderbuffer format
@see Renderbuffer
+@requires_gl30 %Extension @extension{ARB,framebuffer_object}
@todo RGB, RGB8 ES only (ES3 + @es_extension{OES,rgb8_rgba8})
*/
enum class RenderbufferFormat: GLenum {
@@ -481,7 +482,6 @@ enum class RenderbufferFormat: GLenum {
/**
* 24bit depth and 8bit stencil component.
- * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil}
* @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil}
*/
#ifdef MAGNUM_TARGET_GLES2
diff --git a/src/Renderer.cpp b/src/Renderer.cpp
index df9b41313..7fb8ed7a5 100644
--- a/src/Renderer.cpp
+++ b/src/Renderer.cpp
@@ -233,4 +233,51 @@ Renderer::GraphicsResetStatus Renderer::graphicsResetStatusImplementationRobustn
}
#endif
+#ifndef DOXYGEN_GENERATING_OUTPUT
+Debug operator<<(Debug debug, const Renderer::Error value) {
+ switch(value) {
+ #define _c(value) case Renderer::Error::value: return debug << "Renderer::Error::" #value;
+ _c(NoError)
+ _c(InvalidEnum)
+ _c(InvalidValue)
+ _c(InvalidOperation)
+ _c(InvalidFramebufferOperation)
+ _c(OutOfMemory)
+ #ifndef MAGNUM_TARGET_GLES3
+ _c(StackUnderflow)
+ _c(StackOverflow)
+ #endif
+ #undef _c
+ }
+
+ return debug << "Renderer::Error::(invalid)";
+}
+
+#ifndef MAGNUM_TARGET_GLES3
+Debug operator<<(Debug debug, const Renderer::ResetNotificationStrategy value) {
+ switch(value) {
+ #define _c(value) case Renderer::ResetNotificationStrategy::value: return debug << "Renderer::ResetNotificationStrategy::" #value;
+ _c(NoResetNotification)
+ _c(LoseContextOnReset)
+ #undef _c
+ }
+
+ return debug << "Renderer::ResetNotificationStrategy::(invalid)";
+}
+
+Debug operator<<(Debug debug, const Renderer::GraphicsResetStatus value) {
+ switch(value) {
+ #define _c(value) case Renderer::GraphicsResetStatus::value: return debug << "Renderer::GraphicsResetStatus::" #value;
+ _c(NoError)
+ _c(GuiltyContextReset)
+ _c(InnocentContextReset)
+ _c(UnknownContextReset)
+ #undef _c
+ }
+
+ return debug << "Renderer::ResetNotificationStrategy::(invalid)";
+}
+#endif
+#endif
+
}
diff --git a/src/Renderer.h b/src/Renderer.h
index 0ff490450..e66e8311b 100644
--- a/src/Renderer.h
+++ b/src/Renderer.h
@@ -871,6 +871,69 @@ class MAGNUM_EXPORT Renderer {
*/
static void finish() { glFinish(); }
+ /**
+ * @brief Error status
+ *
+ * @see error()
+ */
+ enum class Error: GLenum {
+ /** No error has been recorded */
+ NoError = GL_NO_ERROR,
+
+ /** An unacceptable value specified for enumerated argument */
+ InvalidEnum = GL_INVALID_ENUM,
+
+ /** A numeric argument is out of range */
+ InvalidValue = GL_INVALID_VALUE,
+
+ /** The specified operation is not allowed in the current state */
+ InvalidOperation = GL_INVALID_OPERATION,
+
+ /**
+ * The framebuffer object is not complete.
+ * @see AbstractFramebuffer::checkStatus()
+ * @requires_gl30 %Extension @extension{ARB,framebuffer_object}
+ */
+ InvalidFramebufferOperation = GL_INVALID_FRAMEBUFFER_OPERATION,
+
+ /** There is not enough memory left to execute the command. */
+ OutOfMemory = GL_OUT_OF_MEMORY,
+
+ #ifndef MAGNUM_TARGET_GLES3
+ /**
+ * Given operation would cause an internal stack to underflow.
+ * @requires_gl43 %Extension @extension{KHR,debug}
+ * @requires_es_extension %Extension @es_extension2{KHR,debug,debug}
+ */
+ #ifndef MAGNUM_TARGET_GLES2
+ StackUnderflow = GL_STACK_UNDERFLOW,
+ #else
+ StackUnderflow = GL_STACK_UNDERFLOW_KHR,
+ #endif
+
+ /**
+ * Given operation would cause an internal stack to overflow.
+ * @requires_gl43 %Extension @extension{KHR,debug}
+ * @requires_es_extension %Extension @es_extension2{KHR,debug,debug}
+ */
+ #ifndef MAGNUM_TARGET_GLES2
+ StackOverflow = GL_STACK_OVERFLOW
+ #else
+ StackOverflow = GL_STACK_OVERFLOW_KHR
+ #endif
+ #endif
+ };
+
+ /**
+ * @brief Error status
+ *
+ * Returns error flag, if any set. If there aren't any more error
+ * flags, returns @ref Error "Error::NoError". Thus this function
+ * should be always called in a loop until it returns @ref Error "Error::NoError".
+ * @see @fn_gl{GetError}
+ */
+ static Error error() { return static_cast(glGetError()); }
+
#ifndef MAGNUM_TARGET_GLES3
/**
* @brief Graphics reset notification strategy
@@ -980,6 +1043,17 @@ class MAGNUM_EXPORT Renderer {
#endif
};
+/** @debugoperator{Renderer} */
+Debug MAGNUM_EXPORT operator<<(Debug debug, Renderer::Error value);
+
+#ifndef MAGNUM_TARGET_GLES3
+/** @debugoperator{Renderer} */
+Debug MAGNUM_EXPORT operator<<(Debug debug, Renderer::ResetNotificationStrategy value);
+
+/** @debugoperator{Renderer} */
+Debug MAGNUM_EXPORT operator<<(Debug debug, Renderer::GraphicsResetStatus value);
+#endif
+
}
#endif
diff --git a/src/Shader.cpp b/src/Shader.cpp
index 095cd0b0c..7e643db24 100644
--- a/src/Shader.cpp
+++ b/src/Shader.cpp
@@ -171,10 +171,9 @@ bool Shader::compile() {
/* Error or warning message. The string is returned null-terminated, scrap
the \0 at the end afterwards */
std::string message(logLength, '\0');
- if(!message.empty()) {
+ if(message.size() > 1)
glGetShaderInfoLog(_id, message.size(), nullptr, &message[0]);
- message.resize(logLength-1);
- }
+ message.resize(std::max(logLength, 1)-1);
/* Show error log */
if(!success) {
diff --git a/src/Shaders/DistanceFieldVector.cpp b/src/Shaders/DistanceFieldVector.cpp
index 3f2f34a27..af86822b8 100644
--- a/src/Shaders/DistanceFieldVector.cpp
+++ b/src/Shaders/DistanceFieldVector.cpp
@@ -88,8 +88,16 @@ template DistanceFieldVector::DistanceFieldV
#ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported())
+ #endif
+ {
AbstractShaderProgram::setUniform(AbstractShaderProgram::uniformLocation("vectorTexture"),
AbstractVector::VectorTextureLayer);
+ }
+
+ /* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */
+ #ifdef MAGNUM_TARGET_GLES
+ setOutlineRange(0.5f, 1.0f);
+ setSmoothness(0.04f);
#endif
}
diff --git a/src/Shaders/DistanceFieldVector.frag b/src/Shaders/DistanceFieldVector.frag
index 1e0ae9f1f..07d9bbe2a 100644
--- a/src/Shaders/DistanceFieldVector.frag
+++ b/src/Shaders/DistanceFieldVector.frag
@@ -25,18 +25,19 @@
#ifndef NEW_GLSL
#define in varying
#define fragmentColor gl_FragColor
+#define texture texture2D
#endif
#ifndef GL_ES
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1) uniform lowp vec4 color;
layout(location = 2) uniform lowp vec4 outlineColor;
-layout(location = 3) uniform lowp vec2 outlineRange = vec2(0.5, 0.0);
+layout(location = 3) uniform lowp vec2 outlineRange = vec2(0.5, 1.0);
layout(location = 4) uniform lowp float smoothness = 0.04;
#else
uniform lowp vec4 color;
uniform lowp vec4 outlineColor;
-uniform lowp vec2 outlineRange = vec2(0.5, 0.0);
+uniform lowp vec2 outlineRange = vec2(0.5, 1.0);
uniform lowp float smoothness = 0.04;
#endif
#else
@@ -52,10 +53,10 @@ layout(binding = 16) uniform sampler2D vectorTexture;
uniform lowp sampler2D vectorTexture;
#endif
-in vec2 fragmentTextureCoordinates;
+in mediump vec2 fragmentTextureCoordinates;
#ifdef NEW_GLSL
-out vec4 fragmentColor;
+out lowp vec4 fragmentColor;
#endif
void main() {
@@ -65,9 +66,9 @@ void main() {
fragmentColor = smoothstep(outlineRange.x-smoothness, outlineRange.x+smoothness, intensity)*color;
/* Outline */
- if(outlineRange.x < outlineRange.y) {
+ if(outlineRange.x > outlineRange.y) {
lowp float mid = (outlineRange.x + outlineRange.y)/2.0;
- lowp float half = (outlineRange.y - outlineRange.x)/2.0;
+ lowp float half = (outlineRange.x - outlineRange.y)/2.0;
fragmentColor += smoothstep(half+smoothness, half-smoothness, distance(mid, intensity))*outlineColor;
}
}
diff --git a/src/Shaders/DistanceFieldVector.h b/src/Shaders/DistanceFieldVector.h
index 06bd4c8dc..ab6455e57 100644
--- a/src/Shaders/DistanceFieldVector.h
+++ b/src/Shaders/DistanceFieldVector.h
@@ -43,6 +43,9 @@ Renders vector art in form of signed distance field. See TextureTools::distanceF
for more information. Note that the final rendered outlook will greatly depend
on radius of input distance field and value passed to setSmoothness().
@see DistanceFieldVector2D, DistanceFieldVector3D
+@todo Use fragment shader derivations to have proper smoothness in perspective/
+ large zoom levels, make it optional as it might have negative performance
+ impact
*/
template class MAGNUM_SHADERS_EXPORT DistanceFieldVector: public AbstractVector {
public:
@@ -81,12 +84,12 @@ template class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* @return Pointer to self (for method chaining)
*
* Parameter @p start describes where fill ends and possible outline
- * starts. Initial value is `0.5f`, smaller values will make the vector
- * art look thinner, larger will make it look thicker.
+ * starts. Initial value is `0.5f`, larger values will make the vector
+ * art look thinner, smaller will make it look thicker.
*
* Parameter @p end describes where outline ends. If set to value
- * smaller than @p start the outline is not drawn. Initial value is
- * `0.0f`.
+ * larger than @p start the outline is not drawn. Initial value is
+ * `1.0f`.
*
* @see setOutlineColor()
*/
diff --git a/src/Shaders/Vector.cpp b/src/Shaders/Vector.cpp
index 802283f19..9faf712be 100644
--- a/src/Shaders/Vector.cpp
+++ b/src/Shaders/Vector.cpp
@@ -85,8 +85,10 @@ template Vector::Vector(): transformationPro
#ifndef MAGNUM_TARGET_GLES
if(!Context::current()->isExtensionSupported())
- AbstractShaderProgram::setUniform(AbstractShaderProgram::uniformLocation("vectorTexture"), AbstractVector::VectorTextureLayer);
#endif
+ {
+ AbstractShaderProgram::setUniform(AbstractShaderProgram::uniformLocation("vectorTexture"), AbstractVector::VectorTextureLayer);
+ }
}
template class Vector<2>;
diff --git a/src/Shaders/Vector.frag b/src/Shaders/Vector.frag
index 8384499a7..8dd88fd4c 100644
--- a/src/Shaders/Vector.frag
+++ b/src/Shaders/Vector.frag
@@ -25,6 +25,7 @@
#ifndef NEW_GLSL
#define in varying
#define fragmentColor gl_FragColor
+#define texture texture2D
#endif
#ifdef EXPLICIT_UNIFORM_LOCATION
@@ -39,10 +40,10 @@ layout(binding = 16) uniform sampler2D vectorTexture;
uniform lowp sampler2D vectorTexture;
#endif
-in vec2 fragmentTextureCoordinates;
+in mediump vec2 fragmentTextureCoordinates;
#ifdef NEW_GLSL
-out vec4 fragmentColor;
+out lowp vec4 fragmentColor;
#endif
void main() {
diff --git a/src/Test/CMakeLists.txt b/src/Test/CMakeLists.txt
index 78495259d..e9138989f 100644
--- a/src/Test/CMakeLists.txt
+++ b/src/Test/CMakeLists.txt
@@ -26,7 +26,10 @@ corrade_add_test(AbstractImageTest AbstractImageTest.cpp LIBRARIES Magnum)
corrade_add_test(AbstractShaderProgramTest AbstractShaderProgramTest.cpp LIBRARIES Magnum)
corrade_add_test(ArrayTest ArrayTest.cpp)
corrade_add_test(ColorTest ColorTest.cpp LIBRARIES MagnumMathTestLib)
+corrade_add_test(DefaultFramebufferTest DefaultFramebufferTest.cpp LIBRARIES Magnum)
+corrade_add_test(FramebufferTest FramebufferTest.cpp LIBRARIES Magnum)
corrade_add_test(MeshTest MeshTest.cpp LIBRARIES Magnum)
+corrade_add_test(RendererTest RendererTest.cpp LIBRARIES Magnum)
corrade_add_test(ResourceManagerTest ResourceManagerTest.cpp LIBRARIES MagnumTestLib)
corrade_add_test(SwizzleTest SwizzleTest.cpp LIBRARIES MagnumMathTestLib)
diff --git a/src/Test/DefaultFramebufferTest.cpp b/src/Test/DefaultFramebufferTest.cpp
new file mode 100644
index 000000000..a0dceffbd
--- /dev/null
+++ b/src/Test/DefaultFramebufferTest.cpp
@@ -0,0 +1,52 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 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 "DefaultFramebuffer.h"
+
+namespace Magnum { namespace Test {
+
+class DefaultFramebufferTest: public TestSuite::Tester {
+ public:
+ explicit DefaultFramebufferTest();
+
+ void debugStatus();
+};
+
+DefaultFramebufferTest::DefaultFramebufferTest() {
+ addTests({&DefaultFramebufferTest::debugStatus});
+}
+
+void DefaultFramebufferTest::debugStatus() {
+ std::ostringstream out;
+
+ Debug(&out) << DefaultFramebuffer::Status::Undefined;
+ CORRADE_COMPARE(out.str(), "DefaultFramebuffer::Status::Undefined\n");
+}
+
+}}
+
+CORRADE_TEST_MAIN(Magnum::Test::DefaultFramebufferTest)
diff --git a/src/Test/FramebufferTest.cpp b/src/Test/FramebufferTest.cpp
new file mode 100644
index 000000000..a3b43be21
--- /dev/null
+++ b/src/Test/FramebufferTest.cpp
@@ -0,0 +1,52 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 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 "Framebuffer.h"
+
+namespace Magnum { namespace Test {
+
+class FramebufferTest: public TestSuite::Tester {
+ public:
+ explicit FramebufferTest();
+
+ void debugStatus();
+};
+
+FramebufferTest::FramebufferTest() {
+ addTests({&FramebufferTest::debugStatus});
+}
+
+void FramebufferTest::debugStatus() {
+ std::ostringstream out;
+
+ Debug(&out) << Framebuffer::Status::IncompleteMissingAttachment;
+ CORRADE_COMPARE(out.str(), "Framebuffer::Status::IncompleteMissingAttachment\n");
+}
+
+}}
+
+CORRADE_TEST_MAIN(Magnum::Test::FramebufferTest)
diff --git a/src/Test/RendererTest.cpp b/src/Test/RendererTest.cpp
new file mode 100644
index 000000000..07a386634
--- /dev/null
+++ b/src/Test/RendererTest.cpp
@@ -0,0 +1,72 @@
+/*
+ This file is part of Magnum.
+
+ Copyright © 2010, 2011, 2012, 2013 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 "Renderer.h"
+
+namespace Magnum { namespace Test {
+
+class RendererTest: public TestSuite::Tester {
+ public:
+ explicit RendererTest();
+
+ void debugError();
+ #ifndef MAGNUM_TARGET_GLES3
+ void debugResetNotificationStrategy();
+ void debugGraphicsResetStatus();
+ #endif
+};
+
+RendererTest::RendererTest() {
+ addTests({&RendererTest::debugError});
+}
+
+void RendererTest::debugError() {
+ std::ostringstream out;
+
+ Debug(&out) << Renderer::Error::InvalidOperation;
+ CORRADE_COMPARE(out.str(), "Renderer::Error::InvalidOperation\n");
+}
+
+#ifndef MAGNUM_TARGET_GLES3
+void RendererTest::debugResetNotificationStrategy() {
+ std::ostringstream out;
+
+ Debug(&out) << Renderer::ResetNotificationStrategy::LoseContextOnReset;
+ CORRADE_COMPARE(out.str(), "Renderer::ResetNotificationStrategy::LoseContextOnReset\n");
+}
+
+void RendererTest::debugGraphicsResetStatus() {
+ std::ostringstream out;
+
+ Debug(&out) << Renderer::GraphicsResetStatus::GuiltyContextReset;
+ CORRADE_COMPARE(out.str(), "Renderer::GraphicsResetStatus::GuiltyContextReset\n");
+}
+#endif
+
+}}
+
+CORRADE_TEST_MAIN(Magnum::Test::RendererTest)
diff --git a/src/Text/DistanceFieldGlyphCache.cpp b/src/Text/DistanceFieldGlyphCache.cpp
index 73ffcd4b7..83daad155 100644
--- a/src/Text/DistanceFieldGlyphCache.cpp
+++ b/src/Text/DistanceFieldGlyphCache.cpp
@@ -26,30 +26,54 @@
#include "Extensions.h"
#include "Image.h"
+#ifndef CORRADE_NO_ASSERT
+#include "ImageFormat.h"
+#endif
#include "TextureFormat.h"
#include "TextureTools/DistanceField.h"
namespace Magnum { namespace Text {
-namespace {
+DistanceFieldGlyphCache::DistanceFieldGlyphCache(const Vector2i& originalSize, const Vector2i& distanceFieldSize, UnsignedInt radius): GlyphCache(originalSize, Vector2i(radius)), scale(Vector2(distanceFieldSize)/originalSize), radius(radius) {
+ #ifndef MAGNUM_TARGET_GLES
+ MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_rg);
+ #endif
+
#if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES3)
const TextureFormat internalFormat = TextureFormat::R8;
#else
- const TextureFormat internalFormat = TextureFormat::Red;
+ const TextureFormat internalFormat =
+ Context::current()->isExtensionSupported() ?
+ TextureFormat::Red : TextureFormat::RGB;
+ if(internalFormat == TextureFormat::RGB)
+ Warning() << "Text::DistanceFieldGlyphCache:" << Extensions::GL::EXT::texture_rg::string() << "not supported, using inefficient RGB format for glyph cache texture";
#endif
+
+ initialize(internalFormat, distanceFieldSize);
}
-DistanceFieldGlyphCache::DistanceFieldGlyphCache(const Vector2i& originalSize, const Vector2i& distanceFieldSize, UnsignedInt radius): GlyphCache(originalSize, Vector2i(radius)), scale(Vector2(distanceFieldSize)/originalSize), radius(radius) {
+void DistanceFieldGlyphCache::setImage(const Vector2i& offset, Image2D* const image) {
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_rg);
- #else
- MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::EXT::texture_rg);
#endif
- initialize(internalFormat, distanceFieldSize);
-}
+ #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES3)
+ const TextureFormat internalFormat = TextureFormat::R8;
+ CORRADE_ASSERT(image->format() == ImageFormat::Red,
+ "Text::DistanceFieldGlyphCache::setImage(): expected" << ImageFormat::Red << "but got" << image->format(), );
+ #else
+ TextureFormat internalFormat;
+ if(Context::current()->isExtensionSupported()) {
+ internalFormat = TextureFormat::Red;
+ CORRADE_ASSERT(image->format() == ImageFormat::Red,
+ "Text::DistanceFieldGlyphCache::setImage(): expected" << ImageFormat::Red << "but got" << image->format(), );
+ } else {
+ internalFormat = TextureFormat::Luminance;
+ CORRADE_ASSERT(image->format() == ImageFormat::Luminance,
+ "Text::DistanceFieldGlyphCache::setImage(): expected" << ImageFormat::Luminance << "but got" << image->format(), );
+ }
+ #endif
-void DistanceFieldGlyphCache::setImage(const Vector2i& offset, Image2D* const image) {
Texture2D input;
input.setWrapping(Sampler::Wrapping::ClampToEdge)
->setMinificationFilter(Sampler::Filter::Linear)
@@ -57,7 +81,7 @@ void DistanceFieldGlyphCache::setImage(const Vector2i& offset, Image2D* const im
->setImage(0, internalFormat, image);
/* Create distance field from input texture */
- TextureTools::distanceField(&input, &_texture, Rectanglei::fromSize(offset*scale, image->size()*scale), radius);
+ TextureTools::distanceField(&input, &_texture, Rectanglei::fromSize(offset*scale, image->size()*scale), radius, image->size());
}
void DistanceFieldGlyphCache::setDistanceFieldImage(const Vector2i& offset, Image2D* const image) {
diff --git a/src/Text/DistanceFieldGlyphCache.h b/src/Text/DistanceFieldGlyphCache.h
index e9161a95f..bb5d1194c 100644
--- a/src/Text/DistanceFieldGlyphCache.h
+++ b/src/Text/DistanceFieldGlyphCache.h
@@ -62,7 +62,13 @@ class MAGNUM_TEXT_EXPORT DistanceFieldGlyphCache: public GlyphCache {
* @param radius Distance field computation radius
*
* See TextureTools::distanceField() for more information about the
- * parameters.
+ * parameters. Sets internal texture format to red channel only. On
+ * desktop OpenGL requires @extension{ARB,texture_rg} (also part of
+ * OpenGL ES 3.0), in ES2 uses @es_extension{EXT,texture_rg} if
+ * available or @ref TextureFormat "TextureFormat::RGB" as fallback.
+ * @todo Is Luminance format renderable anywhere? Also would it be
+ * possible to convert the RGB texture to Luminance after it has
+ * been rendered when blitting is not supported to save memory?
*/
explicit DistanceFieldGlyphCache(const Vector2i& originalSize, const Vector2i& distanceFieldSize, UnsignedInt radius);
diff --git a/src/Text/GlyphCache.cpp b/src/Text/GlyphCache.cpp
index 1db6a252d..9caf7976f 100644
--- a/src/Text/GlyphCache.cpp
+++ b/src/Text/GlyphCache.cpp
@@ -31,19 +31,17 @@
namespace Magnum { namespace Text {
-namespace {
- #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES3)
- const TextureFormat internalFormat = TextureFormat::R8;
- #else
- const TextureFormat internalFormat = TextureFormat::Red;
- #endif
-}
-
GlyphCache::GlyphCache(const Vector2i& size): _size(size) {
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_rg);
+ #endif
+
+ #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES3)
+ const TextureFormat internalFormat = TextureFormat::R8;
#else
- MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::EXT::texture_rg);
+ const TextureFormat internalFormat =
+ Context::current()->isExtensionSupported() ?
+ TextureFormat::Red : TextureFormat::Luminance;
#endif
initialize(internalFormat, size);
@@ -59,12 +57,6 @@ GlyphCache::~GlyphCache() = default;
/** @todo Delegating constructor when support for GCC 4.6 is dropped */
void GlyphCache::initialize(const TextureFormat internalFormat, const Vector2i& size) {
- #ifndef MAGNUM_TARGET_GLES
- MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_storage);
- #else
- MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::EXT::texture_storage);
- #endif
-
_texture.setWrapping(Sampler::Wrapping::ClampToEdge)
->setMinificationFilter(Sampler::Filter::Linear)
->setMagnificationFilter(Sampler::Filter::Linear)
diff --git a/src/Text/GlyphCache.h b/src/Text/GlyphCache.h
index bd6c55d5b..35d93cf52 100644
--- a/src/Text/GlyphCache.h
+++ b/src/Text/GlyphCache.h
@@ -28,6 +28,7 @@
* @brief Class Magnum::Text::GlyphCache
*/
+#include
#include
#include "Math/Geometry/Rectangle.h"
@@ -54,6 +55,7 @@ font->createGlyphCache(cache, "abcdefghijklmnopqrstuvwxyz"
@endcode
See TextRenderer for information about text rendering.
+@todo Some way for Font to negotiate or check internal texture format
*/
class MAGNUM_TEXT_EXPORT GlyphCache {
public:
@@ -68,9 +70,10 @@ class MAGNUM_TEXT_EXPORT GlyphCache {
* @brief Constructor
* @param size Glyph cache texture size
*
- * Sets internal texture format to red channel only. Requires
- * @extension{ARB,texture_rg} (also part of OpenGL ES 3.0 or available
- * as @es_extension{EXT,texture_rg} in ES 2.0).
+ * Sets internal texture format to red channel only. On desktop OpenGL
+ * requires @extension{ARB,texture_rg} (also part of OpenGL ES 3.0), in
+ * ES2 uses @es_extension{EXT,texture_rg}, if available, or
+ * @ref TextureFormat "TextureFormat::Luminance" as fallback.
*/
explicit GlyphCache(const Vector2i& size);
diff --git a/src/Texture.h b/src/Texture.h
index 139dc7950..9cd269e5f 100644
--- a/src/Texture.h
+++ b/src/Texture.h
@@ -282,14 +282,19 @@ template class Texture: public AbstractTexture {
* is immutable and calling setStorage() or setImage() is not allowed.
*
* If @extension{EXT,direct_state_access} is not available, the
- * texture is bound to some layer before the operation.
+ * texture is bound to some layer before the operation. If
+ * OpenGL 4.2, @extension{ARB,texture_storage}, OpenGL ES 3.0 or @es_extension{EXT,texture_storage}
+ * in OpenGL ES 2.0 is not available, the feature is emulated with
+ * sequence of setImage() calls.
* @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and
* @fn_gl{TexStorage1D}/@fn_gl{TexStorage2D}/@fn_gl{TexStorage3D}
* or @fn_gl_extension{TextureStorage1D,EXT,direct_state_access}/
* @fn_gl_extension{TextureStorage2D,EXT,direct_state_access}/
- * @fn_gl_extension{TextureStorage3D,EXT,direct_state_access}
- * @requires_gl42 %Extension @extension{ARB,texture_storage}
- * @requires_gles30 %Extension @es_extension{EXT,texture_storage}
+ * @fn_gl_extension{TextureStorage3D,EXT,direct_state_access},
+ * eventually @fn_gl{TexImage1D}/@fn_gl{TexImage2D}/@fn_gl{TexImage3D} or
+ * @fn_gl_extension{TextureImage1D,EXT,direct_state_access}/
+ * @fn_gl_extension{TextureImage2D,EXT,direct_state_access}/
+ * @fn_gl_extension{TextureImage3D,EXT,direct_state_access}.
*/
Texture* setStorage(Int levels, TextureFormat internalFormat, const typename DimensionTraits::VectorType& size) {
DataHelper::setStorage(this, _target, levels, internalFormat, size);
diff --git a/src/TextureFormat.h b/src/TextureFormat.h
index 7857540f7..86d68f36e 100644
--- a/src/TextureFormat.h
+++ b/src/TextureFormat.h
@@ -147,6 +147,7 @@ enum class TextureFormat: GLenum {
* @requires_gles30 Only unsigned formats are available in OpenGL ES 2.0.
*/
RGBA8Snorm = GL_RGBA8_SNORM,
+ #endif
#ifndef MAGNUM_TARGET_GLES
/**
@@ -212,6 +213,7 @@ enum class TextureFormat: GLenum {
RGBA16Snorm = GL_RGBA16_SNORM,
#endif
+ #ifndef MAGNUM_TARGET_GLES2
/**
* Red component, non-normalized unsigned byte.
* @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{EXT,texture_integer}
@@ -469,6 +471,29 @@ enum class TextureFormat: GLenum {
RGBA32F = GL_RGBA32F,
#endif
+ #if defined(MAGNUM_TARGET_GLES2) || defined(DOXYGEN_GENERATING_OUTPUT)
+ /**
+ * Luminance, normalized unsigned, single value used for all RGB channels.
+ * Size implementation-dependent.
+ * @deprecated Included for compatibility reasons only, use
+ * @ref Magnum::TextureFormat "TextureFormat::R8" instead.
+ * @requires_gles20 Not available in ES 3.0 or desktop OpenGL. Use
+ * @ref Magnum::TextureFormat "TextureFormat::R8" instead.
+ */
+ Luminance = GL_LUMINANCE,
+
+ /**
+ * Floating-point luminance and alpha channel. First value is used for all
+ * RGB channels, second value is used for alpha channel. Size
+ * implementation-dependent.
+ * @deprecated Included for compatibility reasons only, use
+ * @ref Magnum::TextureFormat "TextureFormat::RG8" instead.
+ * @requires_gles20 Not available in ES 3.0 or desktop OpenGL. Use
+ * @ref Magnum::TextureFormat "TextureFormat::RG8" instead.
+ */
+ LuminanceAlpha = GL_LUMINANCE_ALPHA,
+ #endif
+
#ifndef MAGNUM_TARGET_GLES
/**
* RGB, normalized unsigned, red and green component 3bit, blue 2bit.
@@ -490,14 +515,16 @@ enum class TextureFormat: GLenum {
RGB5 = GL_RGB5,
#endif
- /* 1.5.6 <= GLEW < 1.8.0 doesn't have this, even if there is
- GL_ARB_ES2_compatibility */
- #if defined(GL_RGB565) || defined(DOXYGEN_GENERATING_OUTPUT)
/**
* RGB, normalized unsigned, red and blue component 5bit, green 6bit.
* @requires_gles30 %Extension @es_extension{OES,required_internalformat}
*/
+ /* 1.5.6 <= GLEW < 1.8.0 doesn't have this, even if there is
+ GL_ARB_ES2_compatibility */
+ #ifdef GL_RGB565
RGB565 = GL_RGB565,
+ #else
+ RGB565 = 0x8D62,
#endif
#ifndef MAGNUM_TARGET_GLES3
@@ -519,7 +546,53 @@ enum class TextureFormat: GLenum {
* @requires_gl Packed 36bit types are not available in OpenGL ES.
*/
RGB12 = GL_RGB12,
+ #endif
+
+ #ifndef MAGNUM_TARGET_GLES2
+ /**
+ * RGB, float, red and green component 11bit, blue 10bit.
+ * @requires_gl30 %Extension @extension{EXT,packed_float}
+ * @requires_gles30 Only normalized integral formats are available in
+ * OpenGL ES 2.0.
+ */
+ R11FG11FB10F = GL_R11F_G11F_B10F,
+
+ /**
+ * RGB, unsigned with exponent, each RGB component 9bit, exponent 5bit.
+ * @requires_gl30 %Extension @extension{EXT,texture_shared_exponent}
+ * @requires_gles30 Use @ref Magnum::TextureFormat "TextureFormat::RGB" in
+ * OpenGL ES 2.0 instead.
+ */
+ RGB9E5 = GL_RGB9_E5,
+ #endif
+
+ #ifndef MAGNUM_TARGET_GLES3
+ /**
+ * sRGB, normalized unsigned, size implementation-dependent.
+ * @todo is this allowed in core?
+ * @deprecated Prefer to use the exactly specified version of this format,
+ * i.e. @ref Magnum::TextureFormat "TextureFormat::SRGB8".
+ * @requires_es_extension %Extension @es_extension{EXT,sRGB} in OpenGL ES
+ * 2.0, use @ref Magnum::TextureFormat "TextureFormat::SRGB8" in
+ * OpenGL ES 3.0 instead.
+ */
+ #ifndef MAGNUM_TARGET_GLES
+ SRGB = GL_SRGB,
+ #else
+ SRGB = GL_SRGB_EXT,
+ #endif
+ #endif
+
+ #ifndef MAGNUM_TARGET_GLES2
+ /**
+ * sRGB, each component normalized unsigned byte.
+ * @requires_gles30 Use @ref Magnum::TextureFormat "TextureFormat::SRGB" in
+ * OpenGL ES 2.0 instead.
+ */
+ SRGB8 = GL_SRGB8,
+ #endif
+ #ifndef MAGNUM_TARGET_GLES
/**
* RGBA, normalized unsigned, each component 2bit.
* @requires_gl Packed 8bit types are not available in OpenGL ES.
@@ -568,52 +641,6 @@ enum class TextureFormat: GLenum {
RGBA12 = GL_RGBA12,
#endif
- #ifndef MAGNUM_TARGET_GLES2
- /**
- * RGB, float, red and green component 11bit, blue 10bit.
- * @requires_gl30 %Extension @extension{EXT,packed_float}
- * @requires_gles30 Only normalized integral formats are available in
- * OpenGL ES 2.0.
- */
- R11FG11FB10F = GL_R11F_G11F_B10F,
- #endif
-
- #ifndef MAGNUM_TARGET_GLES2
- /**
- * RGB, unsigned with exponent, each RGB component 9bit, exponent 5bit.
- * @requires_gl30 %Extension @extension{EXT,texture_shared_exponent}
- * @requires_gles30 Use @ref Magnum::TextureFormat "TextureFormat::RGB" in
- * OpenGL ES 2.0 instead.
- */
- RGB9E5 = GL_RGB9_E5,
- #endif
-
- #ifndef MAGNUM_TARGET_GLES3
- /**
- * sRGB, normalized unsigned, size implementation-dependent.
- * @todo is this allowed in core?
- * @deprecated Prefer to use the exactly specified version of this format,
- * i.e. @ref Magnum::TextureFormat "TextureFormat::SRGB8".
- * @requires_es_extension %Extension @es_extension{EXT,sRGB} in OpenGL ES
- * 2.0, use @ref Magnum::TextureFormat "TextureFormat::SRGB8" in
- * OpenGL ES 3.0 instead.
- */
- #ifndef MAGNUM_TARGET_GLES
- SRGB = GL_SRGB,
- #else
- SRGB = GL_SRGB_EXT,
- #endif
- #endif
-
- #ifndef MAGNUM_TARGET_GLES2
- /**
- * sRGB, each component normalized unsigned byte.
- * @requires_gles30 Use @ref Magnum::TextureFormat "TextureFormat::SRGB" in
- * OpenGL ES 2.0 instead.
- */
- SRGB8 = GL_SRGB8,
- #endif
-
#ifndef MAGNUM_TARGET_GLES3
/**
* sRGBA, normalized unsigned, size implementation-dependent.
@@ -700,32 +727,32 @@ enum class TextureFormat: GLenum {
late as of 1.8.0 { */
/**
- * BPTC compressed RGBA, normalized unsigned.
+ * BPTC compressed RGB, unsigned float.
* @requires_gl42 %Extension @extension{ARB,texture_compression_bptc}
* @requires_gl BPTC texture compression is not available in OpenGL ES.
*/
- CompressedRGBABtpcUnorm = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB,
+ CompressedRGBBptcUnsignedFloat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB,
/**
- * BPTC compressed sRGBA, normalized unsigned.
+ * BPTC compressed RGB, signed float.
* @requires_gl42 %Extension @extension{ARB,texture_compression_bptc}
* @requires_gl BPTC texture compression is not available in OpenGL ES.
*/
- CompressedSRGBAlphaBtpcUnorm = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB,
+ CompressedRGBBptcSignedFloat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB,
/**
- * BPTC compressed RGB, unsigned float.
+ * BPTC compressed RGBA, normalized unsigned.
* @requires_gl42 %Extension @extension{ARB,texture_compression_bptc}
* @requires_gl BPTC texture compression is not available in OpenGL ES.
*/
- CompressedRGBBptcUnsignedFloat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB,
+ CompressedRGBABptcUnorm = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB,
/**
- * BPTC compressed RGB, signed float.
+ * BPTC compressed sRGBA, normalized unsigned.
* @requires_gl42 %Extension @extension{ARB,texture_compression_bptc}
* @requires_gl BPTC texture compression is not available in OpenGL ES.
*/
- CompressedRGBBptcSignedFloat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB,
+ CompressedSRGBAlphaBptcUnorm = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB,
/*}*/
#endif
@@ -739,18 +766,6 @@ enum class TextureFormat: GLenum {
*/
DepthComponent = GL_DEPTH_COMPONENT,
- /**
- * Depth and stencil component, size implementation-dependent.
- * @deprecated Prefer to use exactly specified version of this format, e.g.
- * @ref Magnum::TextureFormat "TextureFormat::Depth24Stencil8".
- * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil}
- */
- #ifndef MAGNUM_TARGET_GLES2
- DepthStencil = GL_DEPTH_STENCIL,
- #else
- DepthStencil = GL_DEPTH_STENCIL_OES,
- #endif
-
/**
* Depth component, 16bit.
* @requires_gles30 %Extension (@es_extension{OES,required_internalformat}
@@ -794,9 +809,21 @@ enum class TextureFormat: GLenum {
DepthComponent32F = GL_DEPTH_COMPONENT32F,
#endif
+ /**
+ * Depth and stencil component, size implementation-dependent.
+ * @deprecated Prefer to use exactly specified version of this format, e.g.
+ * @ref Magnum::TextureFormat "TextureFormat::Depth24Stencil8".
+ * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil}
+ */
+ #ifndef MAGNUM_TARGET_GLES2
+ DepthStencil = GL_DEPTH_STENCIL,
+ #else
+ DepthStencil = GL_DEPTH_STENCIL_OES,
+ #endif
+
/**
* 24bit depth and 8bit stencil component.
- * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil}
+ * @requires_gl30 %Extension @extension{ARB,framebuffer_object}
* @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil} and
* (@es_extension{OES,required_internalformat} or
* (@es_extension{EXT,texture_storage} and @es_extension{ANGLE,depth_texture}))
diff --git a/src/TextureTools/DistanceField.cpp b/src/TextureTools/DistanceField.cpp
index fbc1eeee6..521c86beb 100644
--- a/src/TextureTools/DistanceField.cpp
+++ b/src/TextureTools/DistanceField.cpp
@@ -39,6 +39,8 @@ namespace {
class DistanceFieldShader: public AbstractShaderProgram {
public:
+ typedef Attribute<0, Vector2> Position;
+
enum: Int {
TextureLayer = 8
};
@@ -50,62 +52,148 @@ class DistanceFieldShader: public AbstractShaderProgram {
return this;
}
- DistanceFieldShader* setScaling(Vector2 scaling) {
+ DistanceFieldShader* setScaling(const Vector2& scaling) {
setUniform(scalingUniform, scaling);
return this;
}
+ DistanceFieldShader* setImageSizeInverted(const Vector2& size) {
+ setUniform(imageSizeInvertedUniform, size);
+ return this;
+ }
+
private:
- static const Int radiusUniform = 0,
- scalingUniform = 1;
+ Int radiusUniform,
+ scalingUniform,
+ imageSizeInvertedUniform;
};
-DistanceFieldShader::DistanceFieldShader() {
- MAGNUM_ASSERT_VERSION_SUPPORTED(Version::GL330);
- MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::explicit_attrib_location);
- MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::explicit_uniform_location);
- MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::shading_language_420pack);
-
- /** @todo compatibility! */
-
+DistanceFieldShader::DistanceFieldShader(): radiusUniform(0), scalingUniform(1) {
Utility::Resource rs("MagnumTextureTools");
- Shader vert(Version::GL330, Shader::Type::Vertex);
- vert.addSource(rs.get("DistanceFieldShader.vert"));
+ #ifndef MAGNUM_TARGET_GLES
+ const Version v = Context::current()->supportedVersion({Version::GL320, Version::GL300, Version::GL210});
+ #else
+ const Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200});
+ #endif
+
+ Shader vert(v, Shader::Type::Vertex);
+ vert.addSource(rs.get("compatibility.glsl"))
+ .addSource(rs.get("DistanceFieldShader.vert"));
CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile());
attachShader(vert);
- Shader frag(Version::GL330, Shader::Type::Fragment);
+ Shader frag(v, Shader::Type::Fragment);
frag.addSource(rs.get("compatibility.glsl"))
.addSource(rs.get("DistanceFieldShader.frag"));
CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile());
attachShader(frag);
+ /* Older GLSL doesn't have gl_VertexID, vertices must be supplied explicitly */
+ #ifndef MAGNUM_TARGET_GLES
+ if(!Context::current()->isVersionSupported(Version::GL300))
+ #else
+ if(!Context::current()->isVersionSupported(Version::GLES300))
+ #endif
+ {
+ bindAttributeLocation(Position::Location, "position");
+ }
+
CORRADE_INTERNAL_ASSERT_OUTPUT(link());
-}
+ #ifndef MAGNUM_TARGET_GLES
+ if(!Context::current()->isExtensionSupported())
+ #endif
+ {
+ radiusUniform = uniformLocation("radius");
+ scalingUniform = uniformLocation("scaling");
+
+ #ifndef MAGNUM_TARGET_GLES
+ if(!Context::current()->isVersionSupported(Version::GL300))
+ #else
+ if(!Context::current()->isVersionSupported(Version::GLES300))
+ #endif
+ {
+ imageSizeInvertedUniform = uniformLocation("imageSizeInverted");
+ }
+ }
+
+ #ifndef MAGNUM_TARGET_GLES
+ if(!Context::current()->isExtensionSupported())
+ #endif
+ {
+ setUniform(uniformLocation("textureData"), TextureLayer);
+ }
}
-void distanceField(Texture2D* input, Texture2D* output, const Rectanglei& rectangle, const Int radius) {
- MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::EXT::framebuffer_object);
+}
+#ifndef MAGNUM_TARGET_GLES
+void distanceField(Texture2D* input, Texture2D* output, const Rectanglei& rectangle, const Int radius, const Vector2i&)
+#else
+void distanceField(Texture2D* input, Texture2D* output, const Rectanglei& rectangle, const Int radius, const Vector2i& imageSize)
+#endif
+{
+ #ifndef MAGNUM_TARGET_GLES
+ MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::framebuffer_object);
+ #endif
/** @todo Disable depth test, blending and then enable it back (if was previously) */
+ #ifndef MAGNUM_TARGET_GLES
+ Vector2i imageSize = input->imageSize(0);
+ #endif
+
Framebuffer framebuffer(rectangle);
framebuffer.attachTexture2D(Framebuffer::ColorAttachment(0), output, 0);
framebuffer.bind(FramebufferTarget::Draw);
+ framebuffer.clear(FramebufferClear::Color);
+
+ const Framebuffer::Status status = framebuffer.checkStatus(FramebufferTarget::Draw);
+ if(status != Framebuffer::Status::Complete) {
+ Error() << "TextureTools::distanceField(): cannot render to given output texture, unexpected framebuffer status"
+ << status;
+ return;
+ }
DistanceFieldShader shader;
shader.setRadius(radius)
- ->setScaling(Vector2(input->imageSize(0))/rectangle.size())
+ ->setScaling(Vector2(imageSize)/rectangle.size())
->use();
input->bind(DistanceFieldShader::TextureLayer);
+ #ifndef MAGNUM_TARGET_GLES
+ if(!Context::current()->isVersionSupported(Version::GL300))
+ #else
+ if(!Context::current()->isVersionSupported(Version::GLES300))
+ #endif
+ {
+ shader.setImageSizeInverted(Vector2(1)/imageSize);
+ }
+
Mesh mesh;
mesh.setPrimitive(Mesh::Primitive::Triangles)
- ->setVertexCount(3)
- ->draw();
+ ->setVertexCount(3);
+
+ /* Older GLSL doesn't have gl_VertexID, vertices must be supplied explicitly */
+ Buffer buffer;
+ #ifndef MAGNUM_TARGET_GLES
+ if(!Context::current()->isVersionSupported(Version::GL300))
+ #else
+ if(!Context::current()->isVersionSupported(Version::GLES300))
+ #endif
+ {
+ constexpr Vector2 triangle[] = {
+ Vector2(-1.0, 1.0),
+ Vector2(-1.0, -3.0),
+ Vector2( 3.0, 1.0)
+ };
+ buffer.setData(triangle, Buffer::Usage::StaticDraw);
+ mesh.addVertexBuffer(&buffer, 0, DistanceFieldShader::Position());
+ }
+
+ /* Draw the mesh */
+ mesh.draw();
}
}}
diff --git a/src/TextureTools/DistanceField.h b/src/TextureTools/DistanceField.h
index dfe8c409d..e44e6ba8d 100644
--- a/src/TextureTools/DistanceField.h
+++ b/src/TextureTools/DistanceField.h
@@ -28,6 +28,9 @@
* @brief Function Magnum::TextureTools::distanceField()
*/
+#ifndef MAGNUM_TARGET_GLES
+#include "Math/Vector2.h"
+#endif
#include "Magnum.h"
#include "TextureTools/magnumTextureToolsVisibility.h"
@@ -40,6 +43,8 @@ namespace Magnum { namespace TextureTools {
@param output Output texture
@param rectangle Rectangle in output texture where to render
@param radius Max lookup radius in input texture
+@param imageSize Input texture size. Needed only in OpenGL ES, in desktop
+ OpenGL the information is gathered automatically using Texture::imageSize().
Converts binary image (stored in red channel of @p input) to signed distance
field (stored in red channel in @p rectangle of @p output). The purpose of this
@@ -51,9 +56,9 @@ foundation for features like outlining, glow or drop shadow essentialy for free.
For each pixel inside @p rectangle the algorithm looks at corresponding pixel in
@p input and tries to find nearest pixel of opposite color in area given by
@p radius. Signed distance between the points is then saved as value of given
-pixel in @p output. Value of `0` means that the pixel was originally colored
-white and nearest black pixel is farther than @p radius, value of `1` means that
-the pixel was originally black and nearest white pixel is farther than
+pixel in @p output. Value of `1.0` means that the pixel was originally colored
+white and nearest black pixel is farther than @p radius, value of `0.0` means
+that the pixel was originally black and nearest white pixel is farther than
@p radius. Values around `0.5` are around edges.
The resulting texture can be used with bilinear filtering. It can be converted
@@ -66,8 +71,24 @@ and Special Effects, SIGGRAPH 2007,
http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf*
@attention This is GPU-only implementation, so it expects active context.
+
+@note If internal format of @p output texture is not renderable, this function
+ prints message to error output and does nothing. In desktop OpenGL and
+ OpenGL ES 3.0 it's common to render to @ref TextureFormat "TextureFormat::R8".
+ In OpenGL ES 2.0 you can use @ref TextureFormat "TextureFormat::Red" if
+ @es_extension{EXT,texture_rg} is available, if not, the smallest but still
+ inefficient supported format is in most cases @ref TextureFormat "TextureFormat::RGB",
+ rendering to @ref TextureFormat "TextureFormat::Luminance" is not supported
+ in most cases.
+
+@bug ES (and maybe GL < 3.20) implementation behaves slightly different
+ (jaggies, visible e.g. when rendering outlined fonts)
*/
-void MAGNUM_TEXTURETOOLS_EXPORT distanceField(Texture2D* input, Texture2D* output, const Rectanglei& rectangle, Int radius);
+#ifndef MAGNUM_TARGET_GLES
+void MAGNUM_TEXTURETOOLS_EXPORT distanceField(Texture2D* input, Texture2D* output, const Rectanglei& rectangle, Int radius, const Vector2i& imageSize = Vector2i());
+#else
+void MAGNUM_TEXTURETOOLS_EXPORT distanceField(Texture2D* input, Texture2D* output, const Rectanglei& rectangle, Int radius, const Vector2i& imageSize);
+#endif
}}
diff --git a/src/TextureTools/DistanceFieldShader.frag b/src/TextureTools/DistanceFieldShader.frag
index 9191f9525..c19273b79 100644
--- a/src/TextureTools/DistanceFieldShader.frag
+++ b/src/TextureTools/DistanceFieldShader.frag
@@ -22,40 +22,90 @@
DEALINGS IN THE SOFTWARE.
*/
+#ifndef NEW_GLSL
+#define in varying
+#define value gl_FragColor.x
+#define const
+#define texture texture2D
+#endif
+
+#if (defined(GL_ES) && __VERSION__ >= 300) || (!defined(GL_ES) && __VERSION__ >= 150)
+#define TEXELFETCH_USABLE
+#endif
+
+#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0) uniform int radius;
layout(location = 1) uniform vec2 scaling;
-layout(binding = 8) uniform sampler2D texture;
-
-layout(pixel_center_integer) in vec4 gl_FragCoord;
-
-out float value;
+layout(binding = 8) uniform sampler2D textureData;
+#else
+uniform lowp int radius;
+uniform mediump vec2 scaling;
+uniform lowp sampler2D textureData;
+#endif
+
+#ifdef TEXELFETCH_USABLE
+layout(pixel_center_integer) in mediump vec4 gl_FragCoord;
+#else
+#ifdef EXPLICIT_UNIFORM_LOCATION
+layout(location = 2) uniform vec2 imageSizeInverted;
+#else
+uniform mediump vec2 imageSizeInverted;
+#endif
+#endif
+
+#ifdef NEW_GLSL
+out lowp float value;
+#endif
+
+#ifdef TEXELFETCH_USABLE
+mediump ivec2 rotate(const mediump ivec2 vec) {
+ return mediump ivec2(-vec.y, vec.x);
+}
-ivec2 rotate(const ivec2 vec) {
- return ivec2(-vec.y, vec.x);
+bool hasValue(const mediump ivec2 position, const mediump ivec2 offset) {
+ return texelFetch(textureData, position+offset, 0).r > 0.5;
+}
+#else
+mediump vec2 rotate(const mediump vec2 vec) {
+ return mediump vec2(-vec.y, vec.x);
}
-bool hasValue(const ivec2 position, const ivec2 offset) {
- return texelFetch(texture, position+offset, 0).r > 0.5;
+bool hasValue(const mediump vec2 position, const mediump vec2 offset) {
+ return texture(textureData, position+offset).r > 0.5;
}
+#endif
void main() {
- const ivec2 position = ivec2(gl_FragCoord.xy*scaling);
+ #ifdef TEXELFETCH_USABLE
+ const mediump ivec2 position = ivec2(gl_FragCoord.xy*scaling);
+ #else
+ const mediump vec2 position = gl_FragCoord.xy*scaling*imageSizeInverted;
+ #endif
/* If pixel at the position is inside (1), we are looking for nearest pixel
outside and the value will be positive (> 0.5). If it is outside (0), we
are looking for nearest pixel inside and the value will be negative
(< 0.5). */
+ #ifdef TEXELFETCH_USABLE
const bool isInside = hasValue(position, ivec2(0, 0));
- const float sign = isInside ? 1.0 : -1.0;
+ #else
+ const bool isInside = hasValue(position, vec2(0.0, 0.0));
+ #endif
+ const highp float sign = isInside ? 1.0 : -1.0;
/* Minimal found distance is just out of the radius (i.e. infinity) */
- float minDistanceSquared = float((radius+1)*(radius+1));
+ highp float minDistanceSquared = float((radius+1)*(radius+1));
/* Go in circles around the point and find nearest value */
int radiusLimit = radius;
for(int i = 1; i <= radiusLimit; ++i) {
for(int j = 0, jmax = i*2; j != jmax; ++j) {
- const ivec2 offset = {-i+j, i};
+ #ifdef TEXELFETCH_USABLE
+ const lowp ivec2 offset = ivec2(-i+j, i);
+ #else
+ const lowp vec2 pixelOffset = vec2(float(-i+j), float(i));
+ const lowp vec2 offset = pixelOffset*imageSizeInverted;
+ #endif
/* If any of the four values is opposite of what is on the pixel,
we found nearest value */
@@ -63,7 +113,11 @@ void main() {
hasValue(position, rotate(offset)) == !isInside ||
hasValue(position, rotate(rotate(offset))) == !isInside ||
hasValue(position, rotate(rotate(rotate(offset)))) == !isInside) {
- const float distanceSquared = dot(vec2(offset), vec2(offset));
+ #ifdef TEXELFETCH_USABLE
+ const mediump float distanceSquared = dot(vec2(offset), vec2(offset));
+ #else
+ const mediump float distanceSquared = dot(pixelOffset, pixelOffset);
+ #endif
/* Set smaller distance, if found, or continue with lookup for
smaller */
@@ -73,7 +127,11 @@ void main() {
/* Set radius limit to max radius which can contain smaller
value, e.g. for distance 3.5 we can find smaller value even
in radius 3 */
+ #ifdef NEW_GLSL
radiusLimit = min(radius, int(floor(length(vec2(offset)))));
+ #else
+ radiusLimit = int(min(float(radius), floor(length(vec2(offset)))));
+ #endif
}
}
}
diff --git a/src/TextureTools/DistanceFieldShader.vert b/src/TextureTools/DistanceFieldShader.vert
index a412a0a20..c7970fe47 100644
--- a/src/TextureTools/DistanceFieldShader.vert
+++ b/src/TextureTools/DistanceFieldShader.vert
@@ -22,7 +22,15 @@
DEALINGS IN THE SOFTWARE.
*/
+#ifndef NEW_GLSL
+attribute lowp vec4 position;
+#endif
+
void main() {
+ #ifdef NEW_GLSL
gl_Position = vec4((gl_VertexID == 2) ? 3.0 : -1.0,
(gl_VertexID == 1) ? -3.0 : 1.0, 0.0, 1.0);
+ #else
+ gl_Position = position;
+ #endif
}