diff --git a/README.md b/README.md index 68cfeae81..5a22c7889 100644 --- a/README.md +++ b/README.md @@ -49,8 +49,8 @@ Graphics APIs: Platforms: * **Linux** and embedded Linux (natively using GLX/EGL and Xlib or through - GLUT or SDL2 toolkit) -* **Windows** (through GLUT or SDL2 toolkit) + SDL2 or GLUT toolkit) +* **Windows** (through SDL2 or GLUT toolkit) * **OS X** (through SDL2 toolkit, thanks to [Miguel Martin](https://github.com/miguelishawt)) * **Android** 2.3 (API Level 9) and higher * **Google Chrome** (through [Native Client](https://developers.google.com/native-client/), @@ -97,13 +97,13 @@ Note that full feature set is available only on GCC 4.8.1 and Clang 3.1. Compilation, installation ------------------------- -The library (for example with support for GLUT applications) can be built and +The library (for example with support for SDL2 applications) can be built and installed using these four commands: mkdir -p build && cd build cmake .. \ -DCMAKE_INSTALL_PREFIX=/usr \ - -DWITH_GLUTAPPLICATION=ON + -DWITH_SDL2APPLICATION=ON make make install diff --git a/doc/building.dox b/doc/building.dox index 0146387d2..9c33c9134 100644 --- a/doc/building.dox +++ b/doc/building.dox @@ -66,13 +66,13 @@ assuming you have at least basic knowledge of CMake. @subsection building-linux Via command-line (on Linux/Unix) -On Unix-based OSs, the library (for example with support for GLUT applications) +On Unix-based OSs, the library (for example with support for SDL2 applications) can be built and installed using these four commands: mkdir build && cd build cmake .. \ -DCMAKE_INSTALL_PREFIX=/usr \ - -DWITH_GLUTAPPLICATION=ON + -DWITH_SDL2APPLICATION=ON make make install diff --git a/doc/cmake.dox b/doc/cmake.dox index d5b7aa086..c8cb7b1cb 100644 --- a/doc/cmake.dox +++ b/doc/cmake.dox @@ -120,7 +120,7 @@ in build and use it with CMake. Example usage with specifying additional components is: - find_package(Magnum REQUIRED MeshTools Primitives GlutApplication) + find_package(Magnum REQUIRED MeshTools Primitives Sdl2Application) For each component is then defined: diff --git a/doc/getting-started-blue.png b/doc/getting-started-blue.png index 50b64d15c..10e381ddb 100644 Binary files a/doc/getting-started-blue.png and b/doc/getting-started-blue.png differ diff --git a/doc/getting-started.dox b/doc/getting-started.dox index adcdd39a7..35b90f9ad 100644 --- a/doc/getting-started.dox +++ b/doc/getting-started.dox @@ -33,10 +33,11 @@ namespace Magnum { Get latest version from GitHub and install it. Read full guide on @ref building "how to download, build and install Magnum" on platform of your -choice. For our first project we will use GLUT toolkit, don't forget to enable -it for building using `WITH_GLUTAPPLICATION` CMake parameter. On newer systems, -Mac OS X and Windows you might want to use SDL2 toolkit instead, it is enabled -using `WITH_SDL2APPLICATION` CMake parameter. +choice. For our first project we will use SDL2 toolkit, don't forget to enable +it for building using `WITH_SDL2APPLICATION` CMake parameter. On older Linux +distributions which don't have SDL2 in the repositories you might want to use +GLUT toolkit instead, it is enabled using `WITH_GLUTAPPLICATION` CMake +parameter. @section getting-started-bootstrap Download bootstrap project @@ -54,8 +55,8 @@ extract it somewhere. Do it rather than cloning the full repository, as it's better to init your own repository from scratch to avoid having the history polluted. -If you want to use SDL2 instead of GLUT, download the `base-sdl2` branch -[archive](https://github.com/mosra/magnum-bootstrap/archive/base-sdl2.zip). +If you want to use GLUT instead of SDL2, download the `base-glut` branch +[archive](https://github.com/mosra/magnum-bootstrap/archive/base-glut.zip). The code will be slightly different from what is presented below, but the changes are only minor (two modified lines and one additional file) and the main principles are the same. @@ -67,6 +68,7 @@ CMake build system, see @ref cmake for more information. modules/FindCorrade.cmake modules/FindMagnum.cmake + modules/FindSDL2.cmake src/MyApplication.cpp src/CMakeLists.txt CMakeLists.txt @@ -86,8 +88,8 @@ add_subdirectory(src) @endcode Directory `modules/` contains CMake modules for finding the needed -dependencies. Unlike modules for finding e.g. GLUT and OpenGL, which are part -of standard CMake installation, these aren't part of it and thus must be +dependencies. Unlike modules for finding e.g. OpenGL, which are part of +standard CMake installation, these aren't part of it and thus must be distributed with the project. These files are just verbatim copied from %Magnum repository. @@ -95,7 +97,7 @@ Directory `src/` contains the actual project. To keep things simple, the project consists of just one source file with the most minimal code possible: @code #include -#include +#include using namespace Magnum; @@ -127,7 +129,7 @@ default (dark gray) color and then does buffer swap to actually display it on the screen. `CMakeLists.txt` finds %Magnum, sets up compiler flags, creates the executable and links it to all needed libraries: @code -find_package(Magnum REQUIRED GlutApplication) +find_package(Magnum REQUIRED Sdl2Application) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CORRADE_CXX_FLAGS}") include_directories(${MAGNUM_INCLUDE_DIRS} ${MAGNUM_APPLICATION_INCLUDE_DIRS}) @@ -169,8 +171,8 @@ where to create build directory, allows you to specify initial CMake parameters everything is ready to be built. If CMake isn't able to find the dependencies on Windows, you might want to look -at @ref building-windows. If CMake complains about `GlutApplication` missing, -you forgot to enable `WITH_GLUTAPPLICATION` when building %Magnum, +at @ref building-windows. If CMake complains about `Sdl2Application` missing, +you forgot to enable `WITH_SDL2APPLICATION` when building %Magnum, @ref getting-started-download "go back and fix it". @image html getting-started.png diff --git a/doc/getting-started.png b/doc/getting-started.png index 7f4cf8c3a..2df2b37b3 100644 Binary files a/doc/getting-started.png and b/doc/getting-started.png differ diff --git a/doc/mainpage.dox b/doc/mainpage.dox index 920ad37cb..64774d72e 100644 --- a/doc/mainpage.dox +++ b/doc/mainpage.dox @@ -75,8 +75,8 @@ Graphics APIs: Platforms: - **Linux** and embedded Linux (natively using GLX/EGL and Xlib or through - GLUT or SDL2 toolkit) -- **Windows** (through GLUT or SDL2 toolkit) + SDL2 or GLUT toolkit) +- **Windows** (through SDL2 or GLUT toolkit) - **OS X** (through SDL2 toolkit, thanks to [Miguel Martin](https://github.com/miguelishawt)) - **Android** 2.3 (API Level 9) and higher - **Google Chrome** (through [Native Client](https://developers.google.com/native-client/), diff --git a/doc/opengl-mapping.dox b/doc/opengl-mapping.dox index 7d77dc62f..dae5de8ee 100644 --- a/doc/opengl-mapping.dox +++ b/doc/opengl-mapping.dox @@ -40,7 +40,7 @@ Legend: OpenGL function | Matching API -------------------------------------- | ------------ -@fn_gl{ActiveShaderProgram} | | +@fn_gl{ActiveShaderProgram} | not needed as @fn_gl{ProgramUniform} calls are used @fn_gl{ActiveTexture} | @ref AbstractTexture::bind() @fn_gl{AttachShader} | @ref AbstractShaderProgram::attachShader() @fn_gl{BeginConditionalRender}, `glEndConditionalRender()` | @ref SampleQuery::beginConditionalRender(), \n @ref SampleQuery::endConditionalRender() @@ -48,25 +48,19 @@ OpenGL function | Matching API @fn_gl{BeginQueryIndexed}, `glEndQueryIndexed()` | | @fn_gl{BeginTransformFeedback}, `glEndTransformFeedback()` | | @fn_gl{BindAttribLocation} | @ref AbstractShaderProgram::bindAttributeLocation() -@fn_gl{BindBuffer} | not needed, handhled internally in @ref Buffer and elsewhere -@fn_gl{BindBufferBase} | | -@fn_gl{BindBufferRange} | | -@fn_gl{BindBuffersBase} | | -@fn_gl{BindBuffersRange} | | +@fn_gl{BindBuffer} | not needed, handled internally in @ref Buffer and elsewhere +@fn_gl{BindBufferBase}, \n @fn_gl{BindBuffersBase}, \n @fn_gl{BindBufferRange}, \n @fn_gl{BindBuffersRange} | | @fn_gl{BindFragDataLocation} | @ref AbstractShaderProgram::bindFragmentDataLocation() @fn_gl{BindFragDataLocationIndexed} | @ref AbstractShaderProgram::bindFragmentDataLocationIndexed() @fn_gl{BindFramebuffer} | @ref Framebuffer::bind() -@fn_gl{BindImageTexture} | | -@fn_gl{BindImageTextures} | | +@fn_gl{BindImageTexture}, \n @fn_gl{BindImageTextures} | | @fn_gl{BindProgramPipeline} | | -@fn_gl{BindRenderbuffer} | not needed, handhled internally in @ref Renderbuffer -@fn_gl{BindSampler} | | -@fn_gl{BindSamplers} | | +@fn_gl{BindRenderbuffer} | not needed, handled internally in @ref Renderbuffer +@fn_gl{BindSampler}, \n @fn_gl{BindSamplers} | | @fn_gl{BindTexture}, \n @fn_gl{BindTextures}, \n @fn_gl_extension{BindMultiTexture,EXT,direct_state_access} | @ref AbstractTexture::bind() @fn_gl{BindTransformFeedback} | | -@fn_gl{BindVertexArray} | not needed, handhled internally in @ref Mesh -@fn_gl{BindVertexBuffer} | | -@fn_gl{BindVertexBuffers} | | +@fn_gl{BindVertexArray} | not needed, handled internally in @ref Mesh +@fn_gl{BindVertexBuffer}, \n @fn_gl{BindVertexBuffers} | | @fn_gl{BlendColor} | @ref Renderer::setBlendColor() @fn_gl{BlendEquation}, \n @fn_gl{BlendEquationSeparate} | @ref Renderer::setBlendEquation() @fn_gl{BlendFunc}, \n @fn_gl{BlendFuncSeparate} | @ref Renderer::setBlendFunction() @@ -109,8 +103,8 @@ OpenGL function | Matching API @fn_gl{DetachShader} | | @fn_gl{DispatchCompute} | | @fn_gl{DispatchComputeIndirect} | | -@fn_gl{DrawArrays}, \n @fn_gl{DrawElements}, \n @fn_gl{DrawRangeElements} | @ref Mesh::draw() -@fn_gl{DrawArraysIndirect}, \n @fn_gl{DrawArraysInstanced}, \n @fn_gl{DrawArraysInstancedBaseInstance}, \n @fn_gl{DrawElementsBaseVertex}, \n @fn_gl{DrawElementsIndirect}, \n @fn_gl{DrawElementsInstanced}, \n @fn_gl{DrawElementsInstancedBaseInstance}, \n @fn_gl{DrawElementsInstancedBaseVertex}, \n @fn_gl{DrawElementsInstancedBaseVertexBaseInstance}, \n @fn_gl{DrawRangeElementsBaseVertex} | | +@fn_gl{DrawArrays}, \n @fn_gl{DrawArraysInstanced}, \n @fn_gl{DrawArraysInstancedBaseInstance}, \n @fn_gl{DrawElements}, \n @fn_gl{DrawRangeElements}, \n @fn_gl{DrawElementsBaseVertex}, \n @fn_gl{DrawRangeElementsBaseVertex}, \n @fn_gl{DrawElementsInstanced}, \n @fn_gl{DrawElementsInstancedBaseInstance}, \n @fn_gl{DrawElementsInstancedBaseVertex}, \n @fn_gl{DrawElementsInstancedBaseVertexBaseInstance} | @ref Mesh::draw(), \n @ref MeshView::draw() +@fn_gl{DrawArraysIndirect}, \n @fn_gl{DrawElementsIndirect}, \n @fn_gl{MultiDrawArraysIndirect}, \n @fn_gl{MultiDrawElementsIndirect} | | @fn_gl{DrawBuffer}, \n @fn_gl_extension{FramebufferDrawBuffers,EXT,direct_state_access}, \n @fn_gl{DrawBuffers}, \n @fn_gl_extension{FramebufferDrawBuffers,EXT,direct_state_access} | @ref DefaultFramebuffer::mapForDraw(), \n @ref Framebuffer::mapForDraw() @fn_gl{DrawTransformFeedback}, \n @fn_gl{DrawTransformFeedbackInstanced}, \n @fn_gl{DrawTransformFeedbackStream}, \n @fn_gl{DrawTransformFeedbackStreamInstanced} | | @fn_gl{Enable}, `glDisable()` | @ref Renderer::setFeature() @@ -121,11 +115,10 @@ OpenGL function | Matching API @fn_gl{FlushMappedBufferRange}, \n @fn_gl_extension{FlushMappedNamedBufferRange,EXT,direct_state_access} | @ref Buffer::flushMappedRange() @fn_gl2{FramebufferParameter,FramebufferParameteri} | | @fn_gl{FramebufferRenderbuffer}, \n @fn_gl_extension{NamedFramebufferRenderbuffer,EXT,direct_state_access} | @ref Framebuffer::attachRenderbuffer() -@fn_gl{FramebufferTexture} | | -@fn_gl2{FramebufferTexture1D,FramebufferTexture}, \n @fn_gl_extension{NamedFramebufferTexture1D,EXT,direct_state_access} | @ref Framebuffer::attachTexture1D() -@fn_gl2{FramebufferTexture2D,FramebufferTexture}, \n @fn_gl_extension{NamedFramebufferTexture2D,EXT,direct_state_access} | @ref Framebuffer::attachTexture2D() -@fn_gl2{FramebufferTexture3D,FramebufferTexture}, \n @fn_gl_extension{NamedFramebufferTexture3D,EXT,direct_state_access} | @ref Framebuffer::attachTexture3D() -@fn_gl{FramebufferTextureLayer} | | +@fn_gl{FramebufferTexture} | not used, the functions below are used instead for compatibility reasons +@fn_gl2{FramebufferTexture1D,FramebufferTexture}, \n @fn_gl_extension{NamedFramebufferTexture1D,EXT,direct_state_access}, \n `glFramebufferTexture2D()`, \n `glNamedFramebufferTexture2DEXT()` | @ref Framebuffer::attachTexture() +@fn_gl2{FramebufferTexture3D,FramebufferTexture} | not used, @fn_gl{FramebufferTextureLayer} has more complete features +@fn_gl{FramebufferTextureLayer}, \n @fn_gl_extension{NamedFramebufferTextureLayer,EXT,direct_state_access} | @ref Framebuffer::attachTextureLayer() @fn_gl{FrontFace} | @ref Renderer::setFrontFace() @fn_gl{GenBuffers}, @fn_gl{DeleteBuffers} | @ref Buffer constructor and destructor @fn_gl{GenFramebuffers}, @fn_gl{DeleteFramebuffers} | @ref Framebuffer constructor and destructor @@ -178,8 +171,8 @@ OpenGL function | Matching API @fn_gl{GetSubroutineIndex} | | @fn_gl{GetSubroutineUniformLocation} | | @fn_gl{GetSync} | | -@fn_gl{GetTexImage}, \n @fn_gl_extension{GetTextureImage,EXT,direct_state_access}, \n @fn_gl_extension{GetnTexImage,ARB,robustness} | @ref Texture::image(), \n @ref CubeMapTexture::image(), \n @ref CubeMapTextureArray::image() -@fn_gl{GetTexLevelParameter}, \n @fn_gl_extension{GetTextureLevelParameter,EXT,direct_state_access} | @ref Texture::imageSize(), \n @ref CubeMapTexture::imageSize(), \n @ref CubeMapTextureArray::imageSize() +@fn_gl{GetTexImage}, \n @fn_gl_extension{GetTextureImage,EXT,direct_state_access}, \n @fn_gl_extension{GetnTexImage,ARB,robustness} | @ref Texture::image(), \n @ref TextureArray::image(), \n @ref CubeMapTexture::image(), \n @ref CubeMapTextureArray::image(), \n @ref RectangleTexture::image() +@fn_gl{GetTexLevelParameter}, \n @fn_gl_extension{GetTextureLevelParameter,EXT,direct_state_access} | @ref Texture::imageSize(), \n @ref TextureArray::imageSize(), \n @ref CubeMapTexture::imageSize(), \n @ref CubeMapTextureArray::imageSize(), \n @ref RectangleTexture::imageSize() @fn_gl{GetTexParameter} | | @fn_gl{GetTransformFeedbackVarying} | | @fn_gl{GetUniform} | not queryable, @ref AbstractShaderProgram::setUniform() setter only @@ -192,8 +185,8 @@ OpenGL function | Matching API @fn_gl{InvalidateBufferSubData} | @ref Buffer::invalidateSubData() @fn_gl{InvalidateFramebuffer}, \n @fn_gles_extension{DiscardFramebuffer,EXT,discard_framebuffer} | @ref DefaultFramebuffer::invalidate(), \n @ref Framebuffer::invalidate() @fn_gl{InvalidateSubFramebuffer}, \n @fn_gles_extension{DiscardSubFramebuffer,EXT,discard_framebuffer} | @ref DefaultFramebuffer::invalidate(), \n @ref Framebuffer::invalidate() -@fn_gl{InvalidateTexImage} | @ref Texture::invalidateImage(), \n @ref TextureArray::invalidateImage(), \n @ref CubeMapTexture::invalidateImage(), \n @ref CubeMapTextureArray::invalidateImage(), \n @ref MultisampleTexture::invalidateImage(), \n @ref RectangleTexture::invalidateImage() -@fn_gl{InvalidateTexSubImage} | @ref Texture::invalidateSubImage(), \n @ref TextureArray::invalidateSubImage(), \n @ref CubeMapTexture::invalidateSubImage(), \n @ref CubeMapTextureArray::invalidateSubImage(), \n @ref MultisampleTexture::invalidateSubImage(), \n @ref RectangleTexture::invalidateSubImage() +@fn_gl{InvalidateTexImage} | @ref Texture::invalidateImage(), \n @ref TextureArray::invalidateImage(), \n @ref CubeMapTexture::invalidateImage(), \n @ref CubeMapTextureArray::invalidateImage(), \n @ref RectangleTexture::invalidateImage(), \n @ref MultisampleTexture::invalidateImage() +@fn_gl{InvalidateTexSubImage} | @ref Texture::invalidateSubImage(), \n @ref TextureArray::invalidateSubImage(), \n @ref CubeMapTexture::invalidateSubImage(), \n @ref CubeMapTextureArray::invalidateSubImage(), \n @ref RectangleTexture::invalidateSubImage(), \n @ref MultisampleTexture::invalidateSubImage() @fn_gl{IsBuffer}, \n @fn_gl{IsFramebuffer}, \n @fn_gl{IsProgram}, \n @fn_gl{IsProgramPipeline}, \n @fn_gl{IsQuery}, \n @fn_gl{IsRenderbuffer}, \n @fn_gl{IsSampler}, \n @fn_gl{IsShader}, \n @fn_gl{IsSync}, \n @fn_gl{IsTexture}, \n @fn_gl{IsTransformFeedback}, \n @fn_gl{IsVertexArray} | not needed, objects are strongly typed @fn_gl{IsEnabled} | not queryable, @ref Renderer::setFeature() setter only @fn_gl{LineWidth} | @ref Renderer::setLineWidth() @@ -203,7 +196,8 @@ OpenGL function | Matching API @fn_gl_extension{MapBufferSubData,CHROMIUM,map_sub}, @fn_gl_extension{UnmapBufferSubData,CHROMIUM,map_sub} | @ref Buffer::mapSub(), @ref Buffer::unmapSub() @fn_gl{MemoryBarrier} | | @fn_gl{MinSampleShading} | | -@fn_gl{MultiDrawArrays}, \n @fn_gl{MultiDrawArraysIndirect}, \n @fn_gl{MultiDrawElements}, \n @fn_gl{MultiDrawElementsBaseVertex}, \n @fn_gl{MultiDrawElementsIndirect} | | +@fn_gl{MultiDrawArrays}, \n @fn_gl{MultiDrawElements} | | +@fn_gl{MultiDrawElementsBaseVertex} | | @fn_gl{ObjectLabel}, \n @fn_gl{ObjectPtrLabel}, \n @fn_gl_extension2{LabelObject,EXT,debug_label} | @ref AbstractShaderProgram::setLabel(), \n @ref AbstractQuery::setLabel(), \n @ref AbstractTexture::setLabel(), \n @ref Buffer::setLabel(), \n @ref Framebuffer::setLabel(), \n @ref Mesh::setLabel(), \n @ref Renderbuffer::setLabel(), \n @ref Shader::setLabel() @fn_gl{PatchParameter} | | @fn_gl{PauseTransformFeedback}, @fn_gl{ResumeTransformFeedback} | | @@ -236,12 +230,12 @@ OpenGL function | Matching API @fn_gl{StencilMask}, \n @fn_gl{StencilMaskSeparate} | @ref Renderer::setStencilMask() @fn_gl{StencilOp}, \n @fn_gl{StencilOpSeparate} | @ref Renderer::setStencilOperation() @fn_gl{TexBuffer}, \n @fn_gl_extension{TextureBuffer,EXT,direct_state_access}, \n @fn_gl{TexBufferRange}, \n @fn_gl_extension{TextureBufferRange,EXT,direct_state_access} | @ref BufferTexture::setBuffer() -@fn_gl{TexImage1D}, \n @fn_gl_extension{TextureImage1D,EXT,direct_state_access} \n @fn_gl{TexImage2D}, \n @fn_gl_extension{TextureImage2D,EXT,direct_state_access}, \n @fn_gl{TexImage3D}, \n @fn_gl_extension{TextureImage3D,EXT,direct_state_access} | @ref Texture::setImage(), \n @ref CubeMapTexture::setImage(), \n @ref CubeMapTextureArray::setImage() -@fn_gl{TexImage2DMultisample}, \n @fn_gl{TexImage3DMultisample} | | -@fn_gl{TexParameter}, \n @fn_gl_extension{TextureParameter,EXT,direct_state_access} | @ref Texture::setMinificationFilter(), \n @ref TextureArray::setMinificationFilter(), \n @ref CubeMapTexture::setMinificationFilter(), \n @ref CubeMapTextureArray::setMinificationFilter(), \n @ref RectangleTexture::setMinificationFilter(), \n @ref Texture::setMagnificationFilter(), \n @ref TextureArray::setMagnificationFilter(), \n @ref CubeMapTexture::setMagnificationFilter(), \n @ref CubeMapTextureArray::setMagnificationFilter(), \n @ref RectangleTexture::setMagnificationFilter(), \n @ref Texture::setBorderColor(), \n @ref TextureArray::setBorderColor(), \n @ref CubeMapTexture::setBorderColor(), \n @ref CubeMapTextureArray::setBorderColor(), \n @ref RectangleTexture::setBorderColor(), \n @ref Texture::setMaxAnisotropy(), \n @ref TextureArray::setMaxAnisotropy(), \n @ref CubeMapTexture::setMaxAnisotropy(), \n @ref CubeMapTextureArray::setMaxAnisotropy(), \n @ref RectangleTexture::setMaxAnisotropy(), \n @ref Texture::setWrapping(), \n @ref TextureArray::setWrapping(), \n @ref CubeMapTexture::setWrapping(), \n @ref CubeMapTextureArray::setWrapping(), \n @ref RectangleTexture::setWrapping() -@fn_gl{TexStorage1D}, \n @fn_gl_extension{TextureStorage1D,EXT,direct_state_access}, \n @fn_gl{TexStorage2D}, \n @fn_gl_extension{TextureStorage2D,EXT,direct_state_access}, \n @fn_gl{TexStorage3D}, \n @fn_gl_extension{TextureStorage3D,EXT,direct_state_access} | @ref Texture::setStorage(), \n @ref CubeMapTexture::setStorage(), \n @ref CubeMapTextureArray::setStorage() -@fn_gl{TexStorage2DMultisample}, \n @fn_gl{TexStorage3DMultisample} | | -@fn_gl{TexSubImage1D}, \n @fn_gl_extension{TextureSubImage1D,EXT,direct_state_access}, \n @fn_gl{TexSubImage2D}, \n @fn_gl_extension{TextureSubImage2D,EXT,direct_state_access}, \n @fn_gl{TexSubImage3D}, \n @fn_gl_extension{TextureSubImage3D,EXT,direct_state_access} | @ref Texture::setSubImage(), \n @ref CubeMapTexture::setSubImage(), \n @ref CubeMapTextureArray::setSubImage() +@fn_gl{TexImage1D}, \n @fn_gl_extension{TextureImage1D,EXT,direct_state_access} \n @fn_gl{TexImage2D}, \n @fn_gl_extension{TextureImage2D,EXT,direct_state_access}, \n @fn_gl{TexImage3D}, \n @fn_gl_extension{TextureImage3D,EXT,direct_state_access} | @ref Texture::setImage(), \n @ref TextureArray::setImage(), \n @ref CubeMapTexture::setImage(), \n @ref CubeMapTextureArray::setImage(), \n @ref RectangleTexture::setImage() +@fn_gl{TexImage2DMultisample}, \n @fn_gl{TexImage3DMultisample} | @ref MultisampleTexture::setStorage() +@fn_gl{TexParameter}, \n @fn_gl_extension{TextureParameter,EXT,direct_state_access} | @ref Texture::setBaseLevel() "*Texture::setBaseLevel()", \n @ref Texture::setMaxLevel() "*Texture::setMaxLevel()", \n @ref Texture::setMinificationFilter() "*Texture::setMinificationFilter()", \n @ref Texture::setMagnificationFilter() "*Texture::setMagnificationFilter()", \n @ref Texture::setMinLod() "*Texture::setMinLod()", \n @ref Texture::setMaxLod() "*Texture::setMaxLod()", \n @ref Texture::setLodBias() "*Texture::setLodBias()", \n @ref Texture::setWrapping() "*Texture::setWrapping()", \n @ref Texture::setBorderColor() "*Texture::setBorderColor()", \n @ref Texture::setMaxAnisotropy() "*Texture::setMaxAnisotropy()", \n @ref Texture::setSwizzle() "*Texture::setSwizzle()", \n @ref Texture::setCompareMode() "*Texture::setCompareMode()", \n @ref Texture::setCompareFunction() "*Texture::setCompareFunction()", \n @ref Texture::setDepthStencilMode() "*Texture::setDepthStencilMode()" +@fn_gl{TexStorage1D}, \n @fn_gl_extension{TextureStorage1D,EXT,direct_state_access}, \n @fn_gl{TexStorage2D}, \n @fn_gl_extension{TextureStorage2D,EXT,direct_state_access}, \n @fn_gl{TexStorage3D}, \n @fn_gl_extension{TextureStorage3D,EXT,direct_state_access} | @ref Texture::setStorage(), \n @ref TextureArray::setStorage(), \n @ref CubeMapTexture::setStorage(), \n @ref CubeMapTextureArray::setStorage(), \n @ref RectangleTexture::setStorage() +@fn_gl{TexStorage2DMultisample}, \n @fn_gl_extension{TextureStorage2DMultisample,EXT,direct_state_access}, \n @fn_gl{TexStorage3DMultisample}, \n @fn_gl_extension{TextureStorage3DMultisample,EXT,direct_state_access} | @ref MultisampleTexture::setStorage() +@fn_gl{TexSubImage1D}, \n @fn_gl_extension{TextureSubImage1D,EXT,direct_state_access}, \n @fn_gl{TexSubImage2D}, \n @fn_gl_extension{TextureSubImage2D,EXT,direct_state_access}, \n @fn_gl{TexSubImage3D}, \n @fn_gl_extension{TextureSubImage3D,EXT,direct_state_access} | @ref Texture::setSubImage(), \n @ref TextureArray::setSubImage(), \n @ref CubeMapTexture::setSubImage(), \n @ref CubeMapTextureArray::setSubImage(), \n @ref RectangleTexture::setSubImage() @fn_gl{TextureView} | | @fn_gl{TransformFeedbackVaryings} | | @fn_gl{Uniform}, \n @fn_gl{ProgramUniform}, \n @fn_gl_extension{ProgramUniform,EXT,direct_state_access} | @ref AbstractShaderProgram::setUniform() @@ -253,7 +247,7 @@ OpenGL function | Matching API @fn_gl{ValidateProgramPipeline} | | @fn_gl{VertexAttrib} | not supported (@ref opengl-unsupported "details") @fn_gl{VertexAttribBinding} | | -@fn_gl{VertexAttribDivisor} | | +@fn_gl{VertexAttribDivisor}, \n @fn_gl_extension{VertexArrayVertexAttribDivisor,EXT,direct_state_access} | @ref Mesh::addVertexBufferInstanced() @fn_gl{VertexAttribFormat} | | @fn_gl{VertexAttribPointer}, \n @fn_gl_extension{VertexArrayVertexAttribOffset,EXT,direct_state_access} | @ref Mesh::addVertexBuffer() @fn_gl{VertexBindingDivisor} | | @@ -303,7 +297,7 @@ OpenGL function | Matching API `GL_MAX_*_UNIFORM_BLOCKS`, \n @def_gl{MAX_COMBINED_UNIFORM_BLOCKS} | @ref Shader::maxUniformBlocks(), \n @ref Shader::maxCombinedUniformBlocks() `GL_MAX_*_UNIFORM_COMPONENTS`, \n @def_gl{MAX_VERTEX_UNIFORM_VECTORS}, \n @def_gl{MAX_FRAGMENT_UNIFORM_VECTORS} | @ref Shader::maxUniformComponents() `GL_MAX_COMBINED_*_UNIFORM_COMPONENTS` | @ref Shader::maxCombinedUniformComponents() -@def_gl{MAX_3D_TEXTURE_SIZE}, \n @def_gl{MAX_ARRAY_TEXTURE_LAYERS}, \n @def_gl{MAX_CUBE_MAP_TEXTURE_SIZE}, \n @def_gl{MAX_RECTANGLE_TEXTURE_SIZE}, \n @def_gl{MAX_TEXTURE_SIZE} | | +@def_gl{MAX_3D_TEXTURE_SIZE}, \n @def_gl{MAX_ARRAY_TEXTURE_LAYERS}, \n @def_gl{MAX_CUBE_MAP_TEXTURE_SIZE}, \n @def_gl{MAX_RECTANGLE_TEXTURE_SIZE}, \n @def_gl{MAX_TEXTURE_SIZE} | @ref Texture::maxSize(), \n @ref TextureArray::maxSize(), \n @ref CubeMapTexture::maxSize(), \n @ref CubeMapTextureArray::maxSize(), \n @ref RectangleTexture::maxSize(), \n @ref BufferTexture::maxSize(), \n @ref MultisampleTexture::maxSize() @def_gl{MAX_ATOMIC_COUNTER_BUFFER_SIZE} | @ref AbstractShaderProgram::maxAtomicCounterBufferSize() @def_gl{MAX_ATOMIC_COUNTER_BUFFER_BINDINGS} | @ref Buffer::maxAtomicCounterBindings() @def_gl{MAX_COLOR_ATTACHMENTS} | @ref Framebuffer::maxColorAttachments() @@ -337,7 +331,7 @@ OpenGL function | Matching API @def_gl{MAX_SHADER_STORAGE_BUFFER_BINDINGS} | @ref Buffer::maxShaderStorageBindings() @def_gl{MAX_TEXTURE_BUFFER_SIZE} | | @def_gl_extension{MAX_TEXTURE_MAX_ANISOTROPY,EXT,texture_filter_anisotropic} | @ref Sampler::maxMaxAnisotropy() -@def_gl{MAX_TEXTURE_LOD_BIAS} | | +@def_gl{MAX_TEXTURE_LOD_BIAS} | @ref AbstractTexture::maxLodBias() @def_gl{MAX_UNIFORM_BLOCK_SIZE} | @ref AbstractShaderProgram::maxUniformBlockSize() @def_gl{MAX_UNIFORM_BUFFER_BINDINGS} | @ref Buffer::maxUniformBindings() @def_gl{MAX_UNIFORM_LOCATIONS} | @ref AbstractShaderProgram::maxUniformLocations() diff --git a/doc/opengl-support.dox b/doc/opengl-support.dox index 409d5e9d3..bfd5ea51e 100644 --- a/doc/opengl-support.dox +++ b/doc/opengl-support.dox @@ -81,9 +81,9 @@ following: %Extension | Status -------------------------------------------- | ------ -@extension{ARB,texture_rectangle} | missing limit query -@extension{ARB,draw_instanced} | | -@extension{ARB,texture_buffer_object} | missing limit query +@extension{ARB,texture_rectangle} | done +@extension{ARB,draw_instanced} | done +@extension{ARB,texture_buffer_object} | done @extension{ARB,uniform_buffer_object} | | @extension{ARB,copy_buffer} | done @extension{EXT,texture_snorm} | done @@ -95,7 +95,7 @@ following: -------------------------------------------- | ------ @extension{ARB,geometry_shader4} | missing layered attachments @extension{ARB,depth_clamp} | done -@extension{ARB,draw_elements_base_vertex} | | +@extension{ARB,draw_elements_base_vertex} | missing `Multi*` command @extension{ARB,fragment_coord_conventions} | done (shading language only) @extension{ARB,provoking_vertex} | done @extension{ARB,seamless_cube_map} | done @@ -107,14 +107,14 @@ following: %Extension | Status -------------------------------------------- | ------ -@extension{ARB,instanced_arrays} | | +@extension{ARB,instanced_arrays} | done @extension{ARB,blend_func_extended} | missing limit query @extension{ARB,explicit_attrib_location} | done (shading language only) @extension{ARB,occlusion_query2} | done @extension{ARB,sampler_objects} | | @extension{ARB,shader_bit_encoding} | done (shading language only) @extension{ARB,texture_rgb10_a2ui} | done -@extension{ARB,texture_swizzle} | | +@extension{ARB,texture_swizzle} | done @extension{ARB,timer_query} | missing direct query @extension{ARB,vertex_type_2_10_10_10_rev} | done @@ -152,7 +152,7 @@ following: %Extension | Status -------------------------------------------- | ------ @extension{ARB,texture_compression_bptc} | done -@extension{ARB,base_instance} | | +@extension{ARB,base_instance} | done @extension{ARB,shading_language_420pack} | done (shading language only) @extension{ARB,transform_feedback_instanced} | | @extension{ARB,compressed_texture_pixel_storage} | | @@ -184,7 +184,7 @@ following: @extension{ARB,robust_buffer_access_behavior} | done (nothing to do) @extension{ARB,shader_image_size} | done (shading language only) @extension{ARB,shader_storage_buffer_object} | only limit queries -@extension{ARB,stencil_texturing} | | +@extension{ARB,stencil_texturing} | done @extension{ARB,texture_buffer_range} | done @extension{ARB,texture_query_levels} | done (shading language only) @extension{ARB,texture_storage_multisample} | done @@ -243,6 +243,7 @@ supported. -------------------------------------------- | ------ @es_extension{ANGLE,framebuffer_blit} | done @es_extension{ANGLE,framebuffer_multisample} | done +@es_extension{ANGLE,instanced_arrays} | done @es_extension{ANGLE,depth_texture} | done @es_extension{APPLE,framebuffer_multisample} | done (ES 3.0 subset) @es_extension{APPLE,texture_max_level} | done @@ -250,15 +251,23 @@ supported. @es_extension{EXT,texture_type_2_10_10_10_REV} | done @es_extension{EXT,discard_framebuffer} | done @es_extension2{EXT,blend_minmax,blend_minmax} | done +@es_extension{EXT,shader_texture_lod} | done (shading language only) @es_extension{EXT,occlusion_query_boolean} | done +@es_extension{EXT,shadow_samplers} | done @es_extension{EXT,texture_rg} | done @es_extension{EXT,texture_storage} | done @es_extension{EXT,map_buffer_range} | done +@es_extension{EXT,instanced_arrays} | done +@es_extension2{EXT,draw_instanced,draw_instanced} | done @es_extension{NV,draw_buffers} | done @es_extension{NV,fbo_color_attachments} | done @es_extension{NV,read_buffer} | done +@es_extension{NV,draw_instanced} | done @es_extension{NV,framebuffer_blit} | done @es_extension{NV,framebuffer_multisample} | done +@es_extension{NV,instanced_arrays} | done +@es_extension{NV,shadow_samplers_array} | done (shading language only) +@es_extension{NV,shadow_samplers_cube} | done (shading language only) @es_extension{OES,depth24} | done @es_extension{OES,element_index_uint} | done @es_extension{OES,rgb8_rgba8} | done (desktop-compatible subset) diff --git a/doc/platform.dox b/doc/platform.dox index 44c6700a5..633f38057 100644 --- a/doc/platform.dox +++ b/doc/platform.dox @@ -45,12 +45,12 @@ to subclass the chosen `*Application` class and implement required methods. @section platform-windowed Windowed applications Windowed applications provide a window and keyboard and mouse handling. The -most basic toolkit (and toolkit packaged for most systems) is GLUT, which is -implemented in @ref Platform::GlutApplication. As said above, the usage is -similar for all toolkits, you must provide one-argument constructor and -implement at least @ref GlutApplication::drawEvent() "drawEvent()" function. -The class can be then used directly in `main()`, but for convenience and -portability it's better to use @ref MAGNUM_GLUTAPPLICATION_MAIN() macro. +de-facto standard and most widely used toolkit is SDL2, which is implemented in +@ref Platform::Sdl2Application. As said above, the usage is similar for all +toolkits, you must provide one-argument constructor and implement at least +@ref Sdl2Application::drawEvent() "drawEvent()" function. The class can be then +used directly in `main()`, but for convenience and portability it's better to +use @ref MAGNUM_SDL2APPLICATION_MAIN() macro. To simplify the porting, the library provides `Platform::Application` typedef and `MAGNUM_APPLICATION_MAIN()` macro (but only if only one application header @@ -69,7 +69,7 @@ blue color is shown in the following code listing. #include #include #include -#include +#include using namespace Magnum; @@ -103,7 +103,7 @@ MAGNUM_APPLICATION_MAIN(MyApplication) By default the application doesn't respond to window size changes in any way, as the window has fixed size in most cases. To respond to size change for example by resizing the default framebuffer, you need to reimplement -@ref GlutApplication::viewportEvent() "viewportEvent()" function and pass the +@ref Sdl2Application::viewportEvent() "viewportEvent()" function and pass the new size to the framebuffer: @code class MyApplication: public Platform::Application { @@ -177,19 +177,21 @@ MAGNUM_WINDOWLESSAPPLICATION_MAIN(MyApplication) @section platform-compilation Compilation with CMake Barebone compilation consists just of finding %Magnum library with required -`*Application` component, adding %Magnum's `${MAGNUM_INCLUDE_DIRS}` and application-specific `${MAGNUM_GLUTAPPLICATION_INCLUDE_DIRS}` to include path, compilation of the -executable and linking `${MAGNUM_LIBRARIES}` and `${MAGNUM_GLUTAPPLICATION_LIBRARIES}` -to it. +`*Application` component, adding %Magnum's `${MAGNUM_INCLUDE_DIRS}` and +application-specific `${MAGNUM_SDL2APPLICATION_INCLUDE_DIRS}` to include path, +compilation of the executable and linking `${MAGNUM_LIBRARIES}` and +`${MAGNUM_SDL2APPLICATION_LIBRARIES}` to it. Again, to simplify porting, you can also use generic `${MAGNUM_APPLICATION_INCLUDE_DIRS}` -and `${MAGNUM_WAPPLICATION_LIBRARIES}` aliases (or `${MAGNUM_WINDOWLESSAPPLICATION_INCLUDE_DIRS}`, `${MAGNUM_WINDOWLESSAPPLICATION_LIBRARIES}` for windowless applications), but +and `${MAGNUM_WAPPLICATION_LIBRARIES}` aliases (or `${MAGNUM_WINDOWLESSAPPLICATION_INCLUDE_DIRS}`, +`${MAGNUM_WINDOWLESSAPPLICATION_LIBRARIES}` for windowless applications), but only if only one application (windowless application) component is requested to avoid ambiguity. Changing the build script to use different toolkit is then matter of replacing only the requested `*Application` component (and one #`include` line in the actual code, as said above). @code -find_package(Magnum REQUIRED GlutApplication) +find_package(Magnum REQUIRED Sdl2Application) include_directories(${MAGNUM_INCLUDE_DIRS} ${MAGNUM_APPLICATION_INCLUDE_DIRS}) @@ -203,7 +205,7 @@ target_link_libraries(myapplication By default the application is created with some reasonable defaults (e.g. window size 800x600 pixels). If you want something else, you can pass -@ref GlutApplication::Configuration "Configuration" instance to application +@ref Sdl2Application::Configuration "Configuration" instance to application constructor. Using method chaining it can be done conveniently like this: @code MyApplication::MyApplication(int& argc, char** argv): @@ -217,8 +219,8 @@ MyApplication::MyApplication(int& argc, char** argv): However, sometimes you would need to configure the application based on some configuration file or system introspection. In that case you can pass `nullptr` -instead of @ref GlutApplication::Configuration "Configuration" instance and -then specify it later with @ref GlutApplication::createContext() "createContext()": +instead of @ref Sdl2Application::Configuration "Configuration" instance and +then specify it later with @ref Sdl2Application::createContext() "createContext()": @code MyApplication::MyApplication(int& argc, char** argv): Platform::Application(argc, argv, nullptr) { // ... @@ -231,9 +233,9 @@ MyApplication::MyApplication(int& argc, char** argv): Platform::Application(argc } @endcode -If the context creation in constructor or @ref GlutApplication::createContext() "createContext()" +If the context creation in constructor or @ref Sdl2Application::createContext() "createContext()" fails, the application exits. However, it is also possible to negotiate the -context using @ref GlutApplication::tryCreateContext() "tryCreateContext()". +context using @ref Sdl2Application::tryCreateContext() "tryCreateContext()". The only difference is that this function returns `false` instead of exiting. You can for example try enabling MSAA and if the context creation fails, fall back to no-AA rendering: diff --git a/package/archlinux/magnum-git/PKGBUILD b/package/archlinux/magnum-git/PKGBUILD index 660b77f98..176a5bf9b 100644 --- a/package/archlinux/magnum-git/PKGBUILD +++ b/package/archlinux/magnum-git/PKGBUILD @@ -1,12 +1,12 @@ # Author: mosra pkgname=magnum-git -pkgver=20140123 +pkgver=20140427 pkgrel=1 pkgdesc="C++11 and OpenGL 2D/3D graphics engine (Git version)" arch=('i686' 'x86_64') url="http://mosra.cz/blog/magnum.php" license=('MIT') -depends=('corrade-git' 'openal' 'freeglut') +depends=('corrade-git' 'openal' 'sdl2') makedepends=('cmake' 'git') provides=('magnum') conflicts=('magnum') @@ -40,7 +40,7 @@ build() { -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr \ -DWITH_AUDIO=ON \ - -DWITH_GLUTAPPLICATION=ON \ + -DWITH_SDL2APPLICATION=ON \ -DWITH_GLXAPPLICATION=ON \ -DWITH_WINDOWLESSGLXAPPLICATION=ON \ -DWITH_MAGNUMFONT=ON \ diff --git a/src/Magnum/AbstractFramebuffer.h b/src/Magnum/AbstractFramebuffer.h index 7f07087d2..6a8523abb 100644 --- a/src/Magnum/AbstractFramebuffer.h +++ b/src/Magnum/AbstractFramebuffer.h @@ -319,6 +319,8 @@ class MAGNUM_EXPORT AbstractFramebuffer { * See @ref read(const Vector2i&, const Vector2i&, Image2D&) for more * information. * @requires_gles30 Pixel buffer objects are not available in OpenGL ES 2.0. + * @todo Make it more flexible (usable with + * @extension{ARB,buffer_storage}, avoiding relocations...) */ void read(const Vector2i& offset, const Vector2i& size, BufferImage2D& image, BufferUsage usage); #endif diff --git a/src/Magnum/AbstractTexture.cpp b/src/Magnum/AbstractTexture.cpp index de6440b66..90372c274 100644 --- a/src/Magnum/AbstractTexture.cpp +++ b/src/Magnum/AbstractTexture.cpp @@ -50,6 +50,18 @@ namespace Magnum { Int AbstractTexture::maxLayers() { return Shader::maxCombinedTextureImageUnits(); } #endif +#ifndef MAGNUM_TARGET_GLES2 +Float AbstractTexture::maxLodBias() { + GLfloat& value = Context::current()->state().texture->maxLodBias; + + /* Get the value, if not already cached */ + if(value == 0.0f) + glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &value); + + return value; +} +#endif + #ifndef MAGNUM_TARGET_GLES Int AbstractTexture::maxColorSamples() { if(!Context::current()->isExtensionSupported()) @@ -237,6 +249,22 @@ void AbstractTexture::setMagnificationFilter(const Sampler::Filter filter) { (this->*Context::current()->state().texture->parameteriImplementation)(GL_TEXTURE_MAG_FILTER, GLint(filter)); } +#ifndef MAGNUM_TARGET_GLES2 +void AbstractTexture::setMinLod(const Float lod) { + (this->*Context::current()->state().texture->parameterfImplementation)(GL_TEXTURE_MIN_LOD, lod); +} + +void AbstractTexture::setMaxLod(const Float lod) { + (this->*Context::current()->state().texture->parameterfImplementation)(GL_TEXTURE_MAX_LOD, lod); +} +#endif + +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::setLodBias(const Float bias) { + (this->*Context::current()->state().texture->parameterfImplementation)(GL_TEXTURE_LOD_BIAS, bias); +} +#endif + void AbstractTexture::setBorderColor(const Color4& color) { #ifndef MAGNUM_TARGET_GLES (this->*Context::current()->state().texture->parameterfvImplementation)(GL_TEXTURE_BORDER_COLOR, color.data()); @@ -259,6 +287,46 @@ void AbstractTexture::setMaxAnisotropy(const Float anisotropy) { (this->*Context::current()->state().texture->setMaxAnisotropyImplementation)(anisotropy); } +#ifndef MAGNUM_TARGET_GLES2 +void AbstractTexture::setSwizzleInternal(const GLint r, const GLint g, const GLint b, const GLint a) { + #ifndef MAGNUM_TARGET_GLES + const GLint rgba[] = {r, g, b, a}; + (this->*Context::current()->state().texture->parameterivImplementation)(GL_TEXTURE_SWIZZLE_RGBA, rgba); + #else + (this->*Context::current()->state().texture->parameteriImplementation)(GL_TEXTURE_SWIZZLE_R, r); + (this->*Context::current()->state().texture->parameteriImplementation)(GL_TEXTURE_SWIZZLE_G, g); + (this->*Context::current()->state().texture->parameteriImplementation)(GL_TEXTURE_SWIZZLE_B, b); + (this->*Context::current()->state().texture->parameteriImplementation)(GL_TEXTURE_SWIZZLE_A, a); + #endif +} +#endif + +void AbstractTexture::setCompareMode(const Sampler::CompareMode mode) { + (this->*Context::current()->state().texture->parameteriImplementation)( + #ifndef MAGNUM_TARGET_GLES2 + GL_TEXTURE_COMPARE_MODE + #else + GL_TEXTURE_COMPARE_MODE_EXT + #endif + , GLenum(mode)); +} + +void AbstractTexture::setCompareFunction(const Sampler::CompareFunction function) { + (this->*Context::current()->state().texture->parameteriImplementation)( + #ifndef MAGNUM_TARGET_GLES2 + GL_TEXTURE_COMPARE_FUNC + #else + GL_TEXTURE_COMPARE_FUNC_EXT + #endif + , GLenum(function)); +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::setDepthStencilMode(const Sampler::DepthStencilMode mode) { + (this->*Context::current()->state().texture->parameteriImplementation)(GL_DEPTH_STENCIL_TEXTURE_MODE, GLenum(mode)); +} +#endif + void AbstractTexture::invalidateImage(const Int level) { (this->*Context::current()->state().texture->invalidateImageImplementation)(level); } @@ -692,6 +760,19 @@ void AbstractTexture::parameterImplementationDSA(GLenum parameter, GLfloat value } #endif +#ifndef MAGNUM_TARGET_GLES2 +void AbstractTexture::parameterImplementationDefault(GLenum parameter, const GLint* values) { + bindInternal(); + glTexParameteriv(_target, parameter, values); +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::parameterImplementationDSA(GLenum parameter, const GLint* values) { + glTextureParameterivEXT(_id, _target, parameter, values); +} +#endif +#endif + void AbstractTexture::parameterImplementationDefault(GLenum parameter, const GLfloat* values) { bindInternal(); glTexParameterfv(_target, parameter, values); @@ -704,21 +785,21 @@ void AbstractTexture::parameterImplementationDSA(GLenum parameter, const GLfloat #endif #ifndef MAGNUM_TARGET_GLES -void AbstractTexture::parameterImplementationDefault(GLenum parameter, const GLuint* values) { +void AbstractTexture::parameterIImplementationDefault(GLenum parameter, const GLuint* values) { bindInternal(); glTexParameterIuiv(_target, parameter, values); } -void AbstractTexture::parameterImplementationDSA(GLenum parameter, const GLuint* values) { +void AbstractTexture::parameterIImplementationDSA(GLenum parameter, const GLuint* values) { glTextureParameterIuivEXT(_id, _target, parameter, values); } -void AbstractTexture::parameterImplementationDefault(GLenum parameter, const GLint* values) { +void AbstractTexture::parameterIImplementationDefault(GLenum parameter, const GLint* values) { bindInternal(); glTexParameterIiv(_target, parameter, values); } -void AbstractTexture::parameterImplementationDSA(GLenum parameter, const GLint* values) { +void AbstractTexture::parameterIImplementationDSA(GLenum parameter, const GLint* values) { glTextureParameterIivEXT(_id, _target, parameter, values); } #endif diff --git a/src/Magnum/AbstractTexture.h b/src/Magnum/AbstractTexture.h index f0a9fead8..19b3fdb18 100644 --- a/src/Magnum/AbstractTexture.h +++ b/src/Magnum/AbstractTexture.h @@ -40,14 +40,27 @@ namespace Magnum { -namespace Implementation { struct TextureState; } +namespace Implementation { + struct TextureState; + + #ifndef MAGNUM_TARGET_GLES2 + template struct TextureSwizzle; + template<> struct TextureSwizzle<'r'> { enum: GLint { Value = GL_RED }; }; + template<> struct TextureSwizzle<'g'> { enum: GLint { Value = GL_GREEN }; }; + template<> struct TextureSwizzle<'b'> { enum: GLint { Value = GL_BLUE }; }; + template<> struct TextureSwizzle<'a'> { enum: GLint { Value = GL_ALPHA }; }; + template<> struct TextureSwizzle<'0'> { enum: GLint { Value = GL_ZERO }; }; + template<> struct TextureSwizzle<'1'> { enum: GLint { Value = GL_ONE }; }; + #endif +} /** @brief Base for textures -Encapsulates one OpenGL texture object. See @ref Texture, @ref CubeMapTexture -and @ref CubeMapTextureArray documentation for more information and usage -examples. +Encapsulates one OpenGL texture object. See @ref Texture, @ref TextureArray, +@ref CubeMapTexture, @ref CubeMapTextureArray, @ref RectangleTexture, +@ref BufferTexture and @ref MultisampleTexture documentation for more +information and usage examples. @section AbstractTexture-webgl-restrictions WebGL restrictions @@ -109,8 +122,6 @@ functions do nothing. @todo Move constructor/assignment - how to avoid creation of empty texture and then deleting it immediately? @todo ES2 - proper support for pixel unpack buffer when extension is in headers -@todo `GL_MAX_3D_TEXTURE_SIZE`, `GL_MAX_ARRAY_TEXTURE_LAYERS`, `GL_MAX_CUBE_MAP_TEXTURE_SIZE`, `GL_MAX_RECTANGLE_TEXTURE_SIZE`, `GL_MAX_TEXTURE_SIZE`, `GL_MAX_TEXTURE_BUFFER_SIZE` enable them only where it makes sense? -@todo `GL_MAX_TEXTURE_LOD_BIAS` when `TEXTURE_LOD_BIAS` is implemented @todo `GL_NUM_COMPRESSED_TEXTURE_FORMATS` when compressed textures are implemented @todo `GL_MAX_SAMPLE_MASK_WORDS` when @extension{ARB,texture_multisample} is done @todo Query for immutable levels (@extension{ARB,ES3_compatibility}) @@ -132,6 +143,19 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { static CORRADE_DEPRECATED("use Shader::maxCombinedTextureImageUnits() instead") Int maxLayers(); #endif + #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Max level-of-detail bias + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. + * @see @fn_gl{Get} with @def_gl{MAX_TEXTURE_LOD_BIAS} + * @requires_gles30 %Texture LOD bias doesn't have + * implementation-defined range in OpenGL ES 2.0. + */ + static Float maxLodBias(); + #endif + #ifndef MAGNUM_TARGET_GLES /** * @brief Max supported color sample count @@ -278,10 +302,35 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { void setMaxLevel(Int level); void setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap); void setMagnificationFilter(Sampler::Filter filter); + #ifndef MAGNUM_TARGET_GLES2 + void setMinLod(Float lod); + void setMaxLod(Float lod); + #endif + #ifndef MAGNUM_TARGET_GLES + void setLodBias(Float bias); + #endif void setBorderColor(const Color4& color); + #ifndef MAGNUM_TARGET_GLES void setBorderColor(const Vector4i& color); void setBorderColor(const Vector4ui& color); + #endif void setMaxAnisotropy(Float anisotropy); + + #ifndef MAGNUM_TARGET_GLES2 + template void setSwizzle() { + setSwizzleInternal(Implementation::TextureSwizzle::Value, + Implementation::TextureSwizzle::Value, + Implementation::TextureSwizzle::Value, + Implementation::TextureSwizzle::Value); + } + void setSwizzleInternal(GLint r, GLint g, GLint b, GLint a); + #endif + + void setCompareMode(Sampler::CompareMode mode); + void setCompareFunction(Sampler::CompareFunction function); + #ifndef MAGNUM_TARGET_GLES + void setDepthStencilMode(Sampler::DepthStencilMode mode); + #endif void invalidateImage(Int level); void generateMipmap(); @@ -312,17 +361,21 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, GLint value); void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, GLfloat value); + #ifndef MAGNUM_TARGET_GLES2 + void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, const GLint* values); + #endif void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, const GLfloat* values); #ifndef MAGNUM_TARGET_GLES - void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, const GLuint* values); - void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, const GLint* values); + void MAGNUM_LOCAL parameterIImplementationDefault(GLenum parameter, const GLuint* values); + void MAGNUM_LOCAL parameterIImplementationDefault(GLenum parameter, const GLint* values); #endif #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, GLint value); void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, GLfloat value); - void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, const GLfloat* values); - void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, const GLuint* values); void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, const GLint* values); + void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, const GLfloat* values); + void MAGNUM_LOCAL parameterIImplementationDSA(GLenum parameter, const GLuint* values); + void MAGNUM_LOCAL parameterIImplementationDSA(GLenum parameter, const GLint* values); #endif void MAGNUM_LOCAL setMaxAnisotropyImplementationNoOp(GLfloat); diff --git a/src/Magnum/BufferImage.h b/src/Magnum/BufferImage.h index 651e15f15..6715d579f 100644 --- a/src/Magnum/BufferImage.h +++ b/src/Magnum/BufferImage.h @@ -61,6 +61,8 @@ template class BufferImage: public AbstractImage { * * Note that the image data are not copied on construction, but they * are deleted on class destruction. + * @todo Make it more flexible (usable with + * @extension{ARB,buffer_storage}, avoiding relocations...) */ explicit BufferImage(ColorFormat format, ColorType type, const typename DimensionTraits::VectorType& size, const void* data, BufferUsage usage); @@ -108,6 +110,8 @@ template class BufferImage: public AbstractImage { * Updates the image buffer with given data. The data are not deleted * after filling the buffer. * @see @ref Buffer::setData() + * @todo Make it more flexible (usable with + * @extension{ARB,buffer_storage}, avoiding relocations...) */ void setData(ColorFormat format, ColorType type, const typename DimensionTraits::VectorType& size, const void* data, BufferUsage usage); diff --git a/src/Magnum/BufferTexture.cpp b/src/Magnum/BufferTexture.cpp index 1c91f129e..84b5ad87b 100644 --- a/src/Magnum/BufferTexture.cpp +++ b/src/Magnum/BufferTexture.cpp @@ -35,6 +35,18 @@ namespace Magnum { +Int BufferTexture::maxSize() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().texture->maxBufferSize; + + if(value == 0) + glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &value); + + return value; +} + Int BufferTexture::offsetAlignment() { if(!Context::current()->isExtensionSupported()) return 0; diff --git a/src/Magnum/BufferTexture.h b/src/Magnum/BufferTexture.h index fb1a37801..f8f55ee04 100644 --- a/src/Magnum/BufferTexture.h +++ b/src/Magnum/BufferTexture.h @@ -154,9 +154,8 @@ enum class BufferTextureFormat: GLenum { /** @brief %Buffer texture -This texture is, unlike classic textures such as @ref Texture or -@ref CubeMapTexture, used as simple data source, without any unnecessary -interpolation and wrapping methods. +This texture is, unlike classic textures such as @ref Texture used as simple +data source, without any unnecessary interpolation and wrapping methods. @section BufferTexture-usage Usage @@ -195,7 +194,7 @@ functions use DSA to avoid unnecessary calls to @fn_gl{ActiveTexture} and and respective function documentation for more information. @see @ref Texture, @ref TextureArray, @ref CubeMapTexture, - @ref CubeMapTextureArray, @ref MultisampleTexture, @ref RectangleTexture + @ref CubeMapTextureArray, @ref RectangleTexture, @ref MultisampleTexture @requires_gl31 %Extension @extension{ARB,texture_buffer_object} @requires_gl Texture buffers are not available in OpenGL ES. */ @@ -203,6 +202,16 @@ class MAGNUM_EXPORT BufferTexture: public AbstractTexture { friend struct Implementation::TextureState; public: + /** + * @brief Max supported buffer texture size + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If @extension{ARB,texture_buffer_object} (part of + * OpenGL 3.1) is not available, returns `0`. + * @see @fn_gl{Get} with @def_gl{MAX_TEXTURE_BUFFER_SIZE} + */ + static Int maxSize(); + /** * @brief Minimum required alignment for texture buffer offsets * @@ -240,8 +249,9 @@ class MAGNUM_EXPORT BufferTexture: public AbstractTexture { * Binds given buffer to this texture. The buffer itself can be then * filled with data of proper format at any time using @ref Buffer "Buffer"'s * own data setting functions. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexBuffer} - * or @fn_gl_extension{TextureBuffer,EXT,direct_state_access} + * @see @ref maxSize(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{TexBuffer} or + * @fn_gl_extension{TextureBuffer,EXT,direct_state_access} */ BufferTexture& setBuffer(BufferTextureFormat internalFormat, Buffer& buffer); @@ -256,9 +266,10 @@ class MAGNUM_EXPORT BufferTexture: public AbstractTexture { * Binds range of given buffer to this texture. The buffer itself can * be then filled with data of proper format at any time using @ref Buffer "Buffer"'s * own data setting functions. + * @see @ref maxSize(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{TexBufferRange} or + * @fn_gl_extension{TextureBufferRange,EXT,direct_state_access} * @requires_gl43 %Extension @extension{ARB,texture_buffer_range} - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexBufferRange} - * or @fn_gl_extension{TextureBufferRange,EXT,direct_state_access} */ BufferTexture& setBuffer(BufferTextureFormat internalFormat, Buffer& buffer, GLintptr offset, GLsizeiptr size); diff --git a/src/Magnum/CMakeLists.txt b/src/Magnum/CMakeLists.txt index 5ff0d2030..765addc03 100644 --- a/src/Magnum/CMakeLists.txt +++ b/src/Magnum/CMakeLists.txt @@ -35,6 +35,7 @@ set(Magnum_SRCS AbstractShaderProgram.cpp Buffer.cpp ColorFormat.cpp + CubeMapTexture.cpp Context.cpp DebugMessage.cpp DefaultFramebuffer.cpp @@ -49,6 +50,7 @@ set(Magnum_SRCS Resource.cpp Sampler.cpp Shader.cpp + Texture.cpp Timeline.cpp Version.cpp @@ -60,6 +62,7 @@ set(Magnum_SRCS Implementation/ShaderProgramState.cpp Implementation/State.cpp Implementation/TextureState.cpp + Implementation/maxTextureSize.cpp Implementation/setupDriverWorkarounds.cpp Trade/AbstractImageConverter.cpp @@ -75,18 +78,6 @@ set(Magnum_SRCS Trade/SceneData.cpp Trade/TextureData.cpp) -# Desktop-only code -if(NOT TARGET_GLES) - set(Magnum_SRCS ${Magnum_SRCS} - BufferTexture.cpp) -endif() - -# Not-ES2 code -if(NOT TARGET_GLES2) - set(Magnum_SRCS ${Magnum_SRCS} - BufferImage.cpp) -endif() - set(Magnum_HEADERS AbstractFramebuffer.h AbstractImage.h @@ -133,21 +124,29 @@ if(BUILD_DEPRECATED) DebugMarker.h) endif() -# Desktop-only headers and libraries +# Desktop-only stuff if(NOT TARGET_GLES) set(Magnum_HEADERS ${Magnum_HEADERS} BufferTexture.h CubeMapTextureArray.h MultisampleTexture.h RectangleTexture.h) - set(Magnum_SRCS ${Magnum_SRCS} $) + set(Magnum_SRCS ${Magnum_SRCS} + BufferTexture.cpp + CubeMapTextureArray.cpp + MultisampleTexture.cpp + RectangleTexture.cpp + $) endif() -# Not-ES2 headers +# Non-ES2 stuff if(NOT TARGET_GLES2) set(Magnum_HEADERS ${Magnum_HEADERS} BufferImage.h TextureArray.h) + set(Magnum_SRCS ${Magnum_SRCS} + BufferImage.cpp + TextureArray.cpp) endif() # Files shared between main library and math unit test library diff --git a/src/Magnum/Context.cpp b/src/Magnum/Context.cpp index 949b17f0d..6330402f9 100644 --- a/src/Magnum/Context.cpp +++ b/src/Magnum/Context.cpp @@ -212,6 +212,7 @@ const std::vector& Extension::extensions(Version version) { static const std::vector extensionsES300{ _extension(GL,ANGLE,framebuffer_blit), _extension(GL,ANGLE,framebuffer_multisample), + _extension(GL,ANGLE,instanced_arrays), _extension(GL,ANGLE,depth_texture), _extension(GL,APPLE,framebuffer_multisample), _extension(GL,APPLE,texture_max_level), @@ -219,15 +220,23 @@ const std::vector& Extension::extensions(Version version) { _extension(GL,EXT,texture_type_2_10_10_10_REV), _extension(GL,EXT,discard_framebuffer), _extension(GL,EXT,blend_minmax), + _extension(GL,EXT,shader_texture_lod), _extension(GL,EXT,occlusion_query_boolean), + _extension(GL,EXT,shadow_samplers), _extension(GL,EXT,texture_rg), _extension(GL,EXT,texture_storage), _extension(GL,EXT,map_buffer_range), + _extension(GL,EXT,instanced_arrays), + _extension(GL,EXT,draw_instanced), _extension(GL,NV,draw_buffers), _extension(GL,NV,fbo_color_attachments), _extension(GL,NV,read_buffer), + _extension(GL,NV,draw_instanced), _extension(GL,NV,framebuffer_blit), _extension(GL,NV,framebuffer_multisample), + _extension(GL,NV,instanced_arrays), + _extension(GL,NV,shadow_samplers_array), + _extension(GL,NV,shadow_samplers_cube), _extension(GL,OES,depth24), _extension(GL,OES,element_index_uint), _extension(GL,OES,rgb8_rgba8), @@ -312,13 +321,15 @@ Context::Context() { "Context: cannot retrieve OpenGL version:" << versionNumberError, ); #endif + /* Allow ES2 context on driver that reports ES3 as supported */ const std::string version = versionString(); #ifndef MAGNUM_TARGET_GLES if(version.compare(0, 4, "2.1 ") == 0) #elif defined(MAGNUM_TARGET_WEBGL) if(version.find("WebGL 1") != std::string::npos) #else - if(version.find("OpenGL ES 2.0") != std::string::npos) + if(version.find("OpenGL ES 2.0") != std::string::npos || + version.find("OpenGL ES 3.") != std::string::npos) #endif { _majorVersion = 2; @@ -350,7 +361,7 @@ Context::Context() { #elif defined(MAGNUM_TARGET_GLES2) if(_version != Version::GLES200) #else - if(_version != Version::GLES300) + if(!isVersionSupported(Version::GLES300)) #endif { #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/CubeMapTexture.cpp b/src/Magnum/CubeMapTexture.cpp new file mode 100644 index 000000000..f53d297d4 --- /dev/null +++ b/src/Magnum/CubeMapTexture.cpp @@ -0,0 +1,36 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014 + 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 "CubeMapTexture.h" + +#include "Implementation/maxTextureSize.h" + +namespace Magnum { + +Vector2i CubeMapTexture::maxSize() { + return Vector2i{Implementation::maxCubeMapTextureSideSize()}; +} + +} diff --git a/src/Magnum/CubeMapTexture.h b/src/Magnum/CubeMapTexture.h index 6aada4175..22cd4dd9c 100644 --- a/src/Magnum/CubeMapTexture.h +++ b/src/Magnum/CubeMapTexture.h @@ -76,9 +76,10 @@ which intersects one of the six sides of the cube map. See @ref AbstractShaderProgram for more information about usage in shaders. @see @ref Renderer::Feature::SeamlessCubeMapTexture, @ref CubeMapTextureArray, - @ref Texture, @ref BufferTexture + @ref Texture, @ref TextureArray, @ref RectangleTexture, @ref BufferTexture, + @ref MultisampleTexture */ -class CubeMapTexture: public AbstractTexture { +class MAGNUM_EXPORT CubeMapTexture: public AbstractTexture { public: /** @brief Cube map coordinate */ enum class Coordinate: GLenum { @@ -90,6 +91,15 @@ class CubeMapTexture: public AbstractTexture { NegativeZ = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z /**< -Z cube side */ }; + /** + * @brief Max supported size of one side of cube map texture + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. + * @see @fn_gl{Get} with @def_gl{MAX_CUBE_MAP_TEXTURE_SIZE} + */ + static Vector2i maxSize(); + /** * @brief Constructor * @@ -134,6 +144,28 @@ class CubeMapTexture: public AbstractTexture { return *this; } + #ifndef MAGNUM_TARGET_GLES2 + /** @copydoc Texture::setMinLod() */ + CubeMapTexture& setMinLod(Float lod) { + AbstractTexture::setMinLod(lod); + return *this; + } + + /** @copydoc Texture::setMaxLod() */ + CubeMapTexture& setMaxLod(Float lod) { + AbstractTexture::setMaxLod(lod); + return *this; + } + #endif + + #ifndef MAGNUM_TARGET_GLES + /** @copydoc Texture::setLodBias() */ + CubeMapTexture& setLodBias(Float bias) { + AbstractTexture::setLodBias(bias); + return *this; + } + #endif + /** @copydoc Texture::setWrapping() */ CubeMapTexture& setWrapping(const Array3D& wrapping) { DataHelper<3>::setWrapping(*this, wrapping); @@ -166,6 +198,48 @@ class CubeMapTexture: public AbstractTexture { return *this; } + #ifndef MAGNUM_TARGET_GLES2 + /** @copydoc Texture::setSwizzle() */ + template CubeMapTexture& setSwizzle() { + AbstractTexture::setSwizzle(); + return *this; + } + #endif + + /** + * @copybrief Texture::setCompareMode() + * @return Reference to self (for method chaining) + * + * See @ref Texture::setCompareMode() for more information. + * @requires_gles30 %Extension @es_extension{EXT,shadow_samplers} and + * @es_extension{NV,shadow_samplers_cube} + */ + CubeMapTexture& setCompareMode(Sampler::CompareMode mode) { + AbstractTexture::setCompareMode(mode); + return *this; + } + + /** + * @copybrief Texture::setCompareFunction() + * @return Reference to self (for method chaining) + * + * See @ref Texture::setCompareFunction() for more information. + * @requires_gles30 %Extension @es_extension{EXT,shadow_samplers} and + * @es_extension{NV,shadow_samplers_cube} + */ + CubeMapTexture& setCompareFunction(Sampler::CompareFunction function) { + AbstractTexture::setCompareFunction(function); + return *this; + } + + #ifndef MAGNUM_TARGET_GLES + /** @copydoc Texture::setDepthStencilMode() */ + CubeMapTexture& setDepthStencilMode(Sampler::DepthStencilMode mode) { + AbstractTexture::setDepthStencilMode(mode); + return *this; + } + #endif + #ifndef MAGNUM_TARGET_GLES /** * @brief %Image size in given mip level @@ -184,6 +258,7 @@ class CubeMapTexture: public AbstractTexture { * @brief Set storage * * See @ref Texture::setStorage() for more information. + * @see @ref maxSize() */ CubeMapTexture& setStorage(Int levels, TextureFormat internalFormat, const Vector2i& size) { DataHelper<2>::setStorage(*this, _target, levels, internalFormat, size); @@ -230,6 +305,7 @@ class CubeMapTexture: public AbstractTexture { * @return Reference to self (for method chaining) * * See @ref Texture::setImage() for more information. + * @see @ref maxSize() */ CubeMapTexture& setImage(Coordinate coordinate, Int level, TextureFormat internalFormat, const ImageReference2D& image) { DataHelper<2>::setImage(*this, GLenum(coordinate), level, internalFormat, image); diff --git a/src/Magnum/CubeMapTextureArray.cpp b/src/Magnum/CubeMapTextureArray.cpp new file mode 100644 index 000000000..6a0866716 --- /dev/null +++ b/src/Magnum/CubeMapTextureArray.cpp @@ -0,0 +1,45 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014 + 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 "CubeMapTextureArray.h" + +#ifndef MAGNUM_TARGET_GLES +#include "Magnum/Context.h" +#include "Magnum/Extensions.h" + +#include "Implementation/maxTextureSize.h" + +namespace Magnum { + +Vector3i CubeMapTextureArray::maxSize() { + if(!Context::current()->isExtensionSupported()) + return {}; + + return Vector3i{Vector2i{Implementation::maxCubeMapTextureSideSize()}, + Implementation::maxTextureArrayLayers()}; +} + +} +#endif diff --git a/src/Magnum/CubeMapTextureArray.h b/src/Magnum/CubeMapTextureArray.h index 01a61f686..6dedce2b7 100644 --- a/src/Magnum/CubeMapTextureArray.h +++ b/src/Magnum/CubeMapTextureArray.h @@ -33,7 +33,7 @@ #include "Magnum/AbstractTexture.h" #include "Magnum/Array.h" -#include "Magnum/Math/Vector2.h" +#include "Magnum/Math/Vector3.h" #ifndef MAGNUM_TARGET_GLES namespace Magnum { @@ -45,6 +45,8 @@ See @ref CubeMapTexture documentation for introduction. @section CubeMapTextureArray-usage Usage +See @ref Texture documentation for introduction. + Common usage is to specify each layer and face separately using @ref setSubImage(). You have to allocate the memory for all layers and faces first by calling @ref setStorage(). Example: array with 4 layers of cube maps, each cube map @@ -75,7 +77,8 @@ the six sides of the cube map, fourth part is layer in the array. See @ref AbstractShaderProgram for more information about usage in shaders. @see @ref Renderer::Feature::SeamlessCubeMapTexture, @ref CubeMapTexture, - @ref Texture, @ref BufferTexture + @ref Texture, @ref TextureArray, @ref RectangleTexture, @ref BufferTexture, + @ref MultisampleTexture @requires_gl40 %Extension @extension{ARB,texture_cube_map_array} @requires_gl Cube map texture arrays are not available in OpenGL ES. */ @@ -100,16 +103,21 @@ class CubeMapTextureArray: public AbstractTexture { #endif /** - * @brief Set base mip level + * @brief Max supported size of one side of cube map texture array + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If @extension{ARB,texture_cube_map_array} (part of + * OpenGL 4.0) is not available, returns zero vector. + * @see @fn_gl{Get} with @def_gl{MAX_CUBE_MAP_TEXTURE_SIZE} and + * @def_gl{MAX_ARRAY_TEXTURE_LAYERS} + */ + static Vector3i maxSize(); + + /** + * @copybrief Texture::setBaseLevel() * @return Reference to self (for method chaining) * - * Taken into account when generating mipmap using @ref generateMipmap() - * and when considering texture completeness when using mipmap - * filtering. Initial value is `0`. - * @see @ref setMaxLevel(), @ref setMinificationFilter(), - * @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexParameter} - * or @fn_gl_extension{TextureParameter,EXT,direct_state_access} - * with @def_gl{TEXTURE_BASE_LEVEL} + * See @ref Texture::setBaseLevel() for more information. */ CubeMapTextureArray& setBaseLevel(Int level) { AbstractTexture::setBaseLevel(level); @@ -117,17 +125,10 @@ class CubeMapTextureArray: public AbstractTexture { } /** - * @brief Set max mip level + * @copybrief Texture::setMaxLevel() * @return Reference to self (for method chaining) * - * Taken into account when generating mipmap using @ref generateMipmap() - * and when considering texture completeness when using mipmap - * filtering. Initial value is `1000`, which is clamped to count of - * levels specified when using @ref setStorage(). - * @see @ref setBaseLevel(), @ref setMinificationFilter(), - * @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexParameter} - * or @fn_gl_extension{TextureParameter,EXT,direct_state_access} - * with @def_gl{TEXTURE_MAX_LEVEL} + * See @ref Texture::setMaxLevel() for more information. */ CubeMapTextureArray& setMaxLevel(Int level) { AbstractTexture::setMaxLevel(level); @@ -146,25 +147,76 @@ class CubeMapTextureArray: public AbstractTexture { return *this; } + /** + * @copybrief Texture::setMinLod() + * @return Reference to self (for method chaining) + * + * See @ref Texture::setMinLod() for more information. + */ + CubeMapTextureArray& setMinLod(Float lod) { + AbstractTexture::setMinLod(lod); + return *this; + } + + /** + * @copybrief Texture::setMaxLod() + * @return Reference to self (for method chaining) + * + * See @ref Texture::setMaxLod() for more information. + */ + CubeMapTextureArray& setMaxLod(Float lod) { + AbstractTexture::setMaxLod(lod); + return *this; + } + + /** + * @copybrief Texture::setLodBias() + * @return Reference to self (for method chaining) + * + * See @ref Texture::setLodBias() for more information. + */ + CubeMapTextureArray& setLodBias(Float bias) { + AbstractTexture::setLodBias(bias); + return *this; + } + /** @copydoc Texture::setWrapping() */ CubeMapTextureArray& setWrapping(const Array3D& wrapping) { DataHelper<3>::setWrapping(*this, wrapping); return *this; } - /** @copydoc RectangleTexture::setBorderColor(const Color4&) */ + /** + * @copybrief Texture::setBorderColor(const Color4&) + * @return Reference to self (for method chaining) + * + * See @ref Texture::setBorderColor(const Color4&) for more + * information. + */ CubeMapTextureArray& setBorderColor(const Color4& color) { AbstractTexture::setBorderColor(color); return *this; } - /** @copydoc RectangleTexture::setBorderColor(const Vector4ui&) */ + /** + * @copybrief Texture::setBorderColor(const Vector4ui&) + * @return Reference to self (for method chaining) + * + * See @ref Texture::setBorderColor(const Vector4ui&) for more + * information. + */ CubeMapTextureArray& setBorderColor(const Vector4ui& color) { AbstractTexture::setBorderColor(color); return *this; } - /** @copydoc RectangleTexture::setBorderColor(const Vector4i&) */ + /** + * @copybrief Texture::setBorderColor(const Vector4ui&) + * @return Reference to self (for method chaining) + * + * See @ref Texture::setBorderColor(const Vector4i&) for more + * information. + */ CubeMapTextureArray& setBorderColor(const Vector4i& color) { AbstractTexture::setBorderColor(color); return *this; @@ -176,6 +228,50 @@ class CubeMapTextureArray: public AbstractTexture { return *this; } + /** + * @copybrief Texture::setSwizzle() + * @return Reference to self (for method chaining) + * + * See @ref Texture::setSwizzle() for more information. + */ + template CubeMapTextureArray& setSwizzle() { + AbstractTexture::setSwizzle(); + return *this; + } + + /** + * @copybrief Texture::setCompareMode() + * @return Reference to self (for method chaining) + * + * See @ref Texture::setCompareMode() for more information. + */ + CubeMapTextureArray& setCompareMode(Sampler::CompareMode mode) { + AbstractTexture::setCompareMode(mode); + return *this; + } + + /** + * @copybrief Texture::setCompareFunction() + * @return Reference to self (for method chaining) + * + * See @ref Texture::setCompareFunction() for more information. + */ + CubeMapTextureArray& setCompareFunction(Sampler::CompareFunction function) { + AbstractTexture::setCompareFunction(function); + return *this; + } + + /** + * @copybrief Texture::setDepthStencilMode() + * @return Reference to self (for method chaining) + * + * See @ref Texture::setDepthStencilMode() for more information. + */ + CubeMapTextureArray& setDepthStencilMode(Sampler::DepthStencilMode mode) { + AbstractTexture::setDepthStencilMode(mode); + return *this; + } + /** * @brief %Image size in given mip level * @param level Mip level @@ -191,6 +287,7 @@ class CubeMapTextureArray: public AbstractTexture { * * Z coordinate of @p size must be multiple of 6. See * @ref Texture::setStorage() for more information. + * @see @ref maxSize() */ CubeMapTextureArray& setStorage(Int levels, TextureFormat internalFormat, const Vector3i& size) { DataHelper<3>::setStorage(*this, _target, levels, internalFormat, size); @@ -235,6 +332,7 @@ class CubeMapTextureArray: public AbstractTexture { * images are in order of (+X, -X, +Y, -Y, +Z, -Z). * * See @ref Texture::setImage() for more information. + * @see @ref maxSize() */ CubeMapTextureArray& setImage(Int level, TextureFormat internalFormat, const ImageReference3D& image) { DataHelper<3>::setImage(*this, GL_TEXTURE_CUBE_MAP_ARRAY, level, internalFormat, image); diff --git a/src/Magnum/DebugTools/ForceRenderer.cpp b/src/Magnum/DebugTools/ForceRenderer.cpp index e763955a7..dd785c12f 100644 --- a/src/Magnum/DebugTools/ForceRenderer.cpp +++ b/src/Magnum/DebugTools/ForceRenderer.cpp @@ -88,7 +88,7 @@ template ForceRenderer::ForceRenderer(SceneG Mesh* mesh = new Mesh; mesh->setPrimitive(MeshPrimitive::Lines) - .setIndexCount(indices.size()) + .setCount(indices.size()) .addVertexBuffer(*vertexBuffer, 0, typename Shaders::Flat::Position(Shaders::Flat::Position::Components::Two)) .setIndexBuffer(*indexBuffer, 0, Mesh::IndexType::UnsignedByte, 0, positions.size()); diff --git a/src/Magnum/DebugTools/Implementation/AbstractShapeRenderer.cpp b/src/Magnum/DebugTools/Implementation/AbstractShapeRenderer.cpp index 1927770e8..0258e6609 100644 --- a/src/Magnum/DebugTools/Implementation/AbstractShapeRenderer.cpp +++ b/src/Magnum/DebugTools/Implementation/AbstractShapeRenderer.cpp @@ -53,17 +53,27 @@ template<> void create<2>(Trade::MeshData2D& data, Resource& meshResource, /* Mesh configuration */ Mesh* mesh = new Mesh; mesh->setPrimitive(data.primitive()) - .setVertexCount(data.positions(0).size()) .addVertexBuffer(*buffer, 0, Shaders::Flat2D::Position()); ResourceManager::instance().set(meshResource.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual); /* Index buffer, if needed, if not, resource key doesn't have to be set */ if(data.isIndexed()) { CORRADE_INTERNAL_ASSERT(indexBufferResource.key() != ResourceKey()); + + Containers::Array indexData; + Mesh::IndexType indexType; + UnsignedInt indexStart, indexEnd; + std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(data.indices()); + Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray); - MeshTools::compressIndices(*mesh, *indexBuffer, BufferUsage::StaticDraw, data.indices()); + indexBuffer->setData(indexData, BufferUsage::StaticDraw); + mesh->setCount(data.indices().size()) + .setIndexBuffer(*indexBuffer, 0, indexType, indexStart, indexEnd); + ResourceManager::instance().set(indexBufferResource.key(), indexBuffer, ResourceDataState::Final, ResourcePolicy::Manual); - } + + /* The mesh is not indexed, set proper vertex count */ + } else mesh->setCount(data.positions(0).size()); } template<> void create<3>(Trade::MeshData3D& data, Resource& meshResource, Resource& vertexBufferResource, Resource& indexBufferResource) { @@ -75,17 +85,27 @@ template<> void create<3>(Trade::MeshData3D& data, Resource& meshResource, /* Mesh configuration */ Mesh* mesh = new Mesh; mesh->setPrimitive(data.primitive()) - .setVertexCount(data.positions(0).size()) .addVertexBuffer(*vertexBuffer, 0, Shaders::Flat3D::Position()); ResourceManager::instance().set(meshResource.key(), mesh, ResourceDataState::Final, ResourcePolicy::Manual); /* Index buffer, if needed, if not, resource key doesn't have to be set */ if(data.isIndexed()) { CORRADE_INTERNAL_ASSERT(indexBufferResource.key() != ResourceKey()); + + Containers::Array indexData; + Mesh::IndexType indexType; + UnsignedInt indexStart, indexEnd; + std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(data.indices()); + Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray); - MeshTools::compressIndices(*mesh, *indexBuffer, BufferUsage::StaticDraw, data.indices()); + indexBuffer->setData(indexData, BufferUsage::StaticDraw); + mesh->setCount(data.indices().size()) + .setIndexBuffer(*indexBuffer, 0, indexType, indexStart, indexEnd); + ResourceManager::instance().set(indexBufferResource.key(), indexBuffer, ResourceDataState::Final, ResourcePolicy::Manual); - } + + /* The mesh is not indexed, set proper vertex count */ + } else mesh->setCount(data.positions(0).size()); } } diff --git a/src/Magnum/DebugTools/Implementation/CapsuleRenderer.cpp b/src/Magnum/DebugTools/Implementation/CapsuleRenderer.cpp index 2c46cd430..5c359e593 100644 --- a/src/Magnum/DebugTools/Implementation/CapsuleRenderer.cpp +++ b/src/Magnum/DebugTools/Implementation/CapsuleRenderer.cpp @@ -46,21 +46,24 @@ AbstractCapsuleRenderer<2>::AbstractCapsuleRenderer(): AbstractShapeRenderer<2>( /* Bottom hemisphere */ if(!(bottom = ResourceManager::instance().get("capsule2d-bottom"))) { auto view = new MeshView(*wireframeMesh); - view->setIndexRange(0, rings*4, 0, rings*2+1); + view->setCount(rings*4) + .setIndexRange(0, 0, rings*2+1); ResourceManager::instance().set(bottom.key(), view, ResourceDataState::Final, ResourcePolicy::Manual); } /* Cylinder */ if(!(cylinder = ResourceManager::instance().get("capsule2d-cylinder"))) { auto view = new MeshView(*wireframeMesh); - view->setIndexRange(rings*4, 4, rings*2+1, rings*2+3); + view->setCount(4) + .setIndexRange(rings*4, rings*2+1, rings*2+3); ResourceManager::instance().set(cylinder.key(), view, ResourceDataState::Final, ResourcePolicy::Manual); } /* Top hemisphere */ if(!(top = ResourceManager::instance().get("capsule2d-top"))) { auto view = new MeshView(*wireframeMesh); - view->setIndexRange(rings*4+4, rings*4, rings*2+3, rings*4+4); + view->setCount(rings*4) + .setIndexRange(rings*4+4, rings*2+3, rings*4+4); ResourceManager::instance().set(top.key(), view, ResourceDataState::Final, ResourcePolicy::Manual); } } @@ -73,21 +76,24 @@ AbstractCapsuleRenderer<3>::AbstractCapsuleRenderer(): AbstractShapeRenderer<3>( /* Bottom hemisphere */ if(!(bottom = ResourceManager::instance().get("capsule3d-bottom"))) { auto view = new MeshView(*wireframeMesh); - view->setIndexRange(0, rings*8, 0, rings*4+1); + view->setCount(rings*8) + .setIndexRange(0, 0, rings*4+1); ResourceManager::instance().set(bottom.key(), view, ResourceDataState::Final, ResourcePolicy::Manual); } /* Cylinder */ if(!(cylinder = ResourceManager::instance().get("capsule3d-cylinder"))) { auto view = new MeshView(*wireframeMesh); - view->setIndexRange(rings*8, segments*4+8, rings*4+1, rings*4+segments*2+5); + view->setCount(segments*4+8) + .setIndexRange(rings*8, rings*4+1, rings*4+segments*2+5); ResourceManager::instance().set(cylinder.key(), view, ResourceDataState::Final, ResourcePolicy::Manual); } /* Top */ if(!(top = ResourceManager::instance().get("capsule3d-top"))) { auto view = new MeshView(*wireframeMesh); - view->setIndexRange(rings*8+segments*4+8, rings*8, rings*4+segments*2+5, rings*8+segments*2+6); + view->setCount(rings*8) + .setIndexRange(rings*8+segments*4+8, rings*4+segments*2+5, rings*8+segments*2+6); ResourceManager::instance().set(top.key(), view, ResourceDataState::Final, ResourcePolicy::Manual); } } diff --git a/src/Magnum/DebugTools/ObjectRenderer.cpp b/src/Magnum/DebugTools/ObjectRenderer.cpp index 669f8806a..ee3da5fce 100644 --- a/src/Magnum/DebugTools/ObjectRenderer.cpp +++ b/src/Magnum/DebugTools/ObjectRenderer.cpp @@ -26,6 +26,7 @@ #include "ObjectRenderer.h" #include "Magnum/Buffer.h" +#include "Magnum/Mesh.h" #include "Magnum/DebugTools/ResourceManager.h" #include "Magnum/MeshTools/Interleave.h" #include "Magnum/SceneGraph/AbstractCamera.h" @@ -159,14 +160,14 @@ template ObjectRenderer::ObjectRenderer(Scen Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray); Mesh* mesh = new Mesh; - MeshTools::interleave(*mesh, *vertexBuffer, BufferUsage::StaticDraw, Renderer::positions, Renderer::colors); + vertexBuffer->setData(MeshTools::interleave(Renderer::positions, Renderer::colors), BufferUsage::StaticDraw); ResourceManager::instance().set(this->vertexBuffer.key(), vertexBuffer, ResourceDataState::Final, ResourcePolicy::Manual); indexBuffer->setData(Renderer::indices, BufferUsage::StaticDraw); ResourceManager::instance().set(this->indexBuffer.key(), indexBuffer, ResourceDataState::Final, ResourcePolicy::Manual); mesh->setPrimitive(MeshPrimitive::Lines) - .setIndexCount(Renderer::indices.size()) + .setCount(Renderer::indices.size()) .addVertexBuffer(*vertexBuffer, 0, typename Shaders::VertexColor::Position(), typename Shaders::VertexColor::Color()) diff --git a/src/Magnum/DebugTools/Profiler.h b/src/Magnum/DebugTools/Profiler.h index b40a57eda..cf3f66560 100644 --- a/src/Magnum/DebugTools/Profiler.h +++ b/src/Magnum/DebugTools/Profiler.h @@ -44,7 +44,7 @@ namespace Magnum { namespace DebugTools { @brief %Profiler Measures time passed during specified sections of each frame. It's meant to be -used in rendering and event loops (e.g. Platform::GlutApplication::drawEvent()), +used in rendering and event loops (e.g. Platform::Sdl2Application::drawEvent()), but it's possible to use it standalone elsewhere. Example usage: @code DebugTools::Profiler p; diff --git a/src/Magnum/DefaultFramebuffer.h b/src/Magnum/DefaultFramebuffer.h index 347d3e3dd..b28353fea 100644 --- a/src/Magnum/DefaultFramebuffer.h +++ b/src/Magnum/DefaultFramebuffer.h @@ -45,7 +45,7 @@ surface. When you are using only the default framebuffer, the usage is simple. You must ensure that it is properly resized when application surface is resized, -i.e. you must pass the new size in your @ref Platform::GlutApplication::viewportEvent() "viewportEvent()" +i.e. you must pass the new size in your @ref Platform::Sdl2Application::viewportEvent() "viewportEvent()" implementation, for example: @code void viewportEvent(const Vector2i& size) { @@ -56,7 +56,7 @@ void viewportEvent(const Vector2i& size) { @endcode Next thing you probably want is to clear all used buffers before performing -any drawing in your @ref Platform::GlutApplication::drawEvent() "drawEvent()" +any drawing in your @ref Platform::Sdl2Application::drawEvent() "drawEvent()" implementation, for example: @code void drawEvent() { diff --git a/src/Magnum/Extensions.h b/src/Magnum/Extensions.h index e2f07f16d..dc4dc0cab 100644 --- a/src/Magnum/Extensions.h +++ b/src/Magnum/Extensions.h @@ -205,6 +205,7 @@ namespace GL { #ifdef MAGNUM_TARGET_GLES2 _extension(GL,ANGLE,framebuffer_blit, GLES200, GLES300) // #83 _extension(GL,ANGLE,framebuffer_multisample, GLES200, GLES300) // #84 + _extension(GL,ANGLE,instanced_arrays, GLES200, GLES300) // #109 _extension(GL,ANGLE,depth_texture, GLES200, GLES300) // #138 #endif } namespace APPLE { @@ -232,6 +233,9 @@ namespace GL { _extension(GL,EXT,blend_minmax, GLES200, GLES300) // #65 #endif _extension(GL,EXT,read_format_bgra, GLES200, None) // #66 + #ifdef MAGNUM_TARGET_GLES2 + _extension(GL,EXT,shader_texture_lod, GLES200, GLES300) // #77 + #endif _extension(GL,EXT,debug_label, GLES200, None) // #98 _extension(GL,EXT,debug_marker, GLES200, None) // #99 #ifdef MAGNUM_TARGET_GLES2 @@ -239,6 +243,7 @@ namespace GL { #endif _extension(GL,EXT,separate_shader_objects, GLES200, None) // #101 #ifdef MAGNUM_TARGET_GLES2 + _extension(GL,EXT,shadow_samplers, GLES200, GLES300) // #102 _extension(GL,EXT,texture_rg, GLES200, GLES300) // #103 #endif _extension(GL,EXT,sRGB, GLES200, None) // #105 @@ -249,6 +254,10 @@ namespace GL { _extension(GL,EXT,map_buffer_range, GLES200, GLES300) // #121 #endif _extension(GL,EXT,disjoint_timer_query, GLES200, None) // #150 + #ifdef MAGNUM_TARGET_GLES2 + _extension(GL,EXT,instanced_arrays, GLES200, GLES300) // #156 + _extension(GL,EXT,draw_instanced, GLES200, GLES300) // #157 + #endif #ifndef MAGNUM_TARGET_GLES2 _extension(GL,EXT,shader_integer_mix, GLES300, None) // #161 #endif @@ -265,8 +274,12 @@ namespace GL { _extension(GL,NV,read_stencil, GLES200, None) // #94 _extension(GL,NV,read_depth_stencil, GLES200, None) // #94 #ifdef MAGNUM_TARGET_GLES2 + _extension(GL,NV,draw_instanced, GLES200, GLES300) // #141 _extension(GL,NV,framebuffer_blit, GLES200, GLES300) // #142 _extension(GL,NV,framebuffer_multisample, GLES200, GLES300) // #143 + _extension(GL,NV,instanced_arrays, GLES200, GLES300) // #145 + _extension(GL,NV,shadow_samplers_array, GLES200, GLES300) // #146 + _extension(GL,NV,shadow_samplers_cube, GLES200, GLES300) // #147 #endif _extension(GL,NV,texture_border_clamp, GLES200, None) // #149 } namespace OES { diff --git a/src/Magnum/Implementation/MeshState.cpp b/src/Magnum/Implementation/MeshState.cpp index 3c9ac875a..66d56fb57 100644 --- a/src/Magnum/Implementation/MeshState.cpp +++ b/src/Magnum/Implementation/MeshState.cpp @@ -92,6 +92,50 @@ MeshState::MeshState(Context& context, std::vector& extensions): cu unbindImplementation = &Mesh::unbindImplementationDefault; } #endif + + #ifdef MAGNUM_TARGET_GLES2 + /* Instanced draw ímplementation on ES2 */ + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::ANGLE::instanced_arrays::string()); + + drawArraysInstancedImplementation = &Mesh::drawArraysInstancedImplementationANGLE; + drawElementsInstancedImplementation = &Mesh::drawElementsInstancedImplementationANGLE; + + } else if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::EXT::draw_instanced::string()); + + drawArraysInstancedImplementation = &Mesh::drawArraysInstancedImplementationEXT; + drawElementsInstancedImplementation = &Mesh::drawElementsInstancedImplementationEXT; + + } else if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::NV::draw_instanced::string()); + + drawArraysInstancedImplementation = &Mesh::drawArraysInstancedImplementationNV; + drawElementsInstancedImplementation = &Mesh::drawElementsInstancedImplementationNV; + + } else { + drawArraysInstancedImplementation = nullptr; + drawElementsInstancedImplementation = nullptr; + } + + /* Instanced arrays implementation on ES2 */ + if(context.isExtensionSupported()) { + /* Extension added above */ + + vertexAttribDivisorImplementation = &Mesh::vertexAttribDivisorImplementationANGLE; + + } else if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::EXT::instanced_arrays::string()); + + vertexAttribDivisorImplementation = &Mesh::vertexAttribDivisorImplementationEXT; + + } else if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::NV::instanced_arrays::string()); + + vertexAttribDivisorImplementation = &Mesh::vertexAttribDivisorImplementationNV; + + } else vertexAttribDivisorImplementation = nullptr; + #endif } }} diff --git a/src/Magnum/Implementation/MeshState.h b/src/Magnum/Implementation/MeshState.h index ea4885b4f..2c39037fc 100644 --- a/src/Magnum/Implementation/MeshState.h +++ b/src/Magnum/Implementation/MeshState.h @@ -44,10 +44,18 @@ struct MeshState { void(Mesh::*attributeLPointerImplementation)(const Mesh::LongAttribute&); #endif #endif + #ifdef MAGNUM_TARGET_GLES2 + void(Mesh::*vertexAttribDivisorImplementation)(GLuint, GLuint); + #endif void(Mesh::*bindIndexBufferImplementation)(Buffer&); void(Mesh::*bindImplementation)(); void(Mesh::*unbindImplementation)(); + #ifdef MAGNUM_TARGET_GLES2 + void(Mesh::*drawArraysInstancedImplementation)(GLint, GLsizei, GLsizei); + void(Mesh::*drawElementsInstancedImplementation)(GLsizei, GLintptr, GLsizei); + #endif + GLuint currentVAO; #ifndef MAGNUM_TARGET_GLES2 GLint maxElementsIndices, maxElementsVertices; diff --git a/src/Magnum/Implementation/TextureState.cpp b/src/Magnum/Implementation/TextureState.cpp index 60d362f43..0e5c5e23b 100644 --- a/src/Magnum/Implementation/TextureState.cpp +++ b/src/Magnum/Implementation/TextureState.cpp @@ -36,7 +36,18 @@ namespace Magnum { namespace Implementation { -TextureState::TextureState(Context& context, std::vector& extensions): maxTextureUnits(0), maxMaxAnisotropy(0.0f), currentTextureUnit(0) +TextureState::TextureState(Context& context, std::vector& extensions): maxSize{}, max3DSize{}, maxCubeMapSize{}, + #ifndef MAGNUM_TARGET_GLES2 + maxArrayLayers{}, + #endif + #ifndef MAGNUM_TARGET_GLES + maxRectangleSize{}, maxBufferSize{}, + #endif + maxTextureUnits(0), + #ifndef MAGNUM_TARGET_GLES2 + maxLodBias{0.0f}, + #endif + maxMaxAnisotropy(0.0f), currentTextureUnit(0) #ifndef MAGNUM_TARGET_GLES , maxColorSamples(0), maxDepthSamples(0), maxIntegerSamples(0), bufferOffsetAlignment(0) #endif @@ -72,9 +83,10 @@ TextureState::TextureState(Context& context, std::vector& extension parameteriImplementation = &AbstractTexture::parameterImplementationDSA; parameterfImplementation = &AbstractTexture::parameterImplementationDSA; + parameterivImplementation = &AbstractTexture::parameterImplementationDSA; parameterfvImplementation = &AbstractTexture::parameterImplementationDSA; - parameterIuivImplementation = &AbstractTexture::parameterImplementationDSA; - parameterIivImplementation = &AbstractTexture::parameterImplementationDSA; + parameterIuivImplementation = &AbstractTexture::parameterIImplementationDSA; + parameterIivImplementation = &AbstractTexture::parameterIImplementationDSA; getLevelParameterivImplementation = &AbstractTexture::getLevelParameterImplementationDSA; mipmapImplementation = &AbstractTexture::mipmapImplementationDSA; getImageImplementation = &AbstractTexture::getImageImplementationDSA; @@ -92,10 +104,13 @@ TextureState::TextureState(Context& context, std::vector& extension { parameteriImplementation = &AbstractTexture::parameterImplementationDefault; parameterfImplementation = &AbstractTexture::parameterImplementationDefault; + #ifndef MAGNUM_TARGET_GLES2 + parameterivImplementation = &AbstractTexture::parameterImplementationDefault; + #endif parameterfvImplementation = &AbstractTexture::parameterImplementationDefault; #ifndef MAGNUM_TARGET_GLES - parameterIuivImplementation = &AbstractTexture::parameterImplementationDefault; - parameterIivImplementation = &AbstractTexture::parameterImplementationDefault; + parameterIuivImplementation = &AbstractTexture::parameterIImplementationDefault; + parameterIivImplementation = &AbstractTexture::parameterIImplementationDefault; getLevelParameterivImplementation = &AbstractTexture::getLevelParameterImplementationDefault; #endif mipmapImplementation = &AbstractTexture::mipmapImplementationDefault; diff --git a/src/Magnum/Implementation/TextureState.h b/src/Magnum/Implementation/TextureState.h index 160769c43..f13e27b6c 100644 --- a/src/Magnum/Implementation/TextureState.h +++ b/src/Magnum/Implementation/TextureState.h @@ -60,11 +60,18 @@ struct TextureState { void(AbstractTexture::*bindImplementation)(GLint); void(AbstractTexture::*parameteriImplementation)(GLenum, GLint); void(AbstractTexture::*parameterfImplementation)(GLenum, GLfloat); + #ifndef MAGNUM_TARGET_GLES2 + void(AbstractTexture::*parameterivImplementation)(GLenum, const GLint*); + #endif void(AbstractTexture::*parameterfvImplementation)(GLenum, const GLfloat*); + #ifndef MAGNUM_TARGET_GLES void(AbstractTexture::*parameterIuivImplementation)(GLenum, const GLuint*); void(AbstractTexture::*parameterIivImplementation)(GLenum, const GLint*); + #endif void(AbstractTexture::*setMaxAnisotropyImplementation)(GLfloat); + #ifndef MAGNUM_TARGET_GLES void(AbstractTexture::*getLevelParameterivImplementation)(GLenum, GLint, GLenum, GLint*); + #endif void(AbstractTexture::*mipmapImplementation)(); #ifndef MAGNUM_TARGET_GLES void(AbstractTexture::*storage1DImplementation)(GLenum, GLsizei, TextureFormat, const Math::Vector<1, GLsizei>&); @@ -92,7 +99,20 @@ struct TextureState { void(BufferTexture::*setBufferRangeImplementation)(BufferTextureFormat, Buffer&, GLintptr, GLsizeiptr); #endif + GLint maxSize, + max3DSize, + maxCubeMapSize; + #ifndef MAGNUM_TARGET_GLES2 + GLint maxArrayLayers; + #endif + #ifndef MAGNUM_TARGET_GLES + GLint maxRectangleSize, + maxBufferSize; + #endif GLint maxTextureUnits; + #ifndef MAGNUM_TARGET_GLES2 + GLfloat maxLodBias; + #endif GLfloat maxMaxAnisotropy; GLint currentTextureUnit; #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/Implementation/maxTextureSize.cpp b/src/Magnum/Implementation/maxTextureSize.cpp new file mode 100644 index 000000000..e43b78c70 --- /dev/null +++ b/src/Magnum/Implementation/maxTextureSize.cpp @@ -0,0 +1,77 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014 + 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 "maxTextureSize.h" + +#include "Magnum/Context.h" + +#include "State.h" +#include "TextureState.h" + +namespace Magnum { namespace Implementation { + +GLint maxTextureSideSize() { + GLint& value = Context::current()->state().texture->maxSize; + + if(value == 0) + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); + + return value; +} + +GLint max3DTextureDepth() { + GLint& value = Context::current()->state().texture->max3DSize; + + if(value == 0) + #ifndef MAGNUM_TARGET_GLES2 + glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &value); + #else + glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE_OES, &value); + #endif + + return value; +} + +#ifndef MAGNUM_TARGET_GLES2 +GLint maxTextureArrayLayers() { + GLint& value = Context::current()->state().texture->maxArrayLayers; + + if(value == 0) + glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &value); + + return value; +} +#endif + +GLint maxCubeMapTextureSideSize() { + GLint& value = Context::current()->state().texture->maxCubeMapSize; + + if(value == 0) + glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &value); + + return value; +} + +}} diff --git a/src/Magnum/Implementation/maxTextureSize.h b/src/Magnum/Implementation/maxTextureSize.h new file mode 100644 index 000000000..b269c1463 --- /dev/null +++ b/src/Magnum/Implementation/maxTextureSize.h @@ -0,0 +1,39 @@ +#ifndef Magnum_Implementation_maxTextureSize_h +#define Magnum_Implementation_maxTextureSize_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Magnum/OpenGL.h" + +namespace Magnum { namespace Implementation { + +GLint maxTextureSideSize(); +GLint max3DTextureDepth(); +GLint maxTextureArrayLayers(); +GLint maxCubeMapTextureSideSize(); + +}} + +#endif diff --git a/src/Magnum/Implementation/setupDriverWorkarounds.cpp b/src/Magnum/Implementation/setupDriverWorkarounds.cpp index 7d5d7f8be..e909bf48f 100644 --- a/src/Magnum/Implementation/setupDriverWorkarounds.cpp +++ b/src/Magnum/Implementation/setupDriverWorkarounds.cpp @@ -68,6 +68,7 @@ void Context::setupDriverWorkarounds() { #ifdef MAGNUM_TARGET_GLES2 _setRequiredVersion(GL::ANGLE::framebuffer_blit, None); _setRequiredVersion(GL::ANGLE::framebuffer_multisample, None); + _setRequiredVersion(GL::ANGLE::instanced_arrays, None); _setRequiredVersion(GL::APPLE::framebuffer_multisample, None); _setRequiredVersion(GL::EXT::discard_framebuffer, None); _setRequiredVersion(GL::EXT::blend_minmax, None); @@ -76,11 +77,15 @@ void Context::setupDriverWorkarounds() { #endif _setRequiredVersion(GL::EXT::texture_storage, None); _setRequiredVersion(GL::EXT::map_buffer_range, None); + _setRequiredVersion(GL::EXT::instanced_arrays, None); + _setRequiredVersion(GL::EXT::draw_instanced, None); _setRequiredVersion(GL::NV::draw_buffers, None); _setRequiredVersion(GL::NV::fbo_color_attachments, None); // ?? _setRequiredVersion(GL::NV::read_buffer, None); + _setRequiredVersion(GL::NV::draw_instanced, None); _setRequiredVersion(GL::NV::framebuffer_blit, None); _setRequiredVersion(GL::NV::framebuffer_multisample, None); + _setRequiredVersion(GL::NV::instanced_arrays, None); _setRequiredVersion(GL::OES::texture_3D, None); _setRequiredVersion(GL::OES::vertex_array_object, None); #endif diff --git a/src/Magnum/Mesh.cpp b/src/Magnum/Mesh.cpp index 131a33942..f2937bdc0 100644 --- a/src/Magnum/Mesh.cpp +++ b/src/Magnum/Mesh.cpp @@ -72,11 +72,14 @@ std::size_t Mesh::indexSize(IndexType type) { CORRADE_ASSERT_UNREACHABLE(); } -Mesh::Mesh(MeshPrimitive primitive): _primitive(primitive), _vertexCount(0), _indexCount(0) +Mesh::Mesh(MeshPrimitive primitive): _primitive(primitive), _count(0), _baseVertex(0), _instanceCount{1}, + #ifndef MAGNUM_TARGET_GLES + _baseInstance{0}, + #endif #ifndef MAGNUM_TARGET_GLES2 - , _indexStart(0), _indexEnd(0) + _indexStart(0), _indexEnd(0), #endif - , _indexOffset(0), _indexType(IndexType::UnsignedInt), _indexBuffer(nullptr) + _indexOffset(0), _indexType(IndexType::UnsignedInt), _indexBuffer(nullptr) { (this->*Context::current()->state().mesh->createImplementation)(); } @@ -92,11 +95,14 @@ Mesh::~Mesh() { (this->*Context::current()->state().mesh->destroyImplementation)(); } -Mesh::Mesh(Mesh&& other) noexcept: _id(other._id), _primitive(other._primitive), _vertexCount(other._vertexCount), _indexCount(other._indexCount) +Mesh::Mesh(Mesh&& other) noexcept: _id(other._id), _primitive(other._primitive), _count(other._count), _baseVertex{other._baseVertex}, _instanceCount{other._instanceCount}, + #ifndef MAGNUM_TARGET_GLES + _baseInstance{other._baseInstance}, + #endif #ifndef MAGNUM_TARGET_GLES2 - , _indexStart(other._indexStart), _indexEnd(other._indexEnd) + _indexStart(other._indexStart), _indexEnd(other._indexEnd), #endif - , _indexOffset(other._indexOffset), _indexType(other._indexType), _indexBuffer(other._indexBuffer), _attributes(std::move(other._attributes)) + _indexOffset(other._indexOffset), _indexType(other._indexType), _indexBuffer(other._indexBuffer), _attributes(std::move(other._attributes)) #ifndef MAGNUM_TARGET_GLES2 , _integerAttributes(std::move(other._integerAttributes)) #ifndef MAGNUM_TARGET_GLES @@ -110,8 +116,12 @@ Mesh::Mesh(Mesh&& other) noexcept: _id(other._id), _primitive(other._primitive), Mesh& Mesh::operator=(Mesh&& other) noexcept { std::swap(_id, other._id); std::swap(_primitive, other._primitive); - std::swap(_vertexCount, other._vertexCount); - std::swap(_indexCount, other._indexCount); + std::swap(_count, other._count); + std::swap(_baseVertex, other._baseVertex); + std::swap(_instanceCount, other._instanceCount); + #ifndef MAGNUM_TARGET_GLES + std::swap(_baseInstance, other._baseInstance); + #endif #ifndef MAGNUM_TARGET_GLES2 std::swap(_indexStart, other._indexStart); std::swap(_indexEnd, other._indexEnd); @@ -153,6 +163,7 @@ Mesh& Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, IndexType type, Unsi "Mesh::setIndexBuffer(): the buffer has unexpected target hint, expected" << Buffer::Target::ElementArray << "but got" << buffer.targetHint(), *this); #endif + _indexBuffer = &buffer; _indexOffset = offset; _indexType = type; #ifndef MAGNUM_TARGET_GLES2 @@ -166,32 +177,111 @@ Mesh& Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, IndexType type, Unsi return *this; } -#ifndef MAGNUM_TARGET_GLES2 -void Mesh::drawInternal(Int firstVertex, Int vertexCount, GLintptr indexOffset, Int indexCount, Int indexStart, Int indexEnd) +#ifndef MAGNUM_TARGET_GLES +void Mesh::drawInternal(Int count, Int baseVertex, Int instanceCount, UnsignedInt baseInstance, GLintptr indexOffset, Int indexStart, Int indexEnd) +#elif !defined(MAGNUM_TARGET_GLES2) +void Mesh::drawInternal(Int count, Int baseVertex, Int instanceCount, GLintptr indexOffset, Int indexStart, Int indexEnd) #else -void Mesh::drawInternal(Int firstVertex, Int vertexCount, GLintptr indexOffset, Int indexCount) +void Mesh::drawInternal(Int count, Int baseVertex, Int instanceCount, GLintptr indexOffset) #endif { - /* Nothing to draw */ - if(!vertexCount && !indexCount) return; - (this->*Context::current()->state().mesh->bindImplementation)(); + const Implementation::MeshState& state = *Context::current()->state().mesh; - /* Non-indexed mesh */ - if(!indexCount) - glDrawArrays(GLenum(_primitive), firstVertex, vertexCount); - - #ifndef MAGNUM_TARGET_GLES2 - /* Indexed mesh with specified range */ - else if(indexEnd) - glDrawRangeElements(GLenum(_primitive), indexStart, indexEnd, indexCount, GLenum(_indexType), reinterpret_cast(indexOffset)); - #endif - - /* Indexed mesh without specified range */ - else - glDrawElements(GLenum(_primitive), indexCount, GLenum(_indexType), reinterpret_cast(indexOffset)); + /* Nothing to draw */ + if(!count || !instanceCount) return; + + (this->*state.bindImplementation)(); + + /* Non-instanced mesh */ + if(instanceCount == 1) { + /* Non-indexed mesh */ + if(!_indexBuffer) { + glDrawArrays(GLenum(_primitive), baseVertex, count); + + /* Indexed mesh with base vertex */ + } else if(baseVertex) { + #ifndef MAGNUM_TARGET_GLES + /* Indexed mesh with specified range */ + if(indexEnd) { + glDrawRangeElementsBaseVertex(GLenum(_primitive), indexStart, indexEnd, count, GLenum(_indexType), reinterpret_cast(indexOffset), baseVertex); + + /* Indexed mesh */ + } else glDrawElementsBaseVertex(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast(indexOffset), baseVertex); + #else + CORRADE_ASSERT(false, "Mesh::draw(): desktop OpenGL is required for base vertex specification in indexed meshes", ); + #endif + + /* Indexed mesh */ + } else { + #ifndef MAGNUM_TARGET_GLES2 + /* Indexed mesh with specified range */ + if(indexEnd) { + glDrawRangeElements(GLenum(_primitive), indexStart, indexEnd, count, GLenum(_indexType), reinterpret_cast(indexOffset)); + + /* Indexed mesh */ + } else + #endif + { + glDrawElements(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast(indexOffset)); + } + } + + /* Instanced mesh */ + } else { + /* Non-indexed mesh */ + if(!_indexBuffer) { + #ifndef MAGNUM_TARGET_GLES + /* Non-indexed mesh with base instance */ + if(baseInstance) { + glDrawArraysInstancedBaseInstance(GLenum(_primitive), baseVertex, count, instanceCount, baseInstance); + + /* Non-indexed mesh */ + } else + #endif + { + #ifndef MAGNUM_TARGET_GLES2 + glDrawArraysInstanced(GLenum(_primitive), baseVertex, count, instanceCount); + #else + (this->*state.drawArraysInstancedImplementation)(baseVertex, count, instanceCount); + #endif + } + + /* Indexed mesh with base vertex */ + } else if(baseVertex) { + #ifndef MAGNUM_TARGET_GLES + /* Indexed mesh with base vertex and base instance */ + if(baseInstance) + glDrawElementsInstancedBaseVertexBaseInstance(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast(indexOffset), instanceCount, baseVertex, baseInstance); + + /* Indexed mesh with base vertex */ + else + glDrawElementsInstancedBaseVertex(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast(indexOffset), instanceCount, baseVertex); + #else + CORRADE_ASSERT(false, "Mesh::draw(): desktop OpenGL is required for base vertex specification in indexed meshes", ); + #endif + + /* Indexed mesh */ + } else { + #ifndef MAGNUM_TARGET_GLES + /* Indexed mesh with base instance */ + if(baseInstance) { + glDrawElementsInstancedBaseInstance(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast(indexOffset), instanceCount, baseInstance); + + /* Instanced mesh */ + } else + #endif + { + #ifndef MAGNUM_TARGET_GLES2 + glDrawElementsInstanced(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast(indexOffset), instanceCount); + #else + (this->*state.drawElementsInstancedImplementation)(count, indexOffset, instanceCount); + #endif + } + } + } - (this->*Context::current()->state().mesh->unbindImplementation)(); + (this->*state.unbindImplementation)(); } void Mesh::bindVAO(GLuint vao) { @@ -207,44 +297,6 @@ void Mesh::bindVAO(GLuint vao) { } } -void Mesh::attributePointerInternal(const Attribute& attribute) { - (this->*Context::current()->state().mesh->attributePointerImplementation)(attribute); -} - -#ifndef MAGNUM_TARGET_GLES2 -void Mesh::attributePointerInternal(const IntegerAttribute& attribute) { - (this->*Context::current()->state().mesh->attributeIPointerImplementation)(attribute); -} - -#ifndef MAGNUM_TARGET_GLES -void Mesh::attributePointerInternal(const LongAttribute& attribute) { - (this->*Context::current()->state().mesh->attributeLPointerImplementation)(attribute); -} -#endif -#endif - -void Mesh::vertexAttribPointer(const Attribute& attribute) { - glEnableVertexAttribArray(attribute.location); - attribute.buffer->bind(Buffer::Target::Array); - glVertexAttribPointer(attribute.location, attribute.size, attribute.type, attribute.normalized, attribute.stride, reinterpret_cast(attribute.offset)); -} - -#ifndef MAGNUM_TARGET_GLES2 -void Mesh::vertexAttribPointer(const IntegerAttribute& attribute) { - glEnableVertexAttribArray(attribute.location); - attribute.buffer->bind(Buffer::Target::Array); - glVertexAttribIPointer(attribute.location, attribute.size, attribute.type, attribute.stride, reinterpret_cast(attribute.offset)); -} - -#ifndef MAGNUM_TARGET_GLES -void Mesh::vertexAttribPointer(const LongAttribute& attribute) { - glEnableVertexAttribArray(attribute.location); - attribute.buffer->bind(Buffer::Target::Array); - glVertexAttribLPointer(attribute.location, attribute.size, attribute.type, attribute.stride, reinterpret_cast(attribute.offset)); -} -#endif -#endif - void Mesh::createImplementationDefault() { _id = 0; } void Mesh::createImplementationVAO() { @@ -269,6 +321,10 @@ void Mesh::destroyImplementationVAO() { #endif } +void Mesh::attributePointerInternal(const Attribute& attribute) { + (this->*Context::current()->state().mesh->attributePointerImplementation)(attribute); +} + void Mesh::attributePointerImplementationDefault(const Attribute& attribute) { #if defined(CORRADE_TARGET_NACL) || defined(MAGNUM_TARGET_WEBGL) CORRADE_ASSERT(attribute.buffer->targetHint() == Buffer::Target::Array, @@ -292,10 +348,28 @@ void Mesh::attributePointerImplementationVAO(const Attribute& attribute) { void Mesh::attributePointerImplementationDSA(const Attribute& attribute) { glEnableVertexArrayAttribEXT(_id, attribute.location); glVertexArrayVertexAttribOffsetEXT(_id, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.normalized, attribute.stride, attribute.offset); + if(attribute.divisor) glVertexArrayVertexAttribDivisorEXT(_id, attribute.location, attribute.divisor); } #endif +void Mesh::vertexAttribPointer(const Attribute& attribute) { + glEnableVertexAttribArray(attribute.location); + attribute.buffer->bind(Buffer::Target::Array); + glVertexAttribPointer(attribute.location, attribute.size, attribute.type, attribute.normalized, attribute.stride, reinterpret_cast(attribute.offset)); + if(attribute.divisor) { + #ifndef MAGNUM_TARGET_GLES2 + glVertexAttribDivisor(attribute.location, attribute.divisor); + #else + (this->*Context::current()->state().mesh->vertexAttribDivisorImplementation)(attribute.location, attribute.divisor); + #endif + } +} + #ifndef MAGNUM_TARGET_GLES2 +void Mesh::attributePointerInternal(const IntegerAttribute& attribute) { + (this->*Context::current()->state().mesh->attributeIPointerImplementation)(attribute); +} + void Mesh::attributePointerImplementationDefault(const IntegerAttribute& attribute) { _integerAttributes.push_back(attribute); } @@ -309,10 +383,23 @@ void Mesh::attributePointerImplementationVAO(const IntegerAttribute& attribute) void Mesh::attributePointerImplementationDSA(const IntegerAttribute& attribute) { glEnableVertexArrayAttribEXT(_id, attribute.location); glVertexArrayVertexAttribIOffsetEXT(_id, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.stride, attribute.offset); + if(attribute.divisor) glVertexArrayVertexAttribDivisorEXT(_id, attribute.location, attribute.divisor); +} +#endif + +void Mesh::vertexAttribPointer(const IntegerAttribute& attribute) { + glEnableVertexAttribArray(attribute.location); + attribute.buffer->bind(Buffer::Target::Array); + glVertexAttribIPointer(attribute.location, attribute.size, attribute.type, attribute.stride, reinterpret_cast(attribute.offset)); + if(attribute.divisor) glVertexAttribDivisor(attribute.location, attribute.divisor); } #endif #ifndef MAGNUM_TARGET_GLES +void Mesh::attributePointerInternal(const LongAttribute& attribute) { + (this->*Context::current()->state().mesh->attributeLPointerImplementation)(attribute); +} + void Mesh::attributePointerImplementationDefault(const LongAttribute& attribute) { _longAttributes.push_back(attribute); } @@ -325,14 +412,42 @@ void Mesh::attributePointerImplementationVAO(const LongAttribute& attribute) { void Mesh::attributePointerImplementationDSA(const LongAttribute& attribute) { glEnableVertexArrayAttribEXT(_id, attribute.location); glVertexArrayVertexAttribLOffsetEXT(_id, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.stride, attribute.offset); + if(attribute.divisor) glVertexArrayVertexAttribDivisorEXT(_id, attribute.location, attribute.divisor); +} + +void Mesh::vertexAttribPointer(const LongAttribute& attribute) { + glEnableVertexAttribArray(attribute.location); + attribute.buffer->bind(Buffer::Target::Array); + glVertexAttribLPointer(attribute.location, attribute.size, attribute.type, attribute.stride, reinterpret_cast(attribute.offset)); + if(attribute.divisor) glVertexAttribDivisor(attribute.location, attribute.divisor); } -#endif #endif -void Mesh::bindIndexBufferImplementationDefault(Buffer& buffer) { - _indexBuffer = &buffer; +#ifdef MAGNUM_TARGET_GLES2 +void Mesh::vertexAttribDivisorImplementationANGLE(const GLuint index, const GLuint divisor) { + //glVertexAttribDivisorANGLE(index, divisor); + CORRADE_INTERNAL_ASSERT(false); + static_cast(index); + static_cast(divisor); +} + +void Mesh::vertexAttribDivisorImplementationEXT(const GLuint index, const GLuint divisor) { + //glVertexAttribDivisorEXT(index, divisor); + CORRADE_INTERNAL_ASSERT(false); + static_cast(index); + static_cast(divisor); } +void Mesh::vertexAttribDivisorImplementationNV(const GLuint index, const GLuint divisor) { + //glVertexAttribDivisorNV(index, divisor); + CORRADE_INTERNAL_ASSERT(false); + static_cast(index); + static_cast(divisor); +} +#endif + +void Mesh::bindIndexBufferImplementationDefault(Buffer&) {} + void Mesh::bindIndexBufferImplementationVAO(Buffer& buffer) { bindVAO(_id); @@ -359,7 +474,7 @@ void Mesh::bindImplementationDefault() { #endif /* Bind index buffer, if the mesh is indexed */ - if(_indexCount) _indexBuffer->bind(Buffer::Target::ElementArray); + if(_indexBuffer) _indexBuffer->bind(Buffer::Target::ElementArray); } void Mesh::bindImplementationVAO() { @@ -383,6 +498,56 @@ void Mesh::unbindImplementationDefault() { void Mesh::unbindImplementationVAO() {} +#ifdef MAGNUM_TARGET_GLES2 +void Mesh::drawArraysInstancedImplementationANGLE(const GLint baseVertex, const GLsizei count, const GLsizei instanceCount) { + //glDrawArraysInstancedANGLE(GLenum(_primitive), baseVertex, count, instanceCount); + CORRADE_INTERNAL_ASSERT(false); + static_cast(baseVertex); + static_cast(count); + static_cast(instanceCount); +} + +void Mesh::drawArraysInstancedImplementationEXT(const GLint baseVertex, const GLsizei count, const GLsizei instanceCount) { + //glDrawArraysInstancedEXT(GLenum(_primitive), baseVertex, count, instanceCount); + CORRADE_INTERNAL_ASSERT(false); + static_cast(baseVertex); + static_cast(count); + static_cast(instanceCount); +} + +void Mesh::drawArraysInstancedImplementationNV(const GLint baseVertex, const GLsizei count, const GLsizei instanceCount) { + //glDrawArraysInstancedNV(GLenum(_primitive), baseVertex, count, instanceCount); + CORRADE_INTERNAL_ASSERT(false); + static_cast(baseVertex); + static_cast(count); + static_cast(instanceCount); +} + +void Mesh::drawElementsInstancedImplementationANGLE(const GLsizei count, const GLintptr indexOffset, const GLsizei instanceCount) { + //glDrawElementsInstancedANGLE(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast(indexOffset), instanceCount); + CORRADE_INTERNAL_ASSERT(false); + static_cast(count); + static_cast(indexOffset); + static_cast(instanceCount); +} + +void Mesh::drawElementsInstancedImplementationEXT(const GLsizei count, const GLintptr indexOffset, const GLsizei instanceCount) { + //glDrawElementsInstancedEXT(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast(indexOffset), instanceCount); + CORRADE_INTERNAL_ASSERT(false); + static_cast(count); + static_cast(indexOffset); + static_cast(instanceCount); +} + +void Mesh::drawElementsInstancedImplementationNV(const GLsizei count, const GLintptr indexOffset, const GLsizei instanceCount) { + //glDrawElementsInstancedNV(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast(indexOffset), instanceCount); + CORRADE_INTERNAL_ASSERT(false); + static_cast(count); + static_cast(indexOffset); + static_cast(instanceCount); +} +#endif + #ifndef DOXYGEN_GENERATING_OUTPUT Debug operator<<(Debug debug, MeshPrimitive value) { switch(value) { diff --git a/src/Magnum/Mesh.h b/src/Magnum/Mesh.h index bf7f899f1..50c5d7d3b 100644 --- a/src/Magnum/Mesh.h +++ b/src/Magnum/Mesh.h @@ -122,29 +122,29 @@ namespace Implementation { struct MeshState; } @section Mesh-configuration Mesh configuration -You have to specify at least primitive and vertex count using @ref setPrimitive() -and @ref setVertexCount(). Then fill your vertex buffers with data, add them to -the mesh and specify @ref AbstractShaderProgram::Attribute "shader attribute" -layout inside the buffers using @ref addVertexBuffer(). You can also -use @ref MeshTools::interleave() conveniently fill interleaved vertex buffer. -The function itself calls @ref setVertexCount(), so you don't have to do it -again, but you still have to specify the layout using @ref addVertexBuffer(). - -If you have indexed mesh, you need to call @ref setIndexCount() instead of -@ref setVertexCount(). Then fill your index buffer with data and specify its +You have to specify at least primitive and vertex/index count using +@ref setPrimitive() and @ref setCount(). Then fill your vertex buffers with +data, add them to the mesh and specify +@ref AbstractShaderProgram::Attribute "shader attribute" layout inside the +buffers using @ref addVertexBuffer(). You can also use +@ref MeshTools::interleave() to conveniently interleave vertex data. + +If you want indexed mesh, fill your index buffer with data and specify its layout using @ref setIndexBuffer(). You can also use @ref MeshTools::compressIndices() -to conveniently compress the indices, fill the index buffer and configure the -mesh instead of calling @ref setIndexCount() and @ref setIndexBuffer() manually. +to conveniently compress the indices based on the range used. + +There is also @ref MeshTools::compile() function which operates directly on +@ref Trade::MeshData2D / @ref Trade::MeshData3D and returns fully configured +mesh and vertex/index buffers for use with stock shaders. Note that neither vertex buffers nor index buffer is managed (e.g. deleted on destruction) by the mesh, so you have to manage them on your own and ensure that they are available for whole mesh lifetime. On the other hand it allows you to use one buffer for more meshes (each mesh for example configured for -different shader) or store data for more meshes in one buffer. +different usage) or store data for more meshes in one buffer. -If the mesh has non-zero index count, it is treated as indexed mesh, otherwise -it is treated as non-indexed mesh. If both index and vertex count is zero, the -mesh is empty and no draw commands are issued when calling @ref draw(). +If vertex/index count or instance count is zero, the mesh is empty and no draw +commands are issued when calling @ref draw(). @subsection Mesh-configuration-examples Example mesh configuration @@ -158,19 +158,19 @@ class MyShader: public AbstractShaderProgram { // ... }; -Buffer vertexBuffer; -Mesh mesh; // Fill vertex buffer with position data static constexpr Vector3 positions[30] = { // ... }; +Buffer vertexBuffer; vertexBuffer.setData(positions, BufferUsage::StaticDraw); -// Set primitive and vertex count, add the buffer and specify its layout +// Configure the mesh, add vertex buffer +Mesh mesh; mesh.setPrimitive(MeshPrimitive::Triangles) - .setVertexCount(30) - .addVertexBuffer(vertexBuffer, 0, MyShader::Position()); + .setCount(30) + .addVertexBuffer(vertexBuffer, 0, MyShader::Position{}); @endcode @subsubsection Mesh-configuration-examples-nonindexed-phong Interleaved vertex data @@ -178,17 +178,16 @@ mesh.setPrimitive(MeshPrimitive::Triangles) @code // Non-indexed primitive with positions and normals Trade::MeshData3D plane = Primitives::Plane::solid(); -Buffer vertexBuffer; -Mesh mesh; // Fill vertex buffer with interleaved position and normal data -MeshTools::interleave(mesh, buffer, BufferUsage::StaticDraw, - plane.positions(0), plane.normals(0)); +Buffer vertexBuffer; +vertexBuffer.setData(MeshTools::interleave(plane.positions(0), plane.normals(0)), BufferUsage::StaticDraw); -// Set primitive and specify layout of interleaved vertex buffer, vertex count -// has been already set by MeshTools::interleave() +// Configure the mesh, add vertex buffer +Mesh mesh; mesh.setPrimitive(plane.primitive()) - .addVertexBuffer(buffer, 0, Shaders::Phong::Position(), Shaders::Phong::Normal()); + .setCount(plane.positions(0).size()) + .addVertexBuffer(buffer, 0, Shaders::Phong::Position{}, Shaders::Phong::Normal{}); @endcode @subsubsection Mesh-configuration-examples-indexed-phong Indexed mesh @@ -201,48 +200,60 @@ class MyShader: public AbstractShaderProgram { // ... }; -Buffer vertexBuffer, indexBuffer; -Mesh mesh; // Fill vertex buffer with position data static constexpr Vector3 positions[300] = { // ... }; +Buffer vertexBuffer; vertexBuffer.setData(positions, BufferUsage::StaticDraw); // Fill index buffer with index data static constexpr GLubyte indices[75] = { // ... }; +Buffer indexBuffer; indexBuffer.setData(indices, BufferUsage::StaticDraw); -// Set primitive, index count, specify the buffers +// Configure the mesh, add both vertex and index buffer +Mesh mesh; mesh.setPrimitive(MeshPrimitive::Triangles) - .setIndexCount(75) - .addVertexBuffer(vertexBuffer, 0, MyShader::Position()) + .setCount(75) + .addVertexBuffer(vertexBuffer, 0, MyShader::Position{}) .setIndexBuffer(indexBuffer, 0, Mesh::IndexType::UnsignedByte, 176, 229); @endcode +Or using @ref MeshTools::interleave() and @ref MeshTools::compressIndices(): + @code // Indexed primitive Trade::MeshData3D cube = Primitives::Cube::solid(); -Buffer vertexBuffer, indexBuffer; -Mesh mesh; // Fill vertex buffer with interleaved position and normal data -MeshTools::interleave(mesh, vertexBuffer, BufferUsage::StaticDraw, - cube.positions(0), cube.normals(0)); +Buffer vertexBuffer; +vertexBuffer.setData(MeshTools::interleave(cube.positions(0), cube.normals(0)), BufferUsage::StaticDraw); + +// Compress index data +Containers::Array indexData; +Mesh::IndexType indexType; +UnsignedInt indexStart, indexEnd; +std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(cube.indices()); -// Fill index buffer with compressed index data -MeshTools::compressIndices(mesh, indexBuffer, BufferUsage::StaticDraw, - cube.indices()); +// Fill index buffer +Buffer indexBuffer; +indexBuffer.setData(data); -// Set primitive and specify layout of interleaved vertex buffer. Index count -// and index buffer has been already specified by MeshTools::compressIndices(). +// Configure the mesh, add both vertex and index buffer +Mesh mesh; mesh.setPrimitive(plane.primitive()) - .addVertexBuffer(vertexBuffer, 0, Shaders::Phong::Position(), Shaders::Phong::Normal()); + .setCount(cube.indices().size()) + .addVertexBuffer(vertexBuffer, 0, Shaders::Phong::Position{}, Shaders::Phong::Normal{}) + .setIndexBuffer(indexBuffer, 0, indexType, indexStart, indexEnd); @endcode +Or, if you plan to use the mesh with stock shaders, you can just use +@ref MeshTools::compile(). + @subsubsection Mesh-configuration-examples-data-options Specific formats of vertex data @code @@ -254,47 +265,52 @@ class MyShader: public AbstractShaderProgram { // ... }; + +// Initial mesh configuration Mesh mesh; +mesh.setPrimitive(...) + .setCount(30); // Fill position buffer with positions specified as two-component XY (i.e., // no Z component, which is meant to be always 0) -Buffer positionBuffer; Vector2 positions[30] = { // ... }; +Buffer positionBuffer; +positionBuffer.setData(positions, BufferUsage::StaticDraw); // Specify layout of positions buffer -- only two components, unspecified Z // component will be automatically set to 0 mesh.addVertexBuffer(positionBuffer, 0, - MyShader::Position(MyShader::Position::Components::Two)); + MyShader::Position{MyShader::Position::Components::Two}); // Fill color buffer with colors specified as four-byte BGRA (e.g. directly // from TGA file) -Buffer colorBuffer; GLubyte colors[4*30] = { // ... }; +Buffer colorBuffer; colorBuffer.setData(colors, BufferUsage::StaticDraw); // Specify layout of color buffer -- BGRA, each component unsigned byte and we // want to normalize them from [0, 255] to [0.0f, 1.0f] -mesh.addVertexBuffer(colorBuffer, 0, MyShader::Color( +mesh.addVertexBuffer(colorBuffer, 0, MyShader::Color{ MyShader::Color::Components::BGRA, MyShader::Color::DataType::UnsignedByte, - MyShader::Color::DataOption::Normalized)); + MyShader::Color::DataOption::Normalized}); @endcode @section Mesh-drawing Rendering meshes Basic workflow is: bind specific framebuffer for drawing (if needed), set up -respective shader, bind required textures (see +respective shader (see @ref AbstractShaderProgram-rendering-workflow "AbstractShaderProgram documentation" for more infromation) and call @ref Mesh::draw(). @section Mesh-webgl-restrictions WebGL restrictions @ref MAGNUM_TARGET_WEBGL "WebGL" puts some restrictions on vertex buffer -layout, see @ref addVertexBuffer() for details. +layout, see @ref addVertexBuffer() documentation for details. @section Mesh-performance-optimization Performance optimizations @@ -315,9 +331,6 @@ calls to @fn_gl{BindBuffer} and @fn_gl{BindVertexArray}. See documentation of If index range is specified in @ref setIndexBuffer(), range-based version of drawing commands are used on desktop OpenGL and OpenGL ES 3.0. See also @ref draw() for more information. - -@todo Redo in a way that allows glMultiDrawArrays, glDrawArraysInstanced etc. -@todo How to glDrawElementsBaseVertex()/vertex offset -- in draw()? */ class MAGNUM_EXPORT Mesh: public AbstractObject { friend class MeshView; @@ -395,7 +408,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { * @param primitive Primitive type * * Creates mesh with no vertex buffers and zero vertex count. - * @see @ref setPrimitive(), @ref setVertexCount(), @fn_gl{GenVertexArrays} + * @see @ref setPrimitive(), @ref setCount(), @fn_gl{GenVertexArrays} * (if @extension{APPLE,vertex_array_object} is available) */ explicit Mesh(MeshPrimitive primitive = MeshPrimitive::Triangles); @@ -454,6 +467,13 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { */ Mesh& setLabel(const std::string& label); + /** + * @brief Whether the mesh is indexed + * + * @see @ref setIndexBuffer(), @ref setCount() + */ + bool isIndexed() const { return _indexBuffer; } + /** * @brief Index size * @@ -469,43 +489,119 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { * @return Reference to self (for method chaining) * * Default is @ref MeshPrimitive::Triangles. - * @see @ref setVertexCount(), @ref addVertexBuffer() + * @see @ref setCount() */ Mesh& setPrimitive(MeshPrimitive primitive) { _primitive = primitive; return *this; } - /** @brief Vertex count */ - Int vertexCount() const { return _vertexCount; } + /** @brief Vertex/index count */ + Int count() const { return _count; } + + /** + * @brief Set vertex/index count + * @return Reference to self (for method chaining) + * + * If the mesh is indexed, the value is treated as index count, + * otherwise the value is vertex count. If set to `0`, no draw commands + * are issued when calling @ref draw(). Default is `0`. + * @see @ref isIndexed() + */ + Mesh& setCount(Int count) { + _count = count; + return *this; + } + + /** @brief Base vertex */ + Int baseVertex() const { return _baseVertex; } + + /** + * @brief Set base vertex + * @return Reference to self (for method chaining) + * + * Sets number of vertices of which the vertex buffer will be offset + * when drawing. Default is `0`. + * @requires_gl32 %Extension @extension{ARB,draw_elements_base_vertex} + * for indexed meshes + * @requires_gl Base vertex cannot be specified for indexed meshes in + * OpenGL ES. + */ + Mesh& setBaseVertex(Int baseVertex) { + _baseVertex = baseVertex; + return *this; + } + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @copybrief count() + * @deprecated Use @ref Magnum::Mesh::count() "count()" instead. + */ + CORRADE_DEPRECATED("use count() instead") Int vertexCount() const { + return isIndexed() ? 0 : count(); + } + + /** + * @copybrief setCount() + * @deprecated Use @ref Magnum::Mesh::setCount() "setCount()" instead. + */ + CORRADE_DEPRECATED("use setCount() instead") Mesh& setVertexCount(Int count) { + if(!isIndexed()) setCount(count); + return *this; + } + + /** + * @copybrief count() + * @deprecated Use @ref Magnum::Mesh::count() "count()" instead. + */ + CORRADE_DEPRECATED("use count() instead") Int indexCount() const { + return count(); + } + + /** + * @copybrief setCount() + * @deprecated Use @ref Magnum::Mesh::setCount() "setCount()" instead. + */ + CORRADE_DEPRECATED("use setCount() instead") Mesh& setIndexCount(Int count) { return setCount(count); } + #endif + + /** @brief Instance count */ + Int instanceCount() const { return _instanceCount; } /** - * @brief Set vertex count + * @brief Set instance count * @return Reference to self (for method chaining) * - * Default is zero. - * @see @ref setPrimitive(), @ref addVertexBuffer(), - * @ref MeshTools::interleave() + * If set to `1`, non-instanced draw commands are issued when calling + * @ref draw(). If set to `0`, no draw commands are issued altogether. + * Default is `1`. + * @requires_gl31 %Extension @extension{ARB,draw_instanced} + * @requires_gles30 %Extension @es_extension{ANGLE,instanced_arrays}, + * @es_extension2{EXT,draw_instanced,draw_instanced} or + * @es_extension{NV,draw_instanced} in OpenGL ES 2.0. */ - Mesh& setVertexCount(Int vertexCount) { - _vertexCount = vertexCount; + Mesh& setInstanceCount(Int count) { + _instanceCount = count; return *this; } - /** @brief Index count */ - Int indexCount() const { return _indexCount; } + #ifndef MAGNUM_TARGET_GLES + /** @brief Base instance */ + UnsignedInt baseInstance() const { return _baseInstance; } /** - * @brief Set index count + * @brief Set base instance * @return Reference to self (for method chaining) * - * Default is zero. - * @see @ref setIndexBuffer(), @ref MeshTools::compressIndices() + * Default is `0`. + * @requires_gl42 %Extension @extension{ARB,base_instance} + * @requires_gl Base instance cannot be specified in OpenGL ES. */ - Mesh& setIndexCount(Int count) { - _indexCount = count; + Mesh& setBaseInstance(UnsignedInt baseInstance) { + _baseInstance = baseInstance; return *this; } + #endif /** * @brief Add buffer with (interleaved) vertex attributes for use with given shader @@ -565,7 +661,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { * but doing so may have performance benefits. * * @see @ref maxVertexAttributes(), @ref setPrimitive(), - * @ref setVertexCount(), @fn_gl{BindVertexArray}, + * @ref setCount(), @fn_gl{BindVertexArray}, * @fn_gl{EnableVertexAttribArray}, @fn_gl{BindBuffer}, * @fn_gl{VertexAttribPointer} or * @fn_gl_extension{EnableVertexArrayAttrib,EXT,direct_state_access}, @@ -573,7 +669,34 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { * if @extension{APPLE,vertex_array_object} is available */ template inline Mesh& addVertexBuffer(Buffer& buffer, GLintptr offset, const T&... attributes) { - addVertexBufferInternal(buffer, offset, strideOfInterleaved(attributes...), attributes...); + addVertexBufferInternal(buffer, offset, strideOfInterleaved(attributes...), 0, attributes...); + return *this; + } + + /** + * @brief Add instanced vertex buffer + * @return Reference to self (for method chaining) + * + * Similar to the above function, the @p divisor parameter specifies + * number of instances that will pass until new data are fetched from + * the buffer. Setting it to `0` is equivalent to calling + * @ref addVertexBuffer(). + * @see @ref maxVertexAttributes(), @ref setPrimitive(), + * @ref setCount(), @ref setInstanceCount(), @ref setBaseInstance(), + * @fn_gl{BindVertexArray}, @fn_gl{EnableVertexAttribArray}, + * @fn_gl{BindBuffer}, @fn_gl{VertexAttribPointer}, + * @fn_gl{VertexAttribDivisor} or + * @fn_gl_extension{EnableVertexArrayAttrib,EXT,direct_state_access}, + * @fn_gl_extension{VertexArrayVertexAttribOffset,EXT,direct_state_access}, + * @fn_gl_extension{VertexArrayVertexAttribDivisor,EXT,direct_state_access} + * if @extension{APPLE,vertex_array_object} is available + * @requires_gl33 %Extension @extension{ARB,instanced_arrays} + * @requires_gles30 %Extension @es_extension{ANGLE,instanced_arrays}, + * @es_extension{EXT,instanced_arrays} or + * @es_extension{NV,instanced_arrays} in OpenGL ES 2.0. + */ + template inline Mesh& addVertexBufferInstanced(Buffer& buffer, UnsignedInt divisor, GLintptr offset, const T&... attributes) { + addVertexBufferInternal(buffer, offset, strideOfInterleaved(attributes...), divisor, attributes...); return *this; } @@ -594,9 +717,9 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { * @ref setIndexBuffer(Buffer&, GLintptr, IndexType), as this * functionality is not available there. * @see @ref maxElementsIndices(), @ref maxElementsVertices(), - * @ref setIndexCount(), @ref MeshTools::compressIndices(), - * @fn_gl{BindVertexArray}, @fn_gl{BindBuffer} (if - * @extension{APPLE,vertex_array_object} is available) + * @ref setCount(), @ref isIndexed(), @fn_gl{BindVertexArray}, + * @fn_gl{BindBuffer} (if @extension{APPLE,vertex_array_object} is + * available) */ Mesh& setIndexBuffer(Buffer& buffer, GLintptr offset, IndexType type, UnsignedInt start, UnsignedInt end); @@ -607,11 +730,9 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { * @param type Index data type * @return Reference to self (for method chaining) * - * Prefer to use @ref setIndexBuffer(Buffer&, GLintptr, IndexType, UnsignedInt, UnsignedInt) - * for better performance. - * @see @ref setIndexCount(), @ref MeshTools::compressIndices(), - * @fn_gl{BindVertexArray}, @fn_gl{BindBuffer} (if - * @extension{APPLE,vertex_array_object} is available) + * Alternative to @ref setIndexBuffer(Buffer&, GLintptr, IndexType, UnsignedInt, UnsignedInt) + * with unspecified index limits, see its documentation for more + * information. Prefer to set index limits for better performance. */ Mesh& setIndexBuffer(Buffer& buffer, GLintptr offset, IndexType type) { return setIndexBuffer(buffer, offset, type, 0, 0); @@ -622,22 +743,31 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { * @param shader Shader to use for drawing * * Expects that the shader is compatible with this mesh and is fully - * set up. See also + * set up. If vertex/index count or instance count is `0`, no draw + * commands are issued. See also * @ref AbstractShaderProgram-rendering-workflow "AbstractShaderProgram documentation" * for more information. - * @see @fn_gl{UseProgram}, @fn_gl{EnableVertexAttribArray}, - * @fn_gl{BindBuffer}, @fn_gl{VertexAttribPointer}, - * @fn_gl{DisableVertexAttribArray} or @fn_gl{BindVertexArray} (if - * @extension{APPLE,vertex_array_object} is available), @fn_gl{DrawArrays} - * or @fn_gl{DrawElements}/@fn_gl{DrawRangeElements}. + * @see @ref setCount(), @ref setInstanceCount(), @fn_gl{UseProgram}, + * @fn_gl{EnableVertexAttribArray}, @fn_gl{BindBuffer}, + * @fn_gl{VertexAttribPointer}, @fn_gl{DisableVertexAttribArray} + * or @fn_gl{BindVertexArray} (if @extension{APPLE,vertex_array_object} + * is available), @fn_gl{DrawArrays}/@fn_gl{DrawArraysInstanced}/ + * @fn_gl{DrawArraysInstancedBaseInstance} or @fn_gl{DrawElements}/ + * @fn_gl{DrawRangeElements}/@fn_gl{DrawElementsBaseVertex}/ + * @fn_gl{DrawRangeElementsBaseVertex}/@fn_gl{DrawElementsInstanced}/ + * @fn_gl{DrawElementsInstancedBaseInstance}/ + * @fn_gl{DrawElementsInstancedBaseVertex}/ + * @fn_gl{DrawElementsInstancedBaseVertexBaseInstance} */ void draw(AbstractShaderProgram& shader) { shader.use(); - #ifndef MAGNUM_TARGET_GLES2 - drawInternal(0, _vertexCount, _indexOffset, _indexCount, _indexStart, _indexEnd); + #ifndef MAGNUM_TARGET_GLES + drawInternal(_count, _baseVertex, _instanceCount, _baseInstance, _indexOffset, _indexStart, _indexEnd); + #elif !defined(MAGNUM_TARGET_GLES2) + drawInternal(_count, _baseVertex, _instanceCount, _indexOffset, _indexStart, _indexEnd); #else - drawInternal(0, _vertexCount, _indexOffset, _indexCount); + drawInternal(_count, _baseVertex, _instanceCount, _indexOffset); #endif } @@ -649,11 +779,13 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { * @deprecated Use @ref Magnum::Mesh::draw(AbstractShaderProgram&) "draw(AbstractShaderProgram&)" * instead. */ - void draw() { - #ifndef MAGNUM_TARGET_GLES2 - drawInternal(0, _vertexCount, _indexOffset, _indexCount, _indexStart, _indexEnd); + CORRADE_DEPRECATED("use draw(AbstractShaderProgram&) instead") void draw() { + #ifndef MAGNUM_TARGET_GLES + drawInternal(_count, _baseVertex, _instanceCount, _baseInstance, _indexOffset, _indexStart, _indexEnd); + #elif !defined(MAGNUM_TARGET_GLES2) + drawInternal(_count, _baseVertex, _instanceCount, _indexOffset, _indexStart, _indexEnd); #else - drawInternal(0, _vertexCount, _indexOffset, _indexCount); + drawInternal(_count, _baseVertex, _instanceCount, _indexOffset); #endif } #endif @@ -668,6 +800,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { bool normalized; GLintptr offset; GLsizei stride; + GLuint divisor; }; #ifndef MAGNUM_TARGET_GLES2 @@ -678,6 +811,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { GLenum type; GLintptr offset; GLsizei stride; + GLuint divisor; }; #ifndef MAGNUM_TARGET_GLES @@ -688,6 +822,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { GLenum type; GLintptr offset; GLsizei stride; + GLuint divisor; }; #endif #endif @@ -703,19 +838,19 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { static GLsizei strideOfInterleaved() { return 0; } /* Adding interleaved vertex attributes */ - template void addVertexBufferInternal(Buffer& buffer, GLintptr offset, GLsizei stride, const AbstractShaderProgram::Attribute& attribute, const U&... attributes) { - addVertexAttribute(buffer, attribute, offset, stride); + template void addVertexBufferInternal(Buffer& buffer, GLintptr offset, GLsizei stride, GLuint divisor, const AbstractShaderProgram::Attribute& attribute, const U&... attributes) { + addVertexAttribute(buffer, attribute, offset, stride, divisor); /* Add size of this attribute to offset for next attribute */ - addVertexBufferInternal(buffer, offset+attribute.vectorSize()*AbstractShaderProgram::Attribute::VectorCount, stride, attributes...); + addVertexBufferInternal(buffer, offset+attribute.vectorSize()*AbstractShaderProgram::Attribute::VectorCount, stride, divisor, attributes...); } - template void addVertexBufferInternal(Buffer& buffer, GLintptr offset, GLsizei stride, GLintptr gap, const T&... attributes) { + template void addVertexBufferInternal(Buffer& buffer, GLintptr offset, GLsizei stride, GLuint divisor, GLintptr gap, const T&... attributes) { /* Add the gap to offset for next attribute */ - addVertexBufferInternal(buffer, offset+gap, stride, attributes...); + addVertexBufferInternal(buffer, offset+gap, stride, divisor, attributes...); } - void addVertexBufferInternal(Buffer&, GLsizei, GLintptr) {} + void addVertexBufferInternal(Buffer&, GLsizei, GLuint, GLintptr) {} - template void addVertexAttribute(typename std::enable_if::ScalarType, Float>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { + template void addVertexAttribute(typename std::enable_if::ScalarType, Float>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride, GLuint divisor) { for(UnsignedInt i = 0; i != AbstractShaderProgram::Attribute::VectorCount; ++i) attributePointerInternal(Attribute{ &buffer, @@ -724,24 +859,26 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { GLenum(attribute.dataType()), bool(attribute.dataOptions() & AbstractShaderProgram::Attribute::DataOption::Normalized), GLintptr(offset+i*attribute.vectorSize()), - stride + stride, + divisor }); } #ifndef MAGNUM_TARGET_GLES2 - template void addVertexAttribute(typename std::enable_if::ScalarType>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { + template void addVertexAttribute(typename std::enable_if::ScalarType>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride, GLuint divisor) { attributePointerInternal(IntegerAttribute{ &buffer, location, GLint(attribute.components()), GLenum(attribute.dataType()), offset, - stride + stride, + divisor }); } #ifndef MAGNUM_TARGET_GLES - template void addVertexAttribute(typename std::enable_if::ScalarType, Double>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { + template void addVertexAttribute(typename std::enable_if::ScalarType, Double>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride, GLuint divisor) { for(UnsignedInt i = 0; i != AbstractShaderProgram::Attribute::VectorCount; ++i) attributePointerInternal(LongAttribute{ &buffer, @@ -749,7 +886,8 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { GLint(attribute.components()), GLenum(attribute.dataType()), GLintptr(offset+i*attribute.vectorSize()), - stride + stride, + divisor }); } #endif @@ -757,26 +895,12 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { static void MAGNUM_LOCAL bindVAO(GLuint vao); - void attributePointerInternal(const Attribute& attribute); - #ifndef MAGNUM_TARGET_GLES2 - void attributePointerInternal(const IntegerAttribute& attribute); - #ifndef MAGNUM_TARGET_GLES - void attributePointerInternal(const LongAttribute& attribute); - #endif - #endif - - void MAGNUM_LOCAL vertexAttribPointer(const Attribute& attribute); - #ifndef MAGNUM_TARGET_GLES2 - void MAGNUM_LOCAL vertexAttribPointer(const IntegerAttribute& attribute); #ifndef MAGNUM_TARGET_GLES - void MAGNUM_LOCAL vertexAttribPointer(const LongAttribute& attribute); - #endif - #endif - - #ifndef MAGNUM_TARGET_GLES2 - void drawInternal(Int firstVertex, Int vertexCount, GLintptr indexOffset, Int indexCount, Int indexStart, Int indexEnd); + void drawInternal(Int count, Int baseVertex, Int instanceCount, UnsignedInt baseInstance, GLintptr indexOffset, Int indexStart, Int indexEnd); + #elif !defined(MAGNUM_TARGET_GLES2) + void drawInternal(Int count, Int baseVertex, Int instanceCount, GLintptr indexOffset, Int indexStart, Int indexEnd); #else - void drawInternal(Int firstVertex, Int vertexCount, GLintptr indexOffset, Int indexCount); + void drawInternal(Int count, Int baseVertex, Int instanceCount, GLintptr indexOffset); #endif void MAGNUM_LOCAL createImplementationDefault(); @@ -785,27 +909,39 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { void MAGNUM_LOCAL destroyImplementationDefault(); void MAGNUM_LOCAL destroyImplementationVAO(); + void attributePointerInternal(const Attribute& attribute); void MAGNUM_LOCAL attributePointerImplementationDefault(const Attribute& attribute); void MAGNUM_LOCAL attributePointerImplementationVAO(const Attribute& attribute); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL attributePointerImplementationDSA(const Attribute& attribute); #endif + void MAGNUM_LOCAL vertexAttribPointer(const Attribute& attribute); #ifndef MAGNUM_TARGET_GLES2 + void attributePointerInternal(const IntegerAttribute& attribute); void MAGNUM_LOCAL attributePointerImplementationDefault(const IntegerAttribute& attribute); void MAGNUM_LOCAL attributePointerImplementationVAO(const IntegerAttribute& attribute); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL attributePointerImplementationDSA(const IntegerAttribute& attribute); #endif + void MAGNUM_LOCAL vertexAttribPointer(const IntegerAttribute& attribute); + #endif #ifndef MAGNUM_TARGET_GLES + void attributePointerInternal(const LongAttribute& attribute); void MAGNUM_LOCAL attributePointerImplementationDefault(const LongAttribute& attribute); void MAGNUM_LOCAL attributePointerImplementationVAO(const LongAttribute& attribute); void MAGNUM_LOCAL attributePointerImplementationDSA(const LongAttribute& attribute); + void MAGNUM_LOCAL vertexAttribPointer(const LongAttribute& attribute); #endif + + #ifdef MAGNUM_TARGET_GLES2 + void MAGNUM_LOCAL vertexAttribDivisorImplementationANGLE(GLuint index, GLuint divisor); + void MAGNUM_LOCAL vertexAttribDivisorImplementationEXT(GLuint index, GLuint divisor); + void MAGNUM_LOCAL vertexAttribDivisorImplementationNV(GLuint index, GLuint divisor); #endif - void MAGNUM_LOCAL bindIndexBufferImplementationDefault(Buffer& buffer); + void MAGNUM_LOCAL bindIndexBufferImplementationDefault(Buffer&); void MAGNUM_LOCAL bindIndexBufferImplementationVAO(Buffer& buffer); void MAGNUM_LOCAL bindImplementationDefault(); @@ -814,9 +950,22 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { void MAGNUM_LOCAL unbindImplementationDefault(); void MAGNUM_LOCAL unbindImplementationVAO(); + #ifdef MAGNUM_TARGET_GLES2 + void MAGNUM_LOCAL drawArraysInstancedImplementationANGLE(GLint baseVertex, GLsizei count, GLsizei instanceCount); + void MAGNUM_LOCAL drawArraysInstancedImplementationEXT(GLint baseVertex, GLsizei count, GLsizei instanceCount); + void MAGNUM_LOCAL drawArraysInstancedImplementationNV(GLint baseVertex, GLsizei count, GLsizei instanceCount); + + void MAGNUM_LOCAL drawElementsInstancedImplementationANGLE(GLsizei count, GLintptr indexOffset, GLsizei instanceCount); + void MAGNUM_LOCAL drawElementsInstancedImplementationEXT(GLsizei count, GLintptr indexOffset, GLsizei instanceCount); + void MAGNUM_LOCAL drawElementsInstancedImplementationNV(GLsizei count, GLintptr indexOffset, GLsizei instanceCount); + #endif + GLuint _id; MeshPrimitive _primitive; - Int _vertexCount, _indexCount; + Int _count, _baseVertex, _instanceCount; + #ifndef MAGNUM_TARGET_GLES + UnsignedInt _baseInstance; + #endif #ifndef MAGNUM_TARGET_GLES2 UnsignedInt _indexStart, _indexEnd; #endif diff --git a/src/Magnum/MeshTools/Compile.cpp b/src/Magnum/MeshTools/Compile.cpp index bc586f77a..b7243cf79 100644 --- a/src/Magnum/MeshTools/Compile.cpp +++ b/src/Magnum/MeshTools/Compile.cpp @@ -25,6 +25,7 @@ #include "Compile.h" +#include "Magnum/Buffer.h" #include "Magnum/Math/Vector3.h" #include "Magnum/MeshTools/CompressIndices.h" #include "Magnum/MeshTools/Interleave.h" @@ -51,9 +52,7 @@ std::tuple, std::unique_ptr> compile(const std::unique_ptr vertexBuffer{new Buffer{Buffer::Target::Array}}; /* Interleave positions */ - std::size_t vertexCount; - Containers::Array data; - std::tie(vertexCount, std::ignore, data) = MeshTools::interleave( + Containers::Array data = MeshTools::interleave( meshData.positions(0), stride - sizeof(Shaders::Generic2D::Position::Type)); mesh.addVertexBuffer(*vertexBuffer, 0, @@ -72,17 +71,24 @@ std::tuple, std::unique_ptr> compile(const stride - normalOffset - sizeof(Shaders::Generic2D::TextureCoordinates::Type)); } - /* Fill vertex buffer with interleaved data and finalize mesh - configuration */ - vertexBuffer->setData(data, BufferUsage::StaticDraw); - mesh.setVertexCount(vertexCount); + /* Fill vertex buffer with interleaved data */ + vertexBuffer->setData(data, usage); - /* Fill index buffer */ + /* If indexed, fill index buffer and configure indexed mesh */ std::unique_ptr indexBuffer; if(meshData.isIndexed()) { + Containers::Array indexData; + Mesh::IndexType indexType; + UnsignedInt indexStart, indexEnd; + std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(meshData.indices()); + indexBuffer.reset(new Buffer{Buffer::Target::ElementArray}); - MeshTools::compressIndices(mesh, *indexBuffer, usage, meshData.indices()); - } + indexBuffer->setData(data, usage); + mesh.setCount(meshData.indices().size()) + .setIndexBuffer(*indexBuffer, 0, indexType, indexStart, indexEnd); + + /* Else set vertex count */ + } else mesh.setCount(meshData.positions(0).size()); return std::make_tuple(std::move(mesh), std::move(vertexBuffer), std::move(indexBuffer)); } @@ -106,9 +112,7 @@ std::tuple, std::unique_ptr> compile(const std::unique_ptr vertexBuffer{new Buffer{Buffer::Target::Array}}; /* Interleave positions */ - std::size_t vertexCount; - Containers::Array data; - std::tie(vertexCount, std::ignore, data) = MeshTools::interleave( + Containers::Array data = MeshTools::interleave( meshData.positions(0), stride - sizeof(Shaders::Generic3D::Position::Type)); mesh.addVertexBuffer(*vertexBuffer, 0, @@ -139,17 +143,24 @@ std::tuple, std::unique_ptr> compile(const stride - textureCoordsOffset - sizeof(Shaders::Generic3D::TextureCoordinates::Type)); } - /* Fill vertex buffer with interleaved data and finalize mesh - configuration */ - vertexBuffer->setData(data, BufferUsage::StaticDraw); - mesh.setVertexCount(vertexCount); + /* Fill vertex buffer with interleaved data */ + vertexBuffer->setData(data, usage); - /* Fill index buffer */ + /* If indexed, fill index buffer and configure indexed mesh */ std::unique_ptr indexBuffer; if(meshData.isIndexed()) { + Containers::Array indexData; + Mesh::IndexType indexType; + UnsignedInt indexStart, indexEnd; + std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(meshData.indices()); + indexBuffer.reset(new Buffer{Buffer::Target::ElementArray}); - MeshTools::compressIndices(mesh, *indexBuffer, usage, meshData.indices()); - } + indexBuffer->setData(data, usage); + mesh.setCount(meshData.indices().size()) + .setIndexBuffer(*indexBuffer, 0, indexType, indexStart, indexEnd); + + /* Else set vertex count */ + } mesh.setCount(meshData.positions(0).size()); return std::make_tuple(std::move(mesh), std::move(vertexBuffer), std::move(indexBuffer)); } diff --git a/src/Magnum/MeshTools/CompressIndices.cpp b/src/Magnum/MeshTools/CompressIndices.cpp index 7d4f53074..b931af946 100644 --- a/src/Magnum/MeshTools/CompressIndices.cpp +++ b/src/Magnum/MeshTools/CompressIndices.cpp @@ -41,50 +41,53 @@ template<> constexpr Mesh::IndexType indexType() { return Mesh::In template<> constexpr Mesh::IndexType indexType() { return Mesh::IndexType::UnsignedShort; } template<> constexpr Mesh::IndexType indexType() { return Mesh::IndexType::UnsignedInt; } -template inline std::tuple> compress(const std::vector& indices) { +template inline std::pair, Mesh::IndexType> compress(const std::vector& indices) { Containers::Array buffer(indices.size()*sizeof(T)); for(std::size_t i = 0; i != indices.size(); ++i) { T index = static_cast(indices[i]); std::memcpy(buffer.begin()+i*sizeof(T), &index, sizeof(T)); } - return std::make_tuple(indices.size(), indexType(), std::move(buffer)); + return {std::move(buffer), indexType()}; } -std::tuple> compressIndicesInternal(const std::vector& indices, UnsignedInt max) { - switch(Math::log(256, max)) { +} + +std::tuple, Mesh::IndexType, UnsignedInt, UnsignedInt> compressIndices(const std::vector& indices) { + /** @todo Performance hint when range can be represented by smaller value? */ + auto minmax = std::minmax_element(indices.begin(), indices.end()); + std::pair, Mesh::IndexType> typeData; + switch(Math::log(256, *minmax.second)) { case 0: - return compress(indices); + typeData = compress(indices); + break; case 1: - return compress(indices); + typeData = compress(indices); + break; case 2: case 3: - return compress(indices); + typeData = compress(indices); + break; default: - CORRADE_ASSERT(false, "MeshTools::compressIndices(): no type able to index" << max << "elements.", {}); + CORRADE_ASSERT(false, "MeshTools::compressIndices(): no type able to index" << *minmax.second << "elements.", {}); } -} - -} -std::tuple> compressIndices(const std::vector& indices) { - return compressIndicesInternal(indices, *std::max_element(indices.begin(), indices.end())); + return std::make_tuple(std::move(typeData.first), typeData.second, *minmax.first, *minmax.second); } +#ifdef MAGNUM_BUILD_DEPRECATED void compressIndices(Mesh& mesh, Buffer& buffer, BufferUsage usage, const std::vector& indices) { - auto minmax = std::minmax_element(indices.begin(), indices.end()); - - /** @todo Performance hint when range can be represented by smaller value? */ - - std::size_t indexCount; - Mesh::IndexType indexType; Containers::Array data; - std::tie(indexCount, indexType, data) = compressIndicesInternal(indices, *minmax.second); + Mesh::IndexType type; + UnsignedInt start, end; + std::tie(data, type, start, end) = compressIndices(indices); - mesh.setIndexCount(indices.size()) - .setIndexBuffer(buffer, 0, indexType, *minmax.first, *minmax.second); buffer.setData(data, usage); + + mesh.setCount(indices.size()) + .setIndexBuffer(buffer, 0, type, start, end); } +#endif }} diff --git a/src/Magnum/MeshTools/CompressIndices.h b/src/Magnum/MeshTools/CompressIndices.h index bf4a96933..08fa28ead 100644 --- a/src/Magnum/MeshTools/CompressIndices.h +++ b/src/Magnum/MeshTools/CompressIndices.h @@ -43,24 +43,34 @@ namespace Magnum { namespace MeshTools { /** @brief Compress vertex indices @param indices Index array -@return Index count, type and compressed index array +@return Index range, type and compressed index array This function takes index array and outputs them compressed to smallest possible size. For example when your indices have maximum number 463, it's wasteful to store them in array of 32bit integers, array of 16bit integers is -sufficient. Example usage: +sufficient. + +Example usage: @code -std::size_t indexCount; +std::vector indices; + +Containers::Array indexData; Mesh::IndexType indexType; -Containers::Array data; -std::tie(indexCount, indexType, data) = MeshTools::compressIndices(indices); -@endcode +UnsignedInt indexStart, indexEnd; +std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(indices); + +Buffer indexBuffer; +indexBuffer.setData(indexData, BufferUsage::StaticDraw); -See also @ref compressIndices(Mesh&, Buffer&, BufferUsage, const std::vector&), -which writes the compressed data directly into index buffer of given mesh. +Mesh mesh; +mesh.setCount(indices.size()) + .setIndexBuffer(indexBuffer, 0, indexType, indexStart, indexEnd); +@endcode +@todo Extract IndexType out of Mesh class */ -std::tuple> MAGNUM_MESHTOOLS_EXPORT compressIndices(const std::vector& indices); +std::tuple, Mesh::IndexType, UnsignedInt, UnsignedInt> MAGNUM_MESHTOOLS_EXPORT compressIndices(const std::vector& indices); +#ifdef MAGNUM_BUILD_DEPRECATED /** @brief Compress vertex indices and write them to index buffer @param mesh Output mesh @@ -68,14 +78,17 @@ std::tuple> MAGNUM_MESHTOO @param usage Index buffer usage @param indices Index array -The same as @ref compressIndices(const std::vector&), but this -function writes the output to given buffer and calls @ref Mesh::setIndexCount() -and @ref Mesh::setIndexBuffer(), thus you don't need to do anything else for -mesh index configuration. +@deprecated Use general-purpose + @ref Magnum::MeshTools::compressIndices(const std::vector&) "compressIndices(const std::vector&)" + instead. -@see @ref MeshTools::interleave(), @ref MeshTools::compile() +The same as @ref compressIndices(const std::vector&), but this +function writes the output to given buffer and calls @ref Mesh::setCount() and +@ref Mesh::setIndexBuffer(), thus you don't need to do anything else for mesh +index configuration. */ void MAGNUM_MESHTOOLS_EXPORT compressIndices(Mesh& mesh, Buffer& buffer, BufferUsage usage, const std::vector& indices); +#endif }} diff --git a/src/Magnum/MeshTools/FullScreenTriangle.cpp b/src/Magnum/MeshTools/FullScreenTriangle.cpp index 5d3b728bf..b7ce1cc63 100644 --- a/src/Magnum/MeshTools/FullScreenTriangle.cpp +++ b/src/Magnum/MeshTools/FullScreenTriangle.cpp @@ -37,7 +37,7 @@ namespace Magnum { namespace MeshTools { std::pair, Mesh> fullScreenTriangle(Version version) { Mesh mesh; mesh.setPrimitive(MeshPrimitive::Triangles) - .setVertexCount(3); + .setCount(3); std::unique_ptr buffer; #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/MeshTools/Interleave.h b/src/Magnum/MeshTools/Interleave.h index 6295f00ca..bb77a5771 100644 --- a/src/Magnum/MeshTools/Interleave.h +++ b/src/Magnum/MeshTools/Interleave.h @@ -30,12 +30,16 @@ */ #include -#include -#include -#include +#include +#include -#include "Magnum/Mesh.h" +#include "Magnum/Magnum.h" + +#ifdef MAGNUM_BUILD_DEPRECATED +#include #include "Magnum/Buffer.h" +#include "Magnum/Mesh.h" +#endif namespace Magnum { namespace MeshTools { @@ -95,20 +99,21 @@ template void writeInterleaved(std::size_t stride, char* st @brief %Interleave vertex attributes This function takes list of attribute arrays and returns them interleaved, so -data for each attribute are in continuous place in memory. Returned tuple -contains attribute count, stride and data array. Deleting the data array is up -to the user. +data for each attribute are in continuous place in memory. -Size of the data buffer can be computed from attribute count and stride, as -shown below. Example usage: +Example usage: @code -std::vector positions; +MeshPrimitive primitive; +std::vector positions; std::vector textureCoordinates; -std::size_t attributeCount; -std::size_t stride; -Containers::Array data; -std::tie(attributeCount, stride, data) = MeshTools::interleave(positions, textureCoordinates); -// ... + +Buffer vertexBuffer; +vertexBuffer.setData(MeshTools::interleave(positions, textureCoordinates), BufferUsage::StaticDraw); + +Mesh mesh; +mesh.setPrimitive(primitive) + .setCount(positions.count()) + .addVertexBuffer(vertexBuffer, 0, MyShader::Position{}, MyShader::TextureCoordinates{}); @endcode It's often desirable to align data for one vertex on 32bit boundaries. To @@ -117,10 +122,8 @@ achieve that, you can specify gaps between the attributes: std::vector positions; std::vector weights; std::vector vertexColors; -std::size_t attributeCount; -std::size_t stride; -Containers::Array data; -std::tie(attributeCount, stride, data) = MeshTools::interleave(positions, weights, 2, textureCoordinates, 1); + +auto data = MeshTools::interleave(positions, weights, 2, textureCoordinates, 1); @endcode All gap bytes are set zero. This way vertex stride is 24 bytes, without gaps it would be 21 bytes, causing possible performance loss. @@ -132,13 +135,13 @@ would be 21 bytes, causing possible performance loss. for) and function `size()` returning count of elements. In most cases it will be `std::vector` or `std::array`. -See also @ref interleave(Mesh&, Buffer&, BufferUsage, const T&...), -which writes the interleaved array directly into buffer of given mesh or -@ref interleaveInto() which writes the data into existing buffer instead of -creating new one. +@see @ref interleaveInto() +@todo remove `std::enable_if` when deprecated overloads are removed */ /* enable_if to avoid clash with overloaded function below */ -template typename std::enable_if::value, std::tuple>>::type interleave(const T& first, const U&... next) { +template typename std::enable_if::value, Containers::Array>::type + interleave(const T& first, const U&... next) +{ /* Compute buffer size and stride */ const std::size_t attributeCount = Implementation::AttributeCount{}(first, next...); const std::size_t stride = Implementation::Stride{}(first, next...); @@ -148,14 +151,14 @@ template typename std::enable_if::va Containers::Array data = Containers::Array::zeroInitialized(attributeCount*stride); Implementation::writeInterleaved(stride, data.begin(), first, next...); - return std::make_tuple(attributeCount, stride, std::move(data)); + return data; /* Otherwise return nullptr */ } else { - #if !defined(CORRADE_GCC44_COMPATIBILITY) && !defined(CORRADE_MSVC2013_COMPATIBILITY) - return std::make_tuple(0, stride, nullptr); + #ifndef CORRADE_GCC45_COMPATIBILITY + return nullptr; #else - return std::tuple>(0, stride, Containers::Array()); + return {}; #endif } } @@ -172,18 +175,17 @@ parameters. arrays have the same size. The passed buffer must also be large enough to contain the interleaved data. */ -template std::tuple interleaveInto(Containers::ArrayReference buffer, const T& first, const U&... next) { +template void interleaveInto(Containers::ArrayReference buffer, const T& first, const U&... next) { /* Verify expected buffer size */ const std::size_t attributeCount = Implementation::AttributeCount{}(first, next...); const std::size_t stride = Implementation::Stride{}(first, next...); - CORRADE_ASSERT(attributeCount*stride <= buffer.size(), "MeshTools::interleaveInto(): the data buffer is too small, expected" << attributeCount*stride << "but got" << buffer.size(), {}); + CORRADE_ASSERT(attributeCount*stride <= buffer.size(), "MeshTools::interleaveInto(): the data buffer is too small, expected" << attributeCount*stride << "but got" << buffer.size(), ); /* Write data */ Implementation::writeInterleaved(stride, buffer.begin(), first, next...); - - return std::make_tuple(attributeCount, stride); } +#ifdef MAGNUM_BUILD_DEPRECATED /** @brief %Interleave vertex attributes, write them to array buffer and configure the mesh @param mesh Output mesh @@ -191,39 +193,44 @@ template std::tuple interleaveInt @param usage Vertex buffer usage @param attributes Attribute arrays and gaps -The same as @ref interleave(const T&, const U&...), but this function writes the -output to given array buffer and updates vertex count in the mesh accordingly, -so you don't have to call @ref Mesh::setVertexCount() on your own. +@deprecated Use general-purpose + @ref Magnum::MeshTools::interleave(const T&...) "interleave(const T&...)" + instead. + +The same as @ref interleave(const T&, const U&...), but this function also +writes the output to given array buffer. If given mesh is not indexed, it also +updates vertex count in the mesh accordingly, so you don't have to call +@ref Mesh::setCount() on your own. @attention You still must call @ref Mesh::setPrimitive() and @ref Mesh::addVertexBuffer() on the mesh afterwards. @see @ref compressIndices(), @ref compile() -@todo rework so Mesh & Buffer doesn't need to be included in header */ -template void interleave(Mesh& mesh, Buffer& buffer, BufferUsage usage, const T&... attributes) { - Containers::Array data; - std::size_t attributeCount; - std::tie(attributeCount, std::ignore, data) = interleave(attributes...); - - mesh.setVertexCount(attributeCount); - buffer.setData(data, usage); +template CORRADE_DEPRECATED("Use interleave(const T&...) instead") void interleave(Mesh& mesh, Buffer& buffer, BufferUsage usage, const T&... attributes) { + if(!mesh.isIndexed()) mesh.setCount(Implementation::AttributeCount{}(attributes...)); + buffer.setData(interleave(attributes...), usage); } /** @brief Write vertex attribute to array buffer and configure the mesh +@deprecated Use general-purpose + @ref Magnum::MeshTools::interleave(const T&...) "interleave(const T&...)" + instead. + Simplified specialization of the above function for only one attribute array, equivalent to the following: @code +if(!mesh.isIndexed()) mesh.setCount(attribute.size()); buffer.setData(attribute, usage); -mesh.setVertexCount(attribute.size()); @endcode */ -template typename std::enable_if::value, void>::type interleave(Mesh& mesh, Buffer& buffer, BufferUsage usage, const T& attribute) { - mesh.setVertexCount(attribute.size()); +template CORRADE_DEPRECATED("Use interleave(const T&...) instead") typename std::enable_if::value, void>::type interleave(Mesh& mesh, Buffer& buffer, BufferUsage usage, const T& attribute) { + if(!mesh.isIndexed()) mesh.setCount(attribute.size()); buffer.setData(attribute, usage); } +#endif }} diff --git a/src/Magnum/MeshTools/Test/CompressIndicesTest.cpp b/src/Magnum/MeshTools/Test/CompressIndicesTest.cpp index 45de3ae31..ddecc90fc 100644 --- a/src/Magnum/MeshTools/Test/CompressIndicesTest.cpp +++ b/src/Magnum/MeshTools/Test/CompressIndicesTest.cpp @@ -47,27 +47,29 @@ CompressIndicesTest::CompressIndicesTest() { } void CompressIndicesTest::compressChar() { - std::size_t indexCount; - Mesh::IndexType indexType; Containers::Array data; - std::tie(indexCount, indexType, data) = MeshTools::compressIndices( + Mesh::IndexType type; + UnsignedInt start, end; + std::tie(data, type, start, end) = MeshTools::compressIndices( std::vector{1, 2, 3, 0, 4}); - CORRADE_COMPARE(indexCount, 5); - CORRADE_VERIFY(indexType == Mesh::IndexType::UnsignedByte); + CORRADE_COMPARE(start, 0); + CORRADE_COMPARE(end, 4); + CORRADE_COMPARE(type, Mesh::IndexType::UnsignedByte); CORRADE_COMPARE(std::vector(data.begin(), data.end()), (std::vector{ 0x01, 0x02, 0x03, 0x00, 0x04 })); } void CompressIndicesTest::compressShort() { - std::size_t indexCount; - Mesh::IndexType indexType; Containers::Array data; - std::tie(indexCount, indexType, data) = MeshTools::compressIndices( + Mesh::IndexType type; + UnsignedInt start, end; + std::tie(data, type, start, end) = MeshTools::compressIndices( std::vector{1, 256, 0, 5}); - CORRADE_COMPARE(indexCount, 4); - CORRADE_VERIFY(indexType == Mesh::IndexType::UnsignedShort); + CORRADE_COMPARE(start, 0); + CORRADE_COMPARE(end, 256); + CORRADE_COMPARE(type, Mesh::IndexType::UnsignedShort); if(!Utility::Endianness::isBigEndian()) { CORRADE_COMPARE(std::vector(data.begin(), data.end()), (std::vector{ 0x01, 0x00, @@ -84,14 +86,15 @@ void CompressIndicesTest::compressShort() { } void CompressIndicesTest::compressInt() { - std::size_t indexCount; - Mesh::IndexType indexType; Containers::Array data; - std::tie(indexCount, indexType, data) = MeshTools::compressIndices( + Mesh::IndexType type; + UnsignedInt start, end; + std::tie(data, type, start, end) = MeshTools::compressIndices( std::vector{65536, 3, 2}); - CORRADE_COMPARE(indexCount, 3); - CORRADE_VERIFY(indexType == Mesh::IndexType::UnsignedInt); + CORRADE_COMPARE(start, 2); + CORRADE_COMPARE(end, 65536); + CORRADE_COMPARE(type, Mesh::IndexType::UnsignedInt); if(!Utility::Endianness::isBigEndian()) { CORRADE_COMPARE(std::vector(data.begin(), data.end()), diff --git a/src/Magnum/MeshTools/Test/InterleaveTest.cpp b/src/Magnum/MeshTools/Test/InterleaveTest.cpp index f79bf14b9..75c2cb250 100644 --- a/src/Magnum/MeshTools/Test/InterleaveTest.cpp +++ b/src/Magnum/MeshTools/Test/InterleaveTest.cpp @@ -87,16 +87,11 @@ void InterleaveTest::strideGaps() { } void InterleaveTest::write() { - std::size_t attributeCount; - std::size_t stride; - Containers::Array data; - std::tie(attributeCount, stride, data) = MeshTools::interleave( + const Containers::Array data = MeshTools::interleave( std::vector{0, 1, 2}, std::vector{3, 4, 5}, std::vector{6, 7, 8}); - CORRADE_COMPARE(attributeCount, std::size_t(3)); - CORRADE_COMPARE(stride, std::size_t(7)); if(!Utility::Endianness::isBigEndian()) { CORRADE_COMPARE(std::vector(data.begin(), data.end()), (std::vector{ 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, @@ -113,17 +108,11 @@ void InterleaveTest::write() { } void InterleaveTest::writeGaps() { - std::size_t attributeCount; - std::size_t stride; - Containers::Array data; - std::tie(attributeCount, stride, data) = MeshTools::interleave( + const Containers::Array data = MeshTools::interleave( std::vector{0, 1, 2}, 3, std::vector{3, 4, 5}, std::vector{6, 7, 8}, 2); - CORRADE_COMPARE(attributeCount, std::size_t(3)); - CORRADE_COMPARE(stride, std::size_t(12)); - if(!Utility::Endianness::isBigEndian()) { /* byte, _____________gap, int___________________, short_____, _______gap */ CORRADE_COMPARE(std::vector(data.begin(), data.end()), (std::vector{ @@ -142,8 +131,6 @@ void InterleaveTest::writeGaps() { } void InterleaveTest::interleaveInto() { - std::size_t attributeCount; - std::size_t stride; auto data = Containers::Array::from( 0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77, @@ -151,11 +138,7 @@ void InterleaveTest::interleaveInto() { 0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77 ); - std::tie(attributeCount, stride) = MeshTools::interleaveInto(data, - 2, std::vector{4, 5, 6, 7}, 1, std::vector{0, 1, 2, 3}, 3); - - CORRADE_COMPARE(attributeCount, std::size_t{4}); - CORRADE_COMPARE(stride, std::size_t{12}); + MeshTools::interleaveInto(data, 2, std::vector{4, 5, 6, 7}, 1, std::vector{0, 1, 2, 3}, 3); if(!Utility::Endianness::isBigEndian()) { /* _______gap, int___________________, _gap, short_____, _____________gap */ diff --git a/src/Magnum/MeshView.cpp b/src/Magnum/MeshView.cpp index 893b50c02..6db77e719 100644 --- a/src/Magnum/MeshView.cpp +++ b/src/Magnum/MeshView.cpp @@ -29,37 +29,31 @@ namespace Magnum { -#ifndef MAGNUM_TARGET_GLES2 -MeshView& MeshView::setIndexRange(Int first, Int count, UnsignedInt start, UnsignedInt end) -#else -MeshView& MeshView::setIndexRange(Int first, Int count, UnsignedInt, UnsignedInt) -#endif -{ +MeshView& MeshView::setIndexRange(Int first) { _indexOffset = _original->_indexOffset + first*_original->indexSize(); - _indexCount = count; - #ifndef MAGNUM_TARGET_GLES2 - _indexStart = start; - _indexEnd = end; - #endif return *this; } void MeshView::draw(AbstractShaderProgram& shader) { shader.use(); - #ifndef MAGNUM_TARGET_GLES2 - _original->drawInternal(_firstVertex, _vertexCount, _indexOffset, _indexCount, _indexStart, _indexEnd); + #ifndef MAGNUM_TARGET_GLES + _original->drawInternal(_count, _baseVertex, _instanceCount, _baseInstance, _indexOffset, _indexStart, _indexEnd); + #elif !defined(MAGNUM_TARGET_GLES2) + _original->drawInternal(_count, _baseVertex, _instanceCount, _indexOffset, _indexStart, _indexEnd); #else - _original->drawInternal(_firstVertex, _vertexCount, _indexOffset, _indexCount); + _original->drawInternal(_count, _baseVertex, _instanceCount, _indexOffset); #endif } #ifdef MAGNUM_BUILD_DEPRECATED void MeshView::draw() { - #ifndef MAGNUM_TARGET_GLES2 - _original->drawInternal(_firstVertex, _vertexCount, _indexOffset, _indexCount, _indexStart, _indexEnd); + #ifndef MAGNUM_TARGET_GLES + _original->drawInternal(_count, _baseVertex, _instanceCount, _baseInstance, _indexOffset, _indexStart, _indexEnd); + #elif !defined(MAGNUM_TARGET_GLES2) + _original->drawInternal(_count, _baseVertex, _instanceCount, _indexOffset, _indexStart, _indexEnd); #else - _original->drawInternal(_firstVertex, _vertexCount, _indexOffset, _indexCount); + _original->drawInternal(_count, _baseVertex, _instanceCount, _indexOffset); #endif } #endif diff --git a/src/Magnum/MeshView.h b/src/Magnum/MeshView.h index d283d6410..94d5ac7f2 100644 --- a/src/Magnum/MeshView.h +++ b/src/Magnum/MeshView.h @@ -71,50 +71,143 @@ class MAGNUM_EXPORT MeshView { /** @brief Movement is not allowed */ MeshView& operator=(MeshView&& other) = delete; + /** + * @brief Set vertex/index count + * @return Reference to self (for method chaining) + * + * Default is `0`. + */ + MeshView& setCount(Int count) { + _count = count; + return *this; + } + + /** + * @brief Set base vertex + * @return Reference to self (for method chaining) + * + * Sets number of vertices of which the vertex buffer will be offset + * when drawing. Default is `0`. + * @requires_gl32 %Extension @extension{ARB,draw_elements_base_vertex} + * for indexed meshes + * @requires_gl Base vertex cannot be specified for indexed meshes in + * OpenGL ES. + */ + MeshView& setBaseVertex(Int baseVertex) { + _baseVertex = baseVertex; + return *this; + } + + #ifdef MAGNUM_BUILD_DEPRECATED /** * @brief Set vertex range * @param first First vertex * @param count Vertex count - * @return Reference to self (for method chaining) * - * Default is zero @p offset and zero @p count. If index range is - * non-zero, vertex range is ignored, see main class documentation for - * more information. + * @deprecated Use @ref Magnum::MeshView::setCount() "setCount()" and + * @ref Magnum::MeshView::setBaseVertex() "setBaseVertex()" + * instead. */ - MeshView& setVertexRange(Int first, Int count) { - _firstVertex = first; - _vertexCount = count; - return *this; + CORRADE_DEPRECATED("use setCount() and setBaseVertex() instead") MeshView& setVertexRange(Int first, Int count) { + return setCount(count), setBaseVertex(first); } + #endif + + /** + * @brief Set index range + * @param first First vertex + * @param start Minimum array index contained in the buffer + * @param end Maximum array index contained in the buffer + * @return Reference to self (for method chaining) + * + * The @p start and @p end parameters may help to improve memory access + * performance, as only a portion of vertex buffer needs to be + * acccessed. On OpenGL ES 2.0 this function behaves the same as + * @ref setIndexRange(Int), as index range functionality is not + * available there. + * @see @ref setCount() + */ + MeshView& setIndexRange(Int first, UnsignedInt start, UnsignedInt end); + #ifdef MAGNUM_BUILD_DEPRECATED /** * @brief Set index range * @param first First index * @param count Index count * @param start Minimum array index contained in the buffer * @param end Maximum array index contained in the buffer + * + * @deprecated Use @ref Magnum::MeshView::setCount() "setCount()" and + * @ref Magnum::MeshView::setIndexRange(Int, UnsignedInt, UnsignedInt) "setIndexRange(Int, UnsignedInt, UnsignedInt)" + * instead. + */ + CORRADE_DEPRECATED("use setCount() and setIndexRange(Int, UnsignedInt, UnsignedInt) instead") MeshView& setIndexRange(Int first, Int count, UnsignedInt start, UnsignedInt end) { + return setCount(count), setIndexRange(first, start, end); + } + #endif + + /** + * @brief Set index range + * @param first First index * @return Reference to self (for method chaining) * - * Specifying `0` for both @p start and @p end behaves the same as - * @ref setIndexRange(Int, Int). On OpenGL ES 2.0 this function behaves - * always as @ref setIndexRange(Int, Int), as this functionality is - * not available there. + * Prefer to use @ref setIndexRange(Int, UnsignedInt, UnsignedInt) for + * better performance. + * @see @ref setCount() */ - MeshView& setIndexRange(Int first, Int count, UnsignedInt start, UnsignedInt end); + MeshView& setIndexRange(Int first); + #ifdef MAGNUM_BUILD_DEPRECATED /** * @brief Set index range * @param first First index * @param count Index count + * + * @deprecated Use @ref Magnum::MeshView::setCount() "setCount()" and + * @ref Magnum::MeshView::setIndexRange(Int) "setIndexRange(Int)" + * instead. + */ + CORRADE_DEPRECATED("use setCount() and setIndexRange(Int) instead") MeshView& setIndexRange(Int first, Int count) { + return setCount(count), setIndexRange(first); + } + #endif + + /** @brief Instance count */ + Int instanceCount() const { return _instanceCount; } + + /** + * @brief Set instance count * @return Reference to self (for method chaining) * - * Prefer to use @ref setIndexRange(Int, Int, UnsignedInt, UnsignedInt) - * for better performance. + * Default is `1`. + * @requires_gl31 %Extension @extension{ARB,draw_instanced} + * @requires_gles30 %Extension @es_extension{ANGLE,instanced_arrays}, + * @es_extension2{EXT,draw_instanced,draw_instanced} or + * @es_extension{NV,draw_instanced} in OpenGL ES 2.0. */ - MeshView& setIndexRange(Int first, Int count) { - return setIndexRange(first, count, 0, 0); + MeshView& setInstanceCount(Int count) { + _instanceCount = count; + return *this; } + #ifndef MAGNUM_TARGET_GLES + /** @brief Base instance */ + UnsignedInt baseInstance() const { return _baseInstance; } + + /** + * @brief Set base instance + * @return Reference to self (for method chaining) + * + * Default is `0`. + * @requires_gl42 %Extension @extension{ARB,base_instance} + * @requires_gl Base instance cannot be specified in OpenGL ES. + */ + MeshView& setBaseInstance(UnsignedInt baseInstance) { + _baseInstance = baseInstance; + return *this; + } + #endif + /** * @brief Draw the mesh * @@ -135,19 +228,38 @@ class MAGNUM_EXPORT MeshView { private: Mesh* _original; - Int _firstVertex, _vertexCount, _indexCount; + Int _count, _baseVertex, _instanceCount; + #ifndef MAGNUM_TARGET_GLES + UnsignedInt _baseInstance; + #endif GLintptr _indexOffset; #ifndef MAGNUM_TARGET_GLES2 UnsignedInt _indexStart, _indexEnd; #endif }; -inline MeshView::MeshView(Mesh& original): _original(&original), _firstVertex(0), _vertexCount(0), _indexCount(0), _indexOffset(0) +inline MeshView::MeshView(Mesh& original): _original(&original), _count(0), _baseVertex(0), _instanceCount{1}, + #ifndef MAGNUM_TARGET_GLES + _baseInstance{0}, + #endif + _indexOffset(0) #ifndef MAGNUM_TARGET_GLES2 , _indexStart(0), _indexEnd(0) #endif {} +inline MeshView& MeshView::setIndexRange(Int first, UnsignedInt start, UnsignedInt end) { + setIndexRange(first); + #ifndef MAGNUM_TARGET_GLES2 + _indexStart = start; + _indexEnd = end; + #else + static_cast(start); + static_cast(end); + #endif + return *this; +} + } #endif diff --git a/src/Magnum/MultisampleTexture.cpp b/src/Magnum/MultisampleTexture.cpp new file mode 100644 index 000000000..7705168ce --- /dev/null +++ b/src/Magnum/MultisampleTexture.cpp @@ -0,0 +1,51 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014 + 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 "MultisampleTexture.h" + +#ifndef MAGNUM_TARGET_GLES +#include "Magnum/Context.h" +#include "Magnum/Extensions.h" + +#include "Implementation/maxTextureSize.h" + +namespace Magnum { namespace Implementation { + +template<> Vector2i MAGNUM_EXPORT maxMultisampleTextureSize<2>() { + if(!Context::current()->isExtensionSupported()) + return {}; + + return Vector2i{Implementation::maxTextureSideSize()}; +} + +template<> Vector3i MAGNUM_EXPORT maxMultisampleTextureSize<3>() { + if(!Context::current()->isExtensionSupported()) + return {}; + + return {Vector2i{Implementation::maxTextureSideSize()}, Implementation::max3DTextureDepth()}; +} + +}} +#endif diff --git a/src/Magnum/MultisampleTexture.h b/src/Magnum/MultisampleTexture.h index 05d54a2c3..882aaff60 100644 --- a/src/Magnum/MultisampleTexture.h +++ b/src/Magnum/MultisampleTexture.h @@ -42,6 +42,10 @@ namespace Implementation { template constexpr GLenum multisampleTextureTarget(); template<> inline constexpr GLenum multisampleTextureTarget<2>() { return GL_TEXTURE_2D_MULTISAMPLE; } template<> inline constexpr GLenum multisampleTextureTarget<3>() { return GL_TEXTURE_2D_MULTISAMPLE_ARRAY; } + + template typename DimensionTraits::VectorType maxMultisampleTextureSize(); + template<> Vector2i maxMultisampleTextureSize<2>(); + template<> Vector3i maxMultisampleTextureSize<3>(); } /** @@ -57,27 +61,47 @@ enum class MultisampleTextureSampleLocations: GLboolean { /** @brief Mulitsample texture -Template class for 2D mulitsample texture and 2D multisample texture array. See +Template class for 2D mulitsample texture and 2D multisample texture array. +Used only from shaders for manual multisample resolve and other operations. See also @ref AbstractTexture documentation for more information. -@todoc Finish when fully implemented +@section Texture-usage Usage + +As multisample textures have no sampler state, the only thing you need is to +set storage: +@code +MultisampleTexture2D texture; +texture.setStorage(16, TextureFormat::RGBA8, {1024, 1024}); +@endcode In shader, the texture is used via `sampler2DMS`/`sampler2DMSArray`, `isampler2DMS`/`isampler2DMSArray` or `usampler2DMS`/`usampler2DMSArray`. See @ref AbstractShaderProgram documentation for more information about usage in shaders. +@see @ref MultisampleTexture2D, @ref MultisampleTexture2DArray, @ref Texture, + @ref TextureArray, @ref CubeMapTexture, @ref CubeMapTextureArray, + @ref RectangleTexture, @ref BufferTexture @requires_gl32 %Extension @extension{ARB,texture_multisample} @requires_gl Multisample textures are not available in OpenGL ES. - -@see @ref MultisampleTexture2D, @ref MultisampleTexture2DArray, @ref Texture, - @ref TextureArray, @ref BufferTexture, @ref CubeMapTexture, - @ref CubeMapTextureArray, @ref RectangleTexture */ template class MultisampleTexture: public AbstractTexture { public: static const UnsignedInt Dimensions = dimensions; /**< @brief %Texture dimension count */ + /** + * @brief Max supported multisample texture size + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,texture_multisample} (part + * of OpenGL 3.2) is not available, returns zero vector. + * @see @fn_gl{Get} with @def_gl{MAX_TEXTURE_SIZE} and + * @def_gl{MAX_3D_TEXTURE_SIZE} + */ + static typename DimensionTraits::VectorType maxSize() { + return Implementation::maxMultisampleTextureSize(); + } + /** * @brief Constructor * @@ -120,7 +144,7 @@ template class MultisampleTexture: public AbstractTextur * @extension{ARB,texture_storage} functionality (which unfortunately * doesn't have any DSA alternative, so the texture must be bound * to some texture unit before). - * @see @ref maxColorSamples(), @ref maxDepthSamples(), + * @see @ref maxSize(), @ref maxColorSamples(), @ref maxDepthSamples(), * @ref maxIntegerSamples(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} * and @fn_gl{TexStorage2DMultisample}/@fn_gl{TexStorage3DMultisample} * or @fn_gl_extension{TextureStorage2DMultisample,EXT,direct_state_access}/ diff --git a/src/Magnum/Platform/AbstractXApplication.h b/src/Magnum/Platform/AbstractXApplication.h index 1de3a2b3e..49397ca48 100644 --- a/src/Magnum/Platform/AbstractXApplication.h +++ b/src/Magnum/Platform/AbstractXApplication.h @@ -228,19 +228,19 @@ class AbstractXApplication::Configuration { return *this; } - /** @copydoc GlutApplication::Configuration::size() */ + /** @copydoc Sdl2Application::Configuration::size() */ Vector2i size() const { return _size; } - /** @copydoc GlutApplication::Configuration::setSize() */ + /** @copydoc Sdl2Application::Configuration::setSize() */ Configuration& setSize(const Vector2i& size) { _size = size; return *this; } - /** @copydoc GlutApplication::Configuration::version() */ + /** @copydoc Sdl2Application::Configuration::version() */ Version version() const { return _version; } - /** @copydoc GlutApplication::Configuration::setVersion() */ + /** @copydoc Sdl2Application::Configuration::setVersion() */ Configuration& setVersion(Version version) { _version = version; return *this; diff --git a/src/Magnum/Platform/AndroidApplication.h b/src/Magnum/Platform/AndroidApplication.h index 38d482c4b..4b9a2431f 100644 --- a/src/Magnum/Platform/AndroidApplication.h +++ b/src/Magnum/Platform/AndroidApplication.h @@ -59,14 +59,14 @@ CMake. ## Bootstrap application -Fully contained base application using @ref GlutApplication for desktop build +Fully contained base application using @ref Sdl2Application for desktop build and @ref AndroidApplication for Android build along with full Android packaging stuff and CMake setup is available in `base-android` branch of [Magnum Bootstrap](https://github.com/mosra/magnum-bootstrap) repository, download it as [tar.gz](https://github.com/mosra/magnum-bootstrap/archive/base-android.tar.gz) or [zip](https://github.com/mosra/magnum-bootstrap/archive/base-android.zip) file. After extracting the downloaded archive, you can do the desktop build in the -same way as with @ref GlutApplication. For the Android build you also +same way as with @ref Sdl2Application. For the Android build you also need to put the contents of toolchains repository from https://github.com/mosra/toolchains in `toolchains/` subdirectory. Don't forget to adapt `ANDROID_NDK_ROOT` in `toolchains/generic/Android-*.cmake` to path where NDK is installed. Default is diff --git a/src/Magnum/Platform/GlxApplication.h b/src/Magnum/Platform/GlxApplication.h index 773d8b937..27adbda03 100644 --- a/src/Magnum/Platform/GlxApplication.h +++ b/src/Magnum/Platform/GlxApplication.h @@ -76,10 +76,10 @@ to simplify porting. */ class GlxApplication: public AbstractXApplication { public: - /** @copydoc Sdl2Application::GlutApplication(const Arguments&, const Configuration&) */ + /** @copydoc Sdl2Application::Sdl2Application(const Arguments&, const Configuration&) */ explicit GlxApplication(const Arguments& arguments, const Configuration& configuration = Configuration()); - /** @copydoc Sdl2Application::GlutApplication(const Arguments&, std::nullptr_t) */ + /** @copydoc Sdl2Application::Sdl2Application(const Arguments&, std::nullptr_t) */ #ifndef CORRADE_GCC45_COMPATIBILITY explicit GlxApplication(const Arguments& arguments, std::nullptr_t); #else diff --git a/src/Magnum/Platform/NaClApplication.h b/src/Magnum/Platform/NaClApplication.h index c2172933c..fa28b655c 100644 --- a/src/Magnum/Platform/NaClApplication.h +++ b/src/Magnum/Platform/NaClApplication.h @@ -72,14 +72,14 @@ CMake. ## Bootstrap application -Fully contained base application using @ref GlutApplication for desktop build +Fully contained base application using @ref Sdl2Application for desktop build and @ref NaClApplication for Native Client build along with full HTML markup and CMake setup is available in `base-nacl` branch of [Magnum Bootstrap](https://github.com/mosra/magnum-bootstrap) repository, download it as [tar.gz](https://github.com/mosra/magnum-bootstrap/archive/base-nacl.tar.gz) or [zip](https://github.com/mosra/magnum-bootstrap/archive/base-nacl.zip) file. After extracting the downloaded archive, you can do the desktop build in the -same way as with @ref GlutApplication. For the Native Client build you also +same way as with @ref Sdl2Application. For the Native Client build you also need to put the contents of toolchains repository from https://github.com/mosra/toolchains in `toolchains/` subdirectory. Don't forget to adapt `NACL_PREFIX` variable in `toolchains/generic/NaCl-newlib-x86-32.cmake` and diff --git a/src/Magnum/Platform/Sdl2Application.cpp b/src/Magnum/Platform/Sdl2Application.cpp index c4fbe5950..35e626c67 100644 --- a/src/Magnum/Platform/Sdl2Application.cpp +++ b/src/Magnum/Platform/Sdl2Application.cpp @@ -340,7 +340,7 @@ Sdl2Application::Configuration::Configuration(): #ifndef CORRADE_TARGET_EMSCRIPTEN _title("Magnum SDL2 Application"), #endif - _size(800, 600), _windowFlags(WindowFlag::Resizable), _sampleCount(0) + _size(800, 600), _windowFlags{}, _sampleCount(0) #ifndef CORRADE_TARGET_EMSCRIPTEN , _version(Version::None) #endif diff --git a/src/Magnum/Platform/Sdl2Application.h b/src/Magnum/Platform/Sdl2Application.h index da83b8bcc..f0c53d177 100644 --- a/src/Magnum/Platform/Sdl2Application.h +++ b/src/Magnum/Platform/Sdl2Application.h @@ -538,7 +538,7 @@ class Sdl2Application::Configuration { * @brief Set window flags * @return Reference to self (for method chaining) * - * Default is @ref WindowFlag::Resizable. + * Default are none. */ Configuration& setWindowFlags(WindowFlags flags) { _windowFlags = flags; diff --git a/src/Magnum/Platform/XEglApplication.h b/src/Magnum/Platform/XEglApplication.h index 0d9e6cd2b..e82f38e36 100644 --- a/src/Magnum/Platform/XEglApplication.h +++ b/src/Magnum/Platform/XEglApplication.h @@ -76,10 +76,10 @@ to simplify porting. */ class XEglApplication: public AbstractXApplication { public: - /** @copydoc Sdl2Application::GlutApplication(const Arguments&, const Configuration&) */ + /** @copydoc Sdl2Application::Sdl2Application(const Arguments&, const Configuration&) */ explicit XEglApplication(const Arguments& arguments, const Configuration& configuration = Configuration()); - /** @copydoc Sdl2Application::GlutApplication(const Arguments&, std::nullptr_t) */ + /** @copydoc Sdl2Application::Sdl2Application(const Arguments&, std::nullptr_t) */ #ifndef CORRADE_GCC45_COMPATIBILITY explicit XEglApplication(const Arguments& arguments, std::nullptr_t); #else diff --git a/src/Magnum/Platform/magnum-info.cpp b/src/Magnum/Platform/magnum-info.cpp index 4c9e26e6a..ef9e13ae0 100644 --- a/src/Magnum/Platform/magnum-info.cpp +++ b/src/Magnum/Platform/magnum-info.cpp @@ -40,8 +40,16 @@ #include "Magnum/Extensions.h" #include "Magnum/Framebuffer.h" #include "Magnum/Mesh.h" +#ifndef MAGNUM_TARGET_GLES +#include "Magnum/MultisampleTexture.h" +#include "Magnum/RectangleTexture.h" +#endif #include "Magnum/Renderbuffer.h" #include "Magnum/Shader.h" +#include "Magnum/Texture.h" +#ifndef MAGNUM_TARGET_GLES2 +#include "Magnum/TextureArray.h" +#endif #ifndef CORRADE_TARGET_NACL #include "Magnum/Platform/WindowlessGlxApplication.h" #else @@ -220,9 +228,10 @@ MagnumInfo::MagnumInfo(const Arguments& arguments): Platform::WindowlessApplicat /* Limits and implementation-defined values */ #define _h(val) Debug() << "\n " << Extensions::GL::val::string() + std::string(":"); #define _l(val) Debug() << " " << #val << (sizeof(#val) > 64 ? "\n" + std::string(68, ' ') : std::string(64 - sizeof(#val), ' ')) << val; + #define _lvec(val) Debug() << " " << #val << (sizeof(#val) > 48 ? "\n" + std::string(52, ' ') : std::string(48 - sizeof(#val), ' ')) << val; Debug() << "Limits and implementation-defined values:"; - _l(AbstractFramebuffer::maxViewportSize()) + _lvec(AbstractFramebuffer::maxViewportSize()) _l(AbstractFramebuffer::maxDrawBuffers()) _l(Framebuffer::maxColorAttachments()) #ifndef MAGNUM_TARGET_GLES2 @@ -259,6 +268,16 @@ MagnumInfo::MagnumInfo(const Arguments& arguments): Platform::WindowlessApplicat _l(AbstractTexture::maxDepthSamples()) _l(AbstractTexture::maxIntegerSamples()) #endif + #ifndef MAGNUM_TARGET_GLES2 + _l(AbstractTexture::maxLodBias()) + #endif + #ifndef MAGNUM_TARGET_GLES + _lvec(Texture1D::maxSize()) + #endif + _lvec(Texture2D::maxSize()) + #ifndef MAGNUM_TARGET_GLES2 + _lvec(Texture3D::maxSize()) + #endif #ifndef MAGNUM_TARGET_GLES if(c->isExtensionSupported()) { @@ -344,11 +363,30 @@ MagnumInfo::MagnumInfo(const Arguments& arguments): Platform::WindowlessApplicat _l(Shader::maxTessellationEvaluationOutputComponents()) } + if(c->isExtensionSupported()) { + _h(ARB::texture_buffer_object) + + _l(BufferTexture::maxSize()) + } + if(c->isExtensionSupported()) { _h(ARB::texture_buffer_range) _l(BufferTexture::offsetAlignment()) } + + if(c->isExtensionSupported()) { + _h(ARB::texture_multisample) + + _lvec(MultisampleTexture2D::maxSize()) + _lvec(MultisampleTexture2DArray::maxSize()) + } + + if(c->isExtensionSupported()) { + _h(ARB::texture_rectangle) + + _lvec(RectangleTexture::maxSize()) + } #endif /** @todo Somehow sort the following into previous list for ES3 */ @@ -394,6 +432,20 @@ MagnumInfo::MagnumInfo(const Arguments& arguments): Platform::WindowlessApplicat _l(AbstractShaderProgram::minTexelOffset()) _l(AbstractShaderProgram::maxTexelOffset()) } + + #ifndef MAGNUM_TARGET_GLES + if(c->isExtensionSupported()) + #endif + { + #ifndef MAGNUM_TARGET_GLES + _h(EXT::texture_array) + #endif + + #ifndef MAGNUM_TARGET_GLES + _lvec(Texture1DArray::maxSize()) + #endif + _lvec(Texture2DArray::maxSize()) + } #endif if(c->isExtensionSupported()) { @@ -410,6 +462,14 @@ MagnumInfo::MagnumInfo(const Arguments& arguments): Platform::WindowlessApplicat _l(DebugMessage::maxMessageLength()) } + #ifdef MAGNUM_TARGET_GLES2 + if(c->isExtensionSupported()) { + _h(OES::texture_3D) + + _lvec(Texture3D::maxSize()) + } + #endif + #undef _l #undef _h } diff --git a/src/Magnum/RectangleTexture.cpp b/src/Magnum/RectangleTexture.cpp new file mode 100644 index 000000000..8fcf6ec00 --- /dev/null +++ b/src/Magnum/RectangleTexture.cpp @@ -0,0 +1,50 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014 + 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 "RectangleTexture.h" + +#ifndef MAGNUM_TARGET_GLES +#include "Magnum/Context.h" +#include "Magnum/Extensions.h" + +#include "Implementation/State.h" +#include "Implementation/TextureState.h" + +namespace Magnum { + +Vector2i RectangleTexture::maxSize() { + if(!Context::current()->isExtensionSupported()) + return {}; + + GLint& value = Context::current()->state().texture->maxRectangleSize; + + if(value == 0) + glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE, &value); + + return Vector2i{value}; +} + +} +#endif diff --git a/src/Magnum/RectangleTexture.h b/src/Magnum/RectangleTexture.h index 1e4b5ba35..3b5e4c5f9 100644 --- a/src/Magnum/RectangleTexture.h +++ b/src/Magnum/RectangleTexture.h @@ -63,14 +63,23 @@ In shader, the texture is used via sampler2DRect`, `sampler2DRectShadow`, `isampler2DRect` or `usampler2DRect`. See @ref AbstractShaderProgram documentation for more information about usage in shaders. +@see @ref Texture, @ref TextureArray, @ref CubeMapTexture, + @ref CubeMapTextureArray, @ref BufferTexture, @ref MultisampleTexture @requires_gl31 %Extension @extension{ARB,texture_rectangle} @requires_gl Rectangle textures are not available in OpenGL ES. - -@see @ref Texture, @ref TextureArray, @ref BufferTexture, @ref CubeMapTexture, - @ref CubeMapTextureArray, @ref MultisampleTexture */ -class RectangleTexture: public AbstractTexture { +class MAGNUM_EXPORT RectangleTexture: public AbstractTexture { public: + /** + * @brief Max supported rectangle texture size + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If @extension{ARB,texture_rectangle} (part of + * OpenGL 3.1) is not available, returns zero vector. + * @see @fn_gl{Get} with @def_gl{MAX_RECTANGLE_TEXTURE_SIZE} + */ + static Vector2i maxSize(); + /** * @brief Constructor * @@ -88,8 +97,9 @@ class RectangleTexture: public AbstractTexture { * texture size. If @extension{EXT,direct_state_access} is not * available, the texture is bound to some texture unit before the * operation. Initial value is @ref Sampler::Filter::Linear. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexParameter} - * or @fn_gl_extension{TextureParameter,EXT,direct_state_access} + * @see @ref setMagnificationFilter(), @fn_gl{ActiveTexture}, + * @fn_gl{BindTexture} and @fn_gl{TexParameter} or + * @fn_gl_extension{TextureParameter,EXT,direct_state_access} * with @def_gl{TEXTURE_MIN_FILTER} */ RectangleTexture& setMinificationFilter(Sampler::Filter filter) { @@ -109,7 +119,7 @@ class RectangleTexture: public AbstractTexture { * The result is not cached in any way. If * @extension{EXT,direct_state_access} is not available, the texture * is bound to some texture unit before the operation. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @see @ref image(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and * @fn_gl{GetTexLevelParameter} or @fn_gl_extension{GetTextureLevelParameter,EXT,direct_state_access} * with @def_gl{TEXTURE_WIDTH} and @def_gl{TEXTURE_HEIGHT} */ @@ -120,16 +130,17 @@ class RectangleTexture: public AbstractTexture { * @param wrapping Wrapping type for all texture dimensions * @return Reference to self (for method chaining) * - * Sets wrapping type for coordinates out of (0, textureSizeInGivenDirection-1) + * Sets wrapping type for coordinates out of @f$ [ 0, size - 1 ] @f$ * range. If @extension{EXT,direct_state_access} is not available, the * texture is bound to some texture unit before the operation. Initial * value is @ref Sampler::Wrapping::ClampToEdge. * @attention Only @ref Sampler::Wrapping::ClampToEdge and * @ref Sampler::Wrapping::ClampToBorder is supported on this * texture type. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexParameter} - * or @fn_gl_extension{TextureParameter,EXT,direct_state_access} - * with @def_gl{TEXTURE_WRAP_S}, @def_gl{TEXTURE_WRAP_T}, + * @see @ref setBorderColor(), @fn_gl{ActiveTexture}, + * @fn_gl{BindTexture} and @fn_gl{TexParameter} or + * @fn_gl_extension{TextureParameter,EXT,direct_state_access} with + * @def_gl{TEXTURE_WRAP_S}, @def_gl{TEXTURE_WRAP_T}, * @def_gl{TEXTURE_WRAP_R} */ RectangleTexture& setWrapping(const Array2D& wrapping) { @@ -138,16 +149,11 @@ class RectangleTexture: public AbstractTexture { } /** - * @brief Set border color + * @copybrief Texture::setBorderColor(const Color4&) * @return Reference to self (for method chaining) * - * Border color when wrapping is set to @ref Sampler::Wrapping::ClampToBorder. - * If @extension{EXT,direct_state_access} is not available, the texture - * is bound to some texture unit before the operation. Initial value is - * `{0.0f, 0.0f, 0.0f, 0.0f}`. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexParameter} - * or @fn_gl_extension{TextureParameter,EXT,direct_state_access} - * with @def_gl{TEXTURE_BORDER_COLOR} + * See @ref Texture::setBorderColor(const Color4&) for more + * information. */ RectangleTexture& setBorderColor(const Color4& color) { AbstractTexture::setBorderColor(color); @@ -155,25 +161,23 @@ class RectangleTexture: public AbstractTexture { } /** - * @brief Set border color for integer texture + * @copybrief Texture::setBorderColor(const Vector4ui&) * @return Reference to self (for method chaining) * - * Border color for integer textures when wrapping is set to - * @ref Sampler::Wrapping::ClampToBorder. If @extension{EXT,direct_state_access} - * is not available, the texture is bound to some texture unit before - * the operation. Initial value is `{0, 0, 0, 0}`. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexParameter} - * or @fn_gl_extension{TextureParameter,EXT,direct_state_access} - * with @def_gl{TEXTURE_BORDER_COLOR} - * @requires_gl30 %Extension @extension{EXT,texture_integer} + * See @ref Texture::setBorderColor(const Vector4ui&) for more + * information. */ RectangleTexture& setBorderColor(const Vector4ui& color) { AbstractTexture::setBorderColor(color); return *this; } - /** @overload - * @requires_gl30 %Extension @extension{EXT,texture_integer} + /** + * @copybrief Texture::setBorderColor(const Vector4ui&) + * @return Reference to self (for method chaining) + * + * See @ref Texture::setBorderColor(const Vector4i&) for more + * information. */ RectangleTexture& setBorderColor(const Vector4i& color) { AbstractTexture::setBorderColor(color); @@ -186,6 +190,50 @@ class RectangleTexture: public AbstractTexture { return *this; } + /** + * @copybrief Texture::setSwizzle() + * @return Reference to self (for method chaining) + * + * See @ref Texture::setSwizzle() for more information. + */ + template RectangleTexture& setSwizzle() { + AbstractTexture::setSwizzle(); + return *this; + } + + /** + * @copybrief Texture::setCompareMode() + * @return Reference to self (for method chaining) + * + * See @ref Texture::setCompareMode() for more information. + */ + RectangleTexture& setCompareMode(Sampler::CompareMode mode) { + AbstractTexture::setCompareMode(mode); + return *this; + } + + /** + * @copybrief Texture::setCompareFunction() + * @return Reference to self (for method chaining) + * + * See @ref Texture::setCompareFunction() for more information. + */ + RectangleTexture& setCompareFunction(Sampler::CompareFunction function) { + AbstractTexture::setCompareFunction(function); + return *this; + } + + /** + * @copybrief Texture::setDepthStencilMode() + * @return Reference to self (for method chaining) + * + * See @ref Texture::setDepthStencilMode() for more information. + */ + RectangleTexture& setDepthStencilMode(Sampler::DepthStencilMode mode) { + AbstractTexture::setDepthStencilMode(mode); + return *this; + } + /** * @brief Set storage * @param internalFormat Internal format @@ -203,8 +251,9 @@ class RectangleTexture: public AbstractTexture { * @extension{ARB,texture_storage} (part of OpenGL 4.2), OpenGL ES 3.0 * or @es_extension{EXT,texture_storage} in OpenGL ES 2.0 is not * available, the feature is emulated with @ref setImage() call. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexStorage2D} - * or @fn_gl_extension{TextureStorage2D,EXT,direct_state_access}, + * @see @ref maxSize(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{TexStorage2D} or + * @fn_gl_extension{TextureStorage2D,EXT,direct_state_access}, * eventually @fn_gl{TexImage2D} or * @fn_gl_extension{TextureImage2D,EXT,direct_state_access}. */ @@ -261,8 +310,9 @@ class RectangleTexture: public AbstractTexture { * * If @extension{EXT,direct_state_access} is not available, the * texture is bound to some texture unit before the operation. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexImage2D} - * or @fn_gl_extension{TextureImage2D,EXT,direct_state_access} + * @see @ref maxSize(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{TexImage2D} or + * @fn_gl_extension{TextureImage2D,EXT,direct_state_access} */ RectangleTexture& setImage(TextureFormat internalFormat, const ImageReference2D& image) { DataHelper<2>::setImage(*this, _target, 0, internalFormat, image); diff --git a/src/Magnum/Renderer.h b/src/Magnum/Renderer.h index ff2226294..b26bd93f2 100644 --- a/src/Magnum/Renderer.h +++ b/src/Magnum/Renderer.h @@ -145,7 +145,7 @@ class MAGNUM_EXPORT Renderer { /** * Multisampling. Enabled by default. Note that the actual presence * of this feature in default framebuffer depends on context - * configuration, see for example Platform::GlutApplication::Configuration::setSampleCount(). + * configuration, see for example @ref Platform::Sdl2Application::Configuration::setSampleCount(). * @requires_gl Always enabled in OpenGL ES. */ Multisampling = GL_MULTISAMPLE, diff --git a/src/Magnum/Sampler.cpp b/src/Magnum/Sampler.cpp index 35de1dab4..7a886575b 100644 --- a/src/Magnum/Sampler.cpp +++ b/src/Magnum/Sampler.cpp @@ -99,6 +99,47 @@ Debug operator<<(Debug debug, const Sampler::Wrapping value) { return debug << "Sampler::Wrapping::(invalid)"; } + +Debug operator<<(Debug debug, const Sampler::CompareMode value) { + switch(value) { + #define _c(value) case Sampler::CompareMode::value: return debug << "Sampler::CompareMode::" #value; + _c(None) + _c(CompareRefToTexture) + #undef _c + } + + return debug << "Sampler::CompareFunction::(invalid)"; +} + +Debug operator<<(Debug debug, const Sampler::CompareFunction value) { + switch(value) { + #define _c(value) case Sampler::CompareFunction::value: return debug << "Sampler::CompareFunction::" #value; + _c(Never) + _c(Always) + _c(Less) + _c(LessOrEqual) + _c(Equal) + _c(NotEqual) + _c(GreaterOrEqual) + _c(Greater) + #undef _c + } + + return debug << "Sampler::CompareFunction::(invalid)"; +} + +#ifndef MAGNUM_TARGET_GLES +Debug operator<<(Debug debug, const Sampler::DepthStencilMode value) { + switch(value) { + #define _c(value) case Sampler::DepthStencilMode::value: return debug << "Sampler::DepthStencilMode::" #value; + _c(DepthComponent) + _c(StencilIndex) + #undef _c + } + + return debug << "Sampler::DepthStencilMode::(invalid)"; +} +#endif #endif } diff --git a/src/Magnum/Sampler.h b/src/Magnum/Sampler.h index 51a6ba890..286c10fa1 100644 --- a/src/Magnum/Sampler.h +++ b/src/Magnum/Sampler.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::Sampler + * @brief Class @ref Magnum::Sampler */ #include "Magnum/Magnum.h" @@ -38,14 +38,16 @@ namespace Magnum { /** @brief %Texture sampler -@see Texture, CubeMapTexture, CubeMapTextureArray +@see @ref Texture, @ref TextureArray, @ref CubeMapTexture, + @ref CubeMapTextureArray, @ref RectangleTexture */ class MAGNUM_EXPORT Sampler { public: /** * @brief %Texture filtering * - * @see setMagnificationFilter() and setMinificationFilter() + * @see @ref Texture::setMinificationFilter() "*Texture::setMinificationFilter()", + * @ref Texture::setMagnificationFilter() "*Texture::setMagnificationFilter()" */ enum class Filter: GLint { Nearest = GL_NEAREST, /**< Nearest neighbor filtering */ @@ -65,7 +67,7 @@ class MAGNUM_EXPORT Sampler { /** * @brief Mip level selection * - * @see setMinificationFilter() + * @see @ref Texture::setMinificationFilter() "*Texture::setMinificationFilter()" */ enum class Mipmap: GLint { Base = GL_NEAREST & ~GL_NEAREST, /**< Select base mip level */ @@ -91,7 +93,7 @@ class MAGNUM_EXPORT Sampler { /** * @brief %Texture wrapping * - * @see setWrapping() + * @see @ref Texture::setWrapping() "*Texture::setWrapping()" */ enum class Wrapping: GLint { /** Repeat texture. **Unavailable on rectangle textures.** */ @@ -110,7 +112,8 @@ class MAGNUM_EXPORT Sampler { /** * Clamp to border color. Coordinates out of range will be clamped - * to border color (set with setBorderColor()). + * to border color (set with + * @ref Texture::setBorderColor() "*Texture::setBorderColor()"). * @requires_es_extension %Extension @es_extension{NV,texture_border_clamp} */ #ifndef MAGNUM_TARGET_GLES @@ -133,13 +136,100 @@ class MAGNUM_EXPORT Sampler { #endif }; + /** + * @brief Depth texture comparison mode + * + * @see @ref CompareFunction, + * @ref Texture::setCompareMode() "*Texture::setCompareMode()" + * @requires_gles30 %Extension @es_extension{EXT,shadow_samplers} + */ + enum class CompareMode: GLenum { + /** Directly output the depth value */ + None = GL_NONE, + + /** Use output from specified @ref CompareFunction */ + CompareRefToTexture = + #ifndef MAGNUM_TARGET_GLES2 + GL_COMPARE_REF_TO_TEXTURE + #else + GL_COMPARE_REF_TO_TEXTURE_EXT + #endif + }; + + /** + * @brief Depth texture comparison function + * + * Comparison operator used when comparison mode is set to + * @ref CompareMode::CompareRefToTexture. + * @see @ref Texture::setCompareFunction() "*Texture::setCompareFunction()", + * @ref Texture::setCompareMode() "*Texture::setCompareMode()" + * @requires_gles30 %Extension @es_extension{EXT,shadow_samplers} + */ + enum class CompareFunction: GLenum { + Never = GL_NEVER, /**< Always `0.0` */ + Always = GL_ALWAYS, /**< Always `1.0` */ + + /** + * `1.0` when texture coordinate is less than depth value, `0.0` + * otherwise + */ + Less = GL_LESS, + + /** + * `1.0` when texture coordinate is less than or equal to depth + * value, `0.0` otherwise + */ + LessOrEqual = GL_LEQUAL, + + /** + * `1.0` when texture coordinate is equal to depth value, `0.0` + * otherwise + */ + Equal = GL_EQUAL, + + /** + * `0.0` when texture coordinate is equal to depth value, `1.0` + * otherwise + */ + NotEqual = GL_NOTEQUAL, + + /** + * `1.0` when texture coordinate is greater than or equal to depth + * value, `0.0` otherwise + */ + GreaterOrEqual = GL_GEQUAL, + + /** + * `1.0` when texture coordinate is greater than depth value, `0.0` + * otherwise + */ + Greater = GL_GREATER + }; + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Depth/stencil texture mode + * + * @see @ref Texture::setDepthStencilMode() "*Texture::setDepthStencilMode()" + * @requires_gl43 %Extension @extension{ARB,stencil_texturing} + * @requires_gl Stencil texturing is not available in OpenGL ES. + */ + enum class DepthStencilMode: GLenum { + /** Sample depth component */ + DepthComponent = GL_DEPTH_COMPONENT, + + /** Sample stencil index (as unsigned integer texture) */ + StencilIndex = GL_STENCIL_INDEX + }; + #endif + /** * @brief Max supported max anisotropy * * The result is cached, repeated queries don't result in repeated * OpenGL calls. If extension @extension{EXT,texture_filter_anisotropic} * (desktop or ES) is not available, returns `0.0f`. - * @see setMaxAnisotropy(), @fn_gl{Get} with @def_gl{MAX_TEXTURE_MAX_ANISOTROPY_EXT} + * @see @fn_gl{Get} with @def_gl{MAX_TEXTURE_MAX_ANISOTROPY_EXT} */ static Float maxMaxAnisotropy(); @@ -162,6 +252,17 @@ Debug MAGNUM_EXPORT operator<<(Debug debug, Sampler::Mipmap value); /** @debugoperator{Magnum::Sampler} */ Debug MAGNUM_EXPORT operator<<(Debug debug, Sampler::Wrapping value); +/** @debugoperator{Magnum::Sampler} */ +Debug MAGNUM_EXPORT operator<<(Debug debug, Sampler::CompareMode value); + +/** @debugoperator{Magnum::Sampler} */ +Debug MAGNUM_EXPORT operator<<(Debug debug, Sampler::CompareFunction value); + +#ifndef MAGNUM_TARGET_GLES +/** @debugoperator{Magnum::Sampler} */ +Debug MAGNUM_EXPORT operator<<(Debug debug, Sampler::DepthStencilMode value); +#endif + } #endif diff --git a/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp b/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp index e6f9fdf63..5fadb807a 100644 --- a/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp +++ b/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp @@ -44,6 +44,8 @@ class CubeMapTextureArrayGLTest: public AbstractOpenGLTester { void sampling(); void samplingBorderInteger(); + void samplingSwizzle(); + void samplingDepthStencilMode(); void storage(); @@ -64,6 +66,8 @@ CubeMapTextureArrayGLTest::CubeMapTextureArrayGLTest() { &CubeMapTextureArrayGLTest::sampling, &CubeMapTextureArrayGLTest::samplingBorderInteger, + &CubeMapTextureArrayGLTest::samplingSwizzle, + &CubeMapTextureArrayGLTest::samplingDepthStencilMode, &CubeMapTextureArrayGLTest::storage, @@ -123,16 +127,23 @@ void CubeMapTextureArrayGLTest::sampling() { CubeMapTextureArray texture; texture.setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) .setMagnificationFilter(Sampler::Filter::Linear) + .setMinLod(-750.0f) + .setMaxLod(750.0f) + .setLodBias(0.5f) .setBaseLevel(1) .setMaxLevel(750) .setWrapping(Sampler::Wrapping::ClampToBorder) .setBorderColor(Color3(0.5f)) - .setMaxAnisotropy(Sampler::maxMaxAnisotropy()); + .setMaxAnisotropy(Sampler::maxMaxAnisotropy()) + .setCompareMode(Sampler::CompareMode::CompareRefToTexture) + .setCompareFunction(Sampler::CompareFunction::GreaterOrEqual); MAGNUM_VERIFY_NO_ERROR(); } void CubeMapTextureArrayGLTest::samplingBorderInteger() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_cube_map_array::string() + std::string(" is not supported.")); if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::EXT::texture_integer::string() + std::string(" is not supported.")); @@ -146,6 +157,30 @@ void CubeMapTextureArrayGLTest::samplingBorderInteger() { MAGNUM_VERIFY_NO_ERROR(); } +void CubeMapTextureArrayGLTest::samplingSwizzle() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_cube_map_array::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_swizzle::string() + std::string(" is not supported.")); + + CubeMapTextureArray texture; + texture.setSwizzle<'b', 'g', 'r', '0'>(); + + MAGNUM_VERIFY_NO_ERROR(); +} + +void CubeMapTextureArrayGLTest::samplingDepthStencilMode() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_cube_map_array::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::stencil_texturing::string() + std::string(" is not supported.")); + + CubeMapTextureArray texture; + texture.setDepthStencilMode(Sampler::DepthStencilMode::StencilIndex); + + MAGNUM_VERIFY_NO_ERROR(); +} + void CubeMapTextureArrayGLTest::storage() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::texture_cube_map_array::string() + std::string(" is not supported.")); diff --git a/src/Magnum/Test/CubeMapTextureGLTest.cpp b/src/Magnum/Test/CubeMapTextureGLTest.cpp index c820d365c..2dd8454dc 100644 --- a/src/Magnum/Test/CubeMapTextureGLTest.cpp +++ b/src/Magnum/Test/CubeMapTextureGLTest.cpp @@ -46,11 +46,15 @@ class CubeMapTextureGLTest: public AbstractOpenGLTester { void bind(); void sampling(); - #ifdef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES2 + void samplingSwizzle(); + #else void samplingMaxLevel(); + void samplingCompare(); #endif #ifndef MAGNUM_TARGET_GLES void samplingBorderInteger(); + void samplingDepthStencilMode(); #endif void storage(); @@ -76,11 +80,15 @@ CubeMapTextureGLTest::CubeMapTextureGLTest() { &CubeMapTextureGLTest::bind, &CubeMapTextureGLTest::sampling, - #ifdef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES2 + &CubeMapTextureGLTest::samplingSwizzle, + #else &CubeMapTextureGLTest::samplingMaxLevel, + &CubeMapTextureGLTest::samplingCompare, #endif #ifndef MAGNUM_TARGET_GLES &CubeMapTextureGLTest::samplingBorderInteger, + &CubeMapTextureGLTest::samplingDepthStencilMode, #endif &CubeMapTextureGLTest::storage, @@ -141,17 +149,39 @@ void CubeMapTextureGLTest::sampling() { texture.setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) .setMagnificationFilter(Sampler::Filter::Linear) #ifndef MAGNUM_TARGET_GLES2 + .setMinLod(-750.0f) + .setMaxLod(750.0f) + #ifndef MAGNUM_TARGET_GLES + .setLodBias(0.5f) + #endif .setBaseLevel(1) .setMaxLevel(750) #endif .setWrapping(Sampler::Wrapping::ClampToBorder) .setBorderColor(Color3(0.5f)) - .setMaxAnisotropy(Sampler::maxMaxAnisotropy()); + .setMaxAnisotropy(Sampler::maxMaxAnisotropy()) + #ifndef MAGNUM_TARGET_GLES2 + .setCompareMode(Sampler::CompareMode::CompareRefToTexture) + .setCompareFunction(Sampler::CompareFunction::GreaterOrEqual) + #endif + ; MAGNUM_VERIFY_NO_ERROR(); } -#ifdef MAGNUM_TARGET_GLES2 +#ifndef MAGNUM_TARGET_GLES2 +void CubeMapTextureGLTest::samplingSwizzle() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_swizzle::string() + std::string(" is not supported.")); + #endif + + CubeMapTexture texture; + texture.setSwizzle<'b', 'g', 'r', '0'>(); + + MAGNUM_VERIFY_NO_ERROR(); +} +#else void CubeMapTextureGLTest::samplingMaxLevel() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::APPLE::texture_max_level::string() + std::string(" is not supported.")); @@ -161,6 +191,18 @@ void CubeMapTextureGLTest::samplingMaxLevel() { MAGNUM_VERIFY_NO_ERROR(); } + +void CubeMapTextureGLTest::samplingCompare() { + if(!Context::current()->isExtensionSupported() || + !Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::NV::shadow_samplers_cube::string() + std::string(" is not supported.")); + + CubeMapTexture texture; + texture.setCompareMode(Sampler::CompareMode::CompareRefToTexture) + .setCompareFunction(Sampler::CompareFunction::GreaterOrEqual); + + MAGNUM_VERIFY_NO_ERROR(); +} #endif #ifndef MAGNUM_TARGET_GLES @@ -177,6 +219,16 @@ void CubeMapTextureGLTest::samplingBorderInteger() { MAGNUM_VERIFY_NO_ERROR(); } + +void CubeMapTextureGLTest::samplingDepthStencilMode() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::stencil_texturing::string() + std::string(" is not supported.")); + + CubeMapTexture texture; + texture.setDepthStencilMode(Sampler::DepthStencilMode::StencilIndex); + + MAGNUM_VERIFY_NO_ERROR(); +} #endif void CubeMapTextureGLTest::storage() { @@ -354,6 +406,16 @@ void CubeMapTextureGLTest::generateMipmap() { CubeMapTexture texture; texture.setImage(CubeMapTexture::Coordinate::PositiveX, 0, TextureFormat::RGBA8, ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(32))); + texture.setImage(CubeMapTexture::Coordinate::PositiveY, 0, TextureFormat::RGBA8, + ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(32))); + texture.setImage(CubeMapTexture::Coordinate::PositiveZ, 0, TextureFormat::RGBA8, + ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(32))); + texture.setImage(CubeMapTexture::Coordinate::NegativeX, 0, TextureFormat::RGBA8, + ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(32))); + texture.setImage(CubeMapTexture::Coordinate::NegativeY, 0, TextureFormat::RGBA8, + ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(32))); + texture.setImage(CubeMapTexture::Coordinate::NegativeZ, 0, TextureFormat::RGBA8, + ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(32))); /** @todo How to test this on ES? */ #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/Test/MeshGLTest.cpp b/src/Magnum/Test/MeshGLTest.cpp index 00ddb979e..b2cf1189a 100644 --- a/src/Magnum/Test/MeshGLTest.cpp +++ b/src/Magnum/Test/MeshGLTest.cpp @@ -106,6 +106,26 @@ class MeshGLTest: public AbstractOpenGLTester { void setIndexBuffer(); void setIndexBufferRange(); void setIndexBufferUnsignedInt(); + + #ifndef MAGNUM_TARGET_GLES + void setBaseVertex(); + #endif + void setInstanceCount(); + void setInstanceCountIndexed(); + #ifndef MAGNUM_TARGET_GLES + void setInstanceCountBaseInstance(); + void setInstanceCountBaseInstanceIndexed(); + void setInstanceCountBaseVertex(); + void setInstanceCountBaseVertexBaseInstance(); + #endif + + void addVertexBufferInstancedFloat(); + #ifndef MAGNUM_TARGET_GLES2 + void addVertexBufferInstancedInteger(); + #endif + #ifndef MAGNUM_TARGET_GLES + void addVertexBufferInstancedDouble(); + #endif }; MeshGLTest::MeshGLTest() { @@ -168,7 +188,28 @@ MeshGLTest::MeshGLTest() { &MeshGLTest::setIndexBuffer, &MeshGLTest::setIndexBufferRange, - &MeshGLTest::setIndexBufferUnsignedInt}); + &MeshGLTest::setIndexBufferUnsignedInt, + + #ifndef MAGNUM_TARGET_GLES + &MeshGLTest::setBaseVertex, + #endif + &MeshGLTest::setInstanceCount, + &MeshGLTest::setInstanceCountIndexed, + #ifndef MAGNUM_TARGET_GLES + &MeshGLTest::setInstanceCountBaseInstance, + &MeshGLTest::setInstanceCountBaseInstanceIndexed, + &MeshGLTest::setInstanceCountBaseVertex, + &MeshGLTest::setInstanceCountBaseVertexBaseInstance, + #endif + + &MeshGLTest::addVertexBufferInstancedFloat, + #ifndef MAGNUM_TARGET_GLES2 + &MeshGLTest::addVertexBufferInstancedInteger, + #endif + #ifndef MAGNUM_TARGET_GLES + &MeshGLTest::addVertexBufferInstancedDouble + #endif + }); } void MeshGLTest::construct() { @@ -323,8 +364,8 @@ FloatShader::FloatShader(const std::string& type, const std::string& conversion) "void main() { gl_FragColor = " + conversion + "; }\n"); #else frag.addSource("in mediump " + type + " valueInterpolated;\n" - "out mediump vec4 output;\n" - "void main() { output = " + conversion + "; }\n"); + "out mediump vec4 result;\n" + "void main() { result = " + conversion + "; }\n"); #endif CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); attachShader(frag); @@ -397,11 +438,18 @@ Checker::Checker(AbstractShaderProgram&& shader, RenderbufferFormat format, Mesh framebuffer.attachRenderbuffer(Framebuffer::ColorAttachment(0), renderbuffer); framebuffer.bind(FramebufferTarget::ReadDraw); - mesh.setVertexCount(2) - .setPrimitive(MeshPrimitive::Points); + mesh.setPrimitive(MeshPrimitive::Points) + .setCount(2); /* Skip first vertex so we test also offsets */ - MeshView(mesh).setVertexRange(1, 1).draw(shader); + MeshView(mesh) + .setCount(1) + .setBaseVertex(1) + .setInstanceCount(mesh.instanceCount()) + #ifndef MAGNUM_TARGET_GLES + .setBaseInstance(mesh.baseInstance()) + #endif + .draw(shader); } template T Checker::get(ColorFormat format, ColorType type) { @@ -1122,7 +1170,7 @@ namespace { const Float indexedVertexData[] = { 0.0f, /* Offset */ - /* First attribute */ + /* First vertex */ Math::normalize(64), Math::normalize(17), Math::normalize(56), @@ -1132,7 +1180,36 @@ namespace { Math::normalize(97), Math::normalize(28), - /* Second attribute */ + /* Second vertex */ + 0.3f, 0.1f, 0.5f, + 0.4f, 0.0f, -0.9f, + 1.0f, -0.5f + }; + + const Float indexedVertexDataBaseVertex[] = { + 0.0f, 0.0f, /* Offset */ + + /* First vertex */ + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, + + /* Second vertex */ + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, + + /* Third vertex */ + Math::normalize(64), + Math::normalize(17), + Math::normalize(56), + Math::normalize(15), + Math::normalize(164), + Math::normalize(17), + Math::normalize(97), + Math::normalize(28), + + /* Fourth vertex */ 0.3f, 0.1f, 0.5f, 0.4f, 0.0f, -0.9f, 1.0f, -0.5f @@ -1151,11 +1228,19 @@ IndexChecker::IndexChecker(Mesh& mesh): framebuffer({{}, Vector2i(1)}) { framebuffer.attachRenderbuffer(Framebuffer::ColorAttachment(0), renderbuffer); framebuffer.bind(FramebufferTarget::ReadDraw); - mesh.setIndexCount(2) - .setPrimitive(MeshPrimitive::Points); + mesh.setPrimitive(MeshPrimitive::Points) + .setCount(2); /* Skip first vertex so we test also offsets */ - MeshView(mesh).setIndexRange(1, 1).draw(MultipleShader{}); + MeshView(mesh) + .setCount(1) + .setBaseVertex(mesh.baseVertex()) + .setInstanceCount(mesh.instanceCount()) + #ifndef MAGNUM_TARGET_GLES + .setBaseInstance(mesh.baseInstance()) + #endif + .setIndexRange(1) + .draw(MultipleShader{}); } Color4ub IndexChecker::get() { @@ -1233,6 +1318,361 @@ void MeshGLTest::setIndexBufferUnsignedInt() { CORRADE_COMPARE(value, indexedResult); } +#ifndef MAGNUM_TARGET_GLES +void MeshGLTest::setBaseVertex() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::draw_elements_base_vertex::string() + std::string(" is not available.")); + + Buffer vertices; + vertices.setData(indexedVertexDataBaseVertex, BufferUsage::StaticDraw); + + constexpr UnsignedShort indexData[] = { 2, 1, 0 }; + Buffer indices(Buffer::Target::ElementArray); + indices.setData(indexData, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setBaseVertex(2) + .addVertexBuffer(vertices, 2*4, MultipleShader::Position(), + MultipleShader::Normal(), MultipleShader::TextureCoordinates()) + .setIndexBuffer(indices, 2, Mesh::IndexType::UnsignedShort); + + MAGNUM_VERIFY_NO_ERROR(); + + const auto value = IndexChecker(mesh).get(); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(value, indexedResult); +} +#endif + +void MeshGLTest::setInstanceCount() { + /* Verbatim copy of addVertexBufferFloat() with added extension check and + setInstanceCount() call. It would just render three times the same + value. I'm too lazy to invent proper test case, so I'll just check that + it didn't generate any error and rendered something */ + + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::draw_instanced::string() + std::string(" is not available.")); + #elif defined(MAGNUM_TARGET_GLES2) + if(!Context::current()->isExtensionSupported() && !Context::current()->isExtensionSupported() && !Context::current()->isExtensionSupported()) + CORRADE_SKIP("Required extension is not available."); + #endif + + typedef AbstractShaderProgram::Attribute<0, Float> Attribute; + + const Float data[] = { 0.0f, -0.7f, Math::normalize(96) }; + Buffer buffer; + buffer.setData(data, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setInstanceCount(3) + .addVertexBuffer(buffer, 4, Attribute()); + + MAGNUM_VERIFY_NO_ERROR(); + + const auto value = Checker(FloatShader("float", "vec4(valueInterpolated, 0.0, 0.0, 0.0)"), + #ifndef MAGNUM_TARGET_GLES2 + RenderbufferFormat::RGBA8, + #else + RenderbufferFormat::RGBA4, + #endif + mesh).get(ColorFormat::RGBA, ColorType::UnsignedByte); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(value, 96); +} + +void MeshGLTest::setInstanceCountIndexed() { + /* Verbatim copy of setIndexBuffer() with added extension check and + setInstanceCount() call. It would just render three times the same + value. I'm too lazy to invent proper test case, so I'll just check that + it didn't generate any error and rendered something */ + + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::draw_instanced::string() + std::string(" is not available.")); + #elif defined(MAGNUM_TARGET_GLES2) + if(!Context::current()->isExtensionSupported() && !Context::current()->isExtensionSupported() && !Context::current()->isExtensionSupported()) + CORRADE_SKIP("Required extension is not available."); + #endif + + Buffer vertices; + vertices.setData(indexedVertexData, BufferUsage::StaticDraw); + + constexpr UnsignedShort indexData[] = { 2, 1, 0 }; + Buffer indices(Buffer::Target::ElementArray); + indices.setData(indexData, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setInstanceCount(3) + .addVertexBuffer(vertices, 1*4, MultipleShader::Position(), + MultipleShader::Normal(), MultipleShader::TextureCoordinates()) + .setIndexBuffer(indices, 2, Mesh::IndexType::UnsignedShort); + + MAGNUM_VERIFY_NO_ERROR(); + + const auto value = IndexChecker(mesh).get(); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(value, indexedResult); +} + +#ifndef MAGNUM_TARGET_GLES +void MeshGLTest::setInstanceCountBaseInstance() { + /* Verbatim copy of setInstanceCount() with additional extension check and + setBaseInstance() call. It would just render three times the same + value. I'm too lazy to invent proper test case, so I'll just check that + it didn't generate any error and rendered something */ + + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::draw_instanced::string() + std::string(" is not available.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::base_instance::string() + std::string(" is not available.")); + + typedef AbstractShaderProgram::Attribute<0, Float> Attribute; + + const Float data[] = { 0.0f, -0.7f, Math::normalize(96) }; + Buffer buffer; + buffer.setData(data, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setInstanceCount(3) + .setBaseInstance(72) + .addVertexBuffer(buffer, 4, Attribute()); + + MAGNUM_VERIFY_NO_ERROR(); + + const auto value = Checker(FloatShader("float", "vec4(valueInterpolated, 0.0, 0.0, 0.0)"), + #ifndef MAGNUM_TARGET_GLES2 + RenderbufferFormat::RGBA8, + #else + RenderbufferFormat::RGBA4, + #endif + mesh).get(ColorFormat::RGBA, ColorType::UnsignedByte); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(value, 96); +} + +void MeshGLTest::setInstanceCountBaseInstanceIndexed() { + /* Verbatim copy of setInstanceCountIndexed() with additional extension + check and setBaseInstance() call. It would just render three times the + same value. I'm too lazy to invent proper test case, so I'll just check + that it didn't generate any error and rendered something */ + + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::draw_instanced::string() + std::string(" is not available.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::base_instance::string() + std::string(" is not available.")); + + Buffer vertices; + vertices.setData(indexedVertexData, BufferUsage::StaticDraw); + + constexpr UnsignedShort indexData[] = { 2, 1, 0 }; + Buffer indices(Buffer::Target::ElementArray); + indices.setData(indexData, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setInstanceCount(3) + .setBaseInstance(72) + .addVertexBuffer(vertices, 1*4, MultipleShader::Position(), + MultipleShader::Normal(), MultipleShader::TextureCoordinates()) + .setIndexBuffer(indices, 2, Mesh::IndexType::UnsignedShort); + + MAGNUM_VERIFY_NO_ERROR(); + + const auto value = IndexChecker(mesh).get(); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(value, indexedResult); +} + +void MeshGLTest::setInstanceCountBaseVertex() { + /* Verbatim copy of setBaseVertex() with additional extension check and + setInstanceCount() call. It would just render three times the same + value. I'm too lazy to invent proper test case, so I'll just check + that it didn't generate any error and rendered something */ + + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::draw_instanced::string() + std::string(" is not available.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::draw_elements_base_vertex::string() + std::string(" is not available.")); + + Buffer vertices; + vertices.setData(indexedVertexDataBaseVertex, BufferUsage::StaticDraw); + + constexpr UnsignedShort indexData[] = { 2, 1, 0 }; + Buffer indices(Buffer::Target::ElementArray); + indices.setData(indexData, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setBaseVertex(2) + .setInstanceCount(3) + .addVertexBuffer(vertices, 2*4, MultipleShader::Position(), + MultipleShader::Normal(), MultipleShader::TextureCoordinates()) + .setIndexBuffer(indices, 2, Mesh::IndexType::UnsignedShort); + + MAGNUM_VERIFY_NO_ERROR(); + + const auto value = IndexChecker(mesh).get(); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(value, indexedResult); +} + +void MeshGLTest::setInstanceCountBaseVertexBaseInstance() { + /* Verbatim copy of setInstanceCountBaseVertex() with added extension check + and setBaseInstance() call. It would just render three times the same + value. I'm too lazy to invent proper test case, so I'll just check + that it didn't generate any error and rendered something */ + + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::draw_instanced::string() + std::string(" is not available.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::draw_elements_base_vertex::string() + std::string(" is not available.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::base_instance::string() + std::string(" is not available.")); + + Buffer vertices; + vertices.setData(indexedVertexDataBaseVertex, BufferUsage::StaticDraw); + + constexpr UnsignedShort indexData[] = { 2, 1, 0 }; + Buffer indices(Buffer::Target::ElementArray); + indices.setData(indexData, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setBaseVertex(2) + .setInstanceCount(3) + .setBaseInstance(72) + .addVertexBuffer(vertices, 2*4, MultipleShader::Position(), + MultipleShader::Normal(), MultipleShader::TextureCoordinates()) + .setIndexBuffer(indices, 2, Mesh::IndexType::UnsignedShort); + + MAGNUM_VERIFY_NO_ERROR(); + + const auto value = IndexChecker(mesh).get(); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(value, indexedResult); +} +#endif + +void MeshGLTest::addVertexBufferInstancedFloat() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::draw_instanced::string() + std::string(" is not available.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::instanced_arrays::string() + std::string(" is not available.")); + #elif defined(MAGNUM_TARGET_GLES2) + if(!Context::current()->isExtensionSupported() && !Context::current()->isExtensionSupported() && !Context::current()->isExtensionSupported()) + CORRADE_SKIP("Required instancing extension is not available."); + if(!Context::current()->isExtensionSupported() && !Context::current()->isExtensionSupported() && !Context::current()->isExtensionSupported()) + CORRADE_SKIP("Required drawing extension is not available."); + #endif + + typedef AbstractShaderProgram::Attribute<0, Float> Attribute; + + const Float data[] = { + 0.0f, /* Offset */ + /* Base vertex is ignored for instanced arrays */ + -0.7f, /* First instance */ + 0.3f, /* Second instance */ + Math::normalize(96) /* Third instance */ + }; + Buffer buffer; + buffer.setData(data, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setInstanceCount(3) + .addVertexBufferInstanced(buffer, 1, 4, Attribute{}); + + MAGNUM_VERIFY_NO_ERROR(); + + const auto value = Checker(FloatShader("float", "vec4(valueInterpolated, 0.0, 0.0, 0.0)"), + #ifndef MAGNUM_TARGET_GLES2 + RenderbufferFormat::RGBA8, + #else + RenderbufferFormat::RGBA4, + #endif + mesh).get(ColorFormat::RGBA, ColorType::UnsignedByte); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(value, 96); +} + +#ifndef MAGNUM_TARGET_GLES2 +void MeshGLTest::addVertexBufferInstancedInteger() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::draw_instanced::string() + std::string(" is not available.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::instanced_arrays::string() + std::string(" is not available.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::gpu_shader4::string() + std::string(" is not available.")); + #endif + + typedef AbstractShaderProgram::Attribute<0, UnsignedInt> Attribute; + + constexpr UnsignedInt data[] = { + 0, /* Offset */ + /* Base vertex is ignored for instanced arrays */ + 157, /* First instance */ + 25, /* Second instance */ + 35681 /* Third instance */ + }; + Buffer buffer; + buffer.setData(data, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setInstanceCount(3) + .addVertexBufferInstanced(buffer, 1, 4, Attribute{}); + + MAGNUM_VERIFY_NO_ERROR(); + + const auto value = Checker(IntegerShader("uint"), RenderbufferFormat::R32UI, mesh) + .get(ColorFormat::RedInteger, ColorType::UnsignedInt); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(value, 35681); +} +#endif + +#ifndef MAGNUM_TARGET_GLES +void MeshGLTest::addVertexBufferInstancedDouble() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::draw_instanced::string() + std::string(" is not available.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::instanced_arrays::string() + std::string(" is not available.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::vertex_attrib_64bit::string() + std::string(" is not available.")); + + typedef AbstractShaderProgram::Attribute<0, Double> Attribute; + + const Double data[] = { + 0.0, /* Offset */ + /* Base vertex is ignored for instanced arrays */ + -0.7, /* First instance */ + 0.3, /* Second instance */ + Math::normalize(45828) /* Third instance */ + }; + Buffer buffer; + buffer.setData(data, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setInstanceCount(3) + .addVertexBufferInstanced(buffer, 1, 8, Attribute{}); + + MAGNUM_VERIFY_NO_ERROR(); + + const auto value = Checker(DoubleShader("double", "float", "vec4(value, 0.0, 0.0, 0.0)"), + RenderbufferFormat::R16, mesh).get(ColorFormat::Red, ColorType::UnsignedShort); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(value, 45828); +} +#endif + }} CORRADE_TEST_MAIN(Magnum::Test::MeshGLTest) diff --git a/src/Magnum/Test/PrimitiveQueryGLTest.cpp b/src/Magnum/Test/PrimitiveQueryGLTest.cpp index d2509454e..7099cd0ae 100644 --- a/src/Magnum/Test/PrimitiveQueryGLTest.cpp +++ b/src/Magnum/Test/PrimitiveQueryGLTest.cpp @@ -88,7 +88,7 @@ void PrimitiveQueryGLTest::query() { Mesh mesh; mesh.setPrimitive(MeshPrimitive::Triangles) - .setVertexCount(9) + .setCount(9) .addVertexBuffer(vertices, 0, MyShader::Position()); MAGNUM_VERIFY_NO_ERROR(); diff --git a/src/Magnum/Test/RectangleTextureGLTest.cpp b/src/Magnum/Test/RectangleTextureGLTest.cpp index 91404f694..7a925626f 100644 --- a/src/Magnum/Test/RectangleTextureGLTest.cpp +++ b/src/Magnum/Test/RectangleTextureGLTest.cpp @@ -45,6 +45,8 @@ class RectangleTextureGLTest: public AbstractOpenGLTester { void sampling(); void samplingBorderInteger(); + void samplingSwizzle(); + void samplingDepthStencilMode(); void storage(); @@ -63,6 +65,8 @@ RectangleTextureGLTest::RectangleTextureGLTest() { &RectangleTextureGLTest::sampling, &RectangleTextureGLTest::samplingBorderInteger, + &RectangleTextureGLTest::samplingSwizzle, + &RectangleTextureGLTest::samplingDepthStencilMode, &RectangleTextureGLTest::storage, @@ -126,12 +130,16 @@ void RectangleTextureGLTest::sampling() { .setMagnificationFilter(Sampler::Filter::Linear) .setWrapping(Sampler::Wrapping::ClampToBorder) .setBorderColor(Color3(0.5f)) - .setMaxAnisotropy(Sampler::maxMaxAnisotropy()); + .setMaxAnisotropy(Sampler::maxMaxAnisotropy()) + .setCompareMode(Sampler::CompareMode::CompareRefToTexture) + .setCompareFunction(Sampler::CompareFunction::GreaterOrEqual); MAGNUM_VERIFY_NO_ERROR(); } void RectangleTextureGLTest::samplingBorderInteger() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::EXT::texture_integer::string() + std::string(" is not supported.")); @@ -145,6 +153,30 @@ void RectangleTextureGLTest::samplingBorderInteger() { MAGNUM_VERIFY_NO_ERROR(); } +void RectangleTextureGLTest::samplingSwizzle() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_swizzle::string() + std::string(" is not supported.")); + + RectangleTexture texture; + texture.setSwizzle<'b', 'g', 'r', '0'>(); + + MAGNUM_VERIFY_NO_ERROR(); +} + +void RectangleTextureGLTest::samplingDepthStencilMode() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::stencil_texturing::string() + std::string(" is not supported.")); + + RectangleTexture texture; + texture.setDepthStencilMode(Sampler::DepthStencilMode::StencilIndex); + + MAGNUM_VERIFY_NO_ERROR(); +} + void RectangleTextureGLTest::storage() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); diff --git a/src/Magnum/Test/SampleQueryGLTest.cpp b/src/Magnum/Test/SampleQueryGLTest.cpp index 39b6ffdd6..1d5acb6fd 100644 --- a/src/Magnum/Test/SampleQueryGLTest.cpp +++ b/src/Magnum/Test/SampleQueryGLTest.cpp @@ -112,7 +112,7 @@ void SampleQueryGLTest::querySamplesPassed() { Mesh mesh; mesh.setPrimitive(MeshPrimitive::Triangles) - .setVertexCount(3) + .setCount(3) .addVertexBuffer(buffer, 0, AbstractShaderProgram::Attribute<0, Vector2>()); MyShader shader; @@ -161,7 +161,7 @@ void SampleQueryGLTest::conditionalRender() { Mesh mesh; mesh.setPrimitive(MeshPrimitive::Triangles) - .setVertexCount(3) + .setCount(3) .addVertexBuffer(buffer, 0, AbstractShaderProgram::Attribute<0, Vector2>()); MyShader shader; diff --git a/src/Magnum/Test/SamplerTest.cpp b/src/Magnum/Test/SamplerTest.cpp index e56a72f8e..67d50df29 100644 --- a/src/Magnum/Test/SamplerTest.cpp +++ b/src/Magnum/Test/SamplerTest.cpp @@ -37,12 +37,23 @@ class SamplerTest: public TestSuite::Tester { void debugFilter(); void debugMipmap(); void debugWrapping(); + void debugCompareMode(); + void debugCompareFunction(); + #ifndef MAGNUM_TARGET_GLES + void debugDepthStencilMode(); + #endif }; SamplerTest::SamplerTest() { addTests({&SamplerTest::debugFilter, &SamplerTest::debugMipmap, - &SamplerTest::debugWrapping}); + &SamplerTest::debugWrapping, + &SamplerTest::debugCompareMode, + &SamplerTest::debugCompareFunction, + #ifndef MAGNUM_TARGET_GLES + &SamplerTest::debugDepthStencilMode + #endif + }); } void SamplerTest::debugFilter() { @@ -66,6 +77,29 @@ void SamplerTest::debugWrapping() { CORRADE_COMPARE(out.str(), "Sampler::Wrapping::ClampToEdge\n"); } +void SamplerTest::debugCompareMode() { + std::ostringstream out; + + Debug(&out) << Sampler::CompareMode::CompareRefToTexture; + CORRADE_COMPARE(out.str(), "Sampler::CompareMode::CompareRefToTexture\n"); +} + +void SamplerTest::debugCompareFunction() { + std::ostringstream out; + + Debug(&out) << Sampler::CompareFunction::GreaterOrEqual; + CORRADE_COMPARE(out.str(), "Sampler::CompareFunction::GreaterOrEqual\n"); +} + +#ifndef MAGNUM_TARGET_GLES +void SamplerTest::debugDepthStencilMode() { + std::ostringstream out; + + Debug(&out) << Sampler::DepthStencilMode::StencilIndex; + CORRADE_COMPARE(out.str(), "Sampler::DepthStencilMode::StencilIndex\n"); +} +#endif + }} CORRADE_TEST_MAIN(Magnum::Test::SamplerTest) diff --git a/src/Magnum/Test/TextureArrayGLTest.cpp b/src/Magnum/Test/TextureArrayGLTest.cpp index d7c2d2f68..495bcc392 100644 --- a/src/Magnum/Test/TextureArrayGLTest.cpp +++ b/src/Magnum/Test/TextureArrayGLTest.cpp @@ -55,13 +55,21 @@ class TextureArrayGLTest: public AbstractOpenGLTester { #endif void sampling2D(); - #ifdef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES + void samplingSwizzle1D(); + #endif + void samplingSwizzle2D(); + #else void samplingMaxLevel2D(); + void samplingCompare2D(); #endif #ifndef MAGNUM_TARGET_GLES void samplingBorderInteger1D(); void samplingBorderInteger2D(); + void samplingDepthStencilMode1D(); + void samplingDepthStencilMode2D(); #else void samplingBorder2D(); #endif @@ -120,13 +128,20 @@ TextureArrayGLTest::TextureArrayGLTest() { #endif &TextureArrayGLTest::sampling2D, - #ifdef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES + &TextureArrayGLTest::samplingSwizzle1D, + #endif + &TextureArrayGLTest::samplingSwizzle2D, + #else &TextureArrayGLTest::samplingMaxLevel2D, #endif #ifndef MAGNUM_TARGET_GLES &TextureArrayGLTest::samplingBorderInteger1D, &TextureArrayGLTest::samplingBorderInteger2D, + &TextureArrayGLTest::samplingDepthStencilMode1D, + &TextureArrayGLTest::samplingDepthStencilMode2D, #else &TextureArrayGLTest::samplingBorder2D, #endif @@ -263,11 +278,26 @@ void TextureArrayGLTest::sampling1D() { Texture1DArray texture; texture.setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) .setMagnificationFilter(Sampler::Filter::Linear) + .setMinLod(-750.0f) + .setMaxLod(750.0f) + .setLodBias(0.5f) .setBaseLevel(1) .setMaxLevel(750) .setWrapping(Sampler::Wrapping::ClampToBorder) .setBorderColor(Color3(0.5f)) - .setMaxAnisotropy(Sampler::maxMaxAnisotropy()); + .setMaxAnisotropy(Sampler::maxMaxAnisotropy()) + .setCompareMode(Sampler::CompareMode::CompareRefToTexture) + .setCompareFunction(Sampler::CompareFunction::GreaterOrEqual); + + MAGNUM_VERIFY_NO_ERROR(); +} + +void TextureArrayGLTest::samplingSwizzle1D() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_swizzle::string() + std::string(" is not supported.")); + + Texture1DArray texture; + texture.setSwizzle<'b', 'g', 'r', '0'>(); MAGNUM_VERIFY_NO_ERROR(); } @@ -285,6 +315,16 @@ void TextureArrayGLTest::samplingBorderInteger1D() { MAGNUM_VERIFY_NO_ERROR(); } + +void TextureArrayGLTest::samplingDepthStencilMode1D() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::stencil_texturing::string() + std::string(" is not supported.")); + + Texture1DArray texture; + texture.setDepthStencilMode(Sampler::DepthStencilMode::StencilIndex); + + MAGNUM_VERIFY_NO_ERROR(); +} #endif void TextureArrayGLTest::sampling2D() { @@ -297,6 +337,11 @@ void TextureArrayGLTest::sampling2D() { texture.setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) .setMagnificationFilter(Sampler::Filter::Linear) #ifndef MAGNUM_TARGET_GLES2 + .setMinLod(-750.0f) + .setMaxLod(750.0f) + #ifndef MAGNUM_TARGET_GLES + .setLodBias(0.5f) + #endif .setBaseLevel(1) .setMaxLevel(750) #endif @@ -306,12 +351,29 @@ void TextureArrayGLTest::sampling2D() { #else .setWrapping(Sampler::Wrapping::ClampToEdge) #endif - .setMaxAnisotropy(Sampler::maxMaxAnisotropy()); + .setMaxAnisotropy(Sampler::maxMaxAnisotropy()) + #ifndef MAGNUM_TARGET_GLES + .setCompareMode(Sampler::CompareMode::CompareRefToTexture) + .setCompareFunction(Sampler::CompareFunction::GreaterOrEqual) + #endif + ; MAGNUM_VERIFY_NO_ERROR(); } -#ifdef MAGNUM_TARGET_GLES2 +#ifndef MAGNUM_TARGET_GLES2 +void TextureArrayGLTest::samplingSwizzle2D() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_swizzle::string() + std::string(" is not supported.")); + #endif + + Texture2DArray texture; + texture.setSwizzle<'b', 'g', 'r', '0'>(); + + MAGNUM_VERIFY_NO_ERROR(); +} +#else void TextureArrayGLTest::samplingMaxLevel2D() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::APPLE::texture_max_level::string() + std::string(" is not supported.")); @@ -321,6 +383,18 @@ void TextureArrayGLTest::samplingMaxLevel2D() { MAGNUM_VERIFY_NO_ERROR(); } + +void TextureArrayGLTest::samplingCompare2D() { + if(!Context::current()->isExtensionSupported() || + !Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::NV::shadow_samplers_array::string() + std::string(" is not supported.")); + + Texture2DArray texture; + texture.setCompareMode(Sampler::CompareMode::CompareRefToTexture) + .setCompareFunction(Sampler::CompareFunction::GreaterOrEqual); + + MAGNUM_VERIFY_NO_ERROR(); +} #endif #ifndef MAGNUM_TARGET_GLES @@ -337,6 +411,16 @@ void TextureArrayGLTest::samplingBorderInteger2D() { MAGNUM_VERIFY_NO_ERROR(); } + +void TextureArrayGLTest::samplingDepthStencilMode2D() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::stencil_texturing::string() + std::string(" is not supported.")); + + Texture2DArray texture; + texture.setDepthStencilMode(Sampler::DepthStencilMode::StencilIndex); + + MAGNUM_VERIFY_NO_ERROR(); +} #else void TextureArrayGLTest::samplingBorder2D() { if(!Context::current()->isExtensionSupported()) diff --git a/src/Magnum/Test/TextureGLTest.cpp b/src/Magnum/Test/TextureGLTest.cpp index ee23b0316..8f6b6fead 100644 --- a/src/Magnum/Test/TextureGLTest.cpp +++ b/src/Magnum/Test/TextureGLTest.cpp @@ -60,14 +60,24 @@ class TextureGLTest: public AbstractOpenGLTester { void sampling2D(); void sampling3D(); - #ifdef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES + void samplingSwizzle1D(); + #endif + void samplingSwizzle2D(); + void samplingSwizzle3D(); + #else void samplingMaxLevel2D(); void samplingMaxLevel3D(); + void samplingCompare2D(); #endif #ifndef MAGNUM_TARGET_GLES void samplingBorderInteger2D(); void samplingBorderInteger3D(); + void samplingDepthStencilMode1D(); + void samplingDepthStencilMode2D(); + void samplingDepthStencilMode3D(); #else void samplingBorder2D(); void samplingBorder3D(); @@ -146,14 +156,24 @@ TextureGLTest::TextureGLTest() { &TextureGLTest::sampling2D, &TextureGLTest::sampling3D, - #ifdef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES + &TextureGLTest::samplingSwizzle1D, + #endif + &TextureGLTest::samplingSwizzle2D, + &TextureGLTest::samplingSwizzle3D, + #else &TextureGLTest::samplingMaxLevel2D, &TextureGLTest::samplingMaxLevel3D, + &TextureGLTest::samplingCompare2D, #endif #ifndef MAGNUM_TARGET_GLES &TextureGLTest::samplingBorderInteger2D, &TextureGLTest::samplingBorderInteger3D, + &TextureGLTest::samplingDepthStencilMode1D, + &TextureGLTest::samplingDepthStencilMode2D, + &TextureGLTest::samplingDepthStencilMode3D, #else &TextureGLTest::samplingBorder2D, &TextureGLTest::samplingBorder3D, @@ -333,11 +353,36 @@ void TextureGLTest::sampling1D() { Texture1D texture; texture.setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) .setMagnificationFilter(Sampler::Filter::Linear) + .setMinLod(-750.0f) + .setMaxLod(750.0f) + .setLodBias(0.5f) .setBaseLevel(1) .setMaxLevel(750) .setWrapping(Sampler::Wrapping::ClampToBorder) .setBorderColor(Color3(0.5f)) - .setMaxAnisotropy(Sampler::maxMaxAnisotropy()); + .setMaxAnisotropy(Sampler::maxMaxAnisotropy()) + .setCompareMode(Sampler::CompareMode::CompareRefToTexture) + .setCompareFunction(Sampler::CompareFunction::GreaterOrEqual); + + MAGNUM_VERIFY_NO_ERROR(); +} + +void TextureGLTest::samplingSwizzle1D() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_swizzle::string() + std::string(" is not supported.")); + + Texture1D texture; + texture.setSwizzle<'b', 'g', 'r', '0'>(); + + MAGNUM_VERIFY_NO_ERROR(); +} + +void TextureGLTest::samplingDepthStencilMode1D() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::stencil_texturing::string() + std::string(" is not supported.")); + + Texture1D texture; + texture.setDepthStencilMode(Sampler::DepthStencilMode::StencilIndex); MAGNUM_VERIFY_NO_ERROR(); } @@ -348,6 +393,11 @@ void TextureGLTest::sampling2D() { texture.setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) .setMagnificationFilter(Sampler::Filter::Linear) #ifndef MAGNUM_TARGET_GLES2 + .setMinLod(-750.0f) + .setMaxLod(750.0f) + #ifndef MAGNUM_TARGET_GLES + .setLodBias(0.5f) + #endif .setBaseLevel(1) .setMaxLevel(750) #endif @@ -357,12 +407,26 @@ void TextureGLTest::sampling2D() { #else .setWrapping(Sampler::Wrapping::ClampToEdge) #endif - .setMaxAnisotropy(Sampler::maxMaxAnisotropy()); + .setMaxAnisotropy(Sampler::maxMaxAnisotropy()) + .setCompareMode(Sampler::CompareMode::CompareRefToTexture) + .setCompareFunction(Sampler::CompareFunction::GreaterOrEqual); MAGNUM_VERIFY_NO_ERROR(); } -#ifdef MAGNUM_TARGET_GLES2 +#ifndef MAGNUM_TARGET_GLES2 +void TextureGLTest::samplingSwizzle2D() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_swizzle::string() + std::string(" is not supported.")); + #endif + + Texture2D texture; + texture.setSwizzle<'b', 'g', 'r', '0'>(); + + MAGNUM_VERIFY_NO_ERROR(); +} +#else void TextureGLTest::samplingMaxLevel2D() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::APPLE::texture_max_level::string() + std::string(" is not supported.")); @@ -372,6 +436,17 @@ void TextureGLTest::samplingMaxLevel2D() { MAGNUM_VERIFY_NO_ERROR(); } + +void TextureGLTest::samplingCompare2D() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::shadow_samplers::string() + std::string(" is not supported.")); + + Texture2D texture; + texture.setCompareMode(Sampler::CompareMode::CompareRefToTexture) + .setCompareFunction(Sampler::CompareFunction::GreaterOrEqual); + + MAGNUM_VERIFY_NO_ERROR(); +} #endif #ifndef MAGNUM_TARGET_GLES @@ -388,6 +463,16 @@ void TextureGLTest::samplingBorderInteger2D() { MAGNUM_VERIFY_NO_ERROR(); } + +void TextureGLTest::samplingDepthStencilMode2D() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::stencil_texturing::string() + std::string(" is not supported.")); + + Texture2D texture; + texture.setDepthStencilMode(Sampler::DepthStencilMode::StencilIndex); + + MAGNUM_VERIFY_NO_ERROR(); +} #else void TextureGLTest::samplingBorder2D() { if(!Context::current()->isExtensionSupported()) @@ -411,6 +496,11 @@ void TextureGLTest::sampling3D() { texture.setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) .setMagnificationFilter(Sampler::Filter::Linear) #ifndef MAGNUM_TARGET_GLES2 + .setMinLod(-750.0f) + .setMaxLod(750.0f) + #ifndef MAGNUM_TARGET_GLES + .setLodBias(0.5f) + #endif .setBaseLevel(1) .setMaxLevel(750) #endif @@ -425,7 +515,19 @@ void TextureGLTest::sampling3D() { MAGNUM_VERIFY_NO_ERROR(); } -#ifdef MAGNUM_TARGET_GLES2 +#ifndef MAGNUM_TARGET_GLES2 +void TextureGLTest::samplingSwizzle3D() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_swizzle::string() + std::string(" is not supported.")); + #endif + + Texture3D texture; + texture.setSwizzle<'b', 'g', 'r', '0'>(); + + MAGNUM_VERIFY_NO_ERROR(); +} +#else void TextureGLTest::samplingMaxLevel3D() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::OES::texture_3D::string() + std::string(" is not supported.")); @@ -453,6 +555,16 @@ void TextureGLTest::samplingBorderInteger3D() { MAGNUM_VERIFY_NO_ERROR(); } + +void TextureGLTest::samplingDepthStencilMode3D() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::stencil_texturing::string() + std::string(" is not supported.")); + + Texture3D texture; + texture.setDepthStencilMode(Sampler::DepthStencilMode::StencilIndex); + + MAGNUM_VERIFY_NO_ERROR(); +} #else void TextureGLTest::samplingBorder3D() { #ifdef MAGNUM_TARGET_GLES2 diff --git a/src/Magnum/Text/Renderer.cpp b/src/Magnum/Text/Renderer.cpp index a26a9dfc9..47674b846 100644 --- a/src/Magnum/Text/Renderer.cpp +++ b/src/Magnum/Text/Renderer.cpp @@ -219,7 +219,7 @@ std::tuple renderInternal(AbstractFont& font, const GlyphCache& c in subclass) */ Mesh mesh; mesh.setPrimitive(MeshPrimitive::Triangles) - .setIndexCount(indexCount) + .setCount(indexCount) .setIndexBuffer(indexBuffer, 0, indexType, 0, vertices.size()); return std::make_tuple(std::move(mesh), rectangle); @@ -347,7 +347,7 @@ void AbstractRenderer::reserve(const uint32_t glyphCount, const BufferUsage vert #ifdef CORRADE_TARGET_EMSCRIPTEN _vertexBufferData = Containers::Array(vertexCount*sizeof(Vertex)); #endif - _mesh.setVertexCount(0); + _mesh.setCount(0); /* Render indices */ Containers::Array indexData; @@ -359,7 +359,7 @@ void AbstractRenderer::reserve(const uint32_t glyphCount, const BufferUsage vert #ifdef CORRADE_TARGET_EMSCRIPTEN _indexBufferData = Containers::Array(indexData.size()); #endif - _mesh.setIndexCount(0) + _mesh.setCount(0) .setIndexBuffer(_indexBuffer, 0, indexType, 0, vertexCount); /* Prefill index buffer */ @@ -391,7 +391,7 @@ void AbstractRenderer::render(const std::string& text) { bufferUnmapImplementation(_vertexBuffer); /* Update index count */ - _mesh.setIndexCount(indexCount); + _mesh.setCount(indexCount); } #ifndef DOXYGEN_GENERATING_OUTPUT diff --git a/src/Magnum/Texture.cpp b/src/Magnum/Texture.cpp new file mode 100644 index 000000000..a7566f218 --- /dev/null +++ b/src/Magnum/Texture.cpp @@ -0,0 +1,54 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014 + 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 "Texture.h" + +#include "Magnum/Context.h" +#include "Magnum/Extensions.h" + +#include "Implementation/maxTextureSize.h" +#include "Implementation/State.h" +#include "Implementation/TextureState.h" + +namespace Magnum { namespace Implementation { + +template typename DimensionTraits::VectorType maxTextureSize() { + return typename DimensionTraits::VectorType{Implementation::maxTextureSideSize()}; +} + +#ifndef MAGNUM_TARGET_GLES +template MAGNUM_EXPORT Math::Vector<1, Int> maxTextureSize<1>(); +#endif +template MAGNUM_EXPORT Vector2i maxTextureSize<2>(); + +template<> MAGNUM_EXPORT Vector3i maxTextureSize<3>() { + #ifdef MAGNUM_TARGET_GLES2 + if(!Context::current()->isExtensionSupported()) + return {}; + #endif + return {Vector2i(Implementation::maxTextureSideSize()), Implementation::max3DTextureDepth()}; +} + +}} diff --git a/src/Magnum/Texture.h b/src/Magnum/Texture.h index 289220034..6fc4e8181 100644 --- a/src/Magnum/Texture.h +++ b/src/Magnum/Texture.h @@ -51,6 +51,9 @@ namespace Implementation { return GL_TEXTURE_3D_OES; #endif } + + template typename DimensionTraits::VectorType maxTextureSize(); + template<> Vector3i maxTextureSize<3>(); } /** @@ -90,13 +93,12 @@ In shader, the texture is used via `sampler1D`/`sampler2D`/`sampler3D`, See @ref AbstractShaderProgram documentation for more information about usage in shaders. +@see @ref Texture1D, @ref Texture2D, @ref Texture3D, @ref TextureArray, + @ref CubeMapTexture, @ref CubeMapTextureArray, @ref RectangleTexture, + @ref BufferTexture, @ref MultisampleTexture @requires_gles30 %Extension @es_extension{OES,texture_3D} for 3D textures in OpenGL ES 2.0 @requires_gl 1D textures are not available in OpenGL ES, only 2D and 3D ones. - -@see @ref Texture1D, @ref Texture2D, @ref Texture3D, @ref TextureArray, - @ref BufferTexture, @ref CubeMapTexture, @ref CubeMapTextureArray, - @ref MultisampleTexture, @ref RectangleTexture */ template class Texture: public AbstractTexture { public: @@ -140,6 +142,20 @@ template class Texture: public AbstractTexture { #endif #endif + /** + * @brief Max supported texture size + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. For 3D textures in OpenGL ES 2.0, if + * @es_extension{OES,texture_3D} extension is not available, returns + * zero vector. + * @see @fn_gl{Get} with @def_gl{MAX_TEXTURE_SIZE}, + * @def_gl{MAX_3D_TEXTURE_SIZE} + */ + static typename DimensionTraits::VectorType maxSize() { + return Implementation::maxTextureSize(); + } + /** * @brief Constructor * @@ -186,7 +202,7 @@ template class Texture: public AbstractTexture { * The result is not cached in any way. If * @extension{EXT,direct_state_access} is not available, the texture * is bound to some texture unit before the operation. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @see @ref image(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and * @fn_gl{GetTexLevelParameter} or @fn_gl_extension{GetTextureLevelParameter,EXT,direct_state_access} * with @def_gl{TEXTURE_WIDTH}, @def_gl{TEXTURE_HEIGHT} or * @def_gl{TEXTURE_DEPTH} @@ -251,8 +267,9 @@ template class Texture: public AbstractTexture { * available, the texture is bound to some texture unit before the * operation. Initial value is {@ref Sampler::Filter::Nearest, * @ref Sampler::Mipmap::Linear}. - * @see @ref setBaseLevel(), @ref setMaxLevel(), @fn_gl{ActiveTexture}, - * @fn_gl{BindTexture} and @fn_gl{TexParameter} or + * @see @ref setMagnificationFilter(), @ref setBaseLevel(), + * @ref setMaxLevel(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} + * and @fn_gl{TexParameter} or * @fn_gl_extension{TextureParameter,EXT,direct_state_access} with * @def_gl{TEXTURE_MIN_FILTER} */ @@ -270,27 +287,93 @@ template class Texture: public AbstractTexture { * texture size. If @extension{EXT,direct_state_access} is not * available, the texture is bound to some texture unit before the * operation. Initial value is @ref Sampler::Filter::Linear. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexParameter} - * or @fn_gl_extension{TextureParameter,EXT,direct_state_access} - * with @def_gl{TEXTURE_MAG_FILTER} + * @see @ref setMinificationFilter(), @fn_gl{ActiveTexture}, + * @fn_gl{BindTexture} and @fn_gl{TexParameter} or + * @fn_gl_extension{TextureParameter,EXT,direct_state_access} with + * @def_gl{TEXTURE_MAG_FILTER} */ Texture& setMagnificationFilter(Sampler::Filter filter) { AbstractTexture::setMagnificationFilter(filter); return *this; } + #ifndef MAGNUM_TARGET_GLES2 /** - * @brief Set wrapping - * @param wrapping Wrapping type for all texture dimensions + * @brief Set minimum level-of-detail parameter * @return Reference to self (for method chaining) * - * Sets wrapping type for coordinates out of range (0.0f, 1.0f). If + * Limits selection of highest resolution mipmap. If * @extension{EXT,direct_state_access} is not available, the texture is * bound to some texture unit before the operation. Initial value is - * @ref Sampler::Wrapping::Repeat. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexParameter} + * `-1000.0f`. + * @see @ref setMaxLod(), @ref setLodBias(), @fn_gl{ActiveTexture}, + * @fn_gl{BindTexture} and @fn_gl{TexParameter} or + * @fn_gl_extension{TextureParameter,EXT,direct_state_access} with + * @def_gl{TEXTURE_MIN_LOD} + * @requires_gles30 %Texture LOD parameters are not available in OpenGL + * ES 2.0. + */ + Texture& setMinLod(Float lod) { + AbstractTexture::setMinLod(lod); + return *this; + } + + /** + * @brief Set maximum level-of-detail parameter + * @return Reference to self (for method chaining) + * + * Limits selection of lowest resolution mipmap. If + * @extension{EXT,direct_state_access} is not available, the texture is + * bound to some texture unit before the operation. Initial value is + * `1000.0f`. + * @see @ref setMinLod(), @ref setLodBias(), @fn_gl{ActiveTexture}, + * @fn_gl{BindTexture} and @fn_gl{TexParameter} or + * @fn_gl_extension{TextureParameter,EXT,direct_state_access} with + * @def_gl{TEXTURE_MAX_LOD} + * @requires_gles30 %Texture LOD parameters are not available in OpenGL + * ES 2.0. + */ + Texture& setMaxLod(Float lod) { + AbstractTexture::setMaxLod(lod); + return *this; + } + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Set level-of-detail bias + * @return Reference to self (for method chaining) + * + * Fixed bias value that is added to the level-of-detail parameter. If + * @extension{EXT,direct_state_access} is not available, the texture is + * bound to some texture unit before the operation. Initial value is + * `0.0f`. + * @see @ref maxLodBias(), @ref setMinLod(), @ref setMaxLod(), + * @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexParameter} * or @fn_gl_extension{TextureParameter,EXT,direct_state_access} - * with @def_gl{TEXTURE_WRAP_S}, @def_gl{TEXTURE_WRAP_T}, + * with @def_gl{TEXTURE_LOD_BIAS} + * @requires_gl %Texture LOD bias can be specified only directly in + * fragment shader in OpenGL ES. + */ + Texture& setLodBias(Float bias) { + AbstractTexture::setLodBias(bias); + return *this; + } + #endif + + /** + * @brief Set wrapping + * @param wrapping Wrapping type for all texture dimensions + * @return Reference to self (for method chaining) + * + * Sets wrapping type for coordinates out of range @f$ [ 0.0, 1.0 ] @f$. + * If @extension{EXT,direct_state_access} is not available, the texture + * is bound to some texture unit before the operation. Initial value is + * @ref Sampler::Wrapping::Repeat. + * @see @ref setBorderColor(), @fn_gl{ActiveTexture}, + * @fn_gl{BindTexture} and @fn_gl{TexParameter} or + * @fn_gl_extension{TextureParameter,EXT,direct_state_access} with + * @def_gl{TEXTURE_WRAP_S}, @def_gl{TEXTURE_WRAP_T}, * @def_gl{TEXTURE_WRAP_R} */ Texture& setWrapping(const Array& wrapping) { @@ -306,9 +389,10 @@ template class Texture: public AbstractTexture { * If @extension{EXT,direct_state_access} is not available, the texture * is bound to some texture unit before the operation. Initial value is * `{0.0f, 0.0f, 0.0f, 0.0f}`. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexParameter} - * or @fn_gl_extension{TextureParameter,EXT,direct_state_access} - * with @def_gl{TEXTURE_BORDER_COLOR} + * @see @ref setWrapping(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} + * and @fn_gl{TexParameter} or + * @fn_gl_extension{TextureParameter,EXT,direct_state_access} with + * @def_gl{TEXTURE_BORDER_COLOR} * @requires_es_extension %Extension @es_extension{NV,texture_border_clamp} */ Texture& setBorderColor(const Color4& color) { @@ -368,6 +452,97 @@ template class Texture: public AbstractTexture { return *this; } + #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Set component swizzle + * @return Reference to self (for method chaining) + * + * You can use letters `r`, `g`, `b`, `a` for addressing components or + * letters `0` and `1` for zero and one, similarly as in + * @ref Math::swizzle() function. Example usage: + * @code + * texture.setSwizzle<'b', 'g', 'r', '0'>(); + * @endcode + * If @extension{EXT,direct_state_access} is not available, + * the texture is bound to some texture unit before the operation. + * Initial value is `rgba`. + * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @fn_gl{TexParameter} or + * @fn_gl_extension{TextureParameter,EXT,direct_state_access} with + * @def_gl{TEXTURE_SWIZZLE_RGBA} (or @def_gl{TEXTURE_SWIZZLE_R}, + * @def_gl{TEXTURE_SWIZZLE_G}, @def_gl{TEXTURE_SWIZZLE_B} and + * @def_gl{TEXTURE_SWIZZLE_A} separately in OpenGL ES) + * @requires_gl33 %Extension @extension{ARB,texture_swizzle} + * @requires_gles30 %Texture swizzle is not available in OpenGL ES 2.0. + */ + template Texture& setSwizzle() { + AbstractTexture::setSwizzle(); + return *this; + } + #endif + + /** + * @brief Set depth texture comparison mode + * @return Reference to self (for method chaining) + * + * If @extension{EXT,direct_state_access} is not available, + * the texture is bound to some texture unit before the operation. + * Initial value is @ref Sampler::CompareMode::None. + * @note Depth textures can be only 1D or 2D. + * @see @ref setCompareFunction(), @fn_gl{ActiveTexture}, + * @fn_gl{BindTexture} and @fn_gl{TexParameter} or + * @fn_gl_extension{TextureParameter,EXT,direct_state_access} with + * @def_gl{TEXTURE_COMPARE_MODE} + * @requires_gles30 %Extension @es_extension{EXT,shadow_samplers} + */ + Texture& setCompareMode(Sampler::CompareMode mode) { + AbstractTexture::setCompareMode(mode); + return *this; + } + + /** + * @brief Set depth texture comparison function + * @return Reference to self (for method chaining) + * + * Comparison operator used when comparison mode is set to + * @ref Sampler::CompareMode::CompareRefToTexture. If + * @extension{EXT,direct_state_access} is not available, the texture is + * bound to some texture unit before the operation. Initial value is + * @ref Sampler::CompareFunction::LessOrEqual. + * @note Depth textures can be only 1D or 2D. + * @see @ref setCompareMode(), @fn_gl{ActiveTexture}, + * @fn_gl{BindTexture} and @fn_gl{TexParameter} or + * @fn_gl_extension{TextureParameter,EXT,direct_state_access} with + * @def_gl{TEXTURE_COMPARE_FUNC} + * @requires_gles30 %Extension @es_extension{EXT,shadow_samplers} + */ + Texture& setCompareFunction(Sampler::CompareFunction function) { + AbstractTexture::setCompareFunction(function); + return *this; + } + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Set depth/stencil texture mode + * @return Reference to self (for method chaining) + * + * Selects which component of packed depth/stencil texture is used for + * texturing. If @extension{EXT,direct_state_access} is not available, + * the texture is bound to some texture unit before the operation. + * Initial value is @ref Sampler::DepthStencilMode::DepthComponent. + * @note Depth textures can be only 1D or 2D. + * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexParameter} + * or @fn_gl_extension{TextureParameter,EXT,direct_state_access} + * with @def_gl{DEPTH_STENCIL_TEXTURE_MODE} + * @requires_gl43 %Extension @extension{ARB,stencil_texturing} + * @requires_gl Stencil texturing is not available in OpenGL ES. + */ + Texture& setDepthStencilMode(Sampler::DepthStencilMode mode) { + AbstractTexture::setDepthStencilMode(mode); + return *this; + } + #endif + /** * @brief Set storage * @param levels Mip level count @@ -389,13 +564,14 @@ template class Texture: public AbstractTexture { * calls. * @todo allow the user to specify ColorType explicitly to avoid * issues in WebGL (see setSubImage()) - * @see @ref setMaxLevel(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} - * and @fn_gl{TexStorage1D}/@fn_gl{TexStorage2D}/@fn_gl{TexStorage3D} + * @see @ref maxSize(), @ref setMaxLevel(), @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}, - * eventually @fn_gl{TexImage1D}/@fn_gl{TexImage2D}/@fn_gl{TexImage3D} or - * @fn_gl_extension{TextureImage1D,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} */ @@ -440,6 +616,8 @@ template class Texture: public AbstractTexture { * * See @ref image(Int, Image&) for more information. * @requires_gl %Texture image queries are not available in OpenGL ES. + * @todo Make it more flexible (usable with + * @extension{ARB,buffer_storage}, avoiding relocations...) */ void image(Int level, BufferImage& image, BufferUsage usage) { AbstractTexture::image(_target, level, image, usage); @@ -460,7 +638,7 @@ template class Texture: public AbstractTexture { * * If @extension{EXT,direct_state_access} is not available, the * texture is bound to some texture unit before the operation. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @see @ref maxSize(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and * @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}/ diff --git a/src/Magnum/TextureArray.cpp b/src/Magnum/TextureArray.cpp new file mode 100644 index 000000000..fafd9d47b --- /dev/null +++ b/src/Magnum/TextureArray.cpp @@ -0,0 +1,58 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014 + 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 "TextureArray.h" + +#ifndef MAGNUM_TARGET_GLES2 +#include "Magnum/Context.h" +#include "Magnum/Extensions.h" + +#include "Implementation/maxTextureSize.h" + +namespace Magnum { + +namespace { + template struct VectorOrScalar; + template<> struct VectorOrScalar<1> { typedef Int Type; }; + template<> struct VectorOrScalar<2> { typedef Vector2i Type; }; +} + +template typename DimensionTraits::VectorType TextureArray::maxSize() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + return {}; + #endif + + return {typename VectorOrScalar::Type{Implementation::maxTextureSideSize()}, + Implementation::maxTextureArrayLayers()}; +} + +#ifndef MAGNUM_TARGET_GLES +template class MAGNUM_EXPORT TextureArray<1>; +#endif +template class MAGNUM_EXPORT TextureArray<2>; + +} +#endif diff --git a/src/Magnum/TextureArray.h b/src/Magnum/TextureArray.h index 4327ff006..0a671dbd7 100644 --- a/src/Magnum/TextureArray.h +++ b/src/Magnum/TextureArray.h @@ -84,18 +84,29 @@ In shader, the texture is used via `sampler1DArray`/`sampler2DArray`, or `usampler1DArray`/`usampler2DArray`. See @ref AbstractShaderProgram documentation for more information about usage in shaders. +@see @ref Texture1DArray, @ref Texture2DArray, @ref Texture, + @ref CubeMapTexture, @ref CubeMapTextureArray, @ref RectangleTexture, + @ref BufferTexture, @ref MultisampleTexture @requires_gl30 %Extension @extension{EXT,texture_array} @requires_gles30 %Array textures are not available in OpenGL ES 2.0. @requires_gl 1D array textures are not available in OpenGL ES, only 2D ones. - -@see @ref Texture1DArray, @ref Texture2DArray, @ref Texture, @ref BufferTexture, - @ref CubeMapTexture, @ref CubeMapTextureArray, @ref MultisampleTexture, - @ref RectangleTexture +@todo Fix this when @es_extension{NV,texture_array} is in ES2 extension headers */ template class TextureArray: public AbstractTexture { public: static const UnsignedInt Dimensions = dimensions; /**< @brief %Texture dimension count */ + /** + * @brief Max supported texture array size + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{EXT,texture_array} (part of + * OpenGL 3.0) is not available, returns zero vector. + * @see @fn_gl{Get} with @def_gl{MAX_TEXTURE_SIZE} and + * @def_gl{MAX_ARRAY_TEXTURE_LAYERS} + */ + static typename DimensionTraits::VectorType maxSize(); + /** * @brief Constructor * @@ -131,6 +142,28 @@ template class TextureArray: public AbstractTexture { return *this; } + #ifndef MAGNUM_TARGET_GLES2 + /** @copydoc Texture::setMinLod() */ + TextureArray& setMinLod(Float lod) { + AbstractTexture::setMinLod(lod); + return *this; + } + + /** @copydoc Texture::setMaxLod() */ + TextureArray& setMaxLod(Float lod) { + AbstractTexture::setMaxLod(lod); + return *this; + } + #endif + + #ifndef MAGNUM_TARGET_GLES + /** @copydoc Texture::setLodBias() */ + TextureArray& setLodBias(Float bias) { + AbstractTexture::setLodBias(bias); + return *this; + } + #endif + /** @copydoc Texture::setWrapping() */ TextureArray& setWrapping(const Array& wrapping) { DataHelper::setWrapping(*this, wrapping); @@ -163,6 +196,53 @@ template class TextureArray: public AbstractTexture { return *this; } + #ifndef MAGNUM_TARGET_GLES2 + /** @copydoc Texture::setSwizzle() */ + template TextureArray& setSwizzle() { + AbstractTexture::setSwizzle(); + return *this; + } + #endif + + /** + * @copybrief Texture::setCompareMode() + * @return Reference to self (for method chaining) + * + * See @ref Texture::setCompareMode() for more information. + * @requires_gles30 %Extension @es_extension{EXT,shadow_samplers} and + * @es_extension{NV,shadow_samplers_array} + */ + TextureArray& setCompareMode(Sampler::CompareMode mode) { + AbstractTexture::setCompareMode(mode); + return *this; + } + + /** + * @copybrief Texture::setCompareFunction() + * @return Reference to self (for method chaining) + * + * See @ref Texture::setCompareFunction() for more information. + * @requires_gles30 %Extension @es_extension{EXT,shadow_samplers} and + * @es_extension{NV,shadow_samplers_array} + */ + TextureArray& setCompareFunction(Sampler::CompareFunction function) { + AbstractTexture::setCompareFunction(function); + return *this; + } + + #ifndef MAGNUM_TARGET_GLES + /** + * @copybrief Texture::setDepthStencilMode() + * @return Reference to self (for method chaining) + * + * See @ref Texture::setDepthStencilMode() for more information. + */ + TextureArray& setDepthStencilMode(Sampler::DepthStencilMode mode) { + AbstractTexture::setDepthStencilMode(mode); + return *this; + } + #endif + #ifndef MAGNUM_TARGET_GLES /** @copydoc Texture::imageSize() */ typename DimensionTraits::VectorType imageSize(Int level) { @@ -188,7 +268,7 @@ template class TextureArray: public AbstractTexture { * @extension{ARB,texture_storage} (part of OpenGL 4.2) or OpenGL ES * 3.0 is not available, the feature is emulated with sequence of * @ref setImage() calls. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @see @ref maxSize(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and * @fn_gl{TexStorage2D}/@fn_gl{TexStorage3D} or * @fn_gl_extension{TextureStorage2D,EXT,direct_state_access}/ * @fn_gl_extension{TextureStorage3D,EXT,direct_state_access}, @@ -227,7 +307,7 @@ template class TextureArray: public AbstractTexture { * * If @extension{EXT,direct_state_access} is not available, the * texture is bound to some texture unit before the operation. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and + * @see @ref maxSize(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and * @fn_gl{TexImage2D}/@fn_gl{TexImage3D} or * @fn_gl_extension{TextureImage2D,EXT,direct_state_access}/ * @fn_gl_extension{TextureImage3D,EXT,direct_state_access} diff --git a/src/Magnum/TextureFormat.h b/src/Magnum/TextureFormat.h index b173c7960..55f83fa44 100644 --- a/src/Magnum/TextureFormat.h +++ b/src/Magnum/TextureFormat.h @@ -834,6 +834,7 @@ enum class TextureFormat: GLenum { * Depth and stencil component, size implementation-dependent. Not * supported in 3D textures, not allowed in unemulated * @ref Texture::setStorage() "*Texture::setStorage()" calls. + * @see @ref Texture::setDepthStencilMode() "*Texture::setDepthStencilMode()" * @deprecated_gl Prefer to use exactly specified version of this format, * e.g. @ref Magnum::TextureFormat::Depth24Stencil8 "TextureFormat::Depth24Stencil8". * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil} or @@ -847,6 +848,7 @@ enum class TextureFormat: GLenum { /** * 24bit depth and 8bit stencil component. Not supported in 3D textures. + * @see @ref Texture::setDepthStencilMode() "*Texture::setDepthStencilMode()" * @requires_gl30 %Extension @extension{ARB,framebuffer_object} * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil} and * (@es_extension{OES,required_internalformat} or @@ -863,6 +865,7 @@ enum class TextureFormat: GLenum { /** * 32bit float depth component and 8bit stencil component. Not supported in * 3D textures. + * @see @ref Texture::setDepthStencilMode() "*Texture::setDepthStencilMode()" * @requires_gl30 %Extension @extension{ARB,depth_buffer_float} * @requires_gles30 Only integral depth textures are available in OpenGL ES * 2.0. diff --git a/src/Magnum/TextureTools/DistanceField.cpp b/src/Magnum/TextureTools/DistanceField.cpp index ccb2aefd6..1145732bd 100644 --- a/src/Magnum/TextureTools/DistanceField.cpp +++ b/src/Magnum/TextureTools/DistanceField.cpp @@ -179,7 +179,7 @@ void distanceField(Texture2D& input, Texture2D& output, const Range2Di& rectangl Mesh mesh; mesh.setPrimitive(MeshPrimitive::Triangles) - .setVertexCount(3); + .setCount(3); /* Older GLSL doesn't have gl_VertexID, vertices must be supplied explicitly */ Buffer buffer;