diff --git a/doc/best-practices.dox b/doc/best-practices.dox index 723f27868..b1f17c9a0 100644 --- a/doc/best-practices.dox +++ b/doc/best-practices.dox @@ -80,6 +80,10 @@ vertex and index buffers in both Native Client and Emscripten. - [PowerVR Performance Recommendations](https://github.com/burningsun/pecker_framework/blob/master/参考资料/PowerVR.Performance%20Recommendations.pdf?raw=true) [PDF] +@subsection best-practices-amd AMD hardware + +- [ATI Radeon HD 2000 programming guide](http://developer.amd.com/wordpress/media/2012/10/ATI_Radeon_HD_2000_programming_guide.pdf) + @subsection best-practices-tegra NVidia Tegra hardware - [Optimize OpenGL ES 2.0 Performance for Tegra](http://docs.nvidia.com/tegra/index.html#GLES2_Perf_Main.html) diff --git a/doc/building.dox b/doc/building.dox index c442ad3ce..31b54c2d9 100644 --- a/doc/building.dox +++ b/doc/building.dox @@ -78,37 +78,53 @@ can be built and installed using these four commands: See @ref building-features "below" for additional configuration options. -@subsection building-windows Using QtCreator and CMake GUI (on Windows) +@subsection building-windows Building on Windows -On Windows, if you don't want to touch the command-line, the easiest way is to -install QtCreator (just QtCreator, you don't need the full Qt SDK) and -configure it to use MinGW and CMake. +On Windows you can use either MinGW or MSVC 2013 compiler. It's then up to you +whether you will use QtCreator, Visual Studio or do the build from command- +line. Note that for most convenient usage it's best use some dedicated +directory (e.g. `C:/Sys`) for installing dependencies instead of putting each +dependency to its own directory in `C:/Program Files`. Then add its `bin/` +subdir (e.g. `C:/Sys/bin`) to PATH so all the DLLs are found when running the +executables. If you are using MinGW, the `C:/MinGW` directory is in most cases +already prepared for exactly this. -For most convenient usage it's best to install (or copy/paste) all library -dependencies into directory where MinGW is installed (e.g. `C:/MinGW/`), -following proper filesystem hierarchy, i.e. headers into `include/` and -binaries into `bin/` or `lib/`. CMake will then have no problem finding them -and you won't need to explicitly specify path to each one. +When running CMake, set `CMAKE_FIND_ROOT_PATH` and `CMAKE_INSTALL_PREFIX` +parameters to that directory so CMake knows where to look for installed +libraries and where to install new ones. -Then just open project's root `CMakeLists.txt` file within QtCreator. It then +@subsubsection building-windows-msvc Using Visual Studio + +On Windows CMake by default creates Visual Studio project files. You need to +use `compatibility` branch to compile with MSVC 2013, as said above. + +The most straightforward way to build and install the library is again via the +command-line. The bonus point is that you don't even need to wait for Visual +Studio to load: + + mkdir build + cd build + cmake -DCMAKE_FIND_ROOT_PATH="C:/Sys" -DCMAKE_INSTALL_PREFIX="C:/Sys" .. + cmake --build . + cmake --build --target install . + +If you want to build and install from Visual Studio, just open the `Magnum.sln` +project file generated by CMake in the build directory. + +@subsubsection building-windows-qtcreator Using QtCreator + +On Windows you can also use QtCreator (just QtCreator, you don't need the full +Qt SDK). Configure it to use CMake and either MSVC compiler or MinGW and and +then just open project's root `CMakeLists.txt` file within it. QtCreator then asks you where to create build directory, allows you to specify initial CMake -parameters and then you can just press *Configure* and everything is be ready -to be built. +parameters (e.g. `CMAKE_FIND_ROOT_PATH` and `CMAKE_INSTALL_PREFIX`) and then +you can just press *Configure* and everything is ready to be built. After the initial import you might want to reconfigure some CMake variables, see @ref building-features "below" for more information. -For most convenient usage it's best to set `CMAKE_INSTALL_PREFIX` to directory -where MinGW is installed (e.g. `C:/MinGW/`) and add `C:/MinGW/bin` and -`C:/MinGW/lib` to `PATH`. Installation to given prefix can be then done from -within QtCreator by adding new `make install` build rule. - -@subsubsection building-windows-troubleshooting Windows troubleshooting - -If CMake isn't able to find dependencies (e.g. %Corrade is not found), point -`CMAKE_FIND_ROOT_PATH` and `CMAKE_INSTALL_PREFIX` to installation prefix of -dependency libraries, e.g. specify `-DCMAKE_FIND_ROOT_PATH=C:/MinGW/` CMake -parameter. +Installation to given prefix can be done from within QtCreator by adding new +`make install` build rule. @subsection building-features Enabling or disabling features @@ -269,6 +285,20 @@ project root: makepkg -p package/archlinux/ +@subsection building-packages-deb DEB packages + +There is also `package/debian/` directory with all files needed for building +Debian packages. You need to have `corrade-dev` DEB packages installed and in +addition also `dpkg-dev` package. Building is easy, just change directory to +package root, copy `package/debian` directory there and run `dpkg-buildpackage`: + + cp -r package/debian . + dpkg-buildpackage + +This will compile binary and development packages, which will then appear in +parent directory. If you need to modify CMake flags (enabling/disabling some +features, for example), modify the last entry in `debian/rules`. + @section building-crosscompiling Crosscompiling For crosscompiling you need to have *both* target and native version of diff --git a/doc/cmake.dox b/doc/cmake.dox index 07cd6fc26..c1b60c6e9 100644 --- a/doc/cmake.dox +++ b/doc/cmake.dox @@ -29,10 +29,17 @@ namespace Magnum { %Magnum uses CMake build system for both building and integration into your projects. The logic is in module `FindMagnum.cmake` distributed with the engine -in `modules/` directory, you are encouraged to copy it (and its dependencies) -into your project and add path to the files to `CMAKE_MODULE_PATH`. Otherwise, -if CMake won't be able to find this file in predefined locations, it will error -out even if %Magnum might be installed on the system. +in `modules/` directory, you are encouraged to copy it along with +`FindCorrade.cmake` into your project and add path to the files to +`CMAKE_MODULE_PATH`. Otherwise, if CMake won't be able to find this file in +predefined locations, it will error out even if %Magnum might be installed on +the system. If you plan to use Magnum on OpenGL ES, you may also need +`FindOpenGLES2.cmake` or `FindOpenGLES3.cmake` and in some cases also +`FindEGL.cmake`. + +Note that the module files are updated as the library evolves, you are +encouraged to update your copies from time to time to avoid strange building +issues. Basic usage is: @@ -44,10 +51,11 @@ variables: - `MAGNUM_FOUND` -- Whether the library was found - `MAGNUM_LIBRARIES` -- %Magnum library and dependent libraries - `MAGNUM_INCLUDE_DIRS` -- Root include dir and include dirs of dependencies -- `MAGNUM_PLUGINS_DIR` -- Base directory with plugins. You can modify it - (e.g. set it to `.` when deploying on Windows with plugins stored - relatively to the executable), the following `MAGNUM_PLUGINS_*_DIR` - variables depend on it. +- `MAGNUM_PLUGINS_DIR` -- Base directory with plugins, defaults to `magnum/` + subdirectory of dir where Magnum library was found. You can modify it (e.g. + set it to `.` when deploying on Windows with plugins stored relatively to + the executable), the following `MAGNUM_PLUGINS_*_DIR` variables depend on + it. - `MAGNUM_PLUGINS_FONT_DIR` -- Directory with font plugins - `MAGNUM_PLUGINS_FONTCONVERTER_DIR` -- Directory with font converter plugins - `MAGNUM_PLUGINS_IMAGECONVERTER_DIR` -- Directory with image converter diff --git a/doc/getting-started.dox b/doc/getting-started.dox index 71fab0589..adcdd39a7 100644 --- a/doc/getting-started.dox +++ b/doc/getting-started.dox @@ -34,7 +34,9 @@ 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. +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. @section getting-started-bootstrap Download bootstrap project @@ -52,6 +54,12 @@ 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). +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. + @section getting-started-review Review project structure The base project consists of just six files in two subfolders. %Magnum uses @@ -144,14 +152,26 @@ of build dir: make ./src/MyApplication -On Windows, if you don't want to touch the command-line, the easiest way is to -open root `CMakeLists.txt` in QtCreator, let it import the project and then -just build and run the application. If CMake isn't able to find the -dependencies or the building fails for some reason, you might want to look at -@ref building-windows-troubleshooting. +On Windows you can use either MinGW or MSVC 2013 compiler. It's then up to you +whether you will use QtCreator or Visual Studio. With Visual Studio the most +straightforward way to create the project file is via the command-line: + + mkdir build + cd build + cmake -DCMAKE_FIND_ROOT_PATH="C:/Sys" .. + +You can also use CMake GUI. Then open the `MyApplication.sln` project file +generated by CMake in the build directory. + +With QtCreator just open project's root `CMakeLists.txt` file. It then asks you +where to create build directory, allows you to specify initial CMake parameters +(e.g. `CMAKE_FIND_ROOT_PATH`) and then you can just press *Configure* and +everything is ready to be built. -If CMake complains about `GlutApplication` missing, you forgot to enable -`WITH_GLUTAPPLICATION` when building %Magnum, @ref getting-started-download "go back and fix it". +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, +@ref getting-started-download "go back and fix it". @image html getting-started.png @image latex getting-started.png @@ -164,6 +184,7 @@ First include the needed headers: #include #include #include +#include @endcode And in the constructor (which is currently empty) change the clear color and diff --git a/doc/opengl-mapping.dox b/doc/opengl-mapping.dox index 9af6e3774..c855e4bb8 100644 --- a/doc/opengl-mapping.dox +++ b/doc/opengl-mapping.dox @@ -137,7 +137,7 @@ OpenGL function | Matching API @fn_gl{GenTextures}, @fn_gl{DeleteTextures} | @ref AbstractTexture constructor and destructor @fn_gl{GenTransformFeedbacks}, @fn_gl{DeleteTransformFeedbacks} | | @fn_gl{GenVertexArrays}, @fn_gl{DeleteVertexArrays} | @ref Mesh constructor and destructor -@fn_gl{GenerateMipmap}, \n @fn_gl_extension{GenerateTextureMipmap,EXT,direct_state_access} | @ref AbstractTexture::generateMipmap() +@fn_gl{GenerateMipmap}, \n @fn_gl_extension{GenerateTextureMipmap,EXT,direct_state_access} | @ref Texture::generateMipmap(), \n @ref TextureArray::generateMipmap(), \n @ref CubeMapTexture::generateMipmap(), \n @ref CubeMapTextureArray::generateMipmap() @fn_gl{Get} | see @ref opengl-mapping-state "table below" @fn_gl2{GetActiveAtomicCounterBuffer,GetActiveAtomicCounterBufferiv} | not queryable @fn_gl{GetActiveAttrib}, \n @fn_gl{GetActiveSubroutineName}, \n @fn_gl{GetActiveSubroutineUniform}, \n @fn_gl{GetActiveSubroutineUniformName}, \n @fn_gl{GetActiveUniform}, \n @fn_gl{GetActiveUniformBlock}, \n @fn_gl{GetActiveUniformBlockName}, \n @fn_gl{GetActiveUniformName}, \n @fn_gl{GetActiveUniforms} | not queryable @@ -155,7 +155,7 @@ OpenGL function | Matching API @fn_gl_extension{GetGraphicsResetStatus,ARB,robustness} | @ref Renderer::graphicsResetStatus() @fn_gl{GetInternalformat} | | @fn_gl{GetMultisample} | | -@fn_gl{GetObjectLabel}, \n @fn_gl{GetObjectPtrLabel} | not queryable, @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() and \n @ref Shader::setLabel() setters only +@fn_gl{GetObjectLabel}, \n @fn_gl{GetObjectPtrLabel} | @ref AbstractShaderProgram::label(), \n @ref AbstractQuery::label(), \n @ref AbstractTexture::label(), \n @ref Buffer::label(), \n @ref Framebuffer::label(), \n @ref Mesh::label(), \n @ref Renderbuffer::label(), \n @ref Shader::label() @fn_gl{GetProgram}, \n @fn_gl{GetProgramInfoLog} | @ref AbstractShaderProgram::link(), \n @ref AbstractShaderProgram::validate() @fn_gl{GetProgramBinary} | | @fn_gl{GetProgramInterface} | | @@ -193,8 +193,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 AbstractTexture::invalidateImage() -@fn_gl{InvalidateTexSubImage} | @ref Texture::invalidateSubImage(),\n @ref CubeMapTexture::invalidateSubImage(), \n @ref CubeMapTextureArray::invalidateSubImage() +@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{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() @@ -239,7 +239,7 @@ OpenGL function | Matching API @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 AbstractTexture::setMinificationFilter(), \n @ref AbstractTexture::setMagnificationFilter(), \n @ref AbstractTexture::setBorderColor(), \n @ref AbstractTexture::setMaxAnisotropy(), \n @ref Texture::setWrapping(), \n @ref CubeMapTexture::setWrapping(), \n @ref CubeMapTextureArray::setWrapping() +@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() @@ -248,7 +248,7 @@ OpenGL function | Matching API @fn_gl{Uniform}, \n @fn_gl{ProgramUniform}, \n @fn_gl_extension{ProgramUniform,EXT,direct_state_access} | @ref AbstractShaderProgram::setUniform() @fn_gl{UniformBlockBinding} | | @fn_gl{UniformSubroutines} | | -@fn_gl{UseProgram} | @ref AbstractShaderProgram::use() +@fn_gl{UseProgram} | @ref Mesh::draw(), @ref MeshView::draw() @fn_gl{UseProgramStages} | | @fn_gl{ValidateProgram} | @ref AbstractShaderProgram::validate() @fn_gl{ValidateProgramPipeline} | | @@ -343,7 +343,7 @@ OpenGL function | Matching API @def_gl{MAX_UNIFORM_BUFFER_BINDINGS} | @ref Buffer::maxUniformBindings() @def_gl{MAX_UNIFORM_LOCATIONS} | @ref AbstractShaderProgram::maxUniformLocations() @def_gl{MAX_VERTEX_ATTRIBS} | @ref AbstractShaderProgram::maxVertexAttributes() -@def_gl{MAX_VERTEX_ATTRIB_BINDINGS} | @ref Buffer::maxVertexAttributeBindings() +@def_gl{MAX_VERTEX_ATTRIB_BINDINGS} | | @def_gl{MAX_VERTEX_ATTRIB_RELATIVE_OFFSET} | | @def_gl{MAX_VIEWPORTS} | | @def_gl{MAX_VIEWPORT_DIMS} | @ref AbstractFramebuffer::maxViewportSize() diff --git a/doc/opengl-support.dox b/doc/opengl-support.dox index e93162150..f103f292b 100644 --- a/doc/opengl-support.dox +++ b/doc/opengl-support.dox @@ -47,8 +47,11 @@ following: @subsection opengl-support-30 OpenGL 3.0 -@todo @extension{APPLE,flush_buffer_range} doesn't add anything to @extension{ARB,map_buffer_range} +@todo Replace @extension{APPLE,vertex_array_object} with ARB version (we use only ARB functions without APPLE fallback) +@todo @extension{APPLE,flush_buffer_range} doesn't add anything to @extension{ARB,map_buffer_range} (remove it and leave only ARB one) @todo @extension{EXT,texture_array} overlaps with @extension{ARB,framebuffer_object} +@todo Add @extension{ARB,depth_buffer_float} and implement the missing @fn_gl{DepthRange} function, but keep (and implement) @extension{NV,depth_buffer_float} for non-linear depth buffer +@todo @extension{ARB,half_float_pixel}, @extension{ARB,half_float_vertex}? %Extension | Status -------------------------------------------- | ------ @@ -60,10 +63,10 @@ following: @extension{ARB,texture_float} | done @extension{ARB,depth_buffer_float} | done @extension{ARB,texture_rg} | done -@extension{ARB,framebuffer_object} | missing texture layer attachments +@extension{ARB,framebuffer_object} | done @extension{EXT,gpu_shader4} | done @extension{EXT,packed_float} | done -@extension{EXT,texture_array} | missing texture layer attachments +@extension{EXT,texture_array} | done @extension{EXT,texture_compression_rgtc} | done @extension{EXT,texture_shared_exponent} | done @extension{EXT,framebuffer_sRGB} | | @@ -90,7 +93,7 @@ following: %Extension | Status -------------------------------------------- | ------ -@extension{ARB,geometry_shader4} | done (GL 3.2 subset) +@extension{ARB,geometry_shader4} | missing layered attachments @extension{ARB,depth_clamp} | done @extension{ARB,draw_elements_base_vertex} | | @extension{ARB,fragment_coord_conventions} | done (shading language only) @@ -139,7 +142,7 @@ following: -------------------------------------------- | ------ @extension{ARB,ES2_compatibility} | only float depth clear @extension{ARB,get_program_binary} | | -@extension{ARB,separate_shader_objects} | | +@extension{ARB,separate_shader_objects} | only direct uniform binding @extension{ARB,shader_precision} | done (shading language only) @extension{ARB,vertex_attrib_64bit} | done @extension{ARB,viewport_array} | | @@ -190,6 +193,9 @@ following: @subsection opengl-support-44 OpenGL 4.4 +@todo Also fallback to @extension{AMD,query_buffer_object} +@todo @extension{AMD,pinned_memory} "fallback" for @extension{ARB,buffer_storage} + %Extension | Status -------------------------------------------- | ------ @extension{ARB,buffer_storage} | | @@ -203,6 +209,10 @@ following: @subsection opengl-support-extensions OpenGL extensions +@todo @extension{ARB,sparse_texture}, @extension{ARB,bindless_texture} + their vendor equivalents +@todo @extension{ATI,meminfo}, @extension{NVX,gpu_memory_info}, GPU temperature +@todo @extension{AMD,performance_monitor}, @extension{INTEL,performance_query} + %Extension | Status -------------------------------------------- | ------ @extension{AMD,vertex_shader_layer} | done (shading language only) @@ -250,6 +260,7 @@ supported. @es_extension{OES,depth24} | done @es_extension{OES,element_index_uint} | done @es_extension{OES,rgb8_rgba8} | done (desktop-compatible subset) +@es_extension{OES,texture_3D} | missing limit query @es_extension2{OES,texture_half_float_linear,OES_texture_float_linear} | done @es_extension{OES,texture_float_linear} | done @es_extension2{OES,texture_half_float,OES_texture_float} | done @@ -266,6 +277,10 @@ supported. Only extensions not already listed in above tables are included here. +@todo @es_extension{NV,non_square_matrices} +@todo Support also IMG_multisampled_render_to_texture? It has different enum + values (!) + %Extension | Status -------------------------------------------- | ------ @es_extension{APPLE,texture_format_BGRA8888} | done @@ -273,7 +288,7 @@ Only extensions not already listed in above tables are included here. @es_extension{EXT,texture_format_BGRA8888} | done @es_extension{EXT,read_format_bgra} | done @es_extension{EXT,disjoint_timer_query} | only time elapsed query -@es_extension{EXT,separate_shader_objects} | | +@es_extension{EXT,separate_shader_objects} | only direct uniform binding @es_extension{EXT,sRGB} | done @es_extension{EXT,multisampled_render_to_texture} | only renderbuffer storage @es_extension{EXT,robustness} | done @@ -286,7 +301,6 @@ Only extensions not already listed in above tables are included here. @es_extension{OES,mapbuffer} | done @es_extension{OES,stencil1} | done @es_extension{OES,stencil4} | done -@es_extension{OES,texture_3D} | missing limit query @section opengl-unsupported Unsupported OpenGL features diff --git a/doc/plugins.dox b/doc/plugins.dox index ddc64c1db..95ab27ca7 100644 --- a/doc/plugins.dox +++ b/doc/plugins.dox @@ -120,10 +120,6 @@ lifetime of all plugin instances created from it. std::exit(1); } std::unique_ptr tgaImporter = manager.instance("TgaImporter"); - if(!tgaImporter) { - Error() << "Cannot instantiate TgaImporter plugin"; - std::exit(2); - } // Use the plugin... diff --git a/doc/scenegraph.dox b/doc/scenegraph.dox index 877d48704..85ec71c42 100644 --- a/doc/scenegraph.dox +++ b/doc/scenegraph.dox @@ -165,10 +165,10 @@ class Bomb: public Object3D, SceneGraph::Drawable3D, SceneGraph::Animable3D { protected: // drawing implementation for Drawable feature - void draw() override; + void draw(...) override; // animation step for Animable feature - void animationStep() override; + void animationStep(...) override; }; @endcode diff --git a/doc/troubleshooting.dox b/doc/troubleshooting.dox index 114d7d280..f9a096240 100644 --- a/doc/troubleshooting.dox +++ b/doc/troubleshooting.dox @@ -26,7 +26,7 @@ namespace Magnum { /** @page troubleshooting Troubleshooting -@brief Various tricks to overcome to common building and rendering issues. +@brief Various tricks to overcome common building and rendering issues. @section troubleshooting-building Building issues diff --git a/modules/FindMagnum.cmake b/modules/FindMagnum.cmake index 6b8a2f99b..998911a3a 100644 --- a/modules/FindMagnum.cmake +++ b/modules/FindMagnum.cmake @@ -7,9 +7,10 @@ # MAGNUM_LIBRARIES - Magnum library and dependent libraries # MAGNUM_INCLUDE_DIRS - Root include dir and include dirs of # dependencies -# MAGNUM_PLUGINS_DIR - Base directory with plugins. You can modify -# it (e.g. set it to `.` when deploying on Windows with plugins stored -# relatively to the executable), the following MAGNUM_PLUGINS_*_DIR +# MAGNUM_PLUGINS_DIR - Base directory with plugins, defaults to +# `magnum/` subdirectory of dir where Magnum library was found. You can +# modify it (e.g. set it to `.` when deploying on Windows with plugins +# stored relatively to the executable), the following MAGNUM_PLUGINS_*_DIR # variables depend on it. # MAGNUM_PLUGINS_FONT_DIR - Directory with font plugins # MAGNUM_PLUGINS_FONTCONVERTER_DIR - Directory with font converter plugins @@ -244,7 +245,7 @@ foreach(component ${Magnum_FIND_COMPONENTS}) if(${component} STREQUAL GlutApplication) find_package(GLUT) if(GLUT_FOUND) - set(_MAGNUM_${_COMPONENT}_LIBRARIES ${GLUT_LIBRARIES} ${_WINDOWCONTEXT_MAGNUM_LIBRARIES_DEPENDENCY}) + set(_MAGNUM_${_COMPONENT}_LIBRARIES ${GLUT_glut_LIBRARY} ${_WINDOWCONTEXT_MAGNUM_LIBRARIES_DEPENDENCY}) else() unset(MAGNUM_${_COMPONENT}_LIBRARY) endif() @@ -404,7 +405,9 @@ if(MAGNUM_BUILD_DEPRECATED) set(MAGNUM_PLUGINS_INCLUDE_DIR ${MAGNUM_INCLUDE_DIR}/MagnumPlugins) endif() -set(MAGNUM_PLUGINS_DIR ${MAGNUM_PLUGINS_INSTALL_DIR} +# Get base plugin directory from main library location +get_filename_component(_MAGNUM_LIBRARY_PATH ${MAGNUM_LIBRARY} PATH) +set(MAGNUM_PLUGINS_DIR ${_MAGNUM_LIBRARY_PATH}/magnum CACHE PATH "Base directory where to look for Magnum plugins") # Plugin directories diff --git a/package/archlinux/PKGBUILD b/package/archlinux/PKGBUILD index 79a64b1a6..c21cc7040 100644 --- a/package/archlinux/PKGBUILD +++ b/package/archlinux/PKGBUILD @@ -8,7 +8,7 @@ url="http://mosra.cz/blog/magnum.php" license=('MIT') depends=('corrade' 'openal' 'freeglut' 'sdl2') makedepends=('cmake' 'ninja') -options=(!strip) +options=('!strip' 'staticlibs') provides=('magnum-git') build() { diff --git a/package/archlinux/PKGBUILD-clang b/package/archlinux/PKGBUILD-clang index f98b4b14e..45f89c36a 100644 --- a/package/archlinux/PKGBUILD-clang +++ b/package/archlinux/PKGBUILD-clang @@ -8,7 +8,7 @@ url="http://mosra.cz/blog/magnum.php" license=('MIT') depends=('corrade' 'openal' 'freeglut' 'sdl2') makedepends=('cmake' 'clang' 'ninja') -options=(!strip) +options=('!strip' 'staticlibs') provides=('magnum-git') build() { diff --git a/package/archlinux/PKGBUILD-clang-libc++ b/package/archlinux/PKGBUILD-clang-libc++ index e11965e27..88bc44219 100644 --- a/package/archlinux/PKGBUILD-clang-libc++ +++ b/package/archlinux/PKGBUILD-clang-libc++ @@ -8,7 +8,7 @@ url="http://mosra.cz/blog/magnum.php" license=('MIT') depends=('corrade' 'openal' 'freeglut' 'sdl2' 'libc++') makedepends=('cmake' 'clang' 'ninja') -options=(!strip) +options=('!strip' 'staticlibs') provides=('magnum-git') build() { diff --git a/package/archlinux/PKGBUILD-emscripten b/package/archlinux/PKGBUILD-emscripten index 30993b1f2..7de134779 100644 --- a/package/archlinux/PKGBUILD-emscripten +++ b/package/archlinux/PKGBUILD-emscripten @@ -8,7 +8,7 @@ url="http://mosra.cz/blog/magnum.php" license=('MIT') depends=('emscripten-corrade') makedepends=('cmake' 'ninja') -options=(!strip !buildflags) +options=('!strip' '!buildflags' 'staticlibs') build() { if [ ! -d "$startdir/build-emscripten" ] ; then diff --git a/package/archlinux/PKGBUILD-es2 b/package/archlinux/PKGBUILD-es2 index a841a7229..c1c9e82d3 100644 --- a/package/archlinux/PKGBUILD-es2 +++ b/package/archlinux/PKGBUILD-es2 @@ -8,7 +8,7 @@ url="http://mosra.cz/blog/magnum.php" license=('MIT') depends=('corrade' 'openal') makedepends=('cmake' 'ninja') -options=(!strip) +options=('!strip' 'staticlibs') provides=('magnum-git') build() { diff --git a/package/archlinux/PKGBUILD-es2desktop b/package/archlinux/PKGBUILD-es2desktop index bdceef969..97e88d78f 100644 --- a/package/archlinux/PKGBUILD-es2desktop +++ b/package/archlinux/PKGBUILD-es2desktop @@ -8,7 +8,7 @@ url="http://mosra.cz/blog/magnum.php" license=('MIT') depends=('corrade' 'openal') makedepends=('cmake' 'ninja') -options=(!strip) +options=('!strip' 'staticlibs') provides=('magnum-git') build() { diff --git a/package/archlinux/PKGBUILD-es3 b/package/archlinux/PKGBUILD-es3 index 4bcf048e0..dbecf3486 100644 --- a/package/archlinux/PKGBUILD-es3 +++ b/package/archlinux/PKGBUILD-es3 @@ -8,7 +8,7 @@ url="http://mosra.cz/blog/magnum.php" license=('MIT') depends=('corrade' 'openal') makedepends=('cmake' 'ninja') -options=(!strip) +options=('!strip' 'staticlibs') provides=('magnum-git') build() { diff --git a/package/archlinux/PKGBUILD-es3desktop b/package/archlinux/PKGBUILD-es3desktop index e47b3fdfc..a84fa45ea 100644 --- a/package/archlinux/PKGBUILD-es3desktop +++ b/package/archlinux/PKGBUILD-es3desktop @@ -8,7 +8,7 @@ url="http://mosra.cz/blog/magnum.php" license=('MIT') depends=('corrade' 'openal') makedepends=('cmake' 'ninja') -options=(!strip) +options=('!strip' 'staticlibs') provides=('magnum-git') build() { diff --git a/package/archlinux/PKGBUILD-gcc46 b/package/archlinux/PKGBUILD-gcc46 index ba70ed497..15a1c6100 100644 --- a/package/archlinux/PKGBUILD-gcc46 +++ b/package/archlinux/PKGBUILD-gcc46 @@ -8,7 +8,7 @@ url="http://mosra.cz/blog/magnum.php" license=('MIT') depends=('corrade' 'openal' 'freeglut' 'sdl2') makedepends=('cmake' 'ninja' 'gcc46') -options=(!strip) +options=('!strip' 'staticlibs') provides=('magnum-git') build() { diff --git a/package/archlinux/PKGBUILD-gcc47 b/package/archlinux/PKGBUILD-gcc47 index 5867486a8..600cc598f 100644 --- a/package/archlinux/PKGBUILD-gcc47 +++ b/package/archlinux/PKGBUILD-gcc47 @@ -8,7 +8,7 @@ url="http://mosra.cz/blog/magnum.php" license=('MIT') depends=('corrade' 'openal' 'freeglut' 'sdl2') makedepends=('cmake' 'ninja' 'gcc47') -options=(!strip) +options=('!strip' 'staticlibs') provides=('magnum-git') build() { diff --git a/package/archlinux/PKGBUILD-gcc49 b/package/archlinux/PKGBUILD-gcc49 index a8043f0f2..02d6db4da 100644 --- a/package/archlinux/PKGBUILD-gcc49 +++ b/package/archlinux/PKGBUILD-gcc49 @@ -8,7 +8,7 @@ url="http://mosra.cz/blog/magnum.php" license=('MIT') depends=('corrade' 'openal' 'freeglut' 'sdl2') makedepends=('cmake' 'ninja' 'gcc-git') -options=(!strip) +options=('!strip' 'staticlibs') provides=('magnum-git') build() { diff --git a/package/archlinux/PKGBUILD-mingw32 b/package/archlinux/PKGBUILD-mingw32 index 782719c79..594932067 100644 --- a/package/archlinux/PKGBUILD-mingw32 +++ b/package/archlinux/PKGBUILD-mingw32 @@ -8,7 +8,7 @@ url="http://mosra.cz/blog/magnum.php" license=('MIT') depends=('mingw32-runtime' 'mingw32-corrade' 'mingw32-freeglut' 'mingw32-openal') makedepends=('mingw32-gcc' 'cmake' 'ninja' 'corrade') -options=(!buildflags !strip) +options=('!buildflags' '!strip' 'staticlibs') build() { mkdir -p "$startdir/build-win" diff --git a/package/archlinux/PKGBUILD-nacl-glibc b/package/archlinux/PKGBUILD-nacl-glibc index ba1684803..3a3477d09 100644 --- a/package/archlinux/PKGBUILD-nacl-glibc +++ b/package/archlinux/PKGBUILD-nacl-glibc @@ -8,7 +8,7 @@ url="http://mosra.cz/blog/magnum.php" license=('MIT') depends=('nacl-corrade') makedepends=('nacl-sdk' 'cmake' 'corrade' 'ninja') -options=(!buildflags !strip) +options=('!buildflags' '!strip' 'staticlibs') build() { # Build 32bit diff --git a/package/archlinux/PKGBUILD-nacl-newlib b/package/archlinux/PKGBUILD-nacl-newlib index 5d9409892..d2a23fb6f 100644 --- a/package/archlinux/PKGBUILD-nacl-newlib +++ b/package/archlinux/PKGBUILD-nacl-newlib @@ -8,7 +8,7 @@ url="http://mosra.cz/blog/magnum.php" license=('MIT') depends=('nacl-corrade') makedepends=('nacl-sdk' 'cmake' 'corrade' 'ninja') -options=(!buildflags !strip) +options=('!buildflags' '!strip' 'staticlibs') build() { # Build 32bit diff --git a/package/archlinux/PKGBUILD-release b/package/archlinux/PKGBUILD-release index 031abcd9d..61ff12d04 100644 --- a/package/archlinux/PKGBUILD-release +++ b/package/archlinux/PKGBUILD-release @@ -9,6 +9,7 @@ license=('MIT') depends=('corrade' 'openal' 'sdl2' 'freeglut') makedepends=('cmake' 'ninja') provides=('magnum-git') +options=('staticlibs') build() { mkdir -p "$startdir/build" diff --git a/package/archlinux/magnum-git/PKGBUILD b/package/archlinux/magnum-git/PKGBUILD index 45260cd8a..e3ca44e5f 100644 --- a/package/archlinux/magnum-git/PKGBUILD +++ b/package/archlinux/magnum-git/PKGBUILD @@ -1,6 +1,6 @@ # Author: mosra pkgname=magnum-git -pkgver=20130819 +pkgver=20140123 pkgrel=1 pkgdesc="C++11 and OpenGL 2D/3D graphics engine (Git version)" arch=('i686' 'x86_64') @@ -10,6 +10,7 @@ depends=('corrade-git' 'openal' 'freeglut') makedepends=('cmake' 'git') provides=('magnum') conflicts=('magnum') +options=('staticlibs') _gitroot="git://github.com/mosra/magnum.git" _gitname="magnum" @@ -38,9 +39,17 @@ build() { cmake ../$_gitname \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr \ + -DWITH_AUDIO=ON \ -DWITH_GLUTAPPLICATION=ON \ -DWITH_GLXAPPLICATION=ON \ -DWITH_WINDOWLESSGLXAPPLICATION=ON \ + -DWITH_MAGNUMFONT=ON \ + -DWITH_MAGNUMFONTCONVERTER=ON \ + -DWITH_TGAIMAGECONVERTER=ON \ + -DWITH_TGAIMPORTER=ON \ + -DWITH_WAVAUDIOIMPORTER=ON \ + -DWITH_DISTANCEFIELDCONVERTER=ON \ + -DWITH_FONTCONVERTER=ON \ -DWITH_MAGNUMINFO=ON make } diff --git a/package/debian/changelog b/package/debian/changelog new file mode 100644 index 000000000..796c69eba --- /dev/null +++ b/package/debian/changelog @@ -0,0 +1,5 @@ +magnum (1.0-1) UNRELEASED; urgency=low + + * Latest upstream version + + -- Vladimír Vondruš Fri, 31 Jan 2014 12:20:58 +0100 diff --git a/package/debian/compat b/package/debian/compat new file mode 100644 index 000000000..ec635144f --- /dev/null +++ b/package/debian/compat @@ -0,0 +1 @@ +9 diff --git a/package/debian/control b/package/debian/control new file mode 100644 index 000000000..c8889b81c --- /dev/null +++ b/package/debian/control @@ -0,0 +1,25 @@ +Source: magnum +Priority: optional +Maintainer: Vladimír Vondruš +Build-Depends: debhelper (>= 9), cmake (>= 2.8.8) +Standards-Version: 3.9.2 +Section: libs +Homepage: http://mosra.cz/blog/magnum.php +Vcs-Git: git://github.com/mosra/magnum.git +Vcs-Browser: https://github.com/mosra/magnum + +Package: magnum-dev +Section: libdevel +Architecture: any +Depends: magnum (= ${binary:Version}), corrade-dev, libgl-dev, freeglut3-dev, libopenal-dev +Description: Magnum development files + Headers and tools needed for developing with Magnum. + +Package: magnum +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, corrade, libgl1, freeglut3, libopenal1 +Description: C++11 and OpenGL 2D/3D graphics engine + Magnum is 2D/3D graphics engine written in C++11 and modern OpenGL. Its goal + is to simplify low-level graphics development and interaction with OpenGL + using recent C++11 features and to abstract away platform-specific issues. diff --git a/package/debian/copyright b/package/debian/copyright new file mode 100644 index 000000000..a9eaab973 --- /dev/null +++ b/package/debian/copyright @@ -0,0 +1,25 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: Magnum +Upstream-Contact: Vladimír Vondruš +Source: https://github.com/mosra/magnum + +Files: * +Copyright: 2010-2014 Vladimír Vondruš +License: Expat + 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. diff --git a/package/debian/magnum-dev.install b/package/debian/magnum-dev.install new file mode 100644 index 000000000..b76bb83af --- /dev/null +++ b/package/debian/magnum-dev.install @@ -0,0 +1,4 @@ +usr/include/Magnum/* +usr/include/MagnumExternal/* +usr/include/MagnumPlugins/* +usr/lib*/lib*.a diff --git a/package/debian/magnum.install b/package/debian/magnum.install new file mode 100644 index 000000000..a6d60262c --- /dev/null +++ b/package/debian/magnum.install @@ -0,0 +1,3 @@ +usr/bin/* +usr/lib*/magnum/* +usr/lib*/lib*.so diff --git a/package/debian/rules b/package/debian/rules new file mode 100755 index 000000000..3723072df --- /dev/null +++ b/package/debian/rules @@ -0,0 +1,19 @@ +#!/usr/bin/make -f + +%: + dh $@ --parallel + +override_dh_auto_configure: + dh_auto_configure -- \ + -DWITH_AUDIO=ON \ + -DWITH_GLUTAPPLICATION=ON \ + -DWITH_GLXAPPLICATION=ON \ + -DWITH_WINDOWLESSGLXAPPLICATION=ON \ + -DWITH_MAGNUMFONT=ON \ + -DWITH_MAGNUMFONTCONVERTER=ON \ + -DWITH_TGAIMAGECONVERTER=ON \ + -DWITH_TGAIMPORTER=ON \ + -DWITH_WAVAUDIOIMPORTER=ON \ + -DWITH_DISTANCEFIELDCONVERTER=ON \ + -DWITH_FONTCONVERTER=ON \ + -DWITH_MAGNUMINFO=ON diff --git a/package/debian/source/format b/package/debian/source/format new file mode 100644 index 000000000..89ae9db8f --- /dev/null +++ b/package/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/src/Magnum/AbstractFramebuffer.cpp b/src/Magnum/AbstractFramebuffer.cpp index 8eb210fa2..9500c4b7f 100644 --- a/src/Magnum/AbstractFramebuffer.cpp +++ b/src/Magnum/AbstractFramebuffer.cpp @@ -37,19 +37,6 @@ namespace Magnum { -AbstractFramebuffer::CheckStatusImplementation AbstractFramebuffer::checkStatusImplementation = &AbstractFramebuffer::checkStatusImplementationDefault; - -AbstractFramebuffer::ReadImplementation AbstractFramebuffer::readImplementation = &AbstractFramebuffer::readImplementationDefault; - -AbstractFramebuffer::DrawBuffersImplementation AbstractFramebuffer::drawBuffersImplementation = &AbstractFramebuffer::drawBuffersImplementationDefault; -AbstractFramebuffer::DrawBufferImplementation AbstractFramebuffer::drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDefault; -AbstractFramebuffer::ReadBufferImplementation AbstractFramebuffer::readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDefault; - -#ifdef MAGNUM_TARGET_GLES2 -FramebufferTarget AbstractFramebuffer::readTarget = FramebufferTarget::ReadDraw; -FramebufferTarget AbstractFramebuffer::drawTarget = FramebufferTarget::ReadDraw; -#endif - Vector2i AbstractFramebuffer::maxViewportSize() { Vector2i& value = Context::current()->state().framebuffer->maxViewportSize; @@ -136,9 +123,9 @@ FramebufferTarget AbstractFramebuffer::bindInternal() { glBindFramebuffer(GLenum(FramebufferTarget::Read), _id); return FramebufferTarget::Read; #else - if(readTarget == FramebufferTarget::ReadDraw) state->drawBinding = _id; - glBindFramebuffer(GLenum(readTarget), _id); - return readTarget; + if(state->readTarget == FramebufferTarget::ReadDraw) state->drawBinding = _id; + glBindFramebuffer(GLenum(state->readTarget), _id); + return state->readTarget; #endif } @@ -186,20 +173,22 @@ void AbstractFramebuffer::clear(FramebufferClearMask mask) { #ifndef MAGNUM_TARGET_GLES2 bindInternal(FramebufferTarget::Draw); #else - bindInternal(drawTarget); + bindInternal(Context::current()->state().framebuffer->drawTarget); #endif glClear(GLbitfield(mask)); } void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, Image2D& image) { + const Implementation::FramebufferState& state = *Context::current()->state().framebuffer; + #ifndef MAGNUM_TARGET_GLES2 bindInternal(FramebufferTarget::Read); #else - bindInternal(readTarget); + bindInternal(state.readTarget); #endif const std::size_t dataSize = image.dataSize(size); char* const data = new char[dataSize]; - readImplementation(offset, size, image.format(), image.type(), dataSize, data); + (state.readImplementation)(offset, size, image.format(), image.type(), dataSize, data); image.setData(image.format(), image.type(), size, data); } @@ -216,7 +205,7 @@ void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, Buf image.setData(image.format(), image.type(), size, nullptr, usage); image.buffer().bind(Buffer::Target::PixelPack); - readImplementation(offset, size, image.format(), image.type(), image.dataSize(size), nullptr); + (Context::current()->state().framebuffer->readImplementation)(offset, size, image.format(), image.type(), image.dataSize(size), nullptr); } #endif @@ -245,60 +234,6 @@ void AbstractFramebuffer::invalidateImplementation(GLsizei count, GLenum* attach #endif } -void AbstractFramebuffer::initializeContextBasedFunctionality(Context& context) { - #ifndef MAGNUM_TARGET_GLES - if(context.isExtensionSupported()) { - Debug() << "AbstractFramebuffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; - - checkStatusImplementation = &AbstractFramebuffer::checkStatusImplementationDSA; - drawBuffersImplementation = &AbstractFramebuffer::drawBuffersImplementationDSA; - drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDSA; - readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDSA; - } - #endif - - #ifdef MAGNUM_TARGET_GLES2 - /* Optimistically set separate binding targets and check if one of the - extensions providing them is available */ - readTarget = FramebufferTarget::Read; - drawTarget = FramebufferTarget::Draw; - - if(context.isExtensionSupported()) - Debug() << "AbstractFramebuffer: using" << Extensions::GL::ANGLE::framebuffer_blit::string() << "features"; - - else if(context.isExtensionSupported()) - Debug() << "AbstractFramebuffer: using" << Extensions::GL::APPLE::framebuffer_multisample::string() << "features"; - - else if(context.isExtensionSupported()) - Debug() << "AbstractFramebuffer: using" << Extensions::GL::NV::framebuffer_blit::string() << "features"; - - /* NV_framebuffer_multisample requires NV_framebuffer_blit, which has these - enums. However, on my system only NV_framebuffer_multisample is - supported, but NV_framebuffer_blit isn't. I will hold my breath and - assume these enums are available. */ - else if(context.isExtensionSupported()) - Debug() << "AbstractFramebuffer: using" << Extensions::GL::NV::framebuffer_multisample::string() << "features"; - - /* If no such extension is available, reset back to unified target */ - else readTarget = drawTarget = FramebufferTarget::ReadDraw; - #endif - - #ifndef MAGNUM_TARGET_GLES - if(context.isExtensionSupported()) - #else - if(context.isExtensionSupported()) - #endif - { - #ifndef MAGNUM_TARGET_GLES - Debug() << "AbstractFramebuffer: using" << Extensions::GL::ARB::robustness::string() << "features"; - #else - Debug() << "AbstractFramebuffer: using" << Extensions::GL::EXT::robustness::string() << "features"; - #endif - - readImplementation = &AbstractFramebuffer::readImplementationRobustness; - } -} - GLenum AbstractFramebuffer::checkStatusImplementationDefault(const FramebufferTarget target) { bindInternal(target); return glCheckFramebufferStatus(GLenum(target)); diff --git a/src/Magnum/AbstractFramebuffer.h b/src/Magnum/AbstractFramebuffer.h index 29d0d4042..7f07087d2 100644 --- a/src/Magnum/AbstractFramebuffer.h +++ b/src/Magnum/AbstractFramebuffer.h @@ -48,9 +48,9 @@ namespace Magnum { @see @ref AbstractFramebuffer, @ref FramebufferClearMask */ enum class FramebufferClear: GLbitfield { - Color = GL_COLOR_BUFFER_BIT, /**< Color */ - Depth = GL_DEPTH_BUFFER_BIT, /**< Depth value */ - Stencil = GL_STENCIL_BUFFER_BIT /**< Stencil value */ + Color = GL_COLOR_BUFFER_BIT, /**< Color buffer */ + Depth = GL_DEPTH_BUFFER_BIT, /**< Depth buffer */ + Stencil = GL_STENCIL_BUFFER_BIT /**< Stencil buffer */ }; /** @@ -67,13 +67,29 @@ typedef Containers::EnumSet FramebufferBlitMask; @@ -93,7 +109,7 @@ typedef Containers::EnumSet @@ -38,28 +38,30 @@ namespace Magnum { /** @brief Base for resource loaders -Provides (a)synchronous resource loading for ResourceManager. +Provides (a)synchronous resource loading for @ref ResourceManager. @section AbstractResourceLoader-usage Usage and subclassing Usage is done by subclassing. Subclass instances can be added to -ResourceManager using ResourceManager::setLoader(). After adding the loader, -each call to ResourceManager::get() will call load() implementation unless the -resource is already loaded (or loading is in progress). Note that resources -requested before the loader was added are not be affected by the loader. - -Subclassing is done by implementing at least doLoad() function. The loading can -be done synchronously or asynchronously (i.e., in another thread). The base -implementation provides interface to ResourceManager and manages loading -progress (which is then available through functions requestedCount(), -loadedCount() and notFoundCount()). You shouldn't access the ResourceManager -directly when loading the data. - -In your doLoad() implementation, after your resources are loaded, call set() to -pass them to ResourceManager or call setNotFound() to indicate that the -resource was not found. - -You can also implement name() to provide meaningful names for resource keys. +@ref ResourceManager using @ref ResourceManager::setLoader(). After adding the +loader, each call to @ref ResourceManager::get() will call @ref load() +implementation unless the resource is already loaded (or loading is in +progress). Note that resources requested before the loader was added are not +affected by the loader. + +Subclassing is done by implementing at least @ref doLoad() function. The +loading can be done synchronously or asynchronously (i.e., in another thread). +The base implementation provides interface to @ref ResourceManager and manages +loading progress (which is then available through functions @ref requestedCount(), +@ref loadedCount() and @ref notFoundCount()). You shouldn't access the +@ref ResourceManager directly when loading the data. + +In your @ref doLoad() implementation, after your resources are loaded, call +@ref set() to pass them to @ref ResourceManager or call @ref setNotFound() to +indicate that the resource was not found. + +You can also implement @ref name() to provide meaningful names for resource +keys. Example implementation for synchronous mesh loader: @code @@ -109,23 +111,23 @@ template class AbstractResourceLoader { /** * @brief Count of requested resources * - * Count of resources requested by calling load(). + * Count of resources requested by calling @ref load(). */ std::size_t requestedCount() const { return _requestedCount; } /** * @brief Count of not found resources * - * Count of resources requested by calling load(), but not found by - * the loader. + * Count of resources requested by calling @ref load(), but not found + * by the loader. */ std::size_t notFoundCount() const { return _notFoundCount; } /** * @brief Count of loaded resources * - * Count of resources requested by calling load(), but not found by - * the loader. + * Count of resources requested by calling @ref load(), but not found + * by the loader. */ std::size_t loadedCount() const { return _loadedCount; } @@ -145,8 +147,8 @@ template class AbstractResourceLoader { * features is incremented. Depending on implementation the resource * might be loaded synchronously or asynchronously. * - * @see ResourceManager::state(), requestedCount(), notFoundCount(), - * loadedCount() + * @see @ref ResourceManager::state(), @ref requestedCount(), + * @ref notFoundCount(), @ref loadedCount() */ void load(ResourceKey key); @@ -155,9 +157,10 @@ template class AbstractResourceLoader { * @brief Set loaded resource to resource manager * * Also increments count of loaded resources. Parameter @p state must - * be either @ref ResourceDataState::Mutable or @ref ResourceDataState::Final. - * See @ref ResourceManager::set() for more information. - * @see loadedCount() + * be either @ref ResourceDataState::Mutable or + * @ref ResourceDataState::Final. See @ref ResourceManager::set() for + * more information. + * @see @ref loadedCount() */ void set(ResourceKey key, T* data, ResourceDataState state, ResourcePolicy policy); @@ -184,9 +187,9 @@ template class AbstractResourceLoader { /** * @brief Mark resource as not found * - * Also increments count of not found resources. See - * ResourceManager::setNotFound() for more information. - * @see notFountCount() + * Also increments count of not found resources. See also + * @ref ResourceManager::set() for more information. + * @see @ref notFoundCount() */ void setNotFound(ResourceKey key); @@ -196,14 +199,14 @@ template class AbstractResourceLoader { protected: #endif /** - * @brief Implementation for name() + * @brief Implementation for @ref name() * * Default implementation returns empty string. */ virtual std::string doName(ResourceKey key) const; /** - * @brief Implementation for load() + * @brief Implementation for @ref load() * * See class documentation for reimplementation guide. */ diff --git a/src/Magnum/AbstractShaderProgram.cpp b/src/Magnum/AbstractShaderProgram.cpp index 468e967cc..890ef328e 100644 --- a/src/Magnum/AbstractShaderProgram.cpp +++ b/src/Magnum/AbstractShaderProgram.cpp @@ -38,50 +38,6 @@ namespace Magnum { -AbstractShaderProgram::Uniform1fvImplementation AbstractShaderProgram::uniform1fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::Uniform2fvImplementation AbstractShaderProgram::uniform2fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::Uniform3fvImplementation AbstractShaderProgram::uniform3fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::Uniform4fvImplementation AbstractShaderProgram::uniform4fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::Uniform1ivImplementation AbstractShaderProgram::uniform1ivImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::Uniform2ivImplementation AbstractShaderProgram::uniform2ivImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::Uniform3ivImplementation AbstractShaderProgram::uniform3ivImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::Uniform4ivImplementation AbstractShaderProgram::uniform4ivImplementation = &AbstractShaderProgram::uniformImplementationDefault; -#ifndef MAGNUM_TARGET_GLES2 -AbstractShaderProgram::Uniform1uivImplementation AbstractShaderProgram::uniform1uivImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::Uniform2uivImplementation AbstractShaderProgram::uniform2uivImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::Uniform3uivImplementation AbstractShaderProgram::uniform3uivImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::Uniform4uivImplementation AbstractShaderProgram::uniform4uivImplementation = &AbstractShaderProgram::uniformImplementationDefault; -#endif -#ifndef MAGNUM_TARGET_GLES -AbstractShaderProgram::Uniform1dvImplementation AbstractShaderProgram::uniform1dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::Uniform2dvImplementation AbstractShaderProgram::uniform2dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::Uniform3dvImplementation AbstractShaderProgram::uniform3dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::Uniform4dvImplementation AbstractShaderProgram::uniform4dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -#endif - -AbstractShaderProgram::UniformMatrix2fvImplementation AbstractShaderProgram::uniformMatrix2fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::UniformMatrix3fvImplementation AbstractShaderProgram::uniformMatrix3fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::UniformMatrix4fvImplementation AbstractShaderProgram::uniformMatrix4fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -#ifndef MAGNUM_TARGET_GLES2 -AbstractShaderProgram::UniformMatrix2x3fvImplementation AbstractShaderProgram::uniformMatrix2x3fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::UniformMatrix3x2fvImplementation AbstractShaderProgram::uniformMatrix3x2fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::UniformMatrix2x4fvImplementation AbstractShaderProgram::uniformMatrix2x4fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::UniformMatrix4x2fvImplementation AbstractShaderProgram::uniformMatrix4x2fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::UniformMatrix3x4fvImplementation AbstractShaderProgram::uniformMatrix3x4fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::UniformMatrix4x3fvImplementation AbstractShaderProgram::uniformMatrix4x3fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -#endif -#ifndef MAGNUM_TARGET_GLES -AbstractShaderProgram::UniformMatrix2dvImplementation AbstractShaderProgram::uniformMatrix2dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::UniformMatrix3dvImplementation AbstractShaderProgram::uniformMatrix3dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::UniformMatrix4dvImplementation AbstractShaderProgram::uniformMatrix4dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::UniformMatrix2x3dvImplementation AbstractShaderProgram::uniformMatrix2x3dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::UniformMatrix3x2dvImplementation AbstractShaderProgram::uniformMatrix3x2dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::UniformMatrix2x4dvImplementation AbstractShaderProgram::uniformMatrix2x4dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::UniformMatrix4x2dvImplementation AbstractShaderProgram::uniformMatrix4x2dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::UniformMatrix3x4dvImplementation AbstractShaderProgram::uniformMatrix3x4dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -AbstractShaderProgram::UniformMatrix4x3dvImplementation AbstractShaderProgram::uniformMatrix4x3dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; -#endif - Int AbstractShaderProgram::maxVertexAttributes() { GLint& value = Context::current()->state().shaderProgram->maxVertexAttributes; @@ -358,52 +314,8 @@ Int AbstractShaderProgram::uniformLocation(const std::string& name) { return location; } -void AbstractShaderProgram::initializeContextBasedFunctionality(Context& context) { - /** @todo OpenGL ES 2 has extension @es_extension{EXT,separate_shader_objects} for this */ - #ifndef MAGNUM_TARGET_GLES - if(context.isExtensionSupported() || - context.isExtensionSupported()) { - Debug() << "AbstractShaderProgram: using" << (context.isExtensionSupported() ? - Extensions::GL::ARB::separate_shader_objects::string() : Extensions::GL::EXT::direct_state_access::string()) << "features"; - uniform1fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniform2fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniform3fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniform4fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniform1ivImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniform2ivImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniform3ivImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniform4ivImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniform1uivImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniform2uivImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniform3uivImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniform4uivImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniform1dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniform2dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniform3dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniform4dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - - uniformMatrix2fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniformMatrix3fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniformMatrix4fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniformMatrix2x3fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniformMatrix3x2fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniformMatrix2x4fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniformMatrix4x2fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniformMatrix3x4fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniformMatrix4x3fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniformMatrix2dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniformMatrix3dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniformMatrix4dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniformMatrix2x3dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniformMatrix3x2dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniformMatrix2x4dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniformMatrix4x2dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniformMatrix3x4dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - uniformMatrix4x3dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; - } - #else - static_cast(context); - #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Float* const values) { + (this->*Context::current()->state().shaderProgram->uniform1fvImplementation)(location, count, values); } void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const GLfloat* const values) { @@ -411,360 +323,817 @@ void AbstractShaderProgram::uniformImplementationDefault(const GLint location, c glUniform1fv(location, count, values); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const GLfloat* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniform1fv(_id, location, count, values); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniform1fvEXT(_id, location, count, values); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const GLfloat* const values) { - glProgramUniform1fv(_id, location, count, values); + glProgramUniform1fvEXT(_id, location, count, values); } #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::Vector<2, Float>* const values) { + (this->*Context::current()->state().shaderProgram->uniform2fvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::Vector<2, GLfloat>* const values) { use(); glUniform2fv(location, count, values[0].data()); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::Vector<2, GLfloat>* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniform2fv(_id, location, count, values[0].data()); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniform2fvEXT(_id, location, count, values[0].data()); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::Vector<2, GLfloat>* const values) { - glProgramUniform2fv(_id, location, count, values[0].data()); + glProgramUniform2fvEXT(_id, location, count, values[0].data()); } #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::Vector<3, Float>* const values) { + (this->*Context::current()->state().shaderProgram->uniform3fvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::Vector<3, GLfloat>* const values) { use(); glUniform3fv(location, count, values[0].data()); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::Vector<3, GLfloat>* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniform3fv(_id, location, count, values[0].data()); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniform3fvEXT(_id, location, count, values[0].data()); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::Vector<3, GLfloat>* const values) { - glProgramUniform3fv(_id, location, count, values[0].data()); + glProgramUniform3fvEXT(_id, location, count, values[0].data()); } #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::Vector<4, Float>* const values) { + (this->*Context::current()->state().shaderProgram->uniform4fvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::Vector<4, GLfloat>* const values) { use(); glUniform4fv(location, count, values[0].data()); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::Vector<4, GLfloat>* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniform4fv(_id, location, count, values[0].data()); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniform4fvEXT(_id, location, count, values[0].data()); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::Vector<4, GLfloat>* const values) { - glProgramUniform4fv(_id, location, count, values[0].data()); + glProgramUniform4fvEXT(_id, location, count, values[0].data()); } #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Int* const values) { + (this->*Context::current()->state().shaderProgram->uniform1ivImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const GLint* const values) { use(); glUniform1iv(location, count, values); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const GLint* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniform1iv(_id, location, count, values); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniform1ivEXT(_id, location, count, values); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const GLint* const values) { - glProgramUniform1iv(_id, location, count, values); + glProgramUniform1ivEXT(_id, location, count, values); } #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::Vector<2, Int>* const values) { + (this->*Context::current()->state().shaderProgram->uniform2ivImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::Vector<2, GLint>* const values) { use(); glUniform2iv(location, count, values[0].data()); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::Vector<2, GLint>* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniform2iv(_id, location, count, values[0].data()); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniform2ivEXT(_id, location, count, values[0].data()); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::Vector<2, GLint>* const values) { - glProgramUniform2iv(_id, location, count, values[0].data()); + glProgramUniform2ivEXT(_id, location, count, values[0].data()); } #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::Vector<3, Int>* const values) { + (this->*Context::current()->state().shaderProgram->uniform3ivImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::Vector<3, GLint>* const values) { use(); glUniform3iv(location, count, values[0].data()); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::Vector<3, GLint>* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniform3iv(_id, location, count, values[0].data()); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniform3ivEXT(_id, location, count, values[0].data()); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::Vector<3, GLint>* const values) { - glProgramUniform3iv(_id, location, count, values[0].data()); + glProgramUniform3ivEXT(_id, location, count, values[0].data()); } #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::Vector<4, Int>* const values) { + (this->*Context::current()->state().shaderProgram->uniform4ivImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::Vector<4, GLint>* const values) { use(); glUniform4iv(location, count, values[0].data()); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::Vector<4, GLint>* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniform4iv(_id, location, count, values[0].data()); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniform4ivEXT(_id, location, count, values[0].data()); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::Vector<4, GLint>* const values) { - glProgramUniform4iv(_id, location, count, values[0].data()); + glProgramUniform4ivEXT(_id, location, count, values[0].data()); } #endif #ifndef MAGNUM_TARGET_GLES2 +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const UnsignedInt* const values) { + (this->*Context::current()->state().shaderProgram->uniform1uivImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const GLuint* const values) { use(); glUniform1uiv(location, count, values); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const GLuint* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniform1uiv(_id, location, count, values); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniform1uivEXT(_id, location, count, values); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const GLuint* const values) { - glProgramUniform1uiv(_id, location, count, values); + glProgramUniform1uivEXT(_id, location, count, values); } #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::Vector<2, UnsignedInt>* const values) { + (this->*Context::current()->state().shaderProgram->uniform2uivImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::Vector<2, GLuint>* const values) { use(); glUniform2uiv(location, count, values[0].data()); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::Vector<2, GLuint>* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniform2uiv(_id, location, count, values[0].data()); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniform2uivEXT(_id, location, count, values[0].data()); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::Vector<2, GLuint>* const values) { - glProgramUniform2uiv(_id, location, count, values[0].data()); + glProgramUniform2uivEXT(_id, location, count, values[0].data()); } #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::Vector<3, UnsignedInt>* const values) { + (this->*Context::current()->state().shaderProgram->uniform3uivImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::Vector<3, GLuint>* const values) { use(); glUniform3uiv(location, count, values[0].data()); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::Vector<3, GLuint>* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniform3uiv(_id, location, count, values[0].data()); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniform3uivEXT(_id, location, count, values[0].data()); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::Vector<3, GLuint>* const values) { - glProgramUniform3uiv(_id, location, count, values[0].data()); + glProgramUniform3uivEXT(_id, location, count, values[0].data()); } #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::Vector<4, UnsignedInt>* const values) { + (this->*Context::current()->state().shaderProgram->uniform4uivImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::Vector<4, GLuint>* const values) { use(); glUniform4uiv(location, count, values[0].data()); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::Vector<4, GLuint>* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniform4uiv(_id, location, count, values[0].data()); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniform4uivEXT(_id, location, count, values[0].data()); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::Vector<4, GLuint>* const values) { - glProgramUniform4uiv(_id, location, count, values[0].data()); + glProgramUniform4uivEXT(_id, location, count, values[0].data()); } #endif #endif #ifndef MAGNUM_TARGET_GLES +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Double* const values) { + (this->*Context::current()->state().shaderProgram->uniform1dvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const GLdouble* const values) { use(); glUniform1dv(location, count, values); } -void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const GLdouble* const values) { +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const GLdouble* const values) { glProgramUniform1dv(_id, location, count, values); } +void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const GLdouble* const values) { + glProgramUniform1dvEXT(_id, location, count, values); +} + +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::Vector<2, Double>* const values) { + (this->*Context::current()->state().shaderProgram->uniform2dvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::Vector<2, GLdouble>* const values) { use(); glUniform2dv(location, count, values[0].data()); } -void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::Vector<2, GLdouble>* const values) { +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::Vector<2, GLdouble>* const values) { glProgramUniform2dv(_id, location, count, values[0].data()); } +void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::Vector<2, GLdouble>* const values) { + glProgramUniform2dvEXT(_id, location, count, values[0].data()); +} + +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::Vector<3, Double>* const values) { + (this->*Context::current()->state().shaderProgram->uniform3dvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::Vector<3, GLdouble>* const values) { use(); glUniform3dv(location, count, values[0].data()); } -void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::Vector<3, GLdouble>* const values) { +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::Vector<3, GLdouble>* const values) { glProgramUniform3dv(_id, location, count, values[0].data()); } +void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::Vector<3, GLdouble>* const values) { + glProgramUniform3dvEXT(_id, location, count, values[0].data()); +} + +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::Vector<4, Double>* const values) { + (this->*Context::current()->state().shaderProgram->uniform4dvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::Vector<4, GLdouble>* const values) { use(); glUniform4dv(location, count, values[0].data()); } -void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::Vector<4, GLdouble>* const values) { +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::Vector<4, GLdouble>* const values) { glProgramUniform4dv(_id, location, count, values[0].data()); } + +void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::Vector<4, GLdouble>* const values) { + glProgramUniform4dvEXT(_id, location, count, values[0].data()); +} #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::RectangularMatrix<2, 2, Float>* const values) { + (this->*Context::current()->state().shaderProgram->uniformMatrix2fvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 2, GLfloat>* const values) { use(); glUniformMatrix2fv(location, count, GL_FALSE, values[0].data()); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 2, GLfloat>* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniformMatrix2fv(_id, location, count, GL_FALSE, values[0].data()); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniformMatrix2fvEXT(_id, location, count, GL_FALSE, values[0].data()); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 2, GLfloat>* const values) { - glProgramUniformMatrix2fv(_id, location, count, GL_FALSE, values[0].data()); + glProgramUniformMatrix2fvEXT(_id, location, count, GL_FALSE, values[0].data()); } #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::RectangularMatrix<3, 3, Float>* const values) { + (this->*Context::current()->state().shaderProgram->uniformMatrix3fvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 3, GLfloat>* const values) { use(); glUniformMatrix3fv(location, count, GL_FALSE, values[0].data()); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 3, GLfloat>* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniformMatrix3fv(_id, location, count, GL_FALSE, values[0].data()); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniformMatrix3fvEXT(_id, location, count, GL_FALSE, values[0].data()); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 3, GLfloat>* const values) { - glProgramUniformMatrix3fv(_id, location, count, GL_FALSE, values[0].data()); + glProgramUniformMatrix3fvEXT(_id, location, count, GL_FALSE, values[0].data()); } #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::RectangularMatrix<4, 4, Float>* const values) { + (this->*Context::current()->state().shaderProgram->uniformMatrix4fvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 4, GLfloat>* const values) { use(); glUniformMatrix4fv(location, count, GL_FALSE, values[0].data()); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 4, GLfloat>* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniformMatrix4fv(_id, location, count, GL_FALSE, values[0].data()); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniformMatrix4fvEXT(_id, location, count, GL_FALSE, values[0].data()); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 4, GLfloat>* const values) { - glProgramUniformMatrix4fv(_id, location, count, GL_FALSE, values[0].data()); + glProgramUniformMatrix4fvEXT(_id, location, count, GL_FALSE, values[0].data()); } #endif #ifndef MAGNUM_TARGET_GLES2 +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::RectangularMatrix<2, 3, Float>* const values) { + (this->*Context::current()->state().shaderProgram->uniformMatrix2x3fvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 3, GLfloat>* const values) { use(); glUniformMatrix2x3fv(location, count, GL_FALSE, values[0].data()); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 3, GLfloat>* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniformMatrix2x3fv(_id, location, count, GL_FALSE, values[0].data()); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniformMatrix2x3fvEXT(_id, location, count, GL_FALSE, values[0].data()); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 3, GLfloat>* const values) { - glProgramUniformMatrix2x3fv(_id, location, count, GL_FALSE, values[0].data()); + glProgramUniformMatrix2x3fvEXT(_id, location, count, GL_FALSE, values[0].data()); } #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::RectangularMatrix<3, 2, Float>* const values) { + (this->*Context::current()->state().shaderProgram->uniformMatrix3x2fvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 2, GLfloat>* const values) { use(); glUniformMatrix3x2fv(location, count, GL_FALSE, values[0].data()); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 2, GLfloat>* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniformMatrix3x2fv(_id, location, count, GL_FALSE, values[0].data()); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniformMatrix3x2fv(_id, location, count, GL_FALSE, values[0].data()); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 2, GLfloat>* const values) { - glProgramUniformMatrix3x2fv(_id, location, count, GL_FALSE, values[0].data()); + glProgramUniformMatrix3x2fvEXT(_id, location, count, GL_FALSE, values[0].data()); } #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::RectangularMatrix<2, 4, Float>* const values) { + (this->*Context::current()->state().shaderProgram->uniformMatrix2x4fvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 4, GLfloat>* const values) { use(); glUniformMatrix2x4fv(location, count, GL_FALSE, values[0].data()); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 4, GLfloat>* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniformMatrix2x4fv(_id, location, count, GL_FALSE, values[0].data()); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniformMatrix2x4fvEXT(_id, location, count, GL_FALSE, values[0].data()); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 4, GLfloat>* const values) { - glProgramUniformMatrix2x4fv(_id, location, count, GL_FALSE, values[0].data()); + glProgramUniformMatrix2x4fvEXT(_id, location, count, GL_FALSE, values[0].data()); } #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::RectangularMatrix<4, 2, Float>* const values) { + (this->*Context::current()->state().shaderProgram->uniformMatrix4x2fvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 2, GLfloat>* const values) { use(); glUniformMatrix4x2fv(location, count, GL_FALSE, values[0].data()); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 2, GLfloat>* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniformMatrix4x2fv(_id, location, count, GL_FALSE, values[0].data()); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniformMatrix4x2fvEXT(_id, location, count, GL_FALSE, values[0].data()); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 2, GLfloat>* const values) { - glProgramUniformMatrix4x2fv(_id, location, count, GL_FALSE, values[0].data()); + glProgramUniformMatrix4x2fvEXT(_id, location, count, GL_FALSE, values[0].data()); } #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::RectangularMatrix<3, 4, Float>* const values) { + (this->*Context::current()->state().shaderProgram->uniformMatrix3x4fvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 4, GLfloat>* const values) { use(); glUniformMatrix3x4fv(location, count, GL_FALSE, values[0].data()); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 4, GLfloat>* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniformMatrix3x4fv(_id, location, count, GL_FALSE, values[0].data()); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniformMatrix3x4fvEXT(_id, location, count, GL_FALSE, values[0].data()); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 4, GLfloat>* const values) { - glProgramUniformMatrix3x4fv(_id, location, count, GL_FALSE, values[0].data()); + glProgramUniformMatrix3x4fvEXT(_id, location, count, GL_FALSE, values[0].data()); } #endif +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::RectangularMatrix<4, 3, Float>* const values) { + (this->*Context::current()->state().shaderProgram->uniformMatrix4x3fvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 3, GLfloat>* const values) { use(); glUniformMatrix4x3fv(location, count, GL_FALSE, values[0].data()); } +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 3, GLfloat>* const values) { + /** @todo Enable when extension loader for ES is available */ + #ifndef MAGNUM_TARGET_GLES + glProgramUniformMatrix4x3fv(_id, location, count, GL_FALSE, values[0].data()); + #else + CORRADE_INTERNAL_ASSERT(false); + //glProgramUniformMatrix4x3fvEXT(_id, location, count, GL_FALSE, values[0].data()); + static_cast(location); + static_cast(count); + static_cast(values); + #endif +} + #ifndef MAGNUM_TARGET_GLES void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 3, GLfloat>* const values) { - glProgramUniformMatrix4x3fv(_id, location, count, GL_FALSE, values[0].data()); + glProgramUniformMatrix4x3fvEXT(_id, location, count, GL_FALSE, values[0].data()); } #endif #endif #ifndef MAGNUM_TARGET_GLES +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::RectangularMatrix<2, 2, Double>* const values) { + (this->*Context::current()->state().shaderProgram->uniformMatrix2dvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 2, GLdouble>* const values) { use(); glUniformMatrix2dv(location, count, GL_FALSE, values[0].data()); } -void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 2, GLdouble>* const values) { +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 2, GLdouble>* const values) { glProgramUniformMatrix2dv(_id, location, count, GL_FALSE, values[0].data()); } +void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 2, GLdouble>* const values) { + glProgramUniformMatrix2dvEXT(_id, location, count, GL_FALSE, values[0].data()); +} + +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::RectangularMatrix<3, 3, Double>* const values) { + (this->*Context::current()->state().shaderProgram->uniformMatrix3dvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 3, GLdouble>* const values) { use(); glUniformMatrix3dv(location, count, GL_FALSE, values[0].data()); } -void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 3, GLdouble>* const values) { +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 3, GLdouble>* const values) { glProgramUniformMatrix3dv(_id, location, count, GL_FALSE, values[0].data()); } +void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 3, GLdouble>* const values) { + glProgramUniformMatrix3dvEXT(_id, location, count, GL_FALSE, values[0].data()); +} + +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::RectangularMatrix<4, 4, Double>* const values) { + (this->*Context::current()->state().shaderProgram->uniformMatrix4dvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 4, GLdouble>* const values) { use(); glUniformMatrix4dv(location, count, GL_FALSE, values[0].data()); } -void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 4, GLdouble>* const values) { +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 4, GLdouble>* const values) { glProgramUniformMatrix4dv(_id, location, count, GL_FALSE, values[0].data()); } +void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 4, GLdouble>* const values) { + glProgramUniformMatrix4dvEXT(_id, location, count, GL_FALSE, values[0].data()); +} + +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::RectangularMatrix<2, 3, Double>* const values) { + (this->*Context::current()->state().shaderProgram->uniformMatrix2x3dvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 3, GLdouble>* const values) { use(); glUniformMatrix2x3dv(location, count, GL_FALSE, values[0].data()); } -void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 3, GLdouble>* const values) { +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 3, GLdouble>* const values) { glProgramUniformMatrix2x3dv(_id, location, count, GL_FALSE, values[0].data()); } +void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 3, GLdouble>* const values) { + glProgramUniformMatrix2x3dvEXT(_id, location, count, GL_FALSE, values[0].data()); +} + +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::RectangularMatrix<3, 2, Double>* const values) { + (this->*Context::current()->state().shaderProgram->uniformMatrix3x2dvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 2, GLdouble>* const values) { use(); glUniformMatrix3x2dv(location, count, GL_FALSE, values[0].data()); } -void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 2, GLdouble>* const values) { +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 2, GLdouble>* const values) { glProgramUniformMatrix3x2dv(_id, location, count, GL_FALSE, values[0].data()); } +void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 2, GLdouble>* const values) { + glProgramUniformMatrix3x2dvEXT(_id, location, count, GL_FALSE, values[0].data()); +} + +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::RectangularMatrix<2, 4, Double>* const values) { + (this->*Context::current()->state().shaderProgram->uniformMatrix2x4dvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 4, GLdouble>* const values) { use(); glUniformMatrix2x4dv(location, count, GL_FALSE, values[0].data()); } -void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 4, GLdouble>* const values) { +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 4, GLdouble>* const values) { glProgramUniformMatrix2x4dv(_id, location, count, GL_FALSE, values[0].data()); } +void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<2, 4, GLdouble>* const values) { + glProgramUniformMatrix2x4dvEXT(_id, location, count, GL_FALSE, values[0].data()); +} + +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::RectangularMatrix<4, 2, Double>* const values) { + (this->*Context::current()->state().shaderProgram->uniformMatrix4x2dvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 2, GLdouble>* const values) { use(); glUniformMatrix4x2dv(location, count, GL_FALSE, values[0].data()); } -void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 2, GLdouble>* const values) { +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 2, GLdouble>* const values) { glProgramUniformMatrix4x2dv(_id, location, count, GL_FALSE, values[0].data()); } +void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 2, GLdouble>* const values) { + glProgramUniformMatrix4x2dvEXT(_id, location, count, GL_FALSE, values[0].data()); +} + +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::RectangularMatrix<3, 4, Double>* const values) { + (this->*Context::current()->state().shaderProgram->uniformMatrix3x4dvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 4, GLdouble>* const values) { use(); glUniformMatrix3x4dv(location, count, GL_FALSE, values[0].data()); } -void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 4, GLdouble>* const values) { +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 4, GLdouble>* const values) { glProgramUniformMatrix3x4dv(_id, location, count, GL_FALSE, values[0].data()); } +void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<3, 4, GLdouble>* const values) { + glProgramUniformMatrix3x4dvEXT(_id, location, count, GL_FALSE, values[0].data()); +} + +void AbstractShaderProgram::setUniform(const Int location, const UnsignedInt count, const Math::RectangularMatrix<4, 3, Double>* const values) { + (this->*Context::current()->state().shaderProgram->uniformMatrix4x3dvImplementation)(location, count, values); +} + void AbstractShaderProgram::uniformImplementationDefault(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 3, GLdouble>* const values) { use(); glUniformMatrix4x3dv(location, count, GL_FALSE, values[0].data()); } -void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 3, GLdouble>* const values) { +void AbstractShaderProgram::uniformImplementationSSO(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 3, GLdouble>* const values) { glProgramUniformMatrix4x3dv(_id, location, count, GL_FALSE, values[0].data()); } + +void AbstractShaderProgram::uniformImplementationDSA(const GLint location, const GLsizei count, const Math::RectangularMatrix<4, 3, GLdouble>* const values) { + glProgramUniformMatrix4x3dvEXT(_id, location, count, GL_FALSE, values[0].data()); +} #endif namespace Implementation { -std::size_t FloatAttribute::size(GLint components, DataType dataType) { +UnsignedInt FloatAttribute::size(GLint components, DataType dataType) { switch(dataType) { case DataType::UnsignedByte: case DataType::Byte: @@ -787,7 +1156,7 @@ std::size_t FloatAttribute::size(GLint components, DataType dataType) { } #ifndef MAGNUM_TARGET_GLES2 -std::size_t IntAttribute::size(GLint components, DataType dataType) { +UnsignedInt IntAttribute::size(GLint components, DataType dataType) { switch(dataType) { case DataType::UnsignedByte: case DataType::Byte: @@ -805,7 +1174,7 @@ std::size_t IntAttribute::size(GLint components, DataType dataType) { #endif #ifndef MAGNUM_TARGET_GLES -std::size_t DoubleAttribute::size(GLint components, DataType dataType) { +UnsignedInt DoubleAttribute::size(GLint components, DataType dataType) { switch(dataType) { case DataType::Double: return 8*components; @@ -815,7 +1184,7 @@ std::size_t DoubleAttribute::size(GLint components, DataType dataType) { } #endif -std::size_t Attribute>::size(GLint components, DataType dataType) { +UnsignedInt Attribute>::size(GLint components, DataType dataType) { #ifndef MAGNUM_TARGET_GLES if(components == GL_BGRA) components = 4; #endif diff --git a/src/Magnum/AbstractShaderProgram.h b/src/Magnum/AbstractShaderProgram.h index d3dc77c4f..1048c193f 100644 --- a/src/Magnum/AbstractShaderProgram.h +++ b/src/Magnum/AbstractShaderProgram.h @@ -39,6 +39,7 @@ namespace Magnum { namespace Implementation { template struct Attribute; + struct ShaderProgramState; } /** @@ -62,14 +63,6 @@ enum: UnsignedInt { NormalOutput = 1 }; @endcode -- **Layers for texture uniforms** to which the textures will be bound before - rendering, for example: -@code -enum: Int { - DiffuseTextureLayer = 0, - SpecularTextureLayer = 1 -}; -@endcode - **Uniform locations** for setting uniform data (see below) (private variables), for example: @code @@ -110,6 +103,18 @@ MyShader& setProjection(const Matrix4& matrix) { return *this; } @endcode +- **Texture setting functions** in which you bind the textures to particular + layers using @ref AbstractTexture::bind() and equivalent, for example: +@code +MyShader& setDiffuseTexture(Texture2D& texture) { + texture->bind(0); + return *this; +} +MyShader& setSpecularTexture(Texture2D& texture) { + texture->bind(1); + return *this; +} +@endcode @subsection AbstractShaderProgram-attribute-location Binding attribute location @@ -176,6 +181,9 @@ bindFragmentDataLocationIndexed(NormalOutput, 1, "normal"); ES 2.0, similar functionality is available in extension @es_extension{NV,draw_buffers}. +@todo @es_extension{EXT,separate_shader_objects} supports explicit attrib + location + @subsection AbstractShaderProgram-uniform-location Uniform locations The preferred workflow is to specify uniform locations directly in the shader @@ -229,8 +237,8 @@ uniform sampler2D diffuseTexture; uniform sampler2D specularTexture; @endcode @code -setUniform(DiffuseTextureUniform, DiffuseTextureLayer); -setUniform(SpecularTextureUniform, SpecularTextureLayer); +setUniform(DiffuseTextureUniform, 0); +setUniform(SpecularTextureUniform, 1); @endcode @see @ref Shader::maxTextureImageUnits() @@ -247,19 +255,15 @@ Basic workflow with %AbstractShaderProgram subclasses is: instance shader class, configure attribute binding in meshes (see @ref Mesh-configuration "Mesh documentation" for more information) and map shader outputs to framebuffer attachments if needed (see @ref Framebuffer-usage "Framebuffer documentation" for more -information). In each draw event set uniforms, mark the shader for use, bind -specific framebuffer (if needed) and bind required textures to their -respective layers using @ref AbstractTexture::bind(Int). Then call -@ref Mesh::draw(). Example: +information). In each draw event set all required shader parameters, bind +specific framebuffer (if needed) and then call @ref Mesh::draw(). Example: @code shader.setTransformation(transformation) .setProjection(projection) - .use(); + .setDiffuseTexture(diffuseTexture) + .setSpecularTexture(specularTexture); -diffuseTexture.bind(MyShader::DiffuseTextureLayer); -specularTexture.bind(MyShader::SpecularTextureLayer); - -mesh.draw(); +mesh.draw(shader); @endcode @section AbstractShaderProgram-types Mapping between GLSL and Magnum types @@ -302,9 +306,8 @@ also @ref Attribute::DataType enum for additional type options. @section AbstractShaderProgram-performance-optimization Performance optimizations -The engine tracks currently used shader program to avoid unnecessary calls to -@fn_gl{UseProgram}. %Shader limits (such as @ref maxVertexAttributes()) -are cached, so repeated queries don't result in repeated @fn_gl{Get} calls. +%Shader limits (such as @ref maxVertexAttributes()) are cached, so repeated +queries don't result in repeated @fn_gl{Get} calls. If extension @extension{ARB,separate_shader_objects} (part of OpenGL 4.1) or @extension{EXT,direct_state_access} is available, uniform setting functions @@ -322,7 +325,9 @@ comes in handy. @todo `GL_NUM_{PROGRAM,SHADER}_BINARY_FORMATS` + `GL_{PROGRAM,SHADER}_BINARY_FORMATS` (vector), (@extension{ARB,ES2_compatibility}) */ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject { - friend class Context; + friend class Mesh; + friend class MeshView; + friend struct Implementation::ShaderProgramState; public: template class Attribute; @@ -516,9 +521,9 @@ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject { * @brief %Shader program label * * The result is *not* cached, repeated queries will result in repeated - * OpenGL calls. If neither @extension{KHR,debug} nor - * @extension2{EXT,debug_label} desktop or ES extension is available, - * this function returns empty string. + * OpenGL calls. If OpenGL 4.3 is not supported and neither + * @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES + * extension is available, this function returns empty string. * @see @fn_gl{GetObjectLabel} with @def_gl{PROGRAM} or * @fn_gl_extension2{GetObjectLabel,EXT,debug_label} with * @def_gl{PROGRAM_OBJECT_EXT} @@ -529,9 +534,9 @@ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject { * @brief Set shader program label * @return Reference to self (for method chaining) * - * Default is empty string. If neither @extension{KHR,debug} nor - * @extension2{EXT,debug_label} desktop or ES extension is available, - * this function does nothing. + * Default is empty string. If OpenGL 4.3 is not supported and neither + * @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES + * extension is available, this function does nothing. * @see @ref maxLabelLength(), @fn_gl{ObjectLabel} with * @def_gl{PROGRAM} or @fn_gl_extension2{LabelObject,EXT,debug_label} * with @def_gl{PROGRAM_OBJECT_EXT} @@ -548,12 +553,13 @@ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject { */ std::pair validate(); + #ifdef MAGNUM_BUILD_DEPRECATED /** * @brief Use shader for rendering - * - * @see @fn_gl{UseProgram} + * @deprecated Use @ref Magnum::Mesh::draw(AbstractShaderProgram&) "Mesh::draw(AbstractShaderProgram&)" instead. */ void use(); + #endif protected: #ifndef MAGNUM_TARGET_GLES2 @@ -718,44 +724,16 @@ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject { * @see @ref setUniform(Int, const T&), @fn_gl{UseProgram}, @fn_gl{Uniform} * or @fn_gl{ProgramUniform}/@fn_gl_extension{ProgramUniform,EXT,direct_state_access}. */ - void setUniform(Int location, UnsignedInt count, const Float* values) { - (this->*uniform1fvImplementation)(location, count, values); - } + void setUniform(Int location, UnsignedInt count, const Float* values); + void setUniform(Int location, UnsignedInt count, const Math::Vector<2, Float>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::Vector<3, Float>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::Vector<4, Float>* values); /**< @overload */ /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - void setUniform(Int location, UnsignedInt count, const Math::Vector<2, Float>* values) { - (this->*uniform2fvImplementation)(location, count, values); - } - - /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - void setUniform(Int location, UnsignedInt count, const Math::Vector<3, Float>* values) { - (this->*uniform3fvImplementation)(location, count, values); - } - - /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - void setUniform(Int location, UnsignedInt count, const Math::Vector<4, Float>* values) { - (this->*uniform4fvImplementation)(location, count, values); - } - - /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - void setUniform(Int location, UnsignedInt count, const Int* values) { - (this->*uniform1ivImplementation)(location, count, values); - } - - /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - void setUniform(Int location, UnsignedInt count, const Math::Vector<2, Int>* values) { - (this->*uniform2ivImplementation)(location, count, values); - } - - /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - void setUniform(Int location, UnsignedInt count, const Math::Vector<3, Int>* values) { - (this->*uniform3ivImplementation)(location, count, values); - } - - /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - void setUniform(Int location, UnsignedInt count, const Math::Vector<4, Int>* values) { - (this->*uniform4ivImplementation)(location, count, values); - } + void setUniform(Int location, UnsignedInt count, const Int* values); + void setUniform(Int location, UnsignedInt count, const Math::Vector<2, Int>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::Vector<3, Int>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::Vector<4, Int>* values); /**< @overload */ #ifndef MAGNUM_TARGET_GLES2 /** @@ -763,36 +741,10 @@ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject { * @requires_gl30 %Extension @extension{EXT,gpu_shader4} * @requires_gles30 Only signed integers are available in OpenGL ES 2.0. */ - void setUniform(Int location, UnsignedInt count, const UnsignedInt* values) { - (this->*uniform1uivImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gl30 %Extension @extension{EXT,gpu_shader4} - * @requires_gles30 Only signed integers are available in OpenGL ES 2.0. - */ - void setUniform(Int location, UnsignedInt count, const Math::Vector<2, UnsignedInt>* values) { - (this->*uniform2uivImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gl30 %Extension @extension{EXT,gpu_shader4} - * @requires_gles30 Only signed integers are available in OpenGL ES 2.0. - */ - void setUniform(Int location, UnsignedInt count, const Math::Vector<3, UnsignedInt>* values) { - (this->*uniform3uivImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gl30 %Extension @extension{EXT,gpu_shader4} - * @requires_gles30 Only signed integers are available in OpenGL ES 2.0. - */ - void setUniform(Int location, UnsignedInt count, const Math::Vector<4, UnsignedInt>* values) { - (this->*uniform4uivImplementation)(location, count, values); - } + void setUniform(Int location, UnsignedInt count, const UnsignedInt* values); + void setUniform(Int location, UnsignedInt count, const Math::Vector<2, UnsignedInt>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::Vector<3, UnsignedInt>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::Vector<4, UnsignedInt>* values); /**< @overload */ #endif #ifndef MAGNUM_TARGET_GLES @@ -801,101 +753,28 @@ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject { * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - void setUniform(Int location, UnsignedInt count, const Double* values) { - (this->*uniform1dvImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} - * @requires_gl Only floats are available in OpenGL ES. - */ - void setUniform(Int location, UnsignedInt count, const Math::Vector<2, Double>* values) { - (this->*uniform2dvImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} - * @requires_gl Only floats are available in OpenGL ES. - */ - void setUniform(Int location, UnsignedInt count, const Math::Vector<3, Double>* values) { - (this->*uniform3dvImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} - * @requires_gl Only floats are available in OpenGL ES. - */ - void setUniform(Int location, UnsignedInt count, const Math::Vector<4, Double>* values) { - (this->*uniform4dvImplementation)(location, count, values); - } + void setUniform(Int location, UnsignedInt count, const Double* values); + void setUniform(Int location, UnsignedInt count, const Math::Vector<2, Double>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::Vector<3, Double>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::Vector<4, Double>* values); /**< @overload */ #endif /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 2, Float>* values) { - (this->*uniformMatrix2fvImplementation)(location, count, values); - } - - /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 3, Float>* values) { - (this->*uniformMatrix3fvImplementation)(location, count, values); - } - - /** @copydoc setUniform(Int, UnsignedInt, const Float*) */ - void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 4, Float>* values) { - (this->*uniformMatrix4fvImplementation)(location, count, values); - } + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 2, Float>* values); + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 3, Float>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 4, Float>* values); /**< @overload */ #ifndef MAGNUM_TARGET_GLES2 /** * @copydoc setUniform(Int, UnsignedInt, const Float*) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ - void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 3, Float>* values) { - (this->*uniformMatrix2x3fvImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. - */ - void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 2, Float>* values) { - (this->*uniformMatrix3x2fvImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. - */ - void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 4, Float>* values) { - (this->*uniformMatrix2x4fvImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. - */ - void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 2, Float>* values) { - (this->*uniformMatrix4x2fvImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. - */ - void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 4, Float>* values) { - (this->*uniformMatrix3x4fvImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. - */ - void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 3, Float>* values) { - (this->*uniformMatrix4x3fvImplementation)(location, count, values); - } + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 3, Float>* values); + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 2, Float>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 4, Float>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 2, Float>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 4, Float>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 3, Float>* values); /**< @overload */ #endif #ifndef MAGNUM_TARGET_GLES @@ -904,106 +783,22 @@ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject { * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ - void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 2, Double>* values) { - (this->*uniformMatrix2dvImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} - * @requires_gl Only floats are available in OpenGL ES. - */ - void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 3, Double>* values) { - (this->*uniformMatrix3dvImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} - * @requires_gl Only floats are available in OpenGL ES. - */ - void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 4, Double>* values) { - (this->*uniformMatrix4dvImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} - * @requires_gl Only floats are available in OpenGL ES. - */ - void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 3, Double>* values) { - (this->*uniformMatrix2x3dvImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} - * @requires_gl Only floats are available in OpenGL ES. - */ - void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 2, Double>* values) { - (this->*uniformMatrix3x2dvImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} - * @requires_gl Only floats are available in OpenGL ES. - */ - void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 4, Double>* values) { - (this->*uniformMatrix2x4dvImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} - * @requires_gl Only floats are available in OpenGL ES. - */ - void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 2, Double>* values) { - (this->*uniformMatrix4x2dvImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} - * @requires_gl Only floats are available in OpenGL ES. - */ - void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 4, Double>* values) { - (this->*uniformMatrix3x4dvImplementation)(location, count, values); - } - - /** - * @copydoc setUniform(Int, UnsignedInt, const Float*) - * @requires_gl40 %Extension @extension{ARB,gpu_shader_fp64} - * @requires_gl Only floats are available in OpenGL ES. - */ - void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 3, Double>* values) { - (this->*uniformMatrix4x3dvImplementation)(location, count, values); - } + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 2, Double>* values); + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 3, Double>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 4, Double>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 3, Double>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 2, Double>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<2, 4, Double>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 2, Double>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<3, 4, Double>* values); /**< @overload */ + void setUniform(Int location, UnsignedInt count, const Math::RectangularMatrix<4, 3, Double>* values); /**< @overload */ #endif private: - static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context); - - typedef void(AbstractShaderProgram::*Uniform1fvImplementation)(GLint, GLsizei, const GLfloat*); - typedef void(AbstractShaderProgram::*Uniform2fvImplementation)(GLint, GLsizei, const Math::Vector<2, GLfloat>*); - typedef void(AbstractShaderProgram::*Uniform3fvImplementation)(GLint, GLsizei, const Math::Vector<3, GLfloat>*); - typedef void(AbstractShaderProgram::*Uniform4fvImplementation)(GLint, GLsizei, const Math::Vector<4, GLfloat>*); - typedef void(AbstractShaderProgram::*Uniform1ivImplementation)(GLint, GLsizei, const GLint*); - typedef void(AbstractShaderProgram::*Uniform2ivImplementation)(GLint, GLsizei, const Math::Vector<2, GLint>*); - typedef void(AbstractShaderProgram::*Uniform3ivImplementation)(GLint, GLsizei, const Math::Vector<3, GLint>*); - typedef void(AbstractShaderProgram::*Uniform4ivImplementation)(GLint, GLsizei, const Math::Vector<4, GLint>*); - #ifndef MAGNUM_TARGET_GLES2 - typedef void(AbstractShaderProgram::*Uniform1uivImplementation)(GLint, GLsizei, const GLuint*); - typedef void(AbstractShaderProgram::*Uniform2uivImplementation)(GLint, GLsizei, const Math::Vector<2, GLuint>*); - typedef void(AbstractShaderProgram::*Uniform3uivImplementation)(GLint, GLsizei, const Math::Vector<3, GLuint>*); - typedef void(AbstractShaderProgram::*Uniform4uivImplementation)(GLint, GLsizei, const Math::Vector<4, GLuint>*); - #endif - #ifndef MAGNUM_TARGET_GLES - typedef void(AbstractShaderProgram::*Uniform1dvImplementation)(GLint, GLsizei, const GLdouble*); - typedef void(AbstractShaderProgram::*Uniform2dvImplementation)(GLint, GLsizei, const Math::Vector<2, GLdouble>*); - typedef void(AbstractShaderProgram::*Uniform3dvImplementation)(GLint, GLsizei, const Math::Vector<3, GLdouble>*); - typedef void(AbstractShaderProgram::*Uniform4dvImplementation)(GLint, GLsizei, const Math::Vector<4, GLdouble>*); + #ifndef MAGNUM_BUILD_DEPRECATED + void use(); #endif + void MAGNUM_LOCAL uniformImplementationDefault(GLint location, GLsizei count, const GLfloat* values); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, GLsizei count, const Math::Vector<2, GLfloat>* values); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, GLsizei count, const Math::Vector<3, GLfloat>* values); @@ -1023,6 +818,28 @@ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject { void MAGNUM_LOCAL uniformImplementationDefault(GLint location, GLsizei count, const Math::Vector<2, GLdouble>* values); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, GLsizei count, const Math::Vector<3, GLdouble>* values); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, GLsizei count, const Math::Vector<4, GLdouble>* values); + #endif + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const GLfloat* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::Vector<2, GLfloat>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::Vector<3, GLfloat>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::Vector<4, GLfloat>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const GLint* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::Vector<2, GLint>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::Vector<3, GLint>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::Vector<4, GLint>* values); + #ifndef MAGNUM_TARGET_GLES2 + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const GLuint* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::Vector<2, GLuint>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::Vector<3, GLuint>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::Vector<4, GLuint>* values); + #endif + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const GLdouble* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::Vector<2, GLdouble>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::Vector<3, GLdouble>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::Vector<4, GLdouble>* values); + #endif + #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL uniformImplementationDSA(GLint location, GLsizei count, const GLfloat* values); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, GLsizei count, const Math::Vector<2, GLfloat>* values); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, GLsizei count, const Math::Vector<3, GLfloat>* values); @@ -1040,49 +857,7 @@ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject { void MAGNUM_LOCAL uniformImplementationDSA(GLint location, GLsizei count, const Math::Vector<3, GLdouble>* values); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, GLsizei count, const Math::Vector<4, GLdouble>* values); #endif - static Uniform1fvImplementation uniform1fvImplementation; - static Uniform2fvImplementation uniform2fvImplementation; - static Uniform3fvImplementation uniform3fvImplementation; - static Uniform4fvImplementation uniform4fvImplementation; - static Uniform1ivImplementation uniform1ivImplementation; - static Uniform2ivImplementation uniform2ivImplementation; - static Uniform3ivImplementation uniform3ivImplementation; - static Uniform4ivImplementation uniform4ivImplementation; - #ifndef MAGNUM_TARGET_GLES2 - static Uniform1uivImplementation uniform1uivImplementation; - static Uniform2uivImplementation uniform2uivImplementation; - static Uniform3uivImplementation uniform3uivImplementation; - static Uniform4uivImplementation uniform4uivImplementation; - #endif - #ifndef MAGNUM_TARGET_GLES - static Uniform1dvImplementation uniform1dvImplementation; - static Uniform2dvImplementation uniform2dvImplementation; - static Uniform3dvImplementation uniform3dvImplementation; - static Uniform4dvImplementation uniform4dvImplementation; - #endif - typedef void(AbstractShaderProgram::*UniformMatrix2fvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<2, 2, GLfloat>*); - typedef void(AbstractShaderProgram::*UniformMatrix3fvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<3, 3, GLfloat>*); - typedef void(AbstractShaderProgram::*UniformMatrix4fvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<4, 4, GLfloat>*); - #ifndef MAGNUM_TARGET_GLES2 - typedef void(AbstractShaderProgram::*UniformMatrix2x3fvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<2, 3, GLfloat>*); - typedef void(AbstractShaderProgram::*UniformMatrix3x2fvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<3, 2, GLfloat>*); - typedef void(AbstractShaderProgram::*UniformMatrix2x4fvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<2, 4, GLfloat>*); - typedef void(AbstractShaderProgram::*UniformMatrix4x2fvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<4, 2, GLfloat>*); - typedef void(AbstractShaderProgram::*UniformMatrix3x4fvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<3, 4, GLfloat>*); - typedef void(AbstractShaderProgram::*UniformMatrix4x3fvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<4, 3, GLfloat>*); - #endif - #ifndef MAGNUM_TARGET_GLES - typedef void(AbstractShaderProgram::*UniformMatrix2dvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<2, 2, GLdouble>*); - typedef void(AbstractShaderProgram::*UniformMatrix3dvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<3, 3, GLdouble>*); - typedef void(AbstractShaderProgram::*UniformMatrix4dvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<4, 4, GLdouble>*); - typedef void(AbstractShaderProgram::*UniformMatrix2x3dvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<2, 3, GLdouble>*); - typedef void(AbstractShaderProgram::*UniformMatrix3x2dvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<3, 2, GLdouble>*); - typedef void(AbstractShaderProgram::*UniformMatrix2x4dvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<2, 4, GLdouble>*); - typedef void(AbstractShaderProgram::*UniformMatrix4x2dvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<4, 2, GLdouble>*); - typedef void(AbstractShaderProgram::*UniformMatrix3x4dvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<3, 4, GLdouble>*); - typedef void(AbstractShaderProgram::*UniformMatrix4x3dvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<4, 3, GLdouble>*); - #endif void MAGNUM_LOCAL uniformImplementationDefault(GLint location, GLsizei count, const Math::RectangularMatrix<2, 2, GLfloat>* values); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, GLsizei count, const Math::RectangularMatrix<3, 3, GLfloat>* values); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, GLsizei count, const Math::RectangularMatrix<4, 4, GLfloat>* values); @@ -1104,6 +879,30 @@ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject { void MAGNUM_LOCAL uniformImplementationDefault(GLint location, GLsizei count, const Math::RectangularMatrix<4, 2, GLdouble>* values); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, GLsizei count, const Math::RectangularMatrix<3, 4, GLdouble>* values); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, GLsizei count, const Math::RectangularMatrix<4, 3, GLdouble>* values); + #endif + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::RectangularMatrix<2, 2, GLfloat>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::RectangularMatrix<3, 3, GLfloat>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::RectangularMatrix<4, 4, GLfloat>* values); + #ifndef MAGNUM_TARGET_GLES2 + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::RectangularMatrix<2, 3, GLfloat>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::RectangularMatrix<3, 2, GLfloat>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::RectangularMatrix<2, 4, GLfloat>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::RectangularMatrix<4, 2, GLfloat>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::RectangularMatrix<3, 4, GLfloat>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::RectangularMatrix<4, 3, GLfloat>* values); + #endif + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::RectangularMatrix<2, 2, GLdouble>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::RectangularMatrix<3, 3, GLdouble>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::RectangularMatrix<4, 4, GLdouble>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::RectangularMatrix<2, 3, GLdouble>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::RectangularMatrix<3, 2, GLdouble>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::RectangularMatrix<2, 4, GLdouble>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::RectangularMatrix<4, 2, GLdouble>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::RectangularMatrix<3, 4, GLdouble>* values); + void MAGNUM_LOCAL uniformImplementationSSO(GLint location, GLsizei count, const Math::RectangularMatrix<4, 3, GLdouble>* values); + #endif + #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL uniformImplementationDSA(GLint location, GLsizei count, const Math::RectangularMatrix<2, 2, GLfloat>* values); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, GLsizei count, const Math::RectangularMatrix<3, 3, GLfloat>* values); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, GLsizei count, const Math::RectangularMatrix<4, 4, GLfloat>* values); @@ -1123,28 +922,6 @@ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject { void MAGNUM_LOCAL uniformImplementationDSA(GLint location, GLsizei count, const Math::RectangularMatrix<3, 4, GLdouble>* values); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, GLsizei count, const Math::RectangularMatrix<4, 3, GLdouble>* values); #endif - static UniformMatrix2fvImplementation uniformMatrix2fvImplementation; - static UniformMatrix3fvImplementation uniformMatrix3fvImplementation; - static UniformMatrix4fvImplementation uniformMatrix4fvImplementation; - #ifndef MAGNUM_TARGET_GLES2 - static UniformMatrix2x3fvImplementation uniformMatrix2x3fvImplementation; - static UniformMatrix3x2fvImplementation uniformMatrix3x2fvImplementation; - static UniformMatrix2x4fvImplementation uniformMatrix2x4fvImplementation; - static UniformMatrix4x2fvImplementation uniformMatrix4x2fvImplementation; - static UniformMatrix3x4fvImplementation uniformMatrix3x4fvImplementation; - static UniformMatrix4x3fvImplementation uniformMatrix4x3fvImplementation; - #endif - #ifndef MAGNUM_TARGET_GLES - static UniformMatrix2dvImplementation uniformMatrix2dvImplementation; - static UniformMatrix3dvImplementation uniformMatrix3dvImplementation; - static UniformMatrix4dvImplementation uniformMatrix4dvImplementation; - static UniformMatrix2x3dvImplementation uniformMatrix2x3dvImplementation; - static UniformMatrix3x2dvImplementation uniformMatrix3x2dvImplementation; - static UniformMatrix2x4dvImplementation uniformMatrix2x4dvImplementation; - static UniformMatrix4x2dvImplementation uniformMatrix4x2dvImplementation; - static UniformMatrix3x4dvImplementation uniformMatrix3x4dvImplementation; - static UniformMatrix4x3dvImplementation uniformMatrix4x3dvImplementation; - #endif GLuint _id; }; @@ -1261,6 +1038,7 @@ template class AbstractShaderProgram::Attribute { * Half float. Only for float attribute types. * @requires_gl30 %Extension @extension{NV,half_float} * @requires_gles30 %Extension @es_extension{OES,vertex_half_float} + * in OpenGL ES 2.0 */ HalfFloat = GL_HALF_FLOAT, @@ -1283,7 +1061,8 @@ template class AbstractShaderProgram::Attribute { * float vector attribute type. * @todo How about (incompatible) @es_extension{OES,vertex_type_10_10_10_2}? * @requires_gl33 %Extension @extension{ARB,vertex_type_2_10_10_10_rev} - * @requires_gles30 (no extension providing this functionality) + * @requires_gles30 Packed attributes are not available in OpenGL + * ES 2.0 */ UnsignedInt2101010Rev = GL_UNSIGNED_INT_2_10_10_10_REV, @@ -1291,7 +1070,8 @@ template class AbstractShaderProgram::Attribute { * Signed 2.10.10.10 packed integer. Only for four-component float * vector attribute type. * @requires_gl33 %Extension @extension{ARB,vertex_type_2_10_10_10_rev} - * @requires_gles30 (no extension providing this functionality) + * @requires_gles30 Packed attributes are not available in OpenGL + * ES 2.0 */ Int2101010Rev = GL_INT_2_10_10_10_REV #endif @@ -1510,7 +1290,7 @@ struct FloatAttribute { }; typedef Containers::EnumSet DataOptions; - static std::size_t MAGNUM_EXPORT size(GLint components, DataType dataType); + static UnsignedInt MAGNUM_EXPORT size(GLint components, DataType dataType); }; CORRADE_ENUMSET_OPERATORS(FloatAttribute::DataOptions) @@ -1540,7 +1320,7 @@ struct IntAttribute { enum class DataOption: UnsignedByte {}; typedef Containers::EnumSet DataOptions; - static std::size_t MAGNUM_EXPORT size(GLint components, DataType dataType); + static UnsignedInt MAGNUM_EXPORT size(GLint components, DataType dataType); }; Debug MAGNUM_EXPORT operator<<(Debug debug, IntAttribute::DataType value); @@ -1560,7 +1340,7 @@ struct UnsignedIntAttribute { typedef IntAttribute::DataOption DataOption; typedef Containers::EnumSet DataOptions; - static std::size_t size(GLint components, DataType dataType) { + static UnsignedInt size(GLint components, DataType dataType) { return IntAttribute::size(components, dataType); } }; @@ -1584,7 +1364,7 @@ struct DoubleAttribute { enum class DataOption: UnsignedByte {}; typedef Containers::EnumSet DataOptions; - static std::size_t MAGNUM_EXPORT size(GLint components, DataType dataType); + static UnsignedInt MAGNUM_EXPORT size(GLint components, DataType dataType); }; Debug MAGNUM_EXPORT operator<<(Debug debug, DoubleAttribute::DataType value); @@ -1648,7 +1428,7 @@ template<> struct Attribute> { enum: UnsignedInt { VectorCount = 1 }; - static std::size_t MAGNUM_EXPORT size(GLint components, DataType dataType); + static UnsignedInt MAGNUM_EXPORT size(GLint components, DataType dataType); }; typedef Math::Vector<4, Float> _Vector4; diff --git a/src/Magnum/AbstractTexture.cpp b/src/Magnum/AbstractTexture.cpp index 70bae1dd6..0aa3e9ad7 100644 --- a/src/Magnum/AbstractTexture.cpp +++ b/src/Magnum/AbstractTexture.cpp @@ -28,66 +28,28 @@ #ifndef MAGNUM_TARGET_GLES2 #include "Magnum/BufferImage.h" #endif +#include "Magnum/Array.h" +#include "Magnum/Color.h" #include "Magnum/ColorFormat.h" #include "Magnum/Context.h" #include "Magnum/Extensions.h" #include "Magnum/Image.h" -#include "Magnum/Shader.h" #include "Magnum/TextureFormat.h" +#ifdef MAGNUM_BUILD_DEPRECATED +#include "Magnum/Shader.h" +#endif + #include "Implementation/DebugState.h" #include "Implementation/State.h" #include "Implementation/TextureState.h" namespace Magnum { -AbstractTexture::BindImplementation AbstractTexture::bindImplementation = - &AbstractTexture::bindImplementationDefault; -AbstractTexture::ParameteriImplementation AbstractTexture::parameteriImplementation = - &AbstractTexture::parameterImplementationDefault; -AbstractTexture::ParameterfImplementation AbstractTexture::parameterfImplementation = - &AbstractTexture::parameterImplementationDefault; -AbstractTexture::ParameterfvImplementation AbstractTexture::parameterfvImplementation = - &AbstractTexture::parameterImplementationDefault; -AbstractTexture::SetMaxAnisotropyImplementation AbstractTexture::setMaxAnisotropyImplementation = - &AbstractTexture::setMaxAnisotropyImplementationNoOp; -#ifndef MAGNUM_TARGET_GLES -AbstractTexture::GetLevelParameterivImplementation AbstractTexture::getLevelParameterivImplementation = - &AbstractTexture::getLevelParameterImplementationDefault; -#endif -AbstractTexture::MipmapImplementation AbstractTexture::mipmapImplementation = - &AbstractTexture::mipmapImplementationDefault; -#ifndef MAGNUM_TARGET_GLES -AbstractTexture::Storage1DImplementation AbstractTexture::storage1DImplementation = - &AbstractTexture::storageImplementationFallback; -#endif -AbstractTexture::Storage2DImplementation AbstractTexture::storage2DImplementation = - &AbstractTexture::storageImplementationFallback; -AbstractTexture::Storage3DImplementation AbstractTexture::storage3DImplementation = - &AbstractTexture::storageImplementationFallback; -#ifndef MAGNUM_TARGET_GLES -AbstractTexture::GetImageImplementation AbstractTexture::getImageImplementation = - &AbstractTexture::getImageImplementationDefault; -AbstractTexture::Image1DImplementation AbstractTexture::image1DImplementation = - &AbstractTexture::imageImplementationDefault; -#endif -AbstractTexture::Image2DImplementation AbstractTexture::image2DImplementation = - &AbstractTexture::imageImplementationDefault; -AbstractTexture::Image3DImplementation AbstractTexture::image3DImplementation = - &AbstractTexture::imageImplementationDefault; -#ifndef MAGNUM_TARGET_GLES -AbstractTexture::SubImage1DImplementation AbstractTexture::subImage1DImplementation = - &AbstractTexture::subImageImplementationDefault; -#endif -AbstractTexture::SubImage2DImplementation AbstractTexture::subImage2DImplementation = - &AbstractTexture::subImageImplementationDefault; -AbstractTexture::SubImage3DImplementation AbstractTexture::subImage3DImplementation = - &AbstractTexture::subImageImplementationDefault; - -AbstractTexture::InvalidateImageImplementation AbstractTexture::invalidateImageImplementation = &AbstractTexture::invalidateImageImplementationNoOp; -AbstractTexture::InvalidateSubImageImplementation AbstractTexture::invalidateSubImageImplementation = &AbstractTexture::invalidateSubImageImplementationNoOp; - +#ifdef MAGNUM_BUILD_DEPRECATED Int AbstractTexture::maxLayers() { return Shader::maxCombinedTextureImageUnits(); } +Int AbstractTexture::maxSupportedLayerCount() { return Shader::maxCombinedTextureImageUnits(); } +#endif #ifndef MAGNUM_TARGET_GLES Int AbstractTexture::maxColorSamples() { @@ -161,7 +123,7 @@ void AbstractTexture::bind(Int layer) { /* If already bound in given layer, nothing to do */ if(textureState->bindings[layer] == _id) return; - (this->*bindImplementation)(layer); + (this->*Context::current()->state().texture->bindImplementation)(layer); } void AbstractTexture::bindImplementationDefault(GLint layer) { @@ -181,22 +143,32 @@ void AbstractTexture::bindImplementationDSA(GLint layer) { } #endif -AbstractTexture& AbstractTexture::setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap) { - #ifndef MAGNUM_TARGET_GLES - CORRADE_ASSERT(_target != GL_TEXTURE_RECTANGLE || mipmap == Sampler::Mipmap::Base, "AbstractTexture: rectangle textures cannot have mipmaps", *this); - #endif +void AbstractTexture::setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap) { + (this->*Context::current()->state().texture->parameteriImplementation)(GL_TEXTURE_MIN_FILTER, GLint(filter)|GLint(mipmap)); +} - (this->*parameteriImplementation)(GL_TEXTURE_MIN_FILTER, GLint(filter)|GLint(mipmap)); - return *this; +void AbstractTexture::setMagnificationFilter(const Sampler::Filter filter) { + (this->*Context::current()->state().texture->parameteriImplementation)(GL_TEXTURE_MAG_FILTER, GLint(filter)); } -AbstractTexture& AbstractTexture::generateMipmap() { +void AbstractTexture::setBorderColor(const Color4& color) { #ifndef MAGNUM_TARGET_GLES - CORRADE_ASSERT(_target != GL_TEXTURE_RECTANGLE, "AbstractTexture: rectangle textures cannot have mipmaps", *this); + (this->*Context::current()->state().texture->parameterfvImplementation)(GL_TEXTURE_BORDER_COLOR, color.data()); + #else + (this->*Context::current()->state().texture->parameterfvImplementation)(GL_TEXTURE_BORDER_COLOR_NV, color.data()); #endif +} - (this->*mipmapImplementation)(); - return *this; +void AbstractTexture::setMaxAnisotropy(const Float anisotropy) { + (this->*Context::current()->state().texture->setMaxAnisotropyImplementation)(anisotropy); +} + +void AbstractTexture::invalidateImage(const Int level) { + (this->*Context::current()->state().texture->invalidateImageImplementation)(level); +} + +void AbstractTexture::generateMipmap() { + (this->*Context::current()->state().texture->mipmapImplementation)(); } void AbstractTexture::mipmapImplementationDefault() { @@ -218,7 +190,8 @@ void AbstractTexture::bindInternal() { return; /* Set internal layer as active if not already */ - const GLint internalLayer = maxLayers()-1; + CORRADE_INTERNAL_ASSERT(textureState->maxLayers > 1); + const GLint internalLayer = textureState->maxLayers-1; if(textureState->currentLayer != internalLayer) glActiveTexture(GL_TEXTURE0 + (textureState->currentLayer = internalLayer)); @@ -227,65 +200,6 @@ void AbstractTexture::bindInternal() { glBindTexture(_target, (textureState->bindings[internalLayer] = _id)); } -void AbstractTexture::initializeContextBasedFunctionality(Context& context) { - /* Resize bindings array to hold all possible layers */ - context.state().texture->bindings.resize(maxLayers()); - - #ifndef MAGNUM_TARGET_GLES - if(context.isExtensionSupported()) { - Debug() << "AbstractTexture: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; - - bindImplementation = &AbstractTexture::bindImplementationDSA; - parameteriImplementation = &AbstractTexture::parameterImplementationDSA; - parameterfImplementation = &AbstractTexture::parameterImplementationDSA; - parameterfvImplementation = &AbstractTexture::parameterImplementationDSA; - getLevelParameterivImplementation = &AbstractTexture::getLevelParameterImplementationDSA; - mipmapImplementation = &AbstractTexture::mipmapImplementationDSA; - getImageImplementation = &AbstractTexture::getImageImplementationDSA; - image1DImplementation = &AbstractTexture::imageImplementationDSA; - image2DImplementation = &AbstractTexture::imageImplementationDSA; - image3DImplementation = &AbstractTexture::imageImplementationDSA; - subImage1DImplementation = &AbstractTexture::subImageImplementationDSA; - subImage2DImplementation = &AbstractTexture::subImageImplementationDSA; - subImage3DImplementation = &AbstractTexture::subImageImplementationDSA; - } - - if(context.isExtensionSupported()) { - Debug() << "AbstractTexture: using" << Extensions::GL::ARB::invalidate_subdata::string() << "features"; - - invalidateImageImplementation = &AbstractTexture::invalidateImageImplementationARB; - invalidateSubImageImplementation = &AbstractTexture::invalidateSubImageImplementationARB; - } - - if(context.isExtensionSupported() && - !context.isExtensionSupported()) { - Debug() << "AbstractTexture: using" << Extensions::GL::ARB::robustness::string() << "features"; - - getImageImplementation = &AbstractTexture::getImageImplementationRobustness; - } - - if(context.isExtensionSupported()) { - Debug() << "AbstractTexture: using" << Extensions::GL::ARB::texture_storage::string() << "features"; - - if(context.isExtensionSupported()) { - storage1DImplementation = &AbstractTexture::storageImplementationDSA; - storage2DImplementation = &AbstractTexture::storageImplementationDSA; - storage3DImplementation = &AbstractTexture::storageImplementationDSA; - } else { - storage1DImplementation = &AbstractTexture::storageImplementationDefault; - storage2DImplementation = &AbstractTexture::storageImplementationDefault; - storage3DImplementation = &AbstractTexture::storageImplementationDefault; - } - } - #endif - - if(context.isExtensionSupported()) { - Debug() << "AbstractTexture: using" << Extensions::GL::EXT::texture_filter_anisotropic::string() << "features"; - - setMaxAnisotropyImplementation = &AbstractTexture::setMaxAnisotropyImplementationExt; - } -} - ColorFormat AbstractTexture::imageFormatForInternalFormat(const TextureFormat internalFormat) { switch(internalFormat) { case TextureFormat::Red: @@ -691,7 +605,7 @@ void AbstractTexture::parameterImplementationDSA(GLenum parameter, const GLfloat void AbstractTexture::setMaxAnisotropyImplementationNoOp(GLfloat) {} void AbstractTexture::setMaxAnisotropyImplementationExt(GLfloat anisotropy) { - (this->*parameterfImplementation)(GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); + (this->*Context::current()->state().texture->parameterfImplementation)(GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); } #ifndef MAGNUM_TARGET_GLES @@ -713,7 +627,7 @@ void AbstractTexture::storageImplementationFallback(const GLenum target, const G const ColorType type = imageTypeForInternalFormat(internalFormat); for(GLsizei level = 0; level != levels; ++level) { - (this->*image1DImplementation)(target, level, internalFormat, Math::max(Math::Vector<1, GLsizei>(1), size >> level), format, type, nullptr); + (this->*Context::current()->state().texture->image1DImplementation)(target, level, internalFormat, Math::max(Math::Vector<1, GLsizei>(1), size >> level), format, type, nullptr); } } @@ -749,7 +663,7 @@ void AbstractTexture::storageImplementationFallback(const GLenum target, const G #endif { for(GLsizei level = 0; level != levels; ++level) { - (this->*image2DImplementation)(target, level, internalFormat, Math::max(Vector2i(1), size >> level), format, type, nullptr); + (this->*Context::current()->state().texture->image2DImplementation)(target, level, internalFormat, Math::max(Vector2i(1), size >> level), format, type, nullptr); } /* Cube map additionally needs to specify all faces */ @@ -764,14 +678,14 @@ void AbstractTexture::storageImplementationFallback(const GLenum target, const G GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; for(auto it = faces.begin(); it != faces.end(); ++it) - (this->*image2DImplementation)(*it, level, internalFormat, Math::max(Vector2i(1), size >> level), format, type, nullptr); + (this->*Context::current()->state().texture->image2DImplementation)(*it, level, internalFormat, Math::max(Vector2i(1), size >> level), format, type, nullptr); } #ifndef MAGNUM_TARGET_GLES /* Array texture is not scaled in "layer" dimension */ } else if(target == GL_TEXTURE_1D_ARRAY) { for(GLsizei level = 0; level != levels; ++level) { - (this->*image2DImplementation)(target, level, internalFormat, Math::max(Vector2i(1), size >> level), format, type, nullptr); + (this->*Context::current()->state().texture->image2DImplementation)(target, level, internalFormat, Math::max(Vector2i(1), size >> level), format, type, nullptr); } #endif @@ -812,7 +726,7 @@ void AbstractTexture::storageImplementationFallback(GLenum target, GLsizei level #endif { for(GLsizei level = 0; level != levels; ++level) { - (this->*image3DImplementation)(target, level, internalFormat, Math::max(Vector3i(1), size >> level), format, type, nullptr); + (this->*Context::current()->state().texture->image3DImplementation)(target, level, internalFormat, Math::max(Vector3i(1), size >> level), format, type, nullptr); } #ifndef MAGNUM_TARGET_GLES2 @@ -825,7 +739,7 @@ void AbstractTexture::storageImplementationFallback(GLenum target, GLsizei level #endif { for(GLsizei level = 0; level != levels; ++level) { - (this->*image3DImplementation)(target, level, internalFormat, Math::max(Vector3i(1), size >> level), format, type, nullptr); + (this->*Context::current()->state().texture->image3DImplementation)(target, level, internalFormat, Math::max(Vector3i(1), size >> level), format, type, nullptr); } #endif @@ -992,10 +906,10 @@ void AbstractTexture::invalidateSubImageImplementationARB(GLint level, const Vec #ifndef DOXYGEN_GENERATING_OUTPUT #ifndef MAGNUM_TARGET_GLES template void AbstractTexture::image(GLenum target, GLint level, Image& image) { - const Math::Vector size = DataHelper::imageSize(this, target, level); - const std::size_t dataSize = size.product()*image.pixelSize(); + const Math::Vector size = DataHelper::imageSize(*this, target, level); + const std::size_t dataSize = image.dataSize(size); char* data = new char[dataSize]; - (this->*getImageImplementation)(target, level, image.format(), image.type(), dataSize, data); + (this->*Context::current()->state().texture->getImageImplementation)(target, level, image.format(), image.type(), dataSize, data); image.setData(image.format(), image.type(), size, data); } @@ -1004,13 +918,13 @@ template void MAGNUM_EXPORT AbstractTexture::image<2>(GLenum, GLint, Image<2>&); template void MAGNUM_EXPORT AbstractTexture::image<3>(GLenum, GLint, Image<3>&); template void AbstractTexture::image(GLenum target, GLint level, BufferImage& image, BufferUsage usage) { - const Math::Vector size = DataHelper::imageSize(this, target, level); - const std::size_t dataSize = size.product()*image.pixelSize(); + const Math::Vector size = DataHelper::imageSize(*this, target, level); + const std::size_t dataSize = image.dataSize(size); if(image.size() != size) image.setData(image.format(), image.type(), size, nullptr, usage); image.buffer().bind(Buffer::Target::PixelPack); - (this->*getImageImplementation)(target, level, image.format(), image.type(), dataSize, nullptr); + (this->*Context::current()->state().texture->getImageImplementation)(target, level, image.format(), image.type(), dataSize, nullptr); } template void MAGNUM_EXPORT AbstractTexture::image<1>(GLenum, GLint, BufferImage<1>&, BufferUsage); @@ -1021,120 +935,162 @@ template void MAGNUM_EXPORT AbstractTexture::image<3>(GLenum, GLint, BufferImage #ifndef DOXYGEN_GENERATING_OUTPUT #ifndef MAGNUM_TARGET_GLES -Math::Vector<1, GLint> AbstractTexture::DataHelper<1>::imageSize(AbstractTexture* texture, GLenum target, GLint level) { +Math::Vector<1, GLint> AbstractTexture::DataHelper<1>::imageSize(AbstractTexture& texture, const GLenum target, const GLint level) { Math::Vector<1, GLint> value; - (texture->*getLevelParameterivImplementation)(target, level, GL_TEXTURE_WIDTH, &value[0]); + (texture.*Context::current()->state().texture->getLevelParameterivImplementation)(target, level, GL_TEXTURE_WIDTH, &value[0]); return value; } -Vector2i AbstractTexture::DataHelper<2>::imageSize(AbstractTexture* texture, GLenum target, GLint level) { +Vector2i AbstractTexture::DataHelper<2>::imageSize(AbstractTexture& texture, const GLenum target, const GLint level) { + const Implementation::TextureState& state = *Context::current()->state().texture; + Vector2i value; - (texture->*getLevelParameterivImplementation)(target, level, GL_TEXTURE_WIDTH, &value[0]); - (texture->*getLevelParameterivImplementation)(target, level, GL_TEXTURE_HEIGHT, &value[1]); + (texture.*state.getLevelParameterivImplementation)(target, level, GL_TEXTURE_WIDTH, &value[0]); + (texture.*state.getLevelParameterivImplementation)(target, level, GL_TEXTURE_HEIGHT, &value[1]); return value; } -Vector3i AbstractTexture::DataHelper<3>::imageSize(AbstractTexture* texture, GLenum target, GLint level) { +Vector3i AbstractTexture::DataHelper<3>::imageSize(AbstractTexture& texture, const GLenum target, const GLint level) { + const Implementation::TextureState& state = *Context::current()->state().texture; + Vector3i value; - (texture->*getLevelParameterivImplementation)(target, level, GL_TEXTURE_WIDTH, &value[0]); - (texture->*getLevelParameterivImplementation)(target, level, GL_TEXTURE_HEIGHT, &value[1]); - (texture->*getLevelParameterivImplementation)(target, level, GL_TEXTURE_DEPTH, &value[2]); + (texture.*state.getLevelParameterivImplementation)(target, level, GL_TEXTURE_WIDTH, &value[0]); + (texture.*state.getLevelParameterivImplementation)(target, level, GL_TEXTURE_HEIGHT, &value[1]); + (texture.*state.getLevelParameterivImplementation)(target, level, GL_TEXTURE_DEPTH, &value[2]); return value; } #endif #ifndef MAGNUM_TARGET_GLES -void AbstractTexture::DataHelper<1>::setImage(AbstractTexture* const texture, const GLenum target, const GLint level, const TextureFormat internalFormat, const ImageReference1D& image) { +void AbstractTexture::DataHelper<1>::setStorage(AbstractTexture& texture, const GLenum target, const GLsizei levels, const TextureFormat internalFormat, const Math::Vector< 1, GLsizei >& size) { + (texture.*Context::current()->state().texture->storage1DImplementation)(target, levels, internalFormat, size); +} +#endif + +void AbstractTexture::DataHelper<2>::setStorage(AbstractTexture& texture, const GLenum target, const GLsizei levels, const TextureFormat internalFormat, const Vector2i& size) { + (texture.*Context::current()->state().texture->storage2DImplementation)(target, levels, internalFormat, size); +} + +void AbstractTexture::DataHelper<3>::setStorage(AbstractTexture& texture, const GLenum target, const GLsizei levels, const TextureFormat internalFormat, const Vector3i& size) { + (texture.*Context::current()->state().texture->storage3DImplementation)(target, levels, internalFormat, size); +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::DataHelper<1>::setImage(AbstractTexture& texture, const GLenum target, const GLint level, const TextureFormat internalFormat, const ImageReference1D& image) { Buffer::unbind(Buffer::Target::PixelUnpack); - (texture->*image1DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), image.data()); + (texture.*Context::current()->state().texture->image1DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), image.data()); } -void AbstractTexture::DataHelper<1>::setImage(AbstractTexture* const texture, const GLenum target, const GLint level, const TextureFormat internalFormat, BufferImage1D& image) { +void AbstractTexture::DataHelper<1>::setImage(AbstractTexture& texture, const GLenum target, const GLint level, const TextureFormat internalFormat, BufferImage1D& image) { image.buffer().bind(Buffer::Target::PixelUnpack); - (texture->*image1DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), nullptr); + (texture.*Context::current()->state().texture->image1DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), nullptr); } -void AbstractTexture::DataHelper<1>::setSubImage(AbstractTexture* const texture, const GLenum target, const GLint level, const Math::Vector<1, GLint>& offset, const ImageReference1D& image) { +void AbstractTexture::DataHelper<1>::setSubImage(AbstractTexture& texture, const GLenum target, const GLint level, const Math::Vector<1, GLint>& offset, const ImageReference1D& image) { Buffer::unbind(Buffer::Target::PixelUnpack); - (texture->*subImage1DImplementation)(target, level, offset, image.size(), image.format(), image.type(), image.data()); + (texture.*Context::current()->state().texture->subImage1DImplementation)(target, level, offset, image.size(), image.format(), image.type(), image.data()); } -void AbstractTexture::DataHelper<1>::setSubImage(AbstractTexture* const texture, const GLenum target, const GLint level, const Math::Vector<1, GLint>& offset, BufferImage1D& image) { +void AbstractTexture::DataHelper<1>::setSubImage(AbstractTexture& texture, const GLenum target, const GLint level, const Math::Vector<1, GLint>& offset, BufferImage1D& image) { image.buffer().bind(Buffer::Target::PixelUnpack); - (texture->*subImage1DImplementation)(target, level, offset, image.size(), image.format(), image.type(), nullptr); + (texture.*Context::current()->state().texture->subImage1DImplementation)(target, level, offset, image.size(), image.format(), image.type(), nullptr); } #endif -void AbstractTexture::DataHelper<2>::setImage(AbstractTexture* const texture, const GLenum target, const GLint level, const TextureFormat internalFormat, const ImageReference2D& image) { +void AbstractTexture::DataHelper<2>::setImage(AbstractTexture& texture, const GLenum target, const GLint level, const TextureFormat internalFormat, const ImageReference2D& image) { #ifndef MAGNUM_TARGET_GLES2 Buffer::unbind(Buffer::Target::PixelUnpack); #endif - (texture->*image2DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), image.data()); + (texture.*Context::current()->state().texture->image2DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), image.data()); } #ifndef MAGNUM_TARGET_GLES2 -void AbstractTexture::DataHelper<2>::setImage(AbstractTexture* const texture, const GLenum target, const GLint level, const TextureFormat internalFormat, BufferImage2D& image) { +void AbstractTexture::DataHelper<2>::setImage(AbstractTexture& texture, const GLenum target, const GLint level, const TextureFormat internalFormat, BufferImage2D& image) { image.buffer().bind(Buffer::Target::PixelUnpack); - (texture->*image2DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), nullptr); + (texture.*Context::current()->state().texture->image2DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), nullptr); } #endif -void AbstractTexture::DataHelper<2>::setSubImage(AbstractTexture* const texture, const GLenum target, const GLint level, const Vector2i& offset, const ImageReference2D& image) { +void AbstractTexture::DataHelper<2>::setSubImage(AbstractTexture& texture, const GLenum target, const GLint level, const Vector2i& offset, const ImageReference2D& image) { #ifndef MAGNUM_TARGET_GLES2 Buffer::unbind(Buffer::Target::PixelUnpack); #endif - (texture->*subImage2DImplementation)(target, level, offset, image.size(), image.format(), image.type(), image.data()); + (texture.*Context::current()->state().texture->subImage2DImplementation)(target, level, offset, image.size(), image.format(), image.type(), image.data()); } #ifndef MAGNUM_TARGET_GLES2 -void AbstractTexture::DataHelper<2>::setSubImage(AbstractTexture* const texture, const GLenum target, const GLint level, const Vector2i& offset, BufferImage2D& image) { +void AbstractTexture::DataHelper<2>::setSubImage(AbstractTexture& texture, const GLenum target, const GLint level, const Vector2i& offset, BufferImage2D& image) { image.buffer().bind(Buffer::Target::PixelUnpack); - (texture->*subImage2DImplementation)(target, level, offset, image.size(), image.format(), image.type(), nullptr); + (texture.*Context::current()->state().texture->subImage2DImplementation)(target, level, offset, image.size(), image.format(), image.type(), nullptr); } #endif -void AbstractTexture::DataHelper<3>::setImage(AbstractTexture* const texture, const GLenum target, const GLint level, const TextureFormat internalFormat, const ImageReference3D& image) { +void AbstractTexture::DataHelper<3>::setImage(AbstractTexture& texture, const GLenum target, const GLint level, const TextureFormat internalFormat, const ImageReference3D& image) { #ifndef MAGNUM_TARGET_GLES2 Buffer::unbind(Buffer::Target::PixelUnpack); #endif - (texture->*image3DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), image.data()); + (texture.*Context::current()->state().texture->image3DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), image.data()); } #ifndef MAGNUM_TARGET_GLES2 -void AbstractTexture::DataHelper<3>::setImage(AbstractTexture* const texture, const GLenum target, const GLint level, const TextureFormat internalFormat, BufferImage3D& image) { +void AbstractTexture::DataHelper<3>::setImage(AbstractTexture& texture, const GLenum target, const GLint level, const TextureFormat internalFormat, BufferImage3D& image) { image.buffer().bind(Buffer::Target::PixelUnpack); - (texture->*image3DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), nullptr); + (texture.*Context::current()->state().texture->image3DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), nullptr); } #endif -void AbstractTexture::DataHelper<3>::setSubImage(AbstractTexture* const texture, const GLenum target, const GLint level, const Vector3i& offset, const ImageReference3D& image) { +void AbstractTexture::DataHelper<3>::setSubImage(AbstractTexture& texture, const GLenum target, const GLint level, const Vector3i& offset, const ImageReference3D& image) { #ifndef MAGNUM_TARGET_GLES2 Buffer::unbind(Buffer::Target::PixelUnpack); #endif - (texture->*subImage3DImplementation)(target, level, offset, image.size(), image.format(), image.type(), image.data()); + (texture.*Context::current()->state().texture->subImage3DImplementation)(target, level, offset, image.size(), image.format(), image.type(), image.data()); } #ifndef MAGNUM_TARGET_GLES2 -void AbstractTexture::DataHelper<3>::setSubImage(AbstractTexture* const texture, const GLenum target, const GLint level, const Vector3i& offset, BufferImage3D& image) { +void AbstractTexture::DataHelper<3>::setSubImage(AbstractTexture& texture, const GLenum target, const GLint level, const Vector3i& offset, BufferImage3D& image) { image.buffer().bind(Buffer::Target::PixelUnpack); - (texture->*subImage3DImplementation)(target, level, offset, image.size(), image.format(), image.type(), nullptr); + (texture.*Context::current()->state().texture->subImage3DImplementation)(target, level, offset, image.size(), image.format(), image.type(), nullptr); } #endif -void AbstractTexture::DataHelper<2>::setWrapping(AbstractTexture* texture, const Array2D& wrapping) { +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::DataHelper<1>::invalidateSubImage(AbstractTexture& texture, const GLint level, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLint>& size) { + (texture.*Context::current()->state().texture->invalidateSubImageImplementation)(level, {offset[0], 0, 0}, {size[0], 1, 1}); +} +#endif + +void AbstractTexture::DataHelper<2>::invalidateSubImage(AbstractTexture& texture, const GLint level, const Vector2i& offset, const Vector2i& size) { + (texture.*Context::current()->state().texture->invalidateSubImageImplementation)(level, {offset, 0}, {size, 1}); +} + +void AbstractTexture::DataHelper<3>::invalidateSubImage(AbstractTexture& texture, const GLint level, const Vector3i& offset, const Vector3i& size) { + (texture.*Context::current()->state().texture->invalidateSubImageImplementation)(level, offset, size); +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::DataHelper<1>::setWrapping(AbstractTexture& texture, const Array1D& wrapping) { + (texture.*Context::current()->state().texture->parameteriImplementation)(GL_TEXTURE_WRAP_S, GLint(wrapping.x())); +} +#endif + +void AbstractTexture::DataHelper<2>::setWrapping(AbstractTexture& texture, const Array2D& wrapping) { #ifndef MAGNUM_TARGET_GLES - CORRADE_ASSERT(texture->_target != GL_TEXTURE_RECTANGLE || ((wrapping.x() == Sampler::Wrapping::ClampToEdge || wrapping.x() == Sampler::Wrapping::ClampToBorder) && (wrapping.y() == Sampler::Wrapping::ClampToEdge || wrapping.y() == Sampler::Wrapping::ClampToBorder)), "Texture2D::setWrapping(): rectangle texture must be clamped to border or to edge", ); + CORRADE_ASSERT(texture._target != GL_TEXTURE_RECTANGLE || ((wrapping.x() == Sampler::Wrapping::ClampToEdge || wrapping.x() == Sampler::Wrapping::ClampToBorder) && (wrapping.y() == Sampler::Wrapping::ClampToEdge || wrapping.y() == Sampler::Wrapping::ClampToBorder)), "Texture2D::setWrapping(): rectangle texture must be clamped to border or to edge", ); #endif - (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_S, GLint(wrapping.x())); - (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_T, GLint(wrapping.y())); + const Implementation::TextureState& state = *Context::current()->state().texture; + + (texture.*state.parameteriImplementation)(GL_TEXTURE_WRAP_S, GLint(wrapping.x())); + (texture.*state.parameteriImplementation)(GL_TEXTURE_WRAP_T, GLint(wrapping.y())); } -void AbstractTexture::DataHelper<3>::setWrapping(AbstractTexture* texture, const Array3D& wrapping) { - (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_S, GLint(wrapping.x())); - (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_T, GLint(wrapping.y())); +void AbstractTexture::DataHelper<3>::setWrapping(AbstractTexture& texture, const Array3D& wrapping) { + const Implementation::TextureState& state = *Context::current()->state().texture; + + (texture.*state.parameteriImplementation)(GL_TEXTURE_WRAP_S, GLint(wrapping.x())); + (texture.*state.parameteriImplementation)(GL_TEXTURE_WRAP_T, GLint(wrapping.y())); #ifndef MAGNUM_TARGET_GLES - (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_R, GLint(wrapping.z())); + (texture.*state.parameteriImplementation)(GL_TEXTURE_WRAP_R, GLint(wrapping.z())); #endif } #endif diff --git a/src/Magnum/AbstractTexture.h b/src/Magnum/AbstractTexture.h index 6fd5a09a0..0ef26095c 100644 --- a/src/Magnum/AbstractTexture.h +++ b/src/Magnum/AbstractTexture.h @@ -29,8 +29,6 @@ * @brief Class @ref Magnum::AbstractTexture */ -#include "Magnum/Array.h" -#include "Magnum/Color.h" #include "Magnum/Sampler.h" #include "Magnum/AbstractObject.h" @@ -42,6 +40,8 @@ namespace Magnum { +namespace Implementation { struct TextureState; } + /** @brief Base for textures @@ -85,12 +85,12 @@ OpenGL ES 3.0 or @es_extension{EXT,texture_storage} in OpenGL ES 2.0 is not available, the feature is emulated with sequence of @ref Texture::setImage() "setImage()" calls. -You can use functions @ref invalidateImage() and +You can use functions @ref Texture::invalidateImage() and @ref Texture::invalidateSubImage() "invalidateSubImage()" if you don't need texture data anymore to avoid unnecessary memory operations performed by OpenGL in order to preserve the data. If running on OpenGL ES or extension -@extension{ARB,invalidate_subdata} is not available, these functions do -nothing. +@extension{ARB,invalidate_subdata} (part of OpenGL 4.3) is not available, these +functions do nothing. @todo all texture [level] parameters, global texture parameters @todo Add glPixelStore encapsulation @@ -105,26 +105,25 @@ nothing. @todo Query for immutable levels (@extension{ARB,ES3_compatibility}) */ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { - friend class Context; + friend struct Implementation::TextureState; public: + #ifdef MAGNUM_BUILD_DEPRECATED /** - * @brief Max supported layer count - * - * The result is cached, repeated queries don't result in repeated - * OpenGL calls. This function is in fact alias to - * @ref Shader::maxCombinedTextureImageUnits(). - * @see @ref bind(Int) + * @copybrief Shader::maxCombinedTextureImageUnits() + * @deprecated Use @ref Magnum::Shader::maxCombinedTextureImageUnits() "Shader::maxCombinedTextureImageUnits()" + * instead. */ - static Int maxLayers(); + static CORRADE_DEPRECATED("use Shader::maxCombinedTextureImageUnits() instead") Int maxLayers(); + #endif #ifdef MAGNUM_BUILD_DEPRECATED /** - * @copybrief maxLayers() - * @deprecated Use @ref Magnum::AbstractTexture::maxLayers() "maxLayers()" + * @copybrief Shader::maxCombinedTextureImageUnits() + * @deprecated Use @ref Magnum::Shader::maxCombinedTextureImageUnits() "Shader::maxCombinedTextureImageUnits()" * instead. */ - static CORRADE_DEPRECATED("use maxLayers() instead") Int maxSupportedLayerCount() { return maxLayers(); } + static CORRADE_DEPRECATED("use Shader::maxCombinedTextureImageUnits() instead") Int maxSupportedLayerCount(); #endif #ifndef MAGNUM_TARGET_GLES @@ -162,6 +161,14 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { static Int maxIntegerSamples(); #endif + /** + * @brief Destructor + * + * Deletes associated OpenGL texture. + * @see @fn_gl{DeleteTextures} + */ + ~AbstractTexture(); + /** @brief Copying is not allowed */ AbstractTexture(const AbstractTexture&) = delete; @@ -178,9 +185,9 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { * @brief %Texture label * * The result is *not* cached, repeated queries will result in repeated - * OpenGL calls. If neither @extension{KHR,debug} nor - * @extension2{EXT,debug_label} desktop or ES extension is available, - * this function returns empty string. + * OpenGL calls. If OpenGL 4.3 is not supported and neither + * @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES + * extension is available, this function returns empty string. * @see @fn_gl{GetObjectLabel} or * @fn_gl_extension2{GetObjectLabel,EXT,debug_label} with * @def_gl{TEXTURE} @@ -191,9 +198,9 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { * @brief Set texture label * @return Reference to self (for method chaining) * - * Default is empty string. If neither @extension{KHR,debug} nor - * @extension2{EXT,debug_label} desktop or ES extension is available, - * this function does nothing. + * Default is empty string. If OpenGL 4.3 is not supported and neither + * @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES + * extension is available, this function does nothing. * @see @ref maxLabelLength(), @fn_gl{ObjectLabel} or * @fn_gl_extension2{LabelObject,EXT,debug_label} with * @def_gl{TEXTURE} @@ -206,140 +213,18 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { /** * @brief Bind texture for rendering * - * Sets current texture as active in given layer. The layer must be - * between 0 and @ref maxLayers(). Note that only one texture can be - * bound to given layer. If @extension{EXT,direct_state_access} is not - * available, the layer is made active before binding the texture. + * Sets current texture as active in given layer. Note that only one + * texture can be bound to given layer. If @extension{EXT,direct_state_access} + * is not available, the layer is made active before binding the + * texture. + * @note This function is meant to be used only internally from + * @ref AbstractShaderProgram subclasses. See its documentation + * for more information. * @see @ref maxLayers(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} or * @fn_gl_extension{BindMultiTexture,EXT,direct_state_access} */ void bind(Int layer); - /** - * @brief Set minification filter - * @param filter Filter - * @param mipmap Mipmap filtering. If set to anything else than - * @ref Sampler::Mipmap::Base, make sure textures for all mip - * levels are set or call @ref generateMipmap(). - * @return Reference to self (for method chaining) - * - * Sets filter used when the object pixel size is smaller than the - * texture size. If @extension{EXT,direct_state_access} is not - * available, the texture is bound to some layer before the operation. - * Initial value is (@ref Sampler::Filter::Nearest, @ref Sampler::Mipmap::Linear). - * @attention For rectangle textures only some modes are supported, - * see @ref Sampler::Filter and @ref Sampler::Mipmap documentation - * for more information. - * @see @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} - */ - AbstractTexture& setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base); - - /** - * @brief Set magnification filter - * @param filter Filter - * @return Reference to self (for method chaining) - * - * Sets filter used when the object pixel size is larger than largest - * texture size. If @extension{EXT,direct_state_access} is not - * available, the texture is bound to some layer 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} - */ - AbstractTexture& setMagnificationFilter(Sampler::Filter filter) { - (this->*parameteriImplementation)(GL_TEXTURE_MAG_FILTER, GLint(filter)); - return *this; - } - - /** - * @brief Set border color - * @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 layer 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} - * @requires_es_extension %Extension @es_extension{NV,texture_border_clamp} - */ - AbstractTexture& setBorderColor(const Color4& color) { - #ifndef MAGNUM_TARGET_GLES - (this->*parameterfvImplementation)(GL_TEXTURE_BORDER_COLOR, color.data()); - #else - (this->*parameterfvImplementation)(GL_TEXTURE_BORDER_COLOR_NV, color.data()); - #endif - return *this; - } - - /** - * @brief Set max anisotropy - * @return Reference to self (for method chaining) - * - * Default value is `1.0f`, which means no anisotropy. Set to value - * greater than `1.0f` for anisotropic filtering. If extension - * @extension{EXT,texture_filter_anisotropic} (desktop or ES) is not - * available, this function does nothing. If - * @extension{EXT,direct_state_access} is not available, the texture is - * bound to some layer before the operation. - * @see @ref Sampler::maxMaxAnisotropy(), @fn_gl{ActiveTexture}, - * @fn_gl{BindTexture} and @fn_gl{TexParameter} or - * @fn_gl_extension{TextureParameter,EXT,direct_state_access} with - * @def_gl{TEXTURE_MAX_ANISOTROPY_EXT} - */ - AbstractTexture& setMaxAnisotropy(Float anisotropy) { - (this->*setMaxAnisotropyImplementation)(anisotropy); - return *this; - } - - /** - * @brief Invalidate texture image - * @param level Mip level - * - * If running on OpenGL ES or extension @extension{ARB,invalidate_subdata} - * (part of OpenGL 4.3) is not available, this function does nothing. - * @see @ref Texture::invalidateSubImage() "invalidateSubImage()", - * @fn_gl{InvalidateTexImage} - */ - void invalidateImage(Int level) { - (this->*invalidateImageImplementation)(level); - } - - /** - * @brief Generate mipmap - * @return Reference to self (for method chaining) - * - * Can not be used for rectangle textures. If - * @extension{EXT,direct_state_access} is not available, the texture - * is bound to some layer before the operation. - * @see setMinificationFilter(), @fn_gl{ActiveTexture}, - * @fn_gl{BindTexture} and @fn_gl{GenerateMipmap} or - * @fn_gl_extension{GenerateTextureMipmap,EXT,direct_state_access} - * @requires_gl30 %Extension @extension{ARB,framebuffer_object} - */ - AbstractTexture& generateMipmap(); - - protected: - /** - * @brief Constructor - * - * Creates new OpenGL texture. - * @see @fn_gl{GenTextures} - */ - explicit AbstractTexture(GLenum target); - - /** - * @brief Destructor - * - * Deletes assigned OpenGL texture. - * @see @fn_gl{DeleteTextures} - */ - ~AbstractTexture(); - #ifdef DOXYGEN_GENERATING_OUTPUT private: #else @@ -347,9 +232,18 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { #endif template struct DataHelper {}; + explicit AbstractTexture(GLenum target); + /* Unlike bind() this also sets the binding layer as active */ void MAGNUM_LOCAL bindInternal(); + void setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap); + void setMagnificationFilter(Sampler::Filter filter); + void setBorderColor(const Color4& color); + void setMaxAnisotropy(Float anisotropy); + void invalidateImage(Int level); + void generateMipmap(); + #ifndef MAGNUM_TARGET_GLES template void image(GLenum target, GLint level, Image& image); template void image(GLenum target, GLint level, BufferImage& image, BufferUsage usage); @@ -358,142 +252,102 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { GLenum _target; private: - static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context); - - typedef void(AbstractTexture::*BindImplementation)(GLint); void MAGNUM_LOCAL bindImplementationDefault(GLint layer); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL bindImplementationDSA(GLint layer); #endif - static MAGNUM_LOCAL BindImplementation bindImplementation; - typedef void(AbstractTexture::*ParameteriImplementation)(GLenum, GLint); void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, GLint value); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, GLint value); #endif - static ParameteriImplementation parameteriImplementation; - typedef void(AbstractTexture::*ParameterfImplementation)(GLenum, GLfloat); void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, GLfloat value); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, GLfloat value); #endif - static ParameterfImplementation parameterfImplementation; - typedef void(AbstractTexture::*ParameterfvImplementation)(GLenum, const GLfloat*); void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, const GLfloat* values); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, const GLfloat* values); #endif - static ParameterfvImplementation parameterfvImplementation; - typedef void(AbstractTexture::*SetMaxAnisotropyImplementation)(GLfloat); void MAGNUM_LOCAL setMaxAnisotropyImplementationNoOp(GLfloat); void MAGNUM_LOCAL setMaxAnisotropyImplementationExt(GLfloat anisotropy); - static SetMaxAnisotropyImplementation setMaxAnisotropyImplementation; #ifndef MAGNUM_TARGET_GLES - typedef void(AbstractTexture::*GetLevelParameterivImplementation)(GLenum, GLint, GLenum, GLint*); void MAGNUM_LOCAL getLevelParameterImplementationDefault(GLenum target, GLint level, GLenum parameter, GLint* values); void MAGNUM_LOCAL getLevelParameterImplementationDSA(GLenum target, GLint level, GLenum parameter, GLint* values); - static MAGNUM_LOCAL GetLevelParameterivImplementation getLevelParameterivImplementation; #endif - typedef void(AbstractTexture::*MipmapImplementation)(); void MAGNUM_LOCAL mipmapImplementationDefault(); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL mipmapImplementationDSA(); #endif - static MAGNUM_LOCAL MipmapImplementation mipmapImplementation; #ifndef MAGNUM_TARGET_GLES - typedef void(AbstractTexture::*Storage1DImplementation)(GLenum, GLsizei, TextureFormat, const Math::Vector<1, GLsizei>&); void MAGNUM_LOCAL storageImplementationFallback(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size); void MAGNUM_LOCAL storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size); void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size); - static Storage1DImplementation storage1DImplementation; #endif - typedef void(AbstractTexture::*Storage2DImplementation)(GLenum, GLsizei, TextureFormat, const Vector2i&); void MAGNUM_LOCAL storageImplementationFallback(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size); void MAGNUM_LOCAL storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size); #endif - static Storage2DImplementation storage2DImplementation; - typedef void(AbstractTexture::*Storage3DImplementation)(GLenum, GLsizei, TextureFormat, const Vector3i&); void MAGNUM_LOCAL storageImplementationFallback(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size); void MAGNUM_LOCAL storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size); #endif - static Storage3DImplementation storage3DImplementation; #ifndef MAGNUM_TARGET_GLES - typedef void(AbstractTexture::*GetImageImplementation)(GLenum, GLint, ColorFormat, ColorType, std::size_t, GLvoid*); void MAGNUM_LOCAL getImageImplementationDefault(GLenum target, GLint level, ColorFormat format, ColorType type, std::size_t dataSize, GLvoid* data); void MAGNUM_LOCAL getImageImplementationDSA(GLenum target, GLint level, ColorFormat format, ColorType type, std::size_t dataSize, GLvoid* data); void MAGNUM_LOCAL getImageImplementationRobustness(GLenum target, GLint level, ColorFormat format, ColorType type, std::size_t dataSize, GLvoid* data); - static MAGNUM_LOCAL GetImageImplementation getImageImplementation; #endif #ifndef MAGNUM_TARGET_GLES - typedef void(AbstractTexture::*Image1DImplementation)(GLenum, GLint, TextureFormat, const Math::Vector<1, GLsizei>&, ColorFormat, ColorType, const GLvoid*); void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint level, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size, ColorFormat format, ColorType type, const GLvoid* data); void MAGNUM_LOCAL imageImplementationDSA(GLenum target, GLint level, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size, ColorFormat format, ColorType type, const GLvoid* data); - static Image1DImplementation image1DImplementation; #endif - typedef void(AbstractTexture::*Image2DImplementation)(GLenum, GLint, TextureFormat, const Vector2i&, ColorFormat, ColorType, const GLvoid*); void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint level, TextureFormat internalFormat, const Vector2i& size, ColorFormat format, ColorType type, const GLvoid* data); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL imageImplementationDSA(GLenum target, GLint level, TextureFormat internalFormat, const Vector2i& size, ColorFormat format, ColorType type, const GLvoid* data); #endif - static Image2DImplementation image2DImplementation; - typedef void(AbstractTexture::*Image3DImplementation)(GLenum, GLint, TextureFormat, const Vector3i&, ColorFormat, ColorType, const GLvoid*); void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint level, TextureFormat internalFormat, const Vector3i& size, ColorFormat format, ColorType type, const GLvoid* data); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL imageImplementationDSA(GLenum target, GLint level, TextureFormat internalFormat, const Vector3i& size, ColorFormat format, ColorType type, const GLvoid* data); #endif - static Image3DImplementation image3DImplementation; #ifndef MAGNUM_TARGET_GLES - typedef void(AbstractTexture::*SubImage1DImplementation)(GLenum, GLint, const Math::Vector<1, GLint>&, const Math::Vector<1, GLsizei>&, ColorFormat, ColorType, const GLvoid*); void MAGNUM_LOCAL subImageImplementationDefault(GLenum target, GLint level, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, ColorFormat format, ColorType type, const GLvoid* data); void MAGNUM_LOCAL subImageImplementationDSA(GLenum target, GLint level, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, ColorFormat format, ColorType type, const GLvoid* data); - static SubImage1DImplementation subImage1DImplementation; #endif - typedef void(AbstractTexture::*SubImage2DImplementation)(GLenum, GLint, const Vector2i&, const Vector2i&, ColorFormat, ColorType, const GLvoid*); void MAGNUM_LOCAL subImageImplementationDefault(GLenum target, GLint level, const Vector2i& offset, const Vector2i& size, ColorFormat format, ColorType type, const GLvoid* data); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL subImageImplementationDSA(GLenum target, GLint level, const Vector2i& offset, const Vector2i& size, ColorFormat format, ColorType type, const GLvoid* data); #endif - static SubImage2DImplementation subImage2DImplementation; - typedef void(AbstractTexture::*SubImage3DImplementation)(GLenum, GLint, const Vector3i&, const Vector3i&, ColorFormat, ColorType, const GLvoid*); void MAGNUM_LOCAL subImageImplementationDefault(GLenum target, GLint level, const Vector3i& offset, const Vector3i& size, ColorFormat format, ColorType type, const GLvoid* data); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL subImageImplementationDSA(GLenum target, GLint level, const Vector3i& offset, const Vector3i& size, ColorFormat format, ColorType type, const GLvoid* data); #endif - static SubImage3DImplementation subImage3DImplementation; - typedef void(AbstractTexture::*InvalidateImageImplementation)(GLint); void MAGNUM_LOCAL invalidateImageImplementationNoOp(GLint level); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL invalidateImageImplementationARB(GLint level); #endif - static InvalidateImageImplementation invalidateImageImplementation; - typedef void(AbstractTexture::*InvalidateSubImageImplementation)(GLint, const Vector3i&, const Vector3i&); void MAGNUM_LOCAL invalidateSubImageImplementationNoOp(GLint level, const Vector3i& offset, const Vector3i& size); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL invalidateSubImageImplementationARB(GLint level, const Vector3i& offset, const Vector3i& size); #endif - static InvalidateSubImageImplementation invalidateSubImageImplementation; ColorFormat MAGNUM_LOCAL imageFormatForInternalFormat(TextureFormat internalFormat); ColorType MAGNUM_LOCAL imageTypeForInternalFormat(TextureFormat internalFormat); @@ -504,34 +358,29 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { #ifndef DOXYGEN_GENERATING_OUTPUT #ifndef MAGNUM_TARGET_GLES template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<1> { + #ifdef MAGNUM_BUILD_DEPRECATED enum class Target: GLenum { Texture1D = GL_TEXTURE_1D }; + #endif - constexpr static Target target() { return Target::Texture1D; } - - static Math::Vector<1, GLint> imageSize(AbstractTexture* texture, GLenum target, GLint level); + static Math::Vector<1, GLint> imageSize(AbstractTexture& texture, GLenum target, GLint level); - static void setWrapping(AbstractTexture* texture, const Array1D& wrapping) { - (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_S, GLint(wrapping.x())); - } + static void setWrapping(AbstractTexture& texture, const Array1D& wrapping); - static void setStorage(AbstractTexture* texture, GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size) { - (texture->*storage1DImplementation)(target, levels, internalFormat, size); - } + static void setStorage(AbstractTexture& texture, GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size); - static void setImage(AbstractTexture* texture, GLenum target, GLint level, TextureFormat internalFormat, const ImageReference1D& image); - static void setImage(AbstractTexture* texture, GLenum target, GLint level, TextureFormat internalFormat, BufferImage1D& image); + static void setImage(AbstractTexture& texture, GLenum target, GLint level, TextureFormat internalFormat, const ImageReference1D& image); + static void setImage(AbstractTexture& texture, GLenum target, GLint level, TextureFormat internalFormat, BufferImage1D& image); - static void setSubImage(AbstractTexture* texture, GLenum target, GLint level, const Math::Vector<1, GLint>& offset, const ImageReference1D& image); - static void setSubImage(AbstractTexture* texture, GLenum target, GLint level, const Math::Vector<1, GLint>& offset, BufferImage1D& image); + static void setSubImage(AbstractTexture& texture, GLenum target, GLint level, const Math::Vector<1, GLint>& offset, const ImageReference1D& image); + static void setSubImage(AbstractTexture& texture, GLenum target, GLint level, const Math::Vector<1, GLint>& offset, BufferImage1D& image); - static void invalidateSubImage(AbstractTexture* texture, GLint level, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLint>& size) { - (texture->*invalidateSubImageImplementation)(level, {offset[0], 0, 0}, {size[0], 1, 1}); - } + static void invalidateSubImage(AbstractTexture& texture, GLint level, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLint>& size); }; #endif template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<2> { + #ifdef MAGNUM_BUILD_DEPRECATED enum class Target: GLenum { Texture2D = GL_TEXTURE_2D, #ifndef MAGNUM_TARGET_GLES @@ -540,34 +389,30 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<2> { Rectangle = GL_TEXTURE_RECTANGLE #endif }; - - constexpr static Target target() { return Target::Texture2D; } + #endif #ifndef MAGNUM_TARGET_GLES - static Vector2i imageSize(AbstractTexture* texture, GLenum target, GLint level); + static Vector2i imageSize(AbstractTexture& texture, GLenum target, GLint level); #endif - static void setWrapping(AbstractTexture* texture, const Array2D& wrapping); + static void setWrapping(AbstractTexture& texture, const Array2D& wrapping); - static void setStorage(AbstractTexture* texture, GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size) { - (texture->*storage2DImplementation)(target, levels, internalFormat, size); - } + static void setStorage(AbstractTexture& texture, GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size); - static void setImage(AbstractTexture* texture, GLenum target, GLint level, TextureFormat internalFormat, const ImageReference2D& image); + static void setImage(AbstractTexture& texture, GLenum target, GLint level, TextureFormat internalFormat, const ImageReference2D& image); #ifndef MAGNUM_TARGET_GLES2 - static void setImage(AbstractTexture* texture, GLenum target, GLint level, TextureFormat internalFormat, BufferImage2D& image); + static void setImage(AbstractTexture& texture, GLenum target, GLint level, TextureFormat internalFormat, BufferImage2D& image); #endif - static void setSubImage(AbstractTexture* texture, GLenum target, GLint level, const Vector2i& offset, const ImageReference2D& image); + static void setSubImage(AbstractTexture& texture, GLenum target, GLint level, const Vector2i& offset, const ImageReference2D& image); #ifndef MAGNUM_TARGET_GLES2 - static void setSubImage(AbstractTexture* texture, GLenum target, GLint level, const Vector2i& offset, BufferImage2D& image); + static void setSubImage(AbstractTexture& texture, GLenum target, GLint level, const Vector2i& offset, BufferImage2D& image); #endif - static void invalidateSubImage(AbstractTexture* texture, GLint level, const Vector2i& offset, const Vector2i& size) { - (texture->*invalidateSubImageImplementation)(level, {offset, 0}, {size, 1}); - } + static void invalidateSubImage(AbstractTexture& texture, GLint level, const Vector2i& offset, const Vector2i& size); }; template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> { + #ifdef MAGNUM_BUILD_DEPRECATED enum class Target: GLenum { #ifndef MAGNUM_TARGET_GLES2 Texture3D = GL_TEXTURE_3D, @@ -579,32 +424,27 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> { Texture3D = GL_TEXTURE_3D_OES #endif }; - - constexpr static Target target() { return Target::Texture3D; } + #endif #ifndef MAGNUM_TARGET_GLES - static Vector3i imageSize(AbstractTexture* texture, GLenum target, GLint level); + static Vector3i imageSize(AbstractTexture& texture, GLenum target, GLint level); #endif - static void setWrapping(AbstractTexture* texture, const Array3D& wrapping); + static void setWrapping(AbstractTexture& texture, const Array3D& wrapping); - static void setStorage(AbstractTexture* texture, GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size) { - (texture->*storage3DImplementation)(target, levels, internalFormat, size); - } + static void setStorage(AbstractTexture& texture, GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size); - static void setImage(AbstractTexture* texture, GLenum target, GLint level, TextureFormat internalFormat, const ImageReference3D& image); + static void setImage(AbstractTexture& texture, GLenum target, GLint level, TextureFormat internalFormat, const ImageReference3D& image); #ifndef MAGNUM_TARGET_GLES2 - static void setImage(AbstractTexture* texture, GLenum target, GLint level, TextureFormat internalFormat, BufferImage3D& image); + static void setImage(AbstractTexture& texture, GLenum target, GLint level, TextureFormat internalFormat, BufferImage3D& image); #endif - static void setSubImage(AbstractTexture* texture, GLenum target, GLint level, const Vector3i& offset, const ImageReference3D& image); + static void setSubImage(AbstractTexture& texture, GLenum target, GLint level, const Vector3i& offset, const ImageReference3D& image); #ifndef MAGNUM_TARGET_GLES2 - static void setSubImage(AbstractTexture* texture, GLenum target, GLint level, const Vector3i& offset, BufferImage3D& image); + static void setSubImage(AbstractTexture& texture, GLenum target, GLint level, const Vector3i& offset, BufferImage3D& image); #endif - static void invalidateSubImage(AbstractTexture* texture, GLint level, const Vector3i& offset, const Vector3i& size) { - (texture->*invalidateSubImageImplementation)(level, offset, size); - } + static void invalidateSubImage(AbstractTexture& texture, GLint level, const Vector3i& offset, const Vector3i& size); }; #endif diff --git a/src/Magnum/Audio/Source.cpp b/src/Magnum/Audio/Source.cpp index ab0fadf90..229b65dc6 100644 --- a/src/Magnum/Audio/Source.cpp +++ b/src/Magnum/Audio/Source.cpp @@ -40,15 +40,21 @@ Source& Source::setBuffer(Buffer* buffer) { namespace { -Containers::Array sourceIds(const std::initializer_list& sources) { +Containers::Array sourceIds(const std::initializer_list>& sources) { Containers::Array ids(sources.size()); - for(auto it = sources.begin(); it != sources.end(); ++it) { - CORRADE_INTERNAL_ASSERT(*it); - ids[it-sources.begin()] = (*it)->id(); - } + for(auto it = sources.begin(); it != sources.end(); ++it) + ids[it-sources.begin()] = it->get().id(); + return ids; +} + +Containers::Array sourceIds(const std::vector>& sources) { + Containers::Array ids(sources.size()); + for(auto it = sources.begin(); it != sources.end(); ++it) + ids[it-sources.begin()] = it->get().id(); return ids; } +#ifdef MAGNUM_BUILD_DEPRECATED Containers::Array sourceIds(const std::vector& sources) { Containers::Array ids(sources.size()); for(auto it = sources.begin(); it != sources.end(); ++it) { @@ -57,48 +63,77 @@ Containers::Array sourceIds(const std::vector& sources) { } return ids; } +#endif + +} +void Source::play(std::initializer_list> sources) { + const auto ids = sourceIds(sources); + alSourcePlayv(ids.size(), ids); } -void Source::play(std::initializer_list sources) { +void Source::play(const std::vector>& sources) { const auto ids = sourceIds(sources); alSourcePlayv(ids.size(), ids); } +#ifdef MAGNUM_BUILD_DEPRECATED void Source::play(const std::vector& sources) { const auto ids = sourceIds(sources); alSourcePlayv(ids.size(), ids); } +#endif -void Source::pause(std::initializer_list sources) { +void Source::pause(std::initializer_list> sources) { const auto ids = sourceIds(sources); alSourcePausev(ids.size(), ids); } +void Source::pause(const std::vector>& sources) { + const auto ids = sourceIds(sources); + alSourcePausev(ids.size(), ids); +} + +#ifdef MAGNUM_BUILD_DEPRECATED void Source::pause(const std::vector& sources) { const auto ids = sourceIds(sources); alSourcePausev(ids.size(), ids); } +#endif + +void Source::stop(std::initializer_list> sources) { + const auto ids = sourceIds(sources); + alSourceStopv(ids.size(), ids); +} -void Source::stop(std::initializer_list sources) { +void Source::stop(const std::vector>& sources) { const auto ids = sourceIds(sources); alSourceStopv(ids.size(), ids); } +#ifdef MAGNUM_BUILD_DEPRECATED void Source::stop(const std::vector& sources) { const auto ids = sourceIds(sources); alSourceStopv(ids.size(), ids); } +#endif + +void Source::rewind(std::initializer_list> sources) { + const auto ids = sourceIds(sources); + alSourceRewindv(ids.size(), ids); +} -void Source::rewind(std::initializer_list sources) { +void Source::rewind(const std::vector>& sources) { const auto ids = sourceIds(sources); alSourceRewindv(ids.size(), ids); } +#ifdef MAGNUM_BUILD_DEPRECATED void Source::rewind(const std::vector& sources) { const auto ids = sourceIds(sources); alSourceRewindv(ids.size(), ids); } +#endif Debug operator<<(Debug debug, const Source::State value) { switch(value) { diff --git a/src/Magnum/Audio/Source.h b/src/Magnum/Audio/Source.h index 8fd593976..d121fad9d 100644 --- a/src/Magnum/Audio/Source.h +++ b/src/Magnum/Audio/Source.h @@ -29,6 +29,7 @@ * @brief Class Magnum::Audio::Source */ +#include #include #include #include @@ -377,52 +378,84 @@ class MAGNUM_AUDIO_EXPORT Source { * * The operation is guaranteed to be done for all sources at the same * time. `nullptr` is not allowed. - * @see @ref play(), @ref pause(std::initializer_list), - * @ref stop(std::initializer_list), - * @ref rewind(std::initializer_list), + * @see @ref play(), @ref pause(std::initializer_list>), + * @ref stop(std::initializer_list>), + * @ref rewind(std::initializer_list>), * @fn_al{SourcePlayv} */ - static void play(std::initializer_list sources); - static void play(const std::vector& sources); /**< @overload */ + static void play(std::initializer_list> sources); + static void play(const std::vector>& sources); /**< @overload */ + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @copybrief play(const std::vector>&) + * @deprecated Use @ref Magnum::Audio::Source::play(const std::vector>&) "play(const std::vector>&)" instead. + */ + static CORRADE_DEPRECATED("use play(const std::vector>&) instead") void play(const std::vector& sources); + #endif /** * @brief Pause more sources at once * * The operation is guaranteed to be done for all sources at the same - * time. `nullptr` is not allowed. - * @see @ref pause(), @ref play(std::initializer_list), - * @ref stop(std::initializer_list), - * @ref rewind(std::initializer_list), + * time. + * @see @ref pause(), @ref play(std::initializer_list>), + * @ref stop(std::initializer_list>), + * @ref rewind(std::initializer_list>), * @fn_al{SourcePausev} */ - static void pause(std::initializer_list sources); - static void pause(const std::vector& sources); /**< @overload */ + static void pause(std::initializer_list> sources); + static void pause(const std::vector>& sources); /**< @overload */ + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @copybrief pause(const std::vector>&) + * @deprecated Use @ref Magnum::Audio::Source::pause(const std::vector>&) "pause(const std::vector>&)" instead. + */ + static CORRADE_DEPRECATED("use pause(const std::vector>&) instead") void pause(const std::vector& sources); + #endif /** * @brief Stop more sources at once * * The operation is guaranteed to be done for all sources at the same - * time. `nullptr` is not allowed. - * @see @ref stop(), @ref play(std::initializer_list), - * @ref pause(std::initializer_list), - * @ref rewind(std::initializer_list), + * time. + * @see @ref stop(), @ref play(std::initializer_list>), + * @ref pause(std::initializer_list>), + * @ref rewind(std::initializer_list>), * @fn_al{SourceStopv} */ - static void stop(std::initializer_list sources); - static void stop(const std::vector& sources); /**< @overload */ + static void stop(std::initializer_list> sources); + static void stop(const std::vector>& sources); /**< @overload */ + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @copybrief stop(const std::vector>&) + * @deprecated Use @ref Magnum::Audio::Source::stop(const std::vector>&) "stop(const std::vector>&)" instead. + */ + static CORRADE_DEPRECATED("use stop(const std::vector>&) instead") void stop(const std::vector& sources); + #endif /** * @brief Rewind more sources at once * * The operation is guaranteed to be done for all sources at the same - * time. `nullptr` is not allowed. - * @see @ref rewind(), @ref play(std::initializer_list), - * @ref pause(std::initializer_list), - * @ref stop(std::initializer_list), + * time. + * @see @ref rewind(), @ref play(std::initializer_list>), + * @ref pause(std::initializer_list>), + * @ref stop(std::initializer_list>), * @fn_al{SourceRewindv} */ - static void rewind(std::initializer_list sources); - static void rewind(const std::vector& sources); /**< @overload */ + static void rewind(std::initializer_list> sources); + static void rewind(const std::vector>& sources); /**< @overload */ + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @copybrief rewind(const std::vector>&) + * @deprecated Use @ref Magnum::Audio::Source::rewind(const std::vector>&) "rewind(const std::vector>&)" instead. + */ + static CORRADE_DEPRECATED("use rewind(const std::vector>&) instead") void rewind(const std::vector& sources); + #endif /** * @brief State @@ -435,32 +468,36 @@ class MAGNUM_AUDIO_EXPORT Source { /** * @brief Play * - * @see @ref play(std::initializer_list), @ref state(), - * @ref pause(), @ref stop(), @ref rewind(), @fn_al{SourcePlay} + * @see @ref play(std::initializer_list>), + * @ref state(), @ref pause(), @ref stop(), @ref rewind(), + * @fn_al{SourcePlay} */ void play() { alSourcePlay(_id); } /** * @brief Pause * - * @see @ref pause(std::initializer_list), @ref state(), - * @ref play(), @ref stop(), @ref rewind(), @fn_al{SourcePause} + * @see @ref pause(std::initializer_list>), + * @ref state(), @ref play(), @ref stop(), @ref rewind(), + * @fn_al{SourcePause} */ void pause() { alSourcePause(_id); } /** * @brief Stop * - * @see @ref stop(std::initializer_list), @ref state(), - * @ref play(), @ref pause(), @ref rewind(), @fn_al{SourceStop} + * @see @ref stop(std::initializer_list>), + * @ref state(), @ref play(), @ref pause(), @ref rewind(), + * @fn_al{SourceStop} */ void stop() { alSourceStop(_id); } /** * @brief Rewind * - * @see @ref rewind(std::initializer_list), @ref state(), - * @ref play(), @ref pause(), @ref stop(), @fn_al{SourceRewind} + * @see @ref rewind(std::initializer_list>), + * @ref state(), @ref play(), @ref pause(), @ref stop(), + * @fn_al{SourceRewind} */ void rewind() { alSourceRewind(_id); } diff --git a/src/Magnum/Buffer.cpp b/src/Magnum/Buffer.cpp index ff66c4209..d37f253ae 100644 --- a/src/Magnum/Buffer.cpp +++ b/src/Magnum/Buffer.cpp @@ -36,49 +36,6 @@ namespace Magnum { -#ifndef MAGNUM_TARGET_GLES2 -Buffer::CopyImplementation Buffer::copyImplementation = &Buffer::copyImplementationDefault; -#endif -Buffer::GetParameterImplementation Buffer::getParameterImplementation = &Buffer::getParameterImplementationDefault; -#ifndef MAGNUM_TARGET_GLES -Buffer::GetSubDataImplementation Buffer::getSubDataImplementation = &Buffer::getSubDataImplementationDefault; -#endif -Buffer::DataImplementation Buffer::dataImplementation = &Buffer::dataImplementationDefault; -Buffer::SubDataImplementation Buffer::subDataImplementation = &Buffer::subDataImplementationDefault; -Buffer::InvalidateImplementation Buffer::invalidateImplementation = &Buffer::invalidateImplementationNoOp; -Buffer::InvalidateSubImplementation Buffer::invalidateSubImplementation = &Buffer::invalidateSubImplementationNoOp; -Buffer::MapImplementation Buffer::mapImplementation = &Buffer::mapImplementationDefault; -Buffer::MapRangeImplementation Buffer::mapRangeImplementation = &Buffer::mapRangeImplementationDefault; -Buffer::FlushMappedRangeImplementation Buffer::flushMappedRangeImplementation = &Buffer::flushMappedRangeImplementationDefault; -Buffer::UnmapImplementation Buffer::unmapImplementation = &Buffer::unmapImplementationDefault; - -void Buffer::initializeContextBasedFunctionality(Context& context) { - #ifndef MAGNUM_TARGET_GLES - if(context.isExtensionSupported()) { - Debug() << "Buffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; - - copyImplementation = &Buffer::copyImplementationDSA; - getParameterImplementation = &Buffer::getParameterImplementationDSA; - getSubDataImplementation = &Buffer::getSubDataImplementationDSA; - dataImplementation = &Buffer::dataImplementationDSA; - subDataImplementation = &Buffer::subDataImplementationDSA; - mapImplementation = &Buffer::mapImplementationDSA; - mapRangeImplementation = &Buffer::mapRangeImplementationDSA; - flushMappedRangeImplementation = &Buffer::flushMappedRangeImplementationDSA; - unmapImplementation = &Buffer::unmapImplementationDSA; - } - - if(context.isExtensionSupported()) { - Debug() << "Buffer: using" << Extensions::GL::ARB::invalidate_subdata::string() << "features"; - - invalidateImplementation = &Buffer::invalidateImplementationARB; - invalidateSubImplementation = &Buffer::invalidateSubImplementationARB; - } - #else - static_cast(context); - #endif -} - #ifndef MAGNUM_TARGET_GLES Int Buffer::minMapAlignment() { if(!Context::current()->isExtensionSupported()) @@ -145,6 +102,12 @@ Int Buffer::maxUniformBindings() { } #endif +#ifndef MAGNUM_TARGET_GLES2 +void Buffer::copy(Buffer& read, Buffer& write, const GLintptr readOffset, const GLintptr writeOffset, const GLsizeiptr size) { + Context::current()->state().buffer->copyImplementation(read, write, readOffset, writeOffset, size); +} +#endif + Buffer::Buffer(Buffer::Target targetHint): _targetHint(targetHint) #ifdef CORRADE_TARGET_NACL , _mappedBuffer(nullptr) @@ -218,10 +181,34 @@ Int Buffer::size() { * couldn't find any matching extension, though) */ GLint size; - (this->*getParameterImplementation)(GL_BUFFER_SIZE, &size); + (this->*Context::current()->state().buffer->getParameterImplementation)(GL_BUFFER_SIZE, &size); return size; } +Buffer& Buffer::setData(const Containers::ArrayReference data, const BufferUsage usage) { + (this->*Context::current()->state().buffer->dataImplementation)(data.size(), data, usage); + return *this; +} + +Buffer& Buffer::setSubData(const GLintptr offset, const Containers::ArrayReference data) { + (this->*Context::current()->state().buffer->subDataImplementation)(offset, data.size(), data); + return *this; +} + +Buffer& Buffer::invalidateData() { + (this->*Context::current()->state().buffer->invalidateImplementation)(); + return *this; +} + +Buffer& Buffer::invalidateSubData(const GLintptr offset, const GLsizeiptr length) { + (this->*Context::current()->state().buffer->invalidateSubImplementation)(offset, length); + return *this; +} + +void* Buffer::map(const MapAccess access) { + return (this->*Context::current()->state().buffer->mapImplementation)(access); +} + #ifdef MAGNUM_TARGET_GLES2 void* Buffer::mapSub(const GLintptr offset, const GLsizeiptr length, const MapAccess access) { /** @todo Enable also in Emscripten (?) when extension loader is available */ @@ -235,7 +222,20 @@ void* Buffer::mapSub(const GLintptr offset, const GLsizeiptr length, const MapAc static_cast(access); #endif } +#endif +void* Buffer::map(const GLintptr offset, const GLsizeiptr length, const MapFlags flags) { + return (this->*Context::current()->state().buffer->mapRangeImplementation)(offset, length, flags); +} + +Buffer& Buffer::flushMappedRange(const GLintptr offset, const GLsizeiptr length) { + (this->*Context::current()->state().buffer->flushMappedRangeImplementation)(offset, length); + return *this; +} + +bool Buffer::unmap() { return (this->*Context::current()->state().buffer->unmapImplementation)(); } + +#ifdef MAGNUM_TARGET_GLES2 void Buffer::unmapSub() { /** @todo Enable also in Emscripten (?) when extension loader is available */ #ifdef CORRADE_TARGET_NACL @@ -248,6 +248,12 @@ void Buffer::unmapSub() { } #endif +#ifndef MAGNUM_TARGET_GLES +void Buffer::subDataInternal(GLintptr offset, GLsizeiptr size, GLvoid* data) { + (this->*Context::current()->state().buffer->getSubDataImplementation)(offset, size, data); +} +#endif + #ifndef MAGNUM_TARGET_GLES2 void Buffer::copyImplementationDefault(Buffer& read, Buffer& write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { glCopyBufferSubData(GLenum(read.bindInternal(Target::CopyRead)), GLenum(write.bindInternal(Target::CopyWrite)), readOffset, writeOffset, size); diff --git a/src/Magnum/Buffer.h b/src/Magnum/Buffer.h index 06ffbaf40..167795702 100644 --- a/src/Magnum/Buffer.h +++ b/src/Magnum/Buffer.h @@ -114,6 +114,8 @@ enum class BufferUsage: GLenum { #endif }; +namespace Implementation { struct BufferState; } + /** @brief %Buffer @@ -172,8 +174,8 @@ The engine tracks currently bound buffers to avoid unnecessary calls to and @ref unmap() use that target instead of binding the buffer to some specific target. You can also use @ref setTargetHint() to possibly reduce unnecessary rebinding. %Buffer limits and implementation-defined values (such as -@ref maxVertexAttributeBindings()) are cached, so repeated queries don't result -in repeated @fn_gl{Get} calls. +@ref maxUniformBindings()) are cached, so repeated queries don't result in +repeated @fn_gl{Get} calls. If extension @extension{EXT,direct_state_access} is available, functions @ref copy(), @ref setData(), @ref setSubData(), @ref map(), @ref flushMappedRange() @@ -183,14 +185,11 @@ and @ref unmap() use DSA functions to avoid unnecessary calls to You can use functions @ref invalidateData() and @ref invalidateSubData() if you don't need buffer data anymore to avoid unnecessary memory operations performed by OpenGL in order to preserve the data. If running on OpenGL ES or extension -@extension{ARB,invalidate_subdata} is not available, these functions do -nothing. - -@todo Support for AMD/ARB's query buffer (@extension{AMD,query_buffer_object}, @extension{ARB,query_buffer_object}) -@todo BindBufferRange/BindBufferOffset/BindBufferBase for transform feedback (3.0, @extension{EXT,transform_feedback}) +@extension{ARB,invalidate_subdata} (part of OpenGL 4.3) is not available, these +functions do nothing. */ class MAGNUM_EXPORT Buffer: public AbstractObject { - friend class Context; + friend struct Implementation::BufferState; public: /** @@ -348,7 +347,8 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * * @see @ref MapFlags, @ref map(GLintptr, GLsizeiptr, MapFlags) * @requires_gl30 %Extension @extension{ARB,map_buffer_range} - * @requires_gles30 %Extension @es_extension{EXT,map_buffer_range} + * @requires_gles30 %Extension @es_extension{EXT,map_buffer_range} in + * OpenGL ES 2.0 */ enum class MapFlag: GLbitfield { /** Map buffer for reading. */ @@ -414,7 +414,8 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * * @see @ref map(GLintptr, GLsizeiptr, MapFlags) * @requires_gl30 %Extension @extension{ARB,map_buffer_range} - * @requires_gles30 %Extension @es_extension{EXT,map_buffer_range} + * @requires_gles30 %Extension @es_extension{EXT,map_buffer_range} in + * OpenGL ES 2.0 */ typedef Containers::EnumSet MapFlags; @@ -477,15 +478,6 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { static Int maxUniformBindings(); #endif - /** - * @brief Max supported vertex buffer binding count - * - * The result is cached, repeated queries don't result in repeated - * OpenGL calls. - * @see @fn_gl{Get} with @def_gl{MAX_VERTEX_ATTRIB_BINDINGS} - */ - static Int maxVertexAttributeBindings(); - /** * @brief Unbind any buffer from given target * @param target %Target @@ -512,9 +504,7 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * @requires_gl31 %Extension @extension{ARB,copy_buffer} * @requires_gles30 %Buffer copying is not available in OpenGL ES 2.0. */ - static void copy(Buffer& read, Buffer& write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { - copyImplementation(read, write, readOffset, writeOffset, size); - } + static void copy(Buffer& read, Buffer& write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); #endif /** @@ -554,9 +544,9 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * @brief %Buffer label * * The result is *not* cached, repeated queries will result in repeated - * OpenGL calls. If neither @extension{KHR,debug} nor - * @extension2{EXT,debug_label} desktop or ES extension is available, - * this function returns empty string. + * OpenGL calls. If OpenGL 4.3 is not supported and neither + * @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES + * extension is available, this function returns empty string. * @see @fn_gl{GetObjectLabel} with @def_gl{BUFFER} or * @fn_gl_extension2{GetObjectLabel,EXT,debug_label} with * @def_gl{BUFFER_OBJECT_EXT} @@ -567,9 +557,9 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * @brief Set buffer label * @return Reference to self (for method chaining) * - * Default is empty string. If neither @extension{KHR,debug} nor - * @extension2{EXT,debug_label} desktop or ES extension is available, - * this function does nothing. + * Default is empty string. If OpenGL 4.3 is not supported and neither + * @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES + * extension is available, this function does nothing. * @see @ref maxLabelLength(), @fn_gl{ObjectLabel} with @def_gl{BUFFER} * or @fn_gl_extension2{LabelObject,EXT,debug_label} with * @def_gl{BUFFER_OBJECT_EXT} @@ -669,14 +659,11 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * @see @ref setTargetHint(), @fn_gl{BindBuffer} and @fn_gl{BufferData} * or @fn_gl_extension{NamedBufferData,EXT,direct_state_access} */ - Buffer& setData(Containers::ArrayReference data, BufferUsage usage) { - (this->*dataImplementation)(data.size(), data, usage); - return *this; - } + Buffer& setData(Containers::ArrayReference data, BufferUsage usage); #ifdef MAGNUM_BUILD_DEPRECATED /** - * @brief Set buffer data + * @copybrief setData(Containers::ArrayReference, BufferUsage) * @deprecated Use @ref Magnum::Buffer::setData(Containers::ArrayReference, BufferUsage) "setData(Containers::ArrayReference, BufferUsage)" * instead. */ @@ -709,14 +696,11 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * @see @ref setTargetHint(), @fn_gl{BindBuffer} and @fn_gl{BufferSubData} * or @fn_gl_extension{NamedBufferSubData,EXT,direct_state_access} */ - Buffer& setSubData(GLintptr offset, Containers::ArrayReference data) { - (this->*subDataImplementation)(offset, data.size(), data); - return *this; - } + Buffer& setSubData(GLintptr offset, Containers::ArrayReference data); #ifdef MAGNUM_BUILD_DEPRECATED /** - * @brief Set buffer subdata + * @copybrief setSubData(GLintptr, Containers::ArrayReference) * @deprecated Use @ref Magnum::Buffer::setSubData(GLintptr, Containers::ArrayReference) "setSubData(GLintptr, Containers::ArrayReference)" * instead. */ @@ -737,7 +721,6 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { return *this; } - #ifndef MAGNUM_TARGET_GLES /** * @brief Invalidate buffer data * @return Reference to self (for method chaining) @@ -746,10 +729,7 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * (part of OpenGL 4.3) is not available, this function does nothing. * @see @ref MapFlag::InvalidateBuffer, @fn_gl{InvalidateBufferData} */ - Buffer& invalidateData() { - (this->*invalidateImplementation)(); - return *this; - } + Buffer& invalidateData(); /** * @brief Invalidate buffer subdata @@ -761,11 +741,7 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * (part of OpenGL 4.3) is not available, this function does nothing. * @see @ref MapFlag::InvalidateRange, @fn_gl{InvalidateBufferData} */ - Buffer& invalidateSubData(GLintptr offset, GLsizeiptr length) { - (this->*invalidateSubImplementation)(offset, length); - return *this; - } - #endif + Buffer& invalidateSubData(GLintptr offset, GLsizeiptr length); /** * @brief Map buffer to client memory @@ -784,9 +760,7 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * OpenGL ES 2.0, use @ref Magnum::Buffer::map(GLintptr, GLsizeiptr, MapFlags) "map(GLintptr, GLsizeiptr, MapFlags)" * in OpenGL ES 3.0 instead. */ - void* map(MapAccess access) { - return (this->*mapImplementation)(access); - } + void* map(MapAccess access); #if defined(MAGNUM_TARGET_GLES2) || defined(DOXYGEN_GENERATING_OUTPUT) /** @@ -825,11 +799,10 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * @ref map(MapAccess), @ref setTargetHint(), @fn_gl{BindBuffer} * and @fn_gl{MapBufferRange} or @fn_gl_extension{MapNamedBufferRange,EXT,direct_state_access} * @requires_gl30 %Extension @extension{ARB,map_buffer_range} - * @requires_gles30 %Extension @es_extension{EXT,map_buffer_range} + * @requires_gles30 %Extension @es_extension{EXT,map_buffer_range} in + * OpenGL ES 2.0 */ - void* map(GLintptr offset, GLsizeiptr length, MapFlags flags) { - return (this->*mapRangeImplementation)(offset, length, flags); - } + void* map(GLintptr offset, GLsizeiptr length, MapFlags flags); /** * @brief Flush mapped range @@ -847,12 +820,10 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * @see @ref setTargetHint(), @fn_gl{BindBuffer} and @fn_gl{FlushMappedBufferRange} * or @fn_gl_extension{FlushMappedNamedBufferRange,EXT,direct_state_access} * @requires_gl30 %Extension @extension{ARB,map_buffer_range} - * @requires_gles30 %Extension @es_extension{EXT,map_buffer_range} + * @requires_gles30 %Extension @es_extension{EXT,map_buffer_range} in + * OpenGL ES 2.0 */ - Buffer& flushMappedRange(GLintptr offset, GLsizeiptr length) { - (this->*flushMappedRangeImplementation)(offset, length); - return *this; - } + Buffer& flushMappedRange(GLintptr offset, GLsizeiptr length); /** * @brief Unmap buffer @@ -866,11 +837,10 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { * is bound to hinted target before the operation. * @see setTargetHint(), @fn_gl{BindBuffer} and @fn_gl{UnmapBuffer} or * @fn_gl_extension{UnmapNamedBuffer,EXT,direct_state_access} - * @requires_gles30 %Extension @es_extension{OES,mapbuffer} + * @requires_gles30 %Extension @es_extension{OES,mapbuffer} in OpenGL + * ES 2.0 */ - bool unmap() { - return (this->*unmapImplementation)(); - } + bool unmap(); #if defined(MAGNUM_TARGET_GLES2) || defined(DOXYGEN_GENERATING_OUTPUT) /** @@ -888,89 +858,69 @@ class MAGNUM_EXPORT Buffer: public AbstractObject { #endif private: - static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context); - static void bind(Target hint, GLuint id); Target MAGNUM_LOCAL bindInternal(Target hint); #ifndef MAGNUM_TARGET_GLES2 - typedef void(*CopyImplementation)(Buffer&, Buffer&, GLintptr, GLintptr, GLsizeiptr); static void MAGNUM_LOCAL copyImplementationDefault(Buffer& read, Buffer& write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); #ifndef MAGNUM_TARGET_GLES static void MAGNUM_LOCAL copyImplementationDSA(Buffer& read, Buffer& write, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); #endif - static CopyImplementation copyImplementation; #endif - typedef void(Buffer::*GetParameterImplementation)(GLenum, GLint*); + #ifndef MAGNUM_TARGET_GLES + void subDataInternal(GLintptr offset, GLsizeiptr size, GLvoid* data); + #endif + void MAGNUM_LOCAL getParameterImplementationDefault(GLenum value, GLint* data); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL getParameterImplementationDSA(GLenum value, GLint* data); #endif - static MAGNUM_LOCAL GetParameterImplementation getParameterImplementation; #ifndef MAGNUM_TARGET_GLES - typedef void(Buffer::*GetSubDataImplementation)(GLintptr, GLsizeiptr, GLvoid*); void MAGNUM_LOCAL getSubDataImplementationDefault(GLintptr offset, GLsizeiptr size, GLvoid* data); void MAGNUM_LOCAL getSubDataImplementationDSA(GLintptr offset, GLsizeiptr size, GLvoid* data); - static GetSubDataImplementation getSubDataImplementation; #endif - typedef void(Buffer::*DataImplementation)(GLsizeiptr, const GLvoid*, BufferUsage); void MAGNUM_LOCAL dataImplementationDefault(GLsizeiptr size, const GLvoid* data, BufferUsage usage); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL dataImplementationDSA(GLsizeiptr size, const GLvoid* data, BufferUsage usage); #endif - static DataImplementation dataImplementation; - typedef void(Buffer::*SubDataImplementation)(GLintptr, GLsizeiptr, const GLvoid*); void MAGNUM_LOCAL subDataImplementationDefault(GLintptr offset, GLsizeiptr size, const GLvoid* data); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL subDataImplementationDSA(GLintptr offset, GLsizeiptr size, const GLvoid* data); #endif - static SubDataImplementation subDataImplementation; - typedef void(Buffer::*InvalidateImplementation)(); void MAGNUM_LOCAL invalidateImplementationNoOp(); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL invalidateImplementationARB(); #endif - static InvalidateImplementation invalidateImplementation; - typedef void(Buffer::*InvalidateSubImplementation)(GLintptr, GLsizeiptr); void MAGNUM_LOCAL invalidateSubImplementationNoOp(GLintptr offset, GLsizeiptr length); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL invalidateSubImplementationARB(GLintptr offset, GLsizeiptr length); #endif - static InvalidateSubImplementation invalidateSubImplementation; - typedef void*(Buffer::*MapImplementation)(MapAccess); void MAGNUM_LOCAL * mapImplementationDefault(MapAccess access); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL * mapImplementationDSA(MapAccess access); #endif - static MapImplementation mapImplementation; - typedef void*(Buffer::*MapRangeImplementation)(GLintptr, GLsizeiptr, MapFlags); void MAGNUM_LOCAL * mapRangeImplementationDefault(GLintptr offset, GLsizeiptr length, MapFlags access); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL * mapRangeImplementationDSA(GLintptr offset, GLsizeiptr length, MapFlags access); #endif - static MapRangeImplementation mapRangeImplementation; - typedef void(Buffer::*FlushMappedRangeImplementation)(GLintptr, GLsizeiptr); void MAGNUM_LOCAL flushMappedRangeImplementationDefault(GLintptr offset, GLsizeiptr length); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL flushMappedRangeImplementationDSA(GLintptr offset, GLsizeiptr length); #endif - static FlushMappedRangeImplementation flushMappedRangeImplementation; - typedef bool(Buffer::*UnmapImplementation)(); bool MAGNUM_LOCAL unmapImplementationDefault(); #ifndef MAGNUM_TARGET_GLES bool MAGNUM_LOCAL unmapImplementationDSA(); #endif - static UnmapImplementation unmapImplementation; GLuint _id; Target _targetHint; @@ -1007,7 +957,7 @@ template Containers::Array inline Buffer::data() { template Containers::Array inline Buffer::subData(const GLintptr offset, const GLsizeiptr size) { Containers::Array data(size); - if(size) (this->*getSubDataImplementation)(offset, size*sizeof(T), data); + if(size) subDataInternal(offset, size*sizeof(T), data); return std::move(data); } #endif diff --git a/src/Magnum/BufferImage.cpp b/src/Magnum/BufferImage.cpp index a02f4533f..08c6fb1ae 100644 --- a/src/Magnum/BufferImage.cpp +++ b/src/Magnum/BufferImage.cpp @@ -29,7 +29,7 @@ namespace Magnum { #ifndef MAGNUM_TARGET_GLES2 template BufferImage::BufferImage(ColorFormat format, ColorType type, const typename DimensionTraits< Dimensions, Int >::VectorType& size, const void* data, BufferUsage usage): AbstractImage(format, type), _size(size), _buffer(Buffer::Target::PixelPack) { - _buffer.setData({data, pixelSize()*size.product()}, usage); + _buffer.setData({data, dataSize(size)}, usage); } template BufferImage::BufferImage(ColorFormat format, ColorType type): AbstractImage(format, type), _buffer(Buffer::Target::PixelPack) {} @@ -38,7 +38,7 @@ template void BufferImage::setData(ColorForm _format = format; _type = type; _size = size; - _buffer.setData({data, pixelSize()*size.product()}, usage); + _buffer.setData({data, dataSize(size)}, usage); } #ifndef DOXYGEN_GENERATING_OUTPUT diff --git a/src/Magnum/BufferTexture.cpp b/src/Magnum/BufferTexture.cpp index cf9df1ff8..1c91f129e 100644 --- a/src/Magnum/BufferTexture.cpp +++ b/src/Magnum/BufferTexture.cpp @@ -35,9 +35,6 @@ namespace Magnum { -BufferTexture::SetBufferImplementation BufferTexture::setBufferImplementation = &BufferTexture::setBufferImplementationDefault; -BufferTexture::SetBufferRangeImplementation BufferTexture::setBufferRangeImplementation = &BufferTexture::setBufferRangeImplementationDefault; - Int BufferTexture::offsetAlignment() { if(!Context::current()->isExtensionSupported()) return 0; @@ -51,13 +48,14 @@ Int BufferTexture::offsetAlignment() { return value; } -void BufferTexture::initializeContextBasedFunctionality(Context& context) { - if(context.isExtensionSupported()) { - Debug() << "BufferTexture: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; +BufferTexture& BufferTexture::setBuffer(const BufferTextureFormat internalFormat, Buffer& buffer) { + (this->*Context::current()->state().texture->setBufferImplementation)(internalFormat, buffer); + return *this; +} - setBufferImplementation = &BufferTexture::setBufferImplementationDSA; - setBufferRangeImplementation = &BufferTexture::setBufferRangeImplementationDSA; - } +BufferTexture& BufferTexture::setBuffer(const BufferTextureFormat internalFormat, Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { + (this->*Context::current()->state().texture->setBufferRangeImplementation)(internalFormat, buffer, offset, size); + return *this; } void BufferTexture::setBufferImplementationDefault(BufferTextureFormat internalFormat, Buffer& buffer) { diff --git a/src/Magnum/BufferTexture.h b/src/Magnum/BufferTexture.h index 4e923d0d4..fb1a37801 100644 --- a/src/Magnum/BufferTexture.h +++ b/src/Magnum/BufferTexture.h @@ -181,11 +181,10 @@ constexpr static Vector3 data[] = { buffer.setData(data, BufferUsage::StaticDraw); @endcode -The texture is bound to layer specified by shader via @ref bind(). In shader, -the texture is used via `samplerBuffer`, `isamplerBuffer` or `usamplerBuffer`. -Unlike in classic textures, coordinates for buffer textures are integer -coordinates passed to `texelFetch()`. See also @ref AbstractShaderProgram -documentation for more information. +In shader, the texture is used via `samplerBuffer`, `isamplerBuffer` or +`usamplerBuffer`. Unlike in classic textures, coordinates for buffer textures +are integer coordinates passed to `texelFetch()`. See @ref AbstractShaderProgram +documentation for more information about usage in shaders. @section BufferTexture-performance-optimization Performance optimizations @@ -195,17 +194,15 @@ functions use DSA to avoid unnecessary calls to @fn_gl{ActiveTexture} and @ref AbstractTexture-performance-optimization "relevant section in AbstractTexture documentation" and respective function documentation for more information. -@see @ref Texture, @ref CubeMapTexture, @ref CubeMapTextureArray +@see @ref Texture, @ref TextureArray, @ref CubeMapTexture, + @ref CubeMapTextureArray, @ref MultisampleTexture, @ref RectangleTexture @requires_gl31 %Extension @extension{ARB,texture_buffer_object} @requires_gl Texture buffers are not available in OpenGL ES. */ -class MAGNUM_EXPORT BufferTexture: private AbstractTexture { - friend class Context; +class MAGNUM_EXPORT BufferTexture: public AbstractTexture { + friend struct Implementation::TextureState; public: - /** @copydoc AbstractTexture::maxLabelLength() */ - static Int maxLabelLength() { return AbstractTexture::maxLabelLength(); } - /** * @brief Minimum required alignment for texture buffer offsets * @@ -216,6 +213,12 @@ class MAGNUM_EXPORT BufferTexture: private AbstractTexture { */ static Int offsetAlignment(); + /** + * @brief Constructor + * + * Creates new OpenGL texture object. + * @see @fn_gl{GenTextures} with @def_gl{TEXTURE_BUFFER} + */ explicit BufferTexture(): AbstractTexture(GL_TEXTURE_BUFFER) {} #ifdef CORRADE_GCC45_COMPATIBILITY @@ -228,25 +231,11 @@ class MAGNUM_EXPORT BufferTexture: private AbstractTexture { } #endif - /** @copydoc AbstractTexture::id() */ - Int id() const { return AbstractTexture::id(); } - - /** @copydoc AbstractTexture::label() */ - std::string label() const { return AbstractTexture::label(); } - - /** @copydoc AbstractTexture::setLabel() */ - BufferTexture& setLabel(const std::string& label) { - AbstractTexture::setLabel(label); - return *this; - } - - /** @copydoc AbstractTexture::bind() */ - void bind(Int layer) { AbstractTexture::bind(layer); } - /** * @brief Set texture buffer * @param internalFormat Internal format * @param buffer %Buffer with data + * @return Reference to self (for method chaining) * * 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 @@ -254,9 +243,7 @@ class MAGNUM_EXPORT BufferTexture: private AbstractTexture { * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexBuffer} * or @fn_gl_extension{TextureBuffer,EXT,direct_state_access} */ - void setBuffer(BufferTextureFormat internalFormat, Buffer& buffer) { - (this->*setBufferImplementation)(internalFormat, buffer); - } + BufferTexture& setBuffer(BufferTextureFormat internalFormat, Buffer& buffer); /** * @brief Set texture buffer @@ -264,6 +251,7 @@ class MAGNUM_EXPORT BufferTexture: private AbstractTexture { * @param buffer %Buffer * @param offset Offset * @param size Data size + * @return Reference to self (for method chaining) * * 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 @@ -272,22 +260,22 @@ class MAGNUM_EXPORT BufferTexture: private AbstractTexture { * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexBufferRange} * or @fn_gl_extension{TextureBufferRange,EXT,direct_state_access} */ - void setBuffer(BufferTextureFormat internalFormat, Buffer& buffer, GLintptr offset, GLsizeiptr size) { - (this->*setBufferRangeImplementation)(internalFormat, buffer, offset, size); + BufferTexture& setBuffer(BufferTextureFormat internalFormat, Buffer& buffer, GLintptr offset, GLsizeiptr size); + + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + BufferTexture& setLabel(const std::string& label) { + AbstractTexture::setLabel(label); + return *this; } + #endif private: - static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context); - - typedef void(BufferTexture::*SetBufferImplementation)(BufferTextureFormat, Buffer&); void MAGNUM_LOCAL setBufferImplementationDefault(BufferTextureFormat internalFormat, Buffer& buffer); void MAGNUM_LOCAL setBufferImplementationDSA(BufferTextureFormat internalFormat, Buffer& buffer); - static SetBufferImplementation setBufferImplementation; - typedef void(BufferTexture::*SetBufferRangeImplementation)(BufferTextureFormat, Buffer&, GLintptr, GLsizeiptr); void MAGNUM_LOCAL setBufferRangeImplementationDefault(BufferTextureFormat internalFormat, Buffer& buffer, GLintptr offset, GLsizeiptr size); void MAGNUM_LOCAL setBufferRangeImplementationDSA(BufferTextureFormat internalFormat, Buffer& buffer, GLintptr offset, GLsizeiptr size); - static SetBufferRangeImplementation setBufferRangeImplementation; }; } diff --git a/src/Magnum/CMakeLists.txt b/src/Magnum/CMakeLists.txt index b688a1f46..359fa3301 100644 --- a/src/Magnum/CMakeLists.txt +++ b/src/Magnum/CMakeLists.txt @@ -54,6 +54,10 @@ set(Magnum_SRCS Implementation/BufferState.cpp Implementation/DebugState.cpp + Implementation/FramebufferState.cpp + Implementation/MeshState.cpp + Implementation/RendererState.cpp + Implementation/ShaderProgramState.cpp Implementation/State.cpp Implementation/TextureState.cpp @@ -134,14 +138,17 @@ endif() if(NOT TARGET_GLES) set(Magnum_HEADERS ${Magnum_HEADERS} BufferTexture.h - CubeMapTextureArray.h) + CubeMapTextureArray.h + MultisampleTexture.h + RectangleTexture.h) set(Magnum_SRCS ${Magnum_SRCS} $) endif() # Not-ES2 headers if(NOT TARGET_GLES2) set(Magnum_HEADERS ${Magnum_HEADERS} - BufferImage.h) + BufferImage.h + TextureArray.h) endif() # Files shared between main library and math unit test library diff --git a/src/Magnum/ColorFormat.h b/src/Magnum/ColorFormat.h index cf3272c08..67c6a1e9e 100644 --- a/src/Magnum/ColorFormat.h +++ b/src/Magnum/ColorFormat.h @@ -55,8 +55,9 @@ See documentation of these values for possible limitations when using OpenGL ES enum class ColorFormat: GLenum { /** * Floating-point red channel. - * @requires_gles30 For texture data only, extension @es_extension{EXT,texture_rg}. - * @requires_es_extension For framebuffer reading, extension @es_extension{EXT,texture_rg}. + * @requires_gles30 For texture data only, extension @es_extension{EXT,texture_rg} + * in OpenGL ES 2.0 + * @requires_es_extension For framebuffer reading, extension @es_extension{EXT,texture_rg} */ #ifndef MAGNUM_TARGET_GLES2 Red = GL_RED, @@ -95,7 +96,8 @@ enum class ColorFormat: GLenum { /** * Floating-point red and green channel. * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{EXT,texture_integer} - * @requires_gles30 For texture data only, extension @es_extension{EXT,texture_rg}. + * @requires_gles30 For texture data only, extension @es_extension{EXT,texture_rg} + * in OpenGL ES 2.0 * @requires_es_extension For framebuffer reading, extension @es_extension{EXT,texture_rg}. */ #ifndef MAGNUM_TARGET_GLES2 @@ -223,7 +225,8 @@ enum class ColorFormat: GLenum { /** * Depth component. - * @requires_gles30 For texture data only, extension @es_extension{ANGLE,depth_texture}. + * @requires_gles30 For texture data only, extension @es_extension{OES,depth_texture} + * or @es_extension{ANGLE,depth_texture} in OpenGL ES 2.0 * @requires_es_extension For framebuffer reading only, extension * @es_extension2{NV,read_depth,GL_NV_read_depth_stencil}. */ @@ -246,9 +249,10 @@ enum class ColorFormat: GLenum { /** * Depth and stencil. * @requires_gl30 %Extension @extension{ARB,framebuffer_object} - * @requires_gles30 For texture data only, extension @es_extension{OES,packed_depth_stencil}. + * @requires_gles30 For texture data only, extension @es_extension{OES,packed_depth_stencil} + * in OpenGL ES 2.0 * @requires_es_extension For framebuffer reading only, extension - * @es_extension2{NV,read_depth_stencil,GL_NV_read_depth_stencil}. + * @es_extension2{NV,read_depth_stencil,GL_NV_read_depth_stencil} */ #ifndef MAGNUM_TARGET_GLES2 DepthStencil = GL_DEPTH_STENCIL @@ -293,7 +297,7 @@ enum class ColorType: GLenum { * Each component unsigned short. * @requires_gl Can't be used for framebuffer reading in OpenGL ES. * @requires_gles30 For texture data only, extension @es_extension{OES,depth_texture} - * or @es_extension{ANGLE,depth_texture}. + * or @es_extension{ANGLE,depth_texture} in OpenGL ES 2.0 */ UnsignedShort = GL_UNSIGNED_SHORT, @@ -312,7 +316,7 @@ enum class ColorType: GLenum { * Each component unsigned int. * @requires_gles30 Can't be used for framebuffer reading in OpenGL ES 2.0. * @requires_gles30 For texture data only, extension @es_extension{OES,depth_texture} - * or @es_extension{ANGLE,depth_texture}. + * or @es_extension{ANGLE,depth_texture} in OpenGL ES 2.0 */ UnsignedInt = GL_UNSIGNED_INT, @@ -320,7 +324,7 @@ enum class ColorType: GLenum { /** * Each component signed int. * @requires_gles30 Only @ref Magnum::ColorType::UnsignedInt "ColorType::UnsignedInt" - * is available in OpenGL ES 2.0. + * is available in OpenGL ES 2.0 in OpenGL ES 2.0 */ Int = GL_INT, #endif @@ -329,7 +333,8 @@ enum class ColorType: GLenum { * Each component half float. * @requires_gl30 %Extension @extension{NV,half_float} / @extension{ARB,half_float_pixel} * @requires_gles30 For texture data only, extension - * @es_extension2{OES,texture_half_float,OES_texture_float}. + * @es_extension2{OES,texture_half_float,OES_texture_float} in OpenGL + * ES 2.0 */ #ifndef MAGNUM_TARGET_GLES2 HalfFloat = GL_HALF_FLOAT, @@ -339,7 +344,8 @@ enum class ColorType: GLenum { /** * Each component float. - * @requires_gles30 For texture data only, extension @es_extension{OES,texture_float}. + * @requires_gles30 For texture data only, extension @es_extension{OES,texture_float} + * in OpenGL ES 2.0 */ Float = GL_FLOAT, @@ -434,7 +440,7 @@ enum class ColorType: GLenum { * ABGR, unsigned int, each RGB component 10bit, alpha component 2bit. * @requires_gles30 Can't be used for framebuffer reading in OpenGL ES 2.0. * @requires_gles30 For texture data only, extension - * @es_extension{EXT,texture_type_2_10_10_10_REV}. + * @es_extension{EXT,texture_type_2_10_10_10_REV} in OpenGL ES 2.0 */ #ifndef MAGNUM_TARGET_GLES2 UnsignedInt2101010Rev = GL_UNSIGNED_INT_2_10_10_10_REV, @@ -463,7 +469,8 @@ enum class ColorType: GLenum { /** * Unsigned int, depth component 24bit, stencil index 8bit. * @requires_gl30 %Extension @extension{ARB,framebuffer_object} - * @requires_gles30 For texture data only, extension @es_extension{OES,packed_depth_stencil}. + * @requires_gles30 For texture data only, extension @es_extension{OES,packed_depth_stencil} + * in OpenGL ES 2.0 */ #ifndef MAGNUM_TARGET_GLES2 UnsignedInt248 = GL_UNSIGNED_INT_24_8, diff --git a/src/Magnum/Context.cpp b/src/Magnum/Context.cpp index f044bc684..470496409 100644 --- a/src/Magnum/Context.cpp +++ b/src/Magnum/Context.cpp @@ -54,126 +54,122 @@ const std::vector& Extension::extensions(Version version) { static const std::vector empty; #ifndef MAGNUM_TARGET_GLES static const std::vector extensions{ - _extension(GL,AMD,vertex_shader_layer), // done - _extension(GL,AMD,shader_trinary_minmax), // done - _extension(GL,ARB,robustness), // done + _extension(GL,AMD,vertex_shader_layer), + _extension(GL,AMD,shader_trinary_minmax), + _extension(GL,ARB,robustness), _extension(GL,ATI,texture_mirror_once), - _extension(GL,EXT,texture_filter_anisotropic), // done + _extension(GL,EXT,texture_filter_anisotropic), _extension(GL,EXT,texture_mirror_clamp), _extension(GL,EXT,direct_state_access), _extension(GL,EXT,debug_label), _extension(GL,EXT,debug_marker), - _extension(GL,GREMEDY,string_marker)}; // done + _extension(GL,GREMEDY,string_marker)}; static const std::vector extensions300{ - /** - * @todo Remove as it doesn't have all functionality present in GL 3.0 - * and leave only ARB_map_buffer_range? - */ - _extension(GL,APPLE,flush_buffer_range), // done - _extension(GL,APPLE,vertex_array_object), // done - _extension(GL,ARB,map_buffer_range), // done, replaces APPLE_flush_buffer_range + _extension(GL,APPLE,flush_buffer_range), + _extension(GL,APPLE,vertex_array_object), + _extension(GL,ARB,map_buffer_range), _extension(GL,ARB,color_buffer_float), - _extension(GL,ARB,half_float_pixel), // done - _extension(GL,ARB,texture_float), // done - _extension(GL,ARB,depth_buffer_float), // done - _extension(GL,ARB,texture_rg), // done + _extension(GL,ARB,half_float_pixel), + _extension(GL,ARB,texture_float), + _extension(GL,ARB,depth_buffer_float), + _extension(GL,ARB,texture_rg), _extension(GL,ARB,framebuffer_object), _extension(GL,EXT,gpu_shader4), - _extension(GL,EXT,packed_float), // done + _extension(GL,EXT,packed_float), _extension(GL,EXT,texture_array), - _extension(GL,EXT,texture_compression_rgtc), // done - _extension(GL,EXT,texture_shared_exponent), // done + _extension(GL,EXT,texture_compression_rgtc), + _extension(GL,EXT,texture_shared_exponent), _extension(GL,EXT,framebuffer_sRGB), _extension(GL,EXT,draw_buffers2), _extension(GL,EXT,texture_integer), _extension(GL,EXT,transform_feedback), - _extension(GL,NV,half_float), // done + _extension(GL,NV,half_float), _extension(GL,NV,depth_buffer_float), - _extension(GL,NV,conditional_render)}; // done + _extension(GL,NV,conditional_render)}; static const std::vector extensions310{ _extension(GL,ARB,texture_rectangle), _extension(GL,ARB,draw_instanced), _extension(GL,ARB,texture_buffer_object), _extension(GL,ARB,uniform_buffer_object), - _extension(GL,ARB,copy_buffer), // done - _extension(GL,EXT,texture_snorm), // done + _extension(GL,ARB,copy_buffer), + _extension(GL,EXT,texture_snorm), _extension(GL,NV,primitive_restart)}; static const std::vector extensions320{ _extension(GL,ARB,geometry_shader4), - _extension(GL,ARB,depth_clamp), // done + _extension(GL,ARB,depth_clamp), _extension(GL,ARB,draw_elements_base_vertex), - _extension(GL,ARB,fragment_coord_conventions), // done - _extension(GL,ARB,provoking_vertex), // done - _extension(GL,ARB,seamless_cube_map), // done + _extension(GL,ARB,fragment_coord_conventions), + _extension(GL,ARB,provoking_vertex), + _extension(GL,ARB,seamless_cube_map), _extension(GL,ARB,sync), _extension(GL,ARB,texture_multisample), - _extension(GL,ARB,vertex_array_bgra)}; // done + _extension(GL,ARB,vertex_array_bgra)}; static const std::vector extensions330{ _extension(GL,ARB,instanced_arrays), _extension(GL,ARB,blend_func_extended), - _extension(GL,ARB,explicit_attrib_location), // done - _extension(GL,ARB,occlusion_query2), // done + _extension(GL,ARB,explicit_attrib_location), + _extension(GL,ARB,occlusion_query2), _extension(GL,ARB,sampler_objects), - _extension(GL,ARB,shader_bit_encoding), // done - _extension(GL,ARB,texture_rgb10_a2ui), // done + _extension(GL,ARB,shader_bit_encoding), + _extension(GL,ARB,texture_rgb10_a2ui), _extension(GL,ARB,texture_swizzle), _extension(GL,ARB,timer_query), - _extension(GL,ARB,vertex_type_2_10_10_10_rev)}; // done + _extension(GL,ARB,vertex_type_2_10_10_10_rev)}; static const std::vector extensions400{ _extension(GL,ARB,draw_buffers_blend), _extension(GL,ARB,sample_shading), - _extension(GL,ARB,texture_cube_map_array), // done + _extension(GL,ARB,texture_cube_map_array), _extension(GL,ARB,texture_gather), - _extension(GL,ARB,texture_query_lod), // done + _extension(GL,ARB,texture_query_lod), _extension(GL,ARB,draw_indirect), _extension(GL,ARB,gpu_shader5), - _extension(GL,ARB,gpu_shader_fp64), // done + _extension(GL,ARB,gpu_shader_fp64), _extension(GL,ARB,shader_subroutine), _extension(GL,ARB,tessellation_shader), - _extension(GL,ARB,texture_buffer_object_rgb32), // done + _extension(GL,ARB,texture_buffer_object_rgb32), _extension(GL,ARB,transform_feedback2), _extension(GL,ARB,transform_feedback3)}; static const std::vector extensions410{ _extension(GL,ARB,ES2_compatibility), _extension(GL,ARB,get_program_binary), _extension(GL,ARB,separate_shader_objects), - _extension(GL,ARB,shader_precision), // done - _extension(GL,ARB,vertex_attrib_64bit), // done + _extension(GL,ARB,shader_precision), + _extension(GL,ARB,vertex_attrib_64bit), _extension(GL,ARB,viewport_array)}; static const std::vector extensions420{ - _extension(GL,ARB,texture_compression_bptc), // done + _extension(GL,ARB,texture_compression_bptc), _extension(GL,ARB,base_instance), - _extension(GL,ARB,shading_language_420pack), // done + _extension(GL,ARB,shading_language_420pack), _extension(GL,ARB,transform_feedback_instanced), _extension(GL,ARB,compressed_texture_pixel_storage), - _extension(GL,ARB,conservative_depth), // done + _extension(GL,ARB,conservative_depth), _extension(GL,ARB,internalformat_query), _extension(GL,ARB,map_buffer_alignment), _extension(GL,ARB,shader_atomic_counters), _extension(GL,ARB,shader_image_load_store), /* Mentioned in GLSL 4.20 specs as newly added */ - _extension(GL,ARB,shading_language_packing), // done + _extension(GL,ARB,shading_language_packing), _extension(GL,ARB,texture_storage)}; static const std::vector extensions430{ - _extension(GL,ARB,arrays_of_arrays), // done + _extension(GL,ARB,arrays_of_arrays), _extension(GL,ARB,ES3_compatibility), _extension(GL,ARB,clear_buffer_object), _extension(GL,ARB,compute_shader), _extension(GL,ARB,copy_image), _extension(GL,KHR,debug), _extension(GL,ARB,explicit_uniform_location), - _extension(GL,ARB,fragment_layer_viewport), // done + _extension(GL,ARB,fragment_layer_viewport), _extension(GL,ARB,framebuffer_no_attachments), _extension(GL,ARB,internalformat_query2), - _extension(GL,ARB,invalidate_subdata), // done + _extension(GL,ARB,invalidate_subdata), _extension(GL,ARB,multi_draw_indirect), _extension(GL,ARB,program_interface_query), - _extension(GL,ARB,robust_buffer_access_behavior), // done - _extension(GL,ARB,shader_image_size), // done + _extension(GL,ARB,robust_buffer_access_behavior), + _extension(GL,ARB,shader_image_size), _extension(GL,ARB,shader_storage_buffer_object), _extension(GL,ARB,stencil_texturing), - _extension(GL,ARB,texture_buffer_range), // done - _extension(GL,ARB,texture_query_levels), // done + _extension(GL,ARB,texture_buffer_range), + _extension(GL,ARB,texture_query_levels), _extension(GL,ARB,texture_storage_multisample), _extension(GL,ARB,texture_view), _extension(GL,ARB,vertex_attrib_binding)}; @@ -199,10 +195,6 @@ const std::vector& Extension::extensions(Version version) { _extension(GL,EXT,disjoint_timer_query), _extension(GL,EXT,separate_shader_objects), _extension(GL,EXT,sRGB), - /** - * @todo Support also IMG_multisampled_render_to_texture? It has - * different enum values (!) - */ _extension(GL,EXT,multisampled_render_to_texture), _extension(GL,EXT,robustness), _extension(GL,KHR,debug), @@ -210,17 +202,16 @@ const std::vector& Extension::extensions(Version version) { _extension(GL,NV,read_depth), _extension(GL,NV,read_stencil), _extension(GL,NV,read_depth_stencil), - _extension(GL,NV,texture_border_clamp), // done + _extension(GL,NV,texture_border_clamp), _extension(GL,OES,depth32), _extension(GL,OES,mapbuffer), _extension(GL,OES,stencil1), - _extension(GL,OES,stencil4), - _extension(GL,OES,texture_3D)}; + _extension(GL,OES,stencil4)}; #ifdef MAGNUM_TARGET_GLES2 static const std::vector extensionsES300{ _extension(GL,ANGLE,framebuffer_blit), _extension(GL,ANGLE,framebuffer_multisample), - _extension(GL,ANGLE,depth_texture), // done + _extension(GL,ANGLE,depth_texture), _extension(GL,APPLE,framebuffer_multisample), _extension(GL,ARM,rgba8), _extension(GL,EXT,texture_type_2_10_10_10_REV), @@ -233,11 +224,12 @@ const std::vector& Extension::extensions(Version version) { _extension(GL,NV,draw_buffers), _extension(GL,NV,fbo_color_attachments), _extension(GL,NV,read_buffer), - _extension(GL,NV,framebuffer_blit), // done + _extension(GL,NV,framebuffer_blit), _extension(GL,NV,framebuffer_multisample), _extension(GL,OES,depth24), _extension(GL,OES,element_index_uint), _extension(GL,OES,rgb8_rgba8), + _extension(GL,OES,texture_3D), _extension(GL,OES,texture_half_float_linear), _extension(GL,OES,texture_float_linear), _extension(GL,OES,texture_half_float), @@ -245,10 +237,10 @@ const std::vector& Extension::extensions(Version version) { _extension(GL,OES,vertex_half_float), _extension(GL,OES,packed_depth_stencil), _extension(GL,OES,depth_texture), - _extension(GL,OES,standard_derivatives), // done + _extension(GL,OES,standard_derivatives), _extension(GL,OES,vertex_array_object), _extension(GL,OES,required_internalformat), - _extension(GL,OES,surfaceless_context)}; // done + _extension(GL,OES,surfaceless_context)}; #endif #endif @@ -295,26 +287,77 @@ Context::Context() { } #endif - /* Version */ - #ifndef MAGNUM_TARGET_GLES2 + /* Get version */ + #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2) glGetIntegerv(GL_MAJOR_VERSION, &_majorVersion); glGetIntegerv(GL_MINOR_VERSION, &_minorVersion); #else - _majorVersion = 2; - _minorVersion = 0; + + /* On GL 2.1 and ES 2.0 there is no GL_{MAJOR,MINOR}_VERSION, we have to + parse version string. On desktop GL we have no way to check version + without version (duh) so we work around that by checking for invalid + enum error. */ + #ifndef MAGNUM_TARGET_GLES2 + glGetIntegerv(GL_MAJOR_VERSION, &_majorVersion); + const auto versionNumberError = Renderer::error(); + if(versionNumberError == Renderer::Error::NoError) + glGetIntegerv(GL_MINOR_VERSION, &_minorVersion); + else #endif - _version = static_cast(_majorVersion*100+_minorVersion*10); + { + #ifndef MAGNUM_TARGET_GLES2 + CORRADE_ASSERT(versionNumberError == Renderer::Error::InvalidEnum, + "Context: cannot retrieve OpenGL version:" << versionNumberError, ); + #endif - CORRADE_ASSERT(Renderer::error() == Renderer::Error::NoError, - "Context: cannot retrieve OpenGL version", ); + const std::string version = versionString(); + #ifndef MAGNUM_TARGET_GLES + if(version.compare(0, 4, "2.1 ") == 0) + #elif defined(CORRADE_TARGET_EMSCRIPTEN) + if(version.find("WebGL 1") != std::string::npos) + #else + if(version.find("OpenGL ES 2.0") != std::string::npos) + #endif + { + _majorVersion = 2; + #ifndef MAGNUM_TARGET_GLES + _minorVersion = 1; + #else + _minorVersion = 0; + #endif + } else { + Error() << "Context: unsupported version string:" << version; + std::exit(1); + } + } + #endif + + /* Compose the version enum */ + _version = Magnum::version(_majorVersion, _minorVersion); + + /* Check that version retrieval went right */ + #ifndef CORRADE_NO_ASSERT + const auto error = Renderer::error(); + CORRADE_ASSERT(error == Renderer::Error::NoError, + "Context: cannot retrieve OpenGL version:" << error, ); + #endif + /* Check that the version is supported (now it probably is, but be sure) */ #ifndef MAGNUM_TARGET_GLES - CORRADE_ASSERT(isVersionSupported(Version::GL210), "Context: unsupported OpenGL version" << Int(_version), ); + if(!isVersionSupported(Version::GL210)) #elif defined(MAGNUM_TARGET_GLES2) - CORRADE_ASSERT(isVersionSupported(Version::GLES200), "Context: unsupported OpenGL ES version" << Int(_version), ); + if(!isVersionSupported(Version::GLES200)) #else - CORRADE_ASSERT(isVersionSupported(Version::GLES300), "Context: unsupported OpenGL ES version" << Int(_version), ); + if(!isVersionSupported(Version::GLES300)) #endif + { + #ifndef MAGNUM_TARGET_GLES + Error() << "Context: unsupported OpenGL version" << Int(_version); + #else + Error() << "Context: unsupported OpenGL ES version" << Int(_version); + #endif + std::exit(1); + } /* Context flags are supported since GL 3.0 */ #ifndef MAGNUM_TARGET_GLES @@ -421,7 +464,6 @@ Context::Context() { _disable(GL,KHR,debug) _disable(GL,NV,read_buffer_front) _disable(GL,OES,mapbuffer) - _disable(GL,OES,texture_3D) #ifdef MAGNUM_TARGET_GLES2 _disable(GL,ANGLE,framebuffer_blit) _disable(GL,ANGLE,framebuffer_multisample) @@ -437,6 +479,7 @@ Context::Context() { _disable(GL,NV,fbo_color_attachments) // ?? _disable(GL,NV,read_buffer) _disable(GL,NV,framebuffer_multisample) + _disable(GL,OES,texture_3D) _disable(GL,OES,vertex_array_object) #endif #undef _disable @@ -450,18 +493,9 @@ Context::Context() { _state = new Implementation::State(*this); /* Initialize functionality based on current OpenGL version and extensions */ - AbstractFramebuffer::initializeContextBasedFunctionality(*this); - AbstractShaderProgram::initializeContextBasedFunctionality(*this); - AbstractTexture::initializeContextBasedFunctionality(*this); - Buffer::initializeContextBasedFunctionality(*this); - #ifndef MAGNUM_TARGET_GLES - BufferTexture::initializeContextBasedFunctionality(*this); - #endif + /** @todo Get rid of these */ DefaultFramebuffer::initializeContextBasedFunctionality(*this); - Framebuffer::initializeContextBasedFunctionality(*this); - Mesh::initializeContextBasedFunctionality(*this); - Renderbuffer::initializeContextBasedFunctionality(*this); - Renderer::initializeContextBasedFunctionality(*this); + Renderer::initializeContextBasedFunctionality(); } Context::~Context() { diff --git a/src/Magnum/Context.h b/src/Magnum/Context.h index bd01e4ce2..89bb24747 100644 --- a/src/Magnum/Context.h +++ b/src/Magnum/Context.h @@ -95,8 +95,6 @@ through @ref Context::current() is automatically created during construction of *Application classes in @ref Platform namespace. You can safely assume that the instance is available during whole lifetime of *Application object. See @ref platform documentation for more information about engine setup. -@todo @extension{ATI,meminfo}, @extension{NVX,gpu_memory_info}, GPU temperature? - (here or where?) */ class MAGNUM_EXPORT Context { Context(const Context&) = delete; diff --git a/src/Magnum/CubeMapTexture.h b/src/Magnum/CubeMapTexture.h index 6453e522e..bdd3a19a4 100644 --- a/src/Magnum/CubeMapTexture.h +++ b/src/Magnum/CubeMapTexture.h @@ -30,6 +30,8 @@ */ #include "Magnum/AbstractTexture.h" +#include "Magnum/Array.h" +#include "Magnum/Math/Vector2.h" namespace Magnum { @@ -67,12 +69,11 @@ texture.setMagnificationFilter(Sampler::Filter::Linear) // ... @endcode -The texture is bound to layer specified by shader via @ref bind(). In shader, -the texture is used via `samplerCube`, `samplerCubeShadow`, `isamplerCube` or -`usamplerCube`. Unlike in classic textures, coordinates for cube map textures -is signed three-part vector from the center of the cube, which intersects one -of the six sides of the cube map. See also @ref AbstractShaderProgram for more -information about usage in shaders. +In shader, the texture is used via `samplerCube`, `samplerCubeShadow`, +`isamplerCube` or `usamplerCube`. Unlike in classic textures, coordinates for +cube map textures is signed three-part vector from the center of the cube, +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 @@ -92,7 +93,7 @@ class CubeMapTexture: public AbstractTexture { /** * @brief Constructor * - * Creates one cube map OpenGL texture. + * Creates new OpenGL texture object. * @see @fn_gl{GenTextures} with @def_gl{TEXTURE_CUBE_MAP} */ explicit CubeMapTexture(): AbstractTexture(GL_TEXTURE_CUBE_MAP) {} @@ -107,13 +108,33 @@ class CubeMapTexture: public AbstractTexture { } #endif - /** - * @brief Set wrapping - * - * See @ref Texture::setWrapping() for more information. - */ + /** @copydoc Texture::setMinificationFilter() */ + CubeMapTexture& setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) { + AbstractTexture::setMinificationFilter(filter, mipmap); + return *this; + } + + /** @copydoc Texture::setMagnificationFilter() */ + CubeMapTexture& setMagnificationFilter(Sampler::Filter filter) { + AbstractTexture::setMagnificationFilter(filter); + return *this; + } + + /** @copydoc Texture::setWrapping() */ CubeMapTexture& setWrapping(const Array3D& wrapping) { - DataHelper<3>::setWrapping(this, wrapping); + DataHelper<3>::setWrapping(*this, wrapping); + return *this; + } + + /** @copydoc Texture::setBorderColor() */ + CubeMapTexture& setBorderColor(const Color4& color) { + AbstractTexture::setBorderColor(color); + return *this; + } + + /** @copydoc Texture::setMaxAnisotropy() */ + CubeMapTexture& setMaxAnisotropy(Float anisotropy) { + AbstractTexture::setMaxAnisotropy(anisotropy); return *this; } @@ -127,7 +148,7 @@ class CubeMapTexture: public AbstractTexture { * @requires_gl %Texture image queries are not available in OpenGL ES. */ Vector2i imageSize(Coordinate coordinate, Int level) { - return DataHelper<2>::imageSize(this, GLenum(coordinate), level); + return DataHelper<2>::imageSize(*this, GLenum(coordinate), level); } #endif @@ -137,7 +158,7 @@ class CubeMapTexture: public AbstractTexture { * See @ref Texture::setStorage() for more information. */ CubeMapTexture& setStorage(Int levels, TextureFormat internalFormat, const Vector2i& size) { - DataHelper<2>::setStorage(this, _target, levels, internalFormat, size); + DataHelper<2>::setStorage(*this, _target, levels, internalFormat, size); return *this; } @@ -183,14 +204,14 @@ class CubeMapTexture: public AbstractTexture { * See @ref Texture::setImage() for more information. */ CubeMapTexture& setImage(Coordinate coordinate, Int level, TextureFormat internalFormat, const ImageReference2D& image) { - DataHelper<2>::setImage(this, GLenum(coordinate), level, internalFormat, image); + DataHelper<2>::setImage(*this, GLenum(coordinate), level, internalFormat, image); return *this; } #ifndef MAGNUM_TARGET_GLES2 /** @overload */ CubeMapTexture& setImage(Coordinate coordinate, Int level, TextureFormat internalFormat, BufferImage2D& image) { - DataHelper<2>::setImage(this, GLenum(coordinate), level, internalFormat, image); + DataHelper<2>::setImage(*this, GLenum(coordinate), level, internalFormat, image); return *this; } @@ -212,24 +233,33 @@ class CubeMapTexture: public AbstractTexture { * See @ref Texture::setSubImage() for more information. */ CubeMapTexture& setSubImage(Coordinate coordinate, Int level, const Vector2i& offset, const ImageReference2D& image) { - DataHelper<2>::setSubImage(this, GLenum(coordinate), level, offset, image); + DataHelper<2>::setSubImage(*this, GLenum(coordinate), level, offset, image); return *this; } #ifndef MAGNUM_TARGET_GLES2 /** @overload */ CubeMapTexture& setSubImage(Coordinate coordinate, Int level, const Vector2i& offset, BufferImage2D& image) { - DataHelper<2>::setSubImage(this, GLenum(coordinate), level, offset, image); + DataHelper<2>::setSubImage(*this, GLenum(coordinate), level, offset, image); return *this; } /** @overload */ CubeMapTexture& setSubImage(Coordinate coordinate, Int level, const Vector2i& offset, BufferImage2D&& image) { - DataHelper<2>::setSubImage(this, GLenum(coordinate), level, offset, image); + DataHelper<2>::setSubImage(*this, GLenum(coordinate), level, offset, image); return *this; } #endif + /** @copydoc Texture::generateMipmap() */ + CubeMapTexture& generateMipmap() { + AbstractTexture::generateMipmap(); + return *this; + } + + /** @copydoc Texture::invalidateImage() */ + void invalidateImage(Int level) { AbstractTexture::invalidateImage(level); } + /** * @brief Invalidate texture subimage * @param level Mip level @@ -243,7 +273,7 @@ class CubeMapTexture: public AbstractTexture { * See @ref Texture::invalidateSubImage() for more information. */ void invalidateSubImage(Int level, const Vector3i& offset, const Vector3i& size) { - DataHelper<3>::invalidateSubImage(this, level, offset, size); + DataHelper<3>::invalidateSubImage(*this, level, offset, size); } /* Overloads to remove WTF-factor from method chaining order */ @@ -252,26 +282,6 @@ class CubeMapTexture: public AbstractTexture { AbstractTexture::setLabel(label); return *this; } - CubeMapTexture& setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) { - AbstractTexture::setMinificationFilter(filter, mipmap); - return *this; - } - CubeMapTexture& setMagnificationFilter(Sampler::Filter filter) { - AbstractTexture::setMagnificationFilter(filter); - return *this; - } - CubeMapTexture& setBorderColor(const Color4& color) { - AbstractTexture::setBorderColor(color); - return *this; - } - CubeMapTexture& setMaxAnisotropy(Float anisotropy) { - AbstractTexture::setMaxAnisotropy(anisotropy); - return *this; - } - CubeMapTexture& generateMipmap() { - AbstractTexture::generateMipmap(); - return *this; - } #endif }; diff --git a/src/Magnum/CubeMapTextureArray.h b/src/Magnum/CubeMapTextureArray.h index 6aa27aeed..a29d6ed96 100644 --- a/src/Magnum/CubeMapTextureArray.h +++ b/src/Magnum/CubeMapTextureArray.h @@ -32,6 +32,8 @@ #endif #include "Magnum/AbstractTexture.h" +#include "Magnum/Array.h" +#include "Magnum/Math/Vector2.h" #ifndef MAGNUM_TARGET_GLES namespace Magnum { @@ -65,12 +67,11 @@ for(std::size_t i = 0; i != 4; i += 6) { texture.generateMipmap(); @endcode -The texture is bound to layer specified by shader via @ref bind(). In shader, -the texture is used via `samplerCubeArray`, `samplerCubeArrayShadow`, +In shader, the texture is used via `samplerCubeArray`, `samplerCubeArrayShadow`, `isamplerCubeArray` or `usamplerCubeArray`. Unlike in classic textures, coordinates for cube map texture arrays is signed four-part vector. First three parts define vector from the center of the cube which intersects with one of -the six sides of the cube map, fourth part is layer in the array. See also +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, @@ -83,8 +84,8 @@ class CubeMapTextureArray: public AbstractTexture { /** * @brief Constructor * - * Creates one cube map OpenGL texture. - * @see @fn_gl{GenTextures} with @def_gl{TEXTURE_CUBE_MAP} + * Creates new OpenGL texture object. + * @see @fn_gl{GenTextures} with @def_gl{TEXTURE_CUBE_MAP_ARRAY} */ explicit CubeMapTextureArray(): AbstractTexture(GL_TEXTURE_CUBE_MAP_ARRAY) {} @@ -98,13 +99,33 @@ class CubeMapTextureArray: public AbstractTexture { } #endif - /** - * @brief Set wrapping - * - * See @ref Texture::setWrapping() for more information. - */ + /** @copydoc Texture::setMinificationFilter() */ + CubeMapTextureArray& setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) { + AbstractTexture::setMinificationFilter(filter, mipmap); + return *this; + } + + /** @copydoc Texture::setMagnificationFilter() */ + CubeMapTextureArray& setMagnificationFilter(Sampler::Filter filter) { + AbstractTexture::setMagnificationFilter(filter); + return *this; + } + + /** @copydoc Texture::setWrapping() */ CubeMapTextureArray& setWrapping(const Array3D& wrapping) { - DataHelper<3>::setWrapping(this, wrapping); + DataHelper<3>::setWrapping(*this, wrapping); + return *this; + } + + /** @copydoc Texture::setBorderColor() */ + CubeMapTextureArray& setBorderColor(const Color4& color) { + AbstractTexture::setBorderColor(color); + return *this; + } + + /** @copydoc Texture::setMaxAnisotropy() */ + CubeMapTextureArray& setMaxAnisotropy(Float anisotropy) { + AbstractTexture::setMaxAnisotropy(anisotropy); return *this; } @@ -115,7 +136,7 @@ class CubeMapTextureArray: public AbstractTexture { * See @ref Texture::imageSize() for more information. */ Vector3i imageSize(Int level) { - return DataHelper<3>::imageSize(this, GL_TEXTURE_CUBE_MAP_ARRAY, level); + return DataHelper<3>::imageSize(*this, GL_TEXTURE_CUBE_MAP_ARRAY, level); } /** @@ -125,7 +146,7 @@ class CubeMapTextureArray: public AbstractTexture { * @ref Texture::setStorage() for more information. */ CubeMapTextureArray& setStorage(Int levels, TextureFormat internalFormat, const Vector3i& size) { - DataHelper<3>::setStorage(this, _target, levels, internalFormat, size); + DataHelper<3>::setStorage(*this, _target, levels, internalFormat, size); return *this; } @@ -173,13 +194,13 @@ class CubeMapTextureArray: public AbstractTexture { * See @ref Texture::setImage() for more information. */ CubeMapTextureArray& setImage(Int level, TextureFormat internalFormat, const ImageReference3D& image) { - DataHelper<3>::setImage(this, GL_TEXTURE_CUBE_MAP_ARRAY, level, internalFormat, image); + DataHelper<3>::setImage(*this, GL_TEXTURE_CUBE_MAP_ARRAY, level, internalFormat, image); return *this; } /** @overload */ CubeMapTextureArray& setImage(Int level, TextureFormat internalFormat, BufferImage3D& image) { - DataHelper<3>::setImage(this, GL_TEXTURE_CUBE_MAP_ARRAY, level, internalFormat, image); + DataHelper<3>::setImage(*this, GL_TEXTURE_CUBE_MAP_ARRAY, level, internalFormat, image); return *this; } @@ -202,13 +223,13 @@ class CubeMapTextureArray: public AbstractTexture { * See @ref Texture::setSubImage() for more information. */ CubeMapTextureArray& setSubImage(Int level, const Vector3i& offset, const ImageReference3D& image) { - DataHelper<3>::setSubImage(this, GL_TEXTURE_CUBE_MAP_ARRAY, level, offset, image); + DataHelper<3>::setSubImage(*this, GL_TEXTURE_CUBE_MAP_ARRAY, level, offset, image); return *this; } /** @overload */ CubeMapTextureArray& setSubImage(Int level, const Vector3i& offset, BufferImage3D& image) { - DataHelper<3>::setSubImage(this, GL_TEXTURE_CUBE_MAP_ARRAY, level, offset, image); + DataHelper<3>::setSubImage(*this, GL_TEXTURE_CUBE_MAP_ARRAY, level, offset, image); return *this; } @@ -217,6 +238,15 @@ class CubeMapTextureArray: public AbstractTexture { return setSubImage(level, offset, image); } + /** @copydoc Texture::generateMipmap() */ + CubeMapTextureArray& generateMipmap() { + AbstractTexture::generateMipmap(); + return *this; + } + + /** @copydoc Texture::invalidateImage() */ + void invalidateImage(Int level) { AbstractTexture::invalidateImage(level); } + /** * @brief Invalidate texture subimage * @param level Mip level @@ -229,7 +259,7 @@ class CubeMapTextureArray: public AbstractTexture { * See @ref Texture::invalidateSubImage() for more information. */ void invalidateSubImage(Int level, const Vector3i& offset, const Vector3i& size) { - DataHelper<3>::invalidateSubImage(this, level, offset, size); + DataHelper<3>::invalidateSubImage(*this, level, offset, size); } /* Overloads to remove WTF-factor from method chaining order */ @@ -238,26 +268,6 @@ class CubeMapTextureArray: public AbstractTexture { AbstractTexture::setLabel(label); return *this; } - CubeMapTextureArray& setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) { - AbstractTexture::setMinificationFilter(filter, mipmap); - return *this; - } - CubeMapTextureArray& setMagnificationFilter(Sampler::Filter filter) { - AbstractTexture::setMagnificationFilter(filter); - return *this; - } - CubeMapTextureArray& setBorderColor(const Color4& color) { - AbstractTexture::setBorderColor(color); - return *this; - } - CubeMapTextureArray& setMaxAnisotropy(Float anisotropy) { - AbstractTexture::setMaxAnisotropy(anisotropy); - return *this; - } - CubeMapTextureArray& generateMipmap() { - AbstractTexture::generateMipmap(); - return *this; - } #endif }; diff --git a/src/Magnum/DebugMessage.cpp b/src/Magnum/DebugMessage.cpp index 97eb1edc0..fd3a690e4 100644 --- a/src/Magnum/DebugMessage.cpp +++ b/src/Magnum/DebugMessage.cpp @@ -36,6 +36,8 @@ namespace Magnum { namespace { +/** @todo Re-enable when extension wrangler is available for ES */ +#ifndef MAGNUM_TARGET_GLES void #ifdef CORRADE_TARGET_WINDOWS APIENTRY @@ -43,6 +45,7 @@ APIENTRY callbackWrapper(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { Context::current()->state().debug->messageCallback(DebugMessage::Source(source), DebugMessage::Type(type), id, DebugMessage::Severity(severity), std::string(message, length), userParam); } +#endif void defaultCallback(const DebugMessage::Source source, const DebugMessage::Type type, const UnsignedInt id, const DebugMessage::Severity severity, const std::string& string, const void*) { switch(severity) { diff --git a/src/Magnum/DebugTools/ForceRenderer.cpp b/src/Magnum/DebugTools/ForceRenderer.cpp index 825c2406c..e763955a7 100644 --- a/src/Magnum/DebugTools/ForceRenderer.cpp +++ b/src/Magnum/DebugTools/ForceRenderer.cpp @@ -97,9 +97,8 @@ template ForceRenderer::ForceRenderer(SceneG template void ForceRenderer::draw(const typename DimensionTraits::MatrixType& transformationMatrix, SceneGraph::AbstractCamera& camera) { shader->setTransformationProjectionMatrix(camera.projectionMatrix()*Implementation::forceRendererTransformation(transformationMatrix.transformPoint(forcePosition), force)*DimensionTraits::MatrixType::scaling(typename DimensionTraits::VectorType(options->scale()))) - .setColor(options->color()) - .use(); - mesh->draw(); + .setColor(options->color()); + mesh->draw(*shader); } template class ForceRenderer<2>; diff --git a/src/Magnum/DebugTools/Implementation/AxisAlignedBoxRenderer.cpp b/src/Magnum/DebugTools/Implementation/AxisAlignedBoxRenderer.cpp index c84f1c810..33e014ca5 100644 --- a/src/Magnum/DebugTools/Implementation/AxisAlignedBoxRenderer.cpp +++ b/src/Magnum/DebugTools/Implementation/AxisAlignedBoxRenderer.cpp @@ -38,9 +38,8 @@ template void AxisAlignedBoxRenderer::draw(R AbstractBoxRenderer::wireframeShader->setTransformationProjectionMatrix(projectionMatrix* DimensionTraits::MatrixType::translation((axisAlignedBox.min()+axisAlignedBox.max())/2)* DimensionTraits::MatrixType::scaling(axisAlignedBox.max()-axisAlignedBox.min())) - .setColor(options->color()) - .use(); - AbstractBoxRenderer::wireframeMesh->draw(); + .setColor(options->color()); + AbstractBoxRenderer::wireframeMesh->draw(*AbstractBoxRenderer::wireframeShader); } template class AxisAlignedBoxRenderer<2>; diff --git a/src/Magnum/DebugTools/Implementation/BoxRenderer.cpp b/src/Magnum/DebugTools/Implementation/BoxRenderer.cpp index b47ef553d..e070188c9 100644 --- a/src/Magnum/DebugTools/Implementation/BoxRenderer.cpp +++ b/src/Magnum/DebugTools/Implementation/BoxRenderer.cpp @@ -36,9 +36,8 @@ template BoxRenderer::BoxRenderer(const Shap template void BoxRenderer::draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) { AbstractBoxRenderer::wireframeShader->setTransformationProjectionMatrix(projectionMatrix*box.transformation()) - .setColor(options->color()) - .use(); - AbstractBoxRenderer::wireframeMesh->draw(); + .setColor(options->color()); + AbstractBoxRenderer::wireframeMesh->draw(*AbstractBoxRenderer::wireframeShader); } template class BoxRenderer<2>; diff --git a/src/Magnum/DebugTools/Implementation/CapsuleRenderer.cpp b/src/Magnum/DebugTools/Implementation/CapsuleRenderer.cpp index c897e9d97..2c46cd430 100644 --- a/src/Magnum/DebugTools/Implementation/CapsuleRenderer.cpp +++ b/src/Magnum/DebugTools/Implementation/CapsuleRenderer.cpp @@ -45,21 +45,21 @@ AbstractCapsuleRenderer<2>::AbstractCapsuleRenderer(): AbstractShapeRenderer<2>( /* Bottom hemisphere */ if(!(bottom = ResourceManager::instance().get("capsule2d-bottom"))) { - auto view = new MeshView(wireframeMesh); + auto view = new MeshView(*wireframeMesh); view->setIndexRange(0, rings*4, 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); + auto view = new MeshView(*wireframeMesh); view->setIndexRange(rings*4, 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); + auto view = new MeshView(*wireframeMesh); view->setIndexRange(rings*4+4, rings*4, rings*2+3, rings*4+4); ResourceManager::instance().set(top.key(), view, ResourceDataState::Final, ResourcePolicy::Manual); } @@ -72,21 +72,21 @@ AbstractCapsuleRenderer<3>::AbstractCapsuleRenderer(): AbstractShapeRenderer<3>( /* Bottom hemisphere */ if(!(bottom = ResourceManager::instance().get("capsule3d-bottom"))) { - auto view = new MeshView(wireframeMesh); + auto view = new MeshView(*wireframeMesh); view->setIndexRange(0, rings*8, 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); + auto view = new MeshView(*wireframeMesh); view->setIndexRange(rings*8, segments*4+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); + auto view = new MeshView(*wireframeMesh); view->setIndexRange(rings*8+segments*4+8, rings*8, rings*4+segments*2+5, rings*8+segments*2+6); ResourceManager::instance().set(top.key(), view, ResourceDataState::Final, ResourcePolicy::Manual); } @@ -100,20 +100,19 @@ template CapsuleRenderer::CapsuleRenderer(co template void CapsuleRenderer::draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) { std::array::MatrixType, 3> transformations = Implementation::capsuleRendererTransformation(capsule.a(), capsule.b(), capsule.radius()); - AbstractShapeRenderer::wireframeShader->setColor(options->color()) - .use(); + AbstractShapeRenderer::wireframeShader->setColor(options->color()); /* Bottom */ AbstractShapeRenderer::wireframeShader->setTransformationProjectionMatrix(projectionMatrix*transformations[0]); - AbstractCapsuleRenderer::bottom->draw(); + AbstractCapsuleRenderer::bottom->draw(*AbstractShapeRenderer::wireframeShader); /* Cylinder */ AbstractShapeRenderer::wireframeShader->setTransformationProjectionMatrix(projectionMatrix*transformations[1]); - AbstractCapsuleRenderer::cylinder->draw(); + AbstractCapsuleRenderer::cylinder->draw(*AbstractShapeRenderer::wireframeShader); /* Top */ AbstractShapeRenderer::wireframeShader->setTransformationProjectionMatrix(projectionMatrix*transformations[2]); - AbstractCapsuleRenderer::top->draw(); + AbstractCapsuleRenderer::top->draw(*AbstractShapeRenderer::wireframeShader); } template class CapsuleRenderer<2>; diff --git a/src/Magnum/DebugTools/Implementation/CylinderRenderer.cpp b/src/Magnum/DebugTools/Implementation/CylinderRenderer.cpp index 7e6e14e6d..20f3e1798 100644 --- a/src/Magnum/DebugTools/Implementation/CylinderRenderer.cpp +++ b/src/Magnum/DebugTools/Implementation/CylinderRenderer.cpp @@ -51,9 +51,8 @@ template CylinderRenderer::CylinderRenderer( template void CylinderRenderer::draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) { AbstractShapeRenderer::wireframeShader->setTransformationProjectionMatrix(projectionMatrix* Implementation::cylinderRendererTransformation(cylinder.a(), cylinder.b(), cylinder.radius())) - .setColor(options->color()) - .use(); - AbstractShapeRenderer::wireframeMesh->draw(); + .setColor(options->color()); + AbstractShapeRenderer::wireframeMesh->draw(*AbstractShapeRenderer::wireframeShader); } template class CylinderRenderer<2>; diff --git a/src/Magnum/DebugTools/Implementation/LineSegmentRenderer.cpp b/src/Magnum/DebugTools/Implementation/LineSegmentRenderer.cpp index be8ef4a46..956bbae84 100644 --- a/src/Magnum/DebugTools/Implementation/LineSegmentRenderer.cpp +++ b/src/Magnum/DebugTools/Implementation/LineSegmentRenderer.cpp @@ -58,9 +58,8 @@ template LineSegmentRenderer::LineSegmentRen template void LineSegmentRenderer::draw(Resource& options, const typename DimensionTraits::MatrixType& projectionMatrix) { AbstractShapeRenderer::wireframeShader->setTransformationProjectionMatrix(projectionMatrix* Implementation::lineSegmentRendererTransformation(line.a(), line.b())) - .setColor(options->color()) - .use(); - AbstractShapeRenderer::wireframeMesh->draw(); + .setColor(options->color()); + AbstractShapeRenderer::wireframeMesh->draw(*AbstractShapeRenderer::wireframeShader); } template class LineSegmentRenderer<2>; diff --git a/src/Magnum/DebugTools/Implementation/PointRenderer.cpp b/src/Magnum/DebugTools/Implementation/PointRenderer.cpp index f5434c2ef..29614f3da 100644 --- a/src/Magnum/DebugTools/Implementation/PointRenderer.cpp +++ b/src/Magnum/DebugTools/Implementation/PointRenderer.cpp @@ -58,9 +58,8 @@ template void PointRenderer::draw(Resource::wireframeShader->setTransformationProjectionMatrix(projectionMatrix* DimensionTraits::MatrixType::translation(point.position())* DimensionTraits::MatrixType::scaling(typename DimensionTraits::VectorType(options->pointSize()/2))) - .setColor(options->color()) - .use(); - AbstractShapeRenderer::wireframeMesh->draw(); + .setColor(options->color()); + AbstractShapeRenderer::wireframeMesh->draw(*AbstractShapeRenderer::wireframeShader); } template class PointRenderer<2>; diff --git a/src/Magnum/DebugTools/Implementation/SphereRenderer.cpp b/src/Magnum/DebugTools/Implementation/SphereRenderer.cpp index 58b454712..dbdf66ab4 100644 --- a/src/Magnum/DebugTools/Implementation/SphereRenderer.cpp +++ b/src/Magnum/DebugTools/Implementation/SphereRenderer.cpp @@ -50,9 +50,8 @@ template void SphereRenderer::draw(Resource< AbstractShapeRenderer::wireframeShader->setTransformationProjectionMatrix(projectionMatrix* DimensionTraits::MatrixType::translation(sphere.position())* DimensionTraits::MatrixType::scaling(typename DimensionTraits::VectorType(sphere.radius()))) - .setColor(options->color()) - .use(); - AbstractShapeRenderer::wireframeMesh->draw(); + .setColor(options->color()); + AbstractShapeRenderer::wireframeMesh->draw(*AbstractShapeRenderer::wireframeShader); } template class SphereRenderer<2>; diff --git a/src/Magnum/DebugTools/ObjectRenderer.cpp b/src/Magnum/DebugTools/ObjectRenderer.cpp index 618a2064c..669f8806a 100644 --- a/src/Magnum/DebugTools/ObjectRenderer.cpp +++ b/src/Magnum/DebugTools/ObjectRenderer.cpp @@ -175,10 +175,8 @@ template ObjectRenderer::ObjectRenderer(Scen } template void ObjectRenderer::draw(const typename DimensionTraits::MatrixType& transformationMatrix, SceneGraph::AbstractCamera& camera) { - shader->setTransformationProjectionMatrix(camera.projectionMatrix()*transformationMatrix*DimensionTraits::MatrixType::scaling(typename DimensionTraits::VectorType(options->size()))) - .use(); - - mesh->draw(); + shader->setTransformationProjectionMatrix(camera.projectionMatrix()*transformationMatrix*DimensionTraits::MatrixType::scaling(typename DimensionTraits::VectorType(options->size()))); + mesh->draw(*shader); } template class ObjectRenderer<2>; diff --git a/src/Magnum/DebugTools/Profiler.h b/src/Magnum/DebugTools/Profiler.h index f6fdc01c9..b40a57eda 100644 --- a/src/Magnum/DebugTools/Profiler.h +++ b/src/Magnum/DebugTools/Profiler.h @@ -77,7 +77,7 @@ void MyApplication::drawEvent() { p.start(sections.draw); - scene.draw() + camera.draw(drawables); p.start(sections.bufferSwap); diff --git a/src/Magnum/DefaultFramebuffer.cpp b/src/Magnum/DefaultFramebuffer.cpp index 5fb908c63..f494f2872 100644 --- a/src/Magnum/DefaultFramebuffer.cpp +++ b/src/Magnum/DefaultFramebuffer.cpp @@ -38,6 +38,10 @@ DefaultFramebuffer defaultFramebuffer; DefaultFramebuffer::DefaultFramebuffer() { _id = 0; } +DefaultFramebuffer::Status DefaultFramebuffer::checkStatus(const FramebufferTarget target) { + return Status((this->*Context::current()->state().framebuffer->checkStatusImplementation)(target)); +} + #ifndef MAGNUM_TARGET_GLES2 DefaultFramebuffer& DefaultFramebuffer::mapForDraw(std::initializer_list> attachments) { /* Max attachment location */ @@ -52,11 +56,21 @@ DefaultFramebuffer& DefaultFramebuffer::mapForDraw(std::initializer_listfirst] = GLenum(it->second); - (this->*drawBuffersImplementation)(max+1, _attachments); + (this->*Context::current()->state().framebuffer->drawBuffersImplementation)(max+1, _attachments); + return *this; +} + +DefaultFramebuffer& DefaultFramebuffer::mapForDraw(const DrawAttachment attachment) { + (this->*Context::current()->state().framebuffer->drawBufferImplementation)(GLenum(attachment)); return *this; } #endif +DefaultFramebuffer& DefaultFramebuffer::mapForRead(const ReadAttachment attachment) { + (this->*Context::current()->state().framebuffer->readBufferImplementation)(GLenum(attachment)); + return *this; +} + void DefaultFramebuffer::invalidate(std::initializer_list attachments) { /** @todo C++14: use VLA to avoid heap allocation */ Containers::Array _attachments(attachments.size()); diff --git a/src/Magnum/DefaultFramebuffer.h b/src/Magnum/DefaultFramebuffer.h index bbd55ca0a..347d3e3dd 100644 --- a/src/Magnum/DefaultFramebuffer.h +++ b/src/Magnum/DefaultFramebuffer.h @@ -95,6 +95,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { /** * The default framebuffer does not exist. * @requires_gles30 %Extension @es_extension{OES,surfaceless_context} + * in OpenGL ES 2.0 */ #ifndef MAGNUM_TARGET_GLES2 Undefined = GL_FRAMEBUFFER_UNDEFINED @@ -170,6 +171,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * * @see @ref mapForRead() * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} + * in OpenGL ES 2.0 */ enum class ReadAttachment: GLenum { /** Don't read from any buffer */ @@ -241,6 +243,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * @see @ref invalidate() * @requires_gl43 %Extension @extension{ARB,invalidate_subdata} * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer} + * in OpenGL ES 2.0 */ enum class InvalidationAttachment: GLenum { #ifndef MAGNUM_TARGET_GLES @@ -316,9 +319,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * @fn_gl_extension{CheckNamedFramebufferStatus,EXT,direct_state_access} * @requires_gl30 %Extension @extension{ARB,framebuffer_object} */ - Status checkStatus(FramebufferTarget target) { - return Status((this->*checkStatusImplementation)(target)); - } + Status checkStatus(FramebufferTarget target); #ifndef MAGNUM_TARGET_GLES2 /** @@ -362,10 +363,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * @requires_gles30 Draw attachments for default framebuffer are * available only in OpenGL ES 3.0. */ - DefaultFramebuffer& mapForDraw(DrawAttachment attachment) { - (this->*drawBufferImplementation)(GLenum(attachment)); - return *this; - } + DefaultFramebuffer& mapForDraw(DrawAttachment attachment); #endif /** @@ -379,11 +377,9 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * @see mapForDraw(), @fn_gl{BindFramebuffer}, @fn_gl{ReadBuffer} or * @fn_gl_extension{FramebufferReadBuffer,EXT,direct_state_access} * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} + * in OpenGL ES 2.0 */ - DefaultFramebuffer& mapForRead(ReadAttachment attachment) { - (this->*readBufferImplementation)(GLenum(attachment)); - return *this; - } + DefaultFramebuffer& mapForRead(ReadAttachment attachment); /** * @brief Invalidate framebuffer @@ -396,8 +392,9 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * @requires_gl43 %Extension @extension{ARB,invalidate_subdata}. Use * @ref Magnum::DefaultFramebuffer::clear() "clear()" instead * where the extension is not supported. - * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer}. - * Use @ref Magnum::DefaultFramebuffer::clear() "clear()" instead + * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer} + * in OpenGL ES 2.0. Use + * @ref Magnum::DefaultFramebuffer::clear() "clear()" instead * where the extension is not supported. */ void invalidate(std::initializer_list attachments); @@ -414,8 +411,9 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * @requires_gl43 %Extension @extension{ARB,invalidate_subdata}. Use * @ref Magnum::DefaultFramebuffer::clear() "clear()" instead * where the extension is not supported. - * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer}. - * Use @ref Magnum::DefaultFramebuffer::clear() "clear()" instead + * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer} + * in OpenGL ES 2.0. Use + * @ref Magnum::DefaultFramebuffer::clear() "clear()" instead * where the extension is not supported. */ void invalidate(std::initializer_list attachments, const Range2Di& rectangle); diff --git a/src/Magnum/Extensions.h b/src/Magnum/Extensions.h index 6a7aafb6e..67ef86c65 100644 --- a/src/Magnum/Extensions.h +++ b/src/Magnum/Extensions.h @@ -276,8 +276,8 @@ namespace GL { #endif _extension(GL,OES,stencil1, GLES200, None) // #31 _extension(GL,OES,stencil4, GLES200, None) // #32 - _extension(GL,OES,texture_3D, GLES200, None) // #34 #ifdef MAGNUM_TARGET_GLES2 + _extension(GL,OES,texture_3D, GLES200, GLES300) // #34 _extension(GL,OES,texture_half_float_linear, GLES200, GLES300) // #35 _extension(GL,OES,texture_float_linear, GLES200, GLES300) // #35 _extension(GL,OES,texture_half_float, GLES200, GLES300) // #36 diff --git a/src/Magnum/Framebuffer.cpp b/src/Magnum/Framebuffer.cpp index 3d81d1aaa..d9e4c0116 100644 --- a/src/Magnum/Framebuffer.cpp +++ b/src/Magnum/Framebuffer.cpp @@ -27,28 +27,29 @@ #include -#ifndef MAGNUM_TARGET_GLES2 -#include "Magnum/BufferImage.h" -#endif #include "Magnum/Context.h" #include "Magnum/Extensions.h" #include "Magnum/Image.h" #include "Magnum/Renderbuffer.h" #include "Magnum/Texture.h" +#ifndef MAGNUM_TARGET_GLES2 +#include "Magnum/BufferImage.h" +#include "Magnum/TextureArray.h" +#endif + +#ifndef MAGNUM_TARGET_GLES +#include "Magnum/CubeMapTextureArray.h" +#include "Magnum/MultisampleTexture.h" +#include "Magnum/RectangleTexture.h" +#endif + #include "Implementation/DebugState.h" #include "Implementation/State.h" #include "Implementation/FramebufferState.h" namespace Magnum { -Framebuffer::RenderbufferImplementation Framebuffer::renderbufferImplementation = &Framebuffer::renderbufferImplementationDefault; -#ifndef MAGNUM_TARGET_GLES -Framebuffer::Texture1DImplementation Framebuffer::texture1DImplementation = &Framebuffer::texture1DImplementationDefault; -#endif -Framebuffer::Texture2DImplementation Framebuffer::texture2DImplementation = &Framebuffer::texture2DImplementationDefault; -Framebuffer::Texture3DImplementation Framebuffer::texture3DImplementation = &Framebuffer::texture3DImplementationDefault; - const Framebuffer::DrawAttachment Framebuffer::DrawAttachment::None = Framebuffer::DrawAttachment(GL_NONE); const Framebuffer::BufferAttachment Framebuffer::BufferAttachment::Depth = Framebuffer::BufferAttachment(GL_DEPTH_ATTACHMENT); const Framebuffer::BufferAttachment Framebuffer::BufferAttachment::Stencil = Framebuffer::BufferAttachment(GL_STENCIL_ATTACHMENT); @@ -104,6 +105,10 @@ Framebuffer& Framebuffer::setLabel(const std::string& label) { return *this; } +Framebuffer::Status Framebuffer::checkStatus(const FramebufferTarget target) { + return Status((this->*Context::current()->state().framebuffer->checkStatusImplementation)(target)); +} + Framebuffer& Framebuffer::mapForDraw(std::initializer_list> attachments) { /* Max attachment location */ std::size_t max = 0; @@ -117,7 +122,17 @@ Framebuffer& Framebuffer::mapForDraw(std::initializer_listfirst] = GLenum(it->second); - (this->*drawBuffersImplementation)(max+1, _attachments); + (this->*Context::current()->state().framebuffer->drawBuffersImplementation)(max+1, _attachments); + return *this; +} + +Framebuffer& Framebuffer::mapForDraw(const DrawAttachment attachment) { + (this->*Context::current()->state().framebuffer->drawBufferImplementation)(GLenum(attachment)); + return *this; +} + +Framebuffer& Framebuffer::mapForRead(const ColorAttachment attachment) { + (this->*Context::current()->state().framebuffer->readBufferImplementation)(GLenum(attachment)); return *this; } @@ -139,27 +154,78 @@ void Framebuffer::invalidate(std::initializer_list attac invalidateImplementation(attachments.size(), _attachments, rectangle); } -Framebuffer& Framebuffer::attachTexture2D(BufferAttachment attachment, Texture2D& texture, Int mipLevel) { - /** @todo Check for texture target compatibility */ - (this->*texture2DImplementation)(attachment, GLenum(texture.target()), texture.id(), mipLevel); +Framebuffer& Framebuffer::attachRenderbuffer(const BufferAttachment attachment, Renderbuffer& renderbuffer) { + (this->*Context::current()->state().framebuffer->renderbufferImplementation)(attachment, renderbuffer); return *this; } -void Framebuffer::initializeContextBasedFunctionality(Context& context) { - #ifndef MAGNUM_TARGET_GLES - if(context.isExtensionSupported()) { - Debug() << "Framebuffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; +#ifndef MAGNUM_TARGET_GLES +Framebuffer& Framebuffer::attachTexture(const BufferAttachment attachment, Texture1D& texture, const Int level) { + (this->*Context::current()->state().framebuffer->texture1DImplementation)(attachment, texture.id(), level); + return *this; +} +#endif - renderbufferImplementation = &Framebuffer::renderbufferImplementationDSA; - texture1DImplementation = &Framebuffer::texture1DImplementationDSA; - texture2DImplementation = &Framebuffer::texture2DImplementationDSA; - texture3DImplementation = &Framebuffer::texture3DImplementationDSA; - } - #else - static_cast(context); - #endif +Framebuffer& Framebuffer::attachTexture(const BufferAttachment attachment, Texture2D& texture, const Int level) { + (this->*Context::current()->state().framebuffer->texture2DImplementation)(attachment, GL_TEXTURE_2D, texture.id(), level); + return *this; +} + +#ifndef MAGNUM_TARGET_GLES +Framebuffer& Framebuffer::attachTexture(const BufferAttachment attachment, RectangleTexture& texture, const Int level) { + (this->*Context::current()->state().framebuffer->texture2DImplementation)(attachment, GL_TEXTURE_RECTANGLE, texture.id(), level); + return *this; } +Framebuffer& Framebuffer::attachTexture(const BufferAttachment attachment, MultisampleTexture2D& texture, const Int level) { + (this->*Context::current()->state().framebuffer->texture2DImplementation)(attachment, GL_TEXTURE_2D_MULTISAMPLE, texture.id(), level); + return *this; +} +#endif + +Framebuffer& Framebuffer::attachCubeMapTexture(const BufferAttachment attachment, CubeMapTexture& texture, CubeMapTexture::Coordinate coordinate, const Int level) { + (this->*Context::current()->state().framebuffer->texture2DImplementation)(attachment, GLenum(coordinate), texture.id(), level); + return *this; +} + +Framebuffer& Framebuffer::attachTextureLayer(Framebuffer::BufferAttachment attachment, Texture3D& texture, Int level, Int layer) { + (this->*Context::current()->state().framebuffer->textureLayerImplementation)(attachment, texture.id(), level, layer); + return *this; +} + +#ifndef MAGNUM_TARGET_GLES +Framebuffer& Framebuffer::attachTextureLayer(Framebuffer::BufferAttachment attachment, Texture1DArray& texture, Int level, Int layer) { + (this->*Context::current()->state().framebuffer->textureLayerImplementation)(attachment, texture.id(), level, layer); + return *this; +} +#endif + +#ifndef MAGNUM_TARGET_GLES2 +Framebuffer& Framebuffer::attachTextureLayer(Framebuffer::BufferAttachment attachment, Texture2DArray& texture, Int level, Int layer) { + (this->*Context::current()->state().framebuffer->textureLayerImplementation)(attachment, texture.id(), level, layer); + return *this; +} +#endif + +#ifndef MAGNUM_TARGET_GLES +Framebuffer& Framebuffer::attachTextureLayer(Framebuffer::BufferAttachment attachment, CubeMapTextureArray& texture, Int level, Int layer) { + (this->*Context::current()->state().framebuffer->textureLayerImplementation)(attachment, texture.id(), level, layer); + return *this; +} + +Framebuffer& Framebuffer::attachTextureLayer(Framebuffer::BufferAttachment attachment, MultisampleTexture2DArray& texture, Int level, Int layer) { + (this->*Context::current()->state().framebuffer->textureLayerImplementation)(attachment, texture.id(), level, layer); + return *this; +} +#endif + +#ifdef MAGNUM_BUILD_DEPRECATED +Framebuffer& Framebuffer::attachTexture2D(BufferAttachment attachment, Texture2D& texture, Int mipLevel) { + (this->*Context::current()->state().framebuffer->texture2DImplementation)(attachment, GLenum(texture.target()), texture.id(), mipLevel); + return *this; +} +#endif + void Framebuffer::renderbufferImplementationDefault(BufferAttachment attachment, Renderbuffer& renderbuffer) { glFramebufferRenderbuffer(GLenum(bindInternal()), GLenum(attachment), GL_RENDERBUFFER, renderbuffer.id()); } @@ -169,12 +235,12 @@ void Framebuffer::renderbufferImplementationDSA(BufferAttachment attachment, Ren glNamedFramebufferRenderbufferEXT(_id, GLenum(attachment), GL_RENDERBUFFER, renderbuffer.id()); } -void Framebuffer::texture1DImplementationDefault(BufferAttachment attachment, Texture1D& texture, GLint mipLevel) { - glFramebufferTexture1D(GLenum(bindInternal()), GLenum(attachment), GLenum(texture.target()), texture.id(), mipLevel); +void Framebuffer::texture1DImplementationDefault(BufferAttachment attachment, GLuint textureId, GLint mipLevel) { + glFramebufferTexture1D(GLenum(bindInternal()), GLenum(attachment), GL_TEXTURE_1D, textureId, mipLevel); } -void Framebuffer::texture1DImplementationDSA(BufferAttachment attachment, Texture1D& texture, GLint mipLevel) { - glNamedFramebufferTexture1DEXT(_id, GLenum(attachment), GLenum(texture.target()), texture.id(), mipLevel); +void Framebuffer::texture1DImplementationDSA(BufferAttachment attachment, GLuint textureId, GLint mipLevel) { + glNamedFramebufferTexture1DEXT(_id, GLenum(attachment), GL_TEXTURE_1D, textureId, mipLevel); } #endif @@ -188,24 +254,23 @@ void Framebuffer::texture2DImplementationDSA(BufferAttachment attachment, GLenum } #endif -void Framebuffer::texture3DImplementationDefault(BufferAttachment attachment, Texture3D& texture, GLint mipLevel, GLint layer) { - /** @todo Check for texture target compatibility */ - /** @todo Re-enable when extension loader is available for ES */ - #ifndef MAGNUM_TARGET_GLES - glFramebufferTexture3D(GLenum(bindInternal()), GLenum(attachment), GLenum(texture.target()), texture.id(), mipLevel, layer); +void Framebuffer::textureLayerImplementationDefault(BufferAttachment attachment, GLuint textureId, GLint mipLevel, GLint layer) { + /** @todo Re-enable when extension loader is available for ES 2.0 */ + #ifndef MAGNUM_TARGET_GLES2 + glFramebufferTextureLayer(GLenum(bindInternal()), GLenum(attachment), textureId, mipLevel, layer); #else static_cast(attachment); - static_cast(texture); + static_cast(textureId); static_cast(mipLevel); static_cast(layer); CORRADE_INTERNAL_ASSERT(false); - //glFramebufferTexture3DOES(GLenum(bindInternal()), GLenum(attachment), GLenum(texture.target()), texture.id(), mipLevel, layer); + //glFramebufferTexture3DOES(GLenum(bindInternal()), GLenum(attachment), GL_TEXTURE_3D_OES, texture.id(), mipLevel, layer); #endif } #ifndef MAGNUM_TARGET_GLES -void Framebuffer::texture3DImplementationDSA(BufferAttachment attachment, Texture3D& texture, GLint mipLevel, GLint layer) { - glNamedFramebufferTexture3DEXT(_id, GLenum(attachment), GLenum(texture.target()), texture.id(), mipLevel, layer); +void Framebuffer::textureLayerImplementationDSA(BufferAttachment attachment, GLuint textureId, GLint mipLevel, GLint layer) { + glNamedFramebufferTextureLayerEXT(_id, GLenum(attachment), textureId, mipLevel, layer); } #endif diff --git a/src/Magnum/Framebuffer.h b/src/Magnum/Framebuffer.h index a8255cfee..2ef09ed47 100644 --- a/src/Magnum/Framebuffer.h +++ b/src/Magnum/Framebuffer.h @@ -102,7 +102,7 @@ See their respective documentation for more information. @todo `MAX_COLOR_ATTACHMENTS` */ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObject { - friend class Context; + friend struct Implementation::FramebufferState; public: /** @@ -121,7 +121,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * @param id Color attachment ID * * @requires_gles30 %Extension @es_extension{NV,fbo_color_attachments} - * is required for @p id greater than 0. + * is required for @p id greater than 0 in OpenGL ES 2.0 */ constexpr explicit ColorAttachment(UnsignedInt id): attachment(GL_COLOR_ATTACHMENT0 + id) {} @@ -216,6 +216,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * @see @ref invalidate() * @requires_gl43 %Extension @extension{ARB,invalidate_subdata} * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer} + * in OpenGL ES 2.0 */ class InvalidationAttachment { public: @@ -284,7 +285,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_multisample}, * @es_extension{APPLE,framebuffer_multisample}, * @es_extension{EXT,multisampled_render_to_texture} or - * @es_extension{NV,framebuffer_multisample} + * @es_extension{NV,framebuffer_multisample} in OpenGL ES 2.0 */ #ifndef MAGNUM_TARGET_GLES2 IncompleteMultisample = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, @@ -348,9 +349,9 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * @brief %Framebuffer label * * The result is *not* cached, repeated queries will result in repeated - * OpenGL calls. If neither @extension{KHR,debug} nor - * @extension2{EXT,debug_label} desktop or ES extension is available, - * this function returns empty string. + * OpenGL calls. If OpenGL 4.3 is not supported and neither + * @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES + * extension is available, this function returns empty string. * @see @fn_gl{GetObjectLabel} or * @fn_gl_extension2{GetObjectLabel,EXT,debug_label} with * @def_gl{FRAMEBUFFER} @@ -361,9 +362,9 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * @brief Set framebuffer label * @return Reference to self (for method chaining) * - * Default is empty string. If neither @extension{KHR,debug} nor - * @extension2{EXT,debug_label} desktop or ES extension is available, - * this function does nothing. + * Default is empty string. If OpenGL 4.3 is not supported and neither + * @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES + * extension is available, this function does nothing. * @see @ref maxLabelLength(), @fn_gl{ObjectLabel} or * @fn_gl_extension2{LabelObject,EXT,debug_label} with * @def_gl{FRAMEBUFFER} @@ -380,9 +381,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * @see @fn_gl{BindFramebuffer}, @fn_gl{CheckFramebufferStatus} or * @fn_gl_extension{CheckNamedFramebufferStatus,EXT,direct_state_access} */ - Status checkStatus(FramebufferTarget target) { - return Status((this->*checkStatusImplementation)(target)); - } + Status checkStatus(FramebufferTarget target); /** * @brief Map shader output to attachments @@ -405,6 +404,7 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffers} or * @fn_gl_extension{FramebufferDrawBuffers,EXT,direct_state_access} * @requires_gles30 %Extension @es_extension2{NV,draw_buffers,GL_NV_draw_buffers} + * in OpenGL ES 2.0 */ Framebuffer& mapForDraw(std::initializer_list> attachments); @@ -424,11 +424,9 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * @fn_gl_extension{FramebufferDrawBuffer,EXT,direct_state_access}, * @fn_gl{DrawBuffers} in OpenGL ES 3.0 * @requires_gles30 %Extension @es_extension2{NV,draw_buffers,GL_NV_draw_buffers} + * in OpenGL ES 2.0 */ - Framebuffer& mapForDraw(DrawAttachment attachment) { - (this->*drawBufferImplementation)(GLenum(attachment)); - return *this; - } + Framebuffer& mapForDraw(DrawAttachment attachment); /** * @brief Map given color attachment for reading @@ -441,11 +439,9 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * @see @ref mapForDraw(), @fn_gl{BindFramebuffer}, @fn_gl{ReadBuffer} * or @fn_gl_extension{FramebufferReadBuffer,EXT,direct_state_access} * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} + * in OpenGL ES 2.0 */ - Framebuffer& mapForRead(ColorAttachment attachment) { - (this->*readBufferImplementation)(GLenum(attachment)); - return *this; - } + Framebuffer& mapForRead(ColorAttachment attachment); /** * @brief Invalidate framebuffer @@ -458,9 +454,9 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * @requires_gl43 %Extension @extension{ARB,invalidate_subdata}. Use * @ref Magnum::Framebuffer::clear() "clear()" instead where the * extension is not supported. - * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer}. - * Use @ref Magnum::Framebuffer::clear() "clear()" instead where - * the extension is not supported. + * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer} + * in OpenGL ES 2.0. Use @ref Magnum::Framebuffer::clear() "clear()" + * instead where the extension is not supported. */ void invalidate(std::initializer_list attachments); @@ -476,9 +472,9 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * @requires_gl43 %Extension @extension{ARB,invalidate_subdata}. Use * @ref Magnum::Framebuffer::clear() "clear()" instead where the * extension is not supported. - * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer}. - * Use @ref Magnum::Framebuffer::clear() "clear()" instead where - * the extension is not supported. + * @requires_gles30 %Extension @es_extension{EXT,discard_framebuffer} + * in OpenGL ES 2.0. Use @ref Magnum::Framebuffer::clear() "clear()" + * instead where the extension is not supported. */ void invalidate(std::initializer_list attachments, const Range2Di& rectangle); @@ -494,36 +490,31 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferRenderbuffer} or * @fn_gl_extension{NamedFramebufferRenderbuffer,EXT,direct_state_access} */ - Framebuffer& attachRenderbuffer(BufferAttachment attachment, Renderbuffer& renderbuffer) { - (this->*renderbufferImplementation)(attachment, renderbuffer); - return *this; - } + Framebuffer& attachRenderbuffer(BufferAttachment attachment, Renderbuffer& renderbuffer); #ifndef MAGNUM_TARGET_GLES /** - * @brief Attach 1D texture to given buffer + * @brief Attach texture to given buffer * @param attachment %Buffer attachment - * @param texture 1D texture + * @param texture Texture * @param level Mip level * @return Reference to self (for method chaining) * * If @extension{EXT,direct_state_access} is not available and the * framebufferbuffer is not currently bound, it is bound before the * operation. - * @see @fn_gl{BindFramebuffer}, @fn_gl2{FramebufferTexture1D,FramebufferTexture} - * or @fn_gl_extension{NamedFramebufferTexture1D,EXT,direct_state_access} + * @see @ref attachCubeMapTexture(), @fn_gl{BindFramebuffer}, + * @fn_gl2{FramebufferTexture1D,FramebufferTexture} or + * @fn_gl_extension{NamedFramebufferTexture1D,EXT,direct_state_access} * @requires_gl Only 2D and 3D textures are available in OpenGL ES. */ - Framebuffer& attachTexture1D(BufferAttachment attachment, Texture1D& texture, Int level) { - (this->*texture1DImplementation)(attachment, texture, level); - return *this; - } + Framebuffer& attachTexture(BufferAttachment attachment, Texture1D& texture, Int level); #endif /** - * @brief Attach 2D texture to given buffer + * @brief Attach texture to given buffer * @param attachment %Buffer attachment - * @param texture 2D texture + * @param texture Texture * @param level Mip level * @return Reference to self (for method chaining) * @@ -534,7 +525,21 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * @fn_gl2{FramebufferTexture2D,FramebufferTexture} or * @fn_gl_extension{NamedFramebufferTexture2D,EXT,direct_state_access} */ - Framebuffer& attachTexture2D(BufferAttachment attachment, Texture2D& texture, Int level); + Framebuffer& attachTexture(BufferAttachment attachment, Texture2D& texture, Int level); + + #ifndef MAGNUM_TARGET_GLES + /** @overload + * @requires_gl31 %Extension @extension{ARB,texture_rectangle} + * @requires_gl Rectangle textures are not available in OpenGL ES. + */ + Framebuffer& attachTexture(BufferAttachment attachment, RectangleTexture& texture, Int level); + + /** @overload + * @requires_gl32 %Extension @extension{ARB,texture_multisample} + * @requires_gl Multisample textures are not available in OpenGL ES. + */ + Framebuffer& attachTexture(BufferAttachment attachment, MultisampleTexture2D& texture, Int level); + #endif /** * @brief Attach cube map texture to given buffer @@ -551,31 +556,82 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje * @fn_gl2{FramebufferTexture2D,FramebufferTexture} or * @fn_gl_extension{NamedFramebufferTexture2D,EXT,direct_state_access} */ - Framebuffer& attachCubeMapTexture(BufferAttachment attachment, CubeMapTexture& texture, CubeMapTexture::Coordinate coordinate, Int level) { - (this->*texture2DImplementation)(attachment, GLenum(coordinate), texture.id(), level); - return *this; - } + Framebuffer& attachCubeMapTexture(BufferAttachment attachment, CubeMapTexture& texture, CubeMapTexture::Coordinate coordinate, Int level); /** - * @brief Attach 3D texture to given buffer + * @brief Attach texture layer to given buffer * @param attachment %Buffer attachment - * @param texture 3D texture + * @param texture Texture * @param level Mip level - * @param layer Layer of 2D image within a 3D texture + * @param layer Layer * @return Reference to self (for method chaining) * * If @extension{EXT,direct_state_access} is not available and the * framebufferbuffer is not currently bound, it is bound before the * operation. - * @see @fn_gl{BindFramebuffer}, @fn_gl2{FramebufferTexture3D,FramebufferTexture} - * or @fn_gl_extension{NamedFramebufferTexture3D,EXT,direct_state_access} - * @requires_es_extension %Extension @es_extension{OES,texture_3D} + * @see @fn_gl{BindFramebuffer}, @fn_gl2{FramebufferTextureLayer,FramebufferTexture} + * or @fn_gl_extension{NamedFramebufferTextureLayer,EXT,direct_state_access}, + * @fn_gles_extension{FramebufferTexture3D,OES,texture_3D} in OpenGL ES 2.0 + * @requires_gles30 %Extension @es_extension{OES,texture_3D} in OpenGL + * ES 2.0 + */ + Framebuffer& attachTextureLayer(BufferAttachment attachment, Texture3D& texture, Int level, Int layer); + + #ifndef MAGNUM_TARGET_GLES + /** @overload + * @requires_gl30 %Extension @extension{EXT,texture_array} + * @requires_gl Only 2D array textures are available in OpenGL ES. + */ + Framebuffer& attachTextureLayer(BufferAttachment attachment, Texture1DArray& texture, Int level, Int layer); + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** @overload + * @requires_gl30 %Extension @extension{EXT,texture_array} + * @requires_gles30 %Array textures are not available in OpenGL ES 2.0 + */ + Framebuffer& attachTextureLayer(BufferAttachment attachment, Texture2DArray& texture, Int level, Int layer); + #endif + + #ifndef MAGNUM_TARGET_GLES + /** @overload + * @requires_gl40 %Extension @extension{ARB,texture_cube_map_array} + * @requires_gl Cube map texture arrays are not available in OpenGL ES. + */ + Framebuffer& attachTextureLayer(BufferAttachment attachment, CubeMapTextureArray& texture, Int level, Int layer); + + /** @overload + * @requires_gl32 %Extension @extension{ARB,texture_multisample} + * @requires_gl Multisample textures are not available in OpenGL ES. + */ + Framebuffer& attachTextureLayer(BufferAttachment attachment, MultisampleTexture2DArray& texture, Int level, Int layer); + #endif + + #ifdef MAGNUM_BUILD_DEPRECATED + #ifndef MAGNUM_TARGET_GLES + /** + * @copybrief attachTexture() + * @deprecated Use one of @ref Magnum::Framebuffer::attachTexture() "attachTexture()" overloads instead. + */ + Framebuffer& attachTexture1D(BufferAttachment attachment, Texture1D& texture, Int level) { + return attachTexture(attachment, texture, level); + } + #endif + + /** + * @copybrief attachTexture() + * @deprecated Use one of @ref Magnum::Framebuffer::attachTexture() "attachTexture()" overloads instead. + */ + Framebuffer& attachTexture2D(BufferAttachment attachment, Texture2D& texture, Int level); + + /** + * @copybrief attachTextureLayer() + * @deprecated Use one of @ref Magnum::Framebuffer::attachTextureLayer() "attachTextureLayer()" overloads instead. */ Framebuffer& attachTexture3D(BufferAttachment attachment, Texture3D& texture, Int level, Int layer) { - /** @todo Check for texture target compatibility */ - (this->*texture3DImplementation)(attachment, texture, level, layer); - return *this; + return attachTextureLayer(attachment, texture, level, layer); } + #endif /* Overloads to remove WTF-factor from method chaining order */ #ifndef DOXYGEN_GENERATING_OUTPUT @@ -586,35 +642,25 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractObje #endif private: - static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context); - - typedef void(Framebuffer::*RenderbufferImplementation)(BufferAttachment, Renderbuffer&); void MAGNUM_LOCAL renderbufferImplementationDefault(BufferAttachment attachment, Renderbuffer& renderbuffer); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL renderbufferImplementationDSA(BufferAttachment attachment, Renderbuffer& renderbuffer); #endif - static RenderbufferImplementation renderbufferImplementation; #ifndef MAGNUM_TARGET_GLES - typedef void(Framebuffer::*Texture1DImplementation)(BufferAttachment, Texture1D&, GLint); - void MAGNUM_LOCAL texture1DImplementationDefault(BufferAttachment attachment, Texture1D& texture, GLint level); - void MAGNUM_LOCAL texture1DImplementationDSA(BufferAttachment attachment, Texture1D& texture, GLint level); - static Texture1DImplementation texture1DImplementation; + void MAGNUM_LOCAL texture1DImplementationDefault(BufferAttachment attachment, GLuint textureId, GLint level); + void MAGNUM_LOCAL texture1DImplementationDSA(BufferAttachment attachment, GLuint textureId, GLint level); #endif - typedef void(Framebuffer::*Texture2DImplementation)(BufferAttachment, GLenum, GLuint, GLint); void MAGNUM_LOCAL texture2DImplementationDefault(BufferAttachment attachment, GLenum textureTarget, GLuint textureId, GLint level); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL texture2DImplementationDSA(BufferAttachment attachment, GLenum textureTarget, GLuint textureId, GLint level); #endif - static Texture2DImplementation texture2DImplementation; - typedef void(Framebuffer::*Texture3DImplementation)(BufferAttachment, Texture3D&, GLint, GLint); - void MAGNUM_LOCAL texture3DImplementationDefault(BufferAttachment attachment, Texture3D& texture, GLint level, GLint layer); + void MAGNUM_LOCAL textureLayerImplementationDefault(BufferAttachment attachment, GLuint textureId, GLint level, GLint layer); #ifndef MAGNUM_TARGET_GLES - void MAGNUM_LOCAL texture3DImplementationDSA(BufferAttachment attachment, Texture3D& texture, GLint level, GLint layer); + void MAGNUM_LOCAL textureLayerImplementationDSA(BufferAttachment attachment, GLuint textureId, GLint level, GLint layer); #endif - static Texture3DImplementation texture3DImplementation; }; /** @debugoperator{DefaultFramebuffer} */ diff --git a/src/Magnum/Implementation/BufferState.cpp b/src/Magnum/Implementation/BufferState.cpp index 2c6fda44b..6be8f2945 100644 --- a/src/Magnum/Implementation/BufferState.cpp +++ b/src/Magnum/Implementation/BufferState.cpp @@ -27,6 +27,9 @@ #include +#include "Magnum/Context.h" +#include "Magnum/Extensions.h" + namespace Magnum { namespace Implementation { const Buffer::Target BufferState::targetForIndex[] = { @@ -75,4 +78,62 @@ std::size_t BufferState::indexForTarget(Buffer::Target target) { CORRADE_ASSERT_UNREACHABLE(); } +BufferState::BufferState(Context& context, std::vector& extensions): bindings() + #ifndef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES + , minMapAlignment(0), maxAtomicCounterBindings(0), maxShaderStorageBindings(0), shaderStorageOffsetAlignment(0) + #endif + , maxUniformBindings(0) + #endif +{ + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::EXT::direct_state_access::string()); + + copyImplementation = &Buffer::copyImplementationDSA; + getParameterImplementation = &Buffer::getParameterImplementationDSA; + getSubDataImplementation = &Buffer::getSubDataImplementationDSA; + dataImplementation = &Buffer::dataImplementationDSA; + subDataImplementation = &Buffer::subDataImplementationDSA; + mapImplementation = &Buffer::mapImplementationDSA; + mapRangeImplementation = &Buffer::mapRangeImplementationDSA; + flushMappedRangeImplementation = &Buffer::flushMappedRangeImplementationDSA; + unmapImplementation = &Buffer::unmapImplementationDSA; + } else + #endif + { + #ifndef MAGNUM_TARGET_GLES2 + copyImplementation = &Buffer::copyImplementationDefault; + #endif + getParameterImplementation = &Buffer::getParameterImplementationDefault; + #ifndef MAGNUM_TARGET_GLES + getSubDataImplementation = &Buffer::getSubDataImplementationDefault; + #endif + dataImplementation = &Buffer::dataImplementationDefault; + subDataImplementation = &Buffer::subDataImplementationDefault; + mapImplementation = &Buffer::mapImplementationDefault; + mapRangeImplementation = &Buffer::mapRangeImplementationDefault; + flushMappedRangeImplementation = &Buffer::flushMappedRangeImplementationDefault; + unmapImplementation = &Buffer::unmapImplementationDefault; + } + + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::ARB::invalidate_subdata::string()); + + invalidateImplementation = &Buffer::invalidateImplementationARB; + invalidateSubImplementation = &Buffer::invalidateSubImplementationARB; + } else + #endif + { + invalidateImplementation = &Buffer::invalidateImplementationNoOp; + invalidateSubImplementation = &Buffer::invalidateSubImplementationNoOp; + } + + #ifdef MAGNUM_TARGET_GLES + static_cast(context); + static_cast(extensions); + #endif +} + }} diff --git a/src/Magnum/Implementation/BufferState.h b/src/Magnum/Implementation/BufferState.h index e45b5998e..4e16abb18 100644 --- a/src/Magnum/Implementation/BufferState.h +++ b/src/Magnum/Implementation/BufferState.h @@ -44,14 +44,23 @@ struct BufferState { static std::size_t indexForTarget(Buffer::Target target); static const Buffer::Target targetForIndex[TargetCount-1]; - constexpr BufferState(): bindings() - #ifndef MAGNUM_TARGET_GLES2 - #ifndef MAGNUM_TARGET_GLES - , minMapAlignment(0), maxAtomicCounterBindings(0), maxShaderStorageBindings(0), shaderStorageOffsetAlignment(0) - #endif - , maxUniformBindings(0) - #endif - {} + explicit BufferState(Context& context, std::vector& extensions); + + #ifndef MAGNUM_TARGET_GLES2 + void(*copyImplementation)(Buffer&, Buffer&, GLintptr, GLintptr, GLsizeiptr); + #endif + void(Buffer::*getParameterImplementation)(GLenum, GLint*); + #ifndef MAGNUM_TARGET_GLES2 + void(Buffer::*getSubDataImplementation)(GLintptr, GLsizeiptr, GLvoid*); + #endif + void(Buffer::*dataImplementation)(GLsizeiptr, const GLvoid*, BufferUsage); + void(Buffer::*subDataImplementation)(GLintptr, GLsizeiptr, const GLvoid*); + void(Buffer::*invalidateImplementation)(); + void(Buffer::*invalidateSubImplementation)(GLintptr, GLsizeiptr); + void*(Buffer::*mapImplementation)(Buffer::MapAccess); + void*(Buffer::*mapRangeImplementation)(GLintptr, GLsizeiptr, Buffer::MapFlags); + void(Buffer::*flushMappedRangeImplementation)(GLintptr, GLsizeiptr); + bool(Buffer::*unmapImplementation)(); /* Currently bound buffer for all targets */ GLuint bindings[TargetCount]; diff --git a/src/Magnum/Implementation/DebugState.cpp b/src/Magnum/Implementation/DebugState.cpp index 1e514ac54..f030a8689 100644 --- a/src/Magnum/Implementation/DebugState.cpp +++ b/src/Magnum/Implementation/DebugState.cpp @@ -31,8 +31,10 @@ namespace Magnum { namespace Implementation { -DebugState::DebugState(Context& context): maxLabelLength(0), maxLoggedMessages(0), maxMessageLength(0), messageCallback(nullptr) { +DebugState::DebugState(Context& context, std::vector& extensions): maxLabelLength(0), maxLoggedMessages(0), maxMessageLength(0), messageCallback(nullptr) { if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::KHR::debug::string()); + getLabelImplementation = &AbstractObject::getLabelImplementationKhr; labelImplementation = &AbstractObject::labelImplementationKhr; messageInsertImplementation = &DebugMessage::insertImplementationKhr; @@ -40,6 +42,8 @@ DebugState::DebugState(Context& context): maxLabelLength(0), maxLoggedMessages(0 } else { if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::EXT::debug_label::string()); + getLabelImplementation = &AbstractObject::getLabelImplementationExt; labelImplementation = &AbstractObject::labelImplementationExt; } else { @@ -47,14 +51,17 @@ DebugState::DebugState(Context& context): maxLabelLength(0), maxLoggedMessages(0 labelImplementation = &AbstractObject::labelImplementationNoOp; } - if(context.isExtensionSupported()) + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::EXT::debug_marker::string()); + messageInsertImplementation = &DebugMessage::insertImplementationExt; #ifndef MAGNUM_TARGET_GLES - else if(context.isExtensionSupported()) + } else if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::GREMEDY::string_marker::string()); + messageInsertImplementation = &DebugMessage::insertImplementationGremedy; #endif - else - messageInsertImplementation = &DebugMessage::insertImplementationNoOp; + } else messageInsertImplementation = &DebugMessage::insertImplementationNoOp; messageCallbackImplementation = &DebugMessage::callbackImplementationNoOp; } diff --git a/src/Magnum/Implementation/DebugState.h b/src/Magnum/Implementation/DebugState.h index 95955e1c2..a435e1b20 100644 --- a/src/Magnum/Implementation/DebugState.h +++ b/src/Magnum/Implementation/DebugState.h @@ -26,13 +26,14 @@ */ #include +#include #include "Magnum/DebugMessage.h" namespace Magnum { namespace Implementation { struct DebugState { - DebugState(Context& context); + explicit DebugState(Context& context, std::vector& extensions); std::string(*getLabelImplementation)(GLenum, GLuint); void(*labelImplementation)(GLenum, GLuint, const std::string&); diff --git a/src/Magnum/Implementation/FramebufferState.cpp b/src/Magnum/Implementation/FramebufferState.cpp new file mode 100644 index 000000000..4b6a99803 --- /dev/null +++ b/src/Magnum/Implementation/FramebufferState.cpp @@ -0,0 +1,141 @@ +/* + 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 "FramebufferState.h" + +#include "Magnum/Context.h" +#include "Magnum/Extensions.h" +#include "Magnum/Renderbuffer.h" + +namespace Magnum { namespace Implementation { + +FramebufferState::FramebufferState(Context& context, std::vector& extensions): readBinding(0), drawBinding(0), renderbufferBinding(0), maxDrawBuffers(0), maxColorAttachments(0), maxRenderbufferSize(0), maxSamples(0) + #ifndef MAGNUM_TARGET_GLES + , maxDualSourceDrawBuffers(0) + #endif +{ + /* DSA/non-DSA implementation */ + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::EXT::direct_state_access::string()); + + checkStatusImplementation = &AbstractFramebuffer::checkStatusImplementationDSA; + drawBuffersImplementation = &AbstractFramebuffer::drawBuffersImplementationDSA; + drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDSA; + readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDSA; + + renderbufferImplementation = &Framebuffer::renderbufferImplementationDSA; + texture1DImplementation = &Framebuffer::texture1DImplementationDSA; + texture2DImplementation = &Framebuffer::texture2DImplementationDSA; + textureLayerImplementation = &Framebuffer::textureLayerImplementationDSA; + + renderbufferStorageImplementation = &Renderbuffer::storageImplementationDSA; + } else + #endif + { + checkStatusImplementation = &AbstractFramebuffer::checkStatusImplementationDefault; + drawBuffersImplementation = &AbstractFramebuffer::drawBuffersImplementationDefault; + drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDefault; + readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDefault; + + renderbufferImplementation = &Framebuffer::renderbufferImplementationDefault; + #ifndef MAGNUM_TARGET_GLES + texture1DImplementation = &Framebuffer::texture1DImplementationDefault; + #endif + texture2DImplementation = &Framebuffer::texture2DImplementationDefault; + textureLayerImplementation = &Framebuffer::textureLayerImplementationDefault; + + renderbufferStorageImplementation = &Renderbuffer::storageImplementationDefault; + } + + /* Framebuffer binding on ES2 */ + #ifdef MAGNUM_TARGET_GLES2 + /* Optimistically set separate binding targets and check if one of the + extensions providing them is available */ + readTarget = FramebufferTarget::Read; + drawTarget = FramebufferTarget::Draw; + + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::ANGLE::framebuffer_blit::string()); + + } else if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::APPLE::framebuffer_multisample::string()); + + } else if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::NV::framebuffer_blit::string()); + + /* NV_framebuffer_multisample requires NV_framebuffer_blit, which has these + enums. However, on my system only NV_framebuffer_multisample is + supported, but NV_framebuffer_blit isn't. I will hold my breath and + assume these enums are available. */ + } else if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::NV::framebuffer_multisample::string()); + + /* If no such extension is available, reset back to unified target */ + } else readTarget = drawTarget = FramebufferTarget::ReadDraw; + #endif + + /* Framebuffer reading implementation */ + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) + #else + if(context.isExtensionSupported()) + #endif + { + #ifndef MAGNUM_TARGET_GLES + extensions.push_back(Extensions::GL::ARB::robustness::string()); + #else + extensions.push_back(Extensions::GL::EXT::robustness::string()); + #endif + + readImplementation = &AbstractFramebuffer::readImplementationRobustness; + } else readImplementation = &AbstractFramebuffer::readImplementationDefault; + + /* Multisample renderbuffer storage implementation */ + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) { + /* Extension added above */ + + renderbufferStorageMultisampleImplementation = &Renderbuffer::storageMultisampleImplementationDSA; + } else + #endif + { + #ifdef MAGNUM_TARGET_GLES2 + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::ANGLE::framebuffer_multisample::string()); + + renderbufferStorageMultisampleImplementation = &Renderbuffer::storageMultisampleImplementationANGLE; + } else if (context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::NV::framebuffer_multisample::string()); + + renderbufferStorageMultisampleImplementation = &Renderbuffer::storageMultisampleImplementationNV; + } else renderbufferStorageMultisampleImplementation = nullptr; + #else + renderbufferStorageMultisampleImplementation = &Renderbuffer::storageMultisampleImplementationDefault; + #endif + } +} + +}} diff --git a/src/Magnum/Implementation/FramebufferState.h b/src/Magnum/Implementation/FramebufferState.h index b3556f8b0..f8ecde63c 100644 --- a/src/Magnum/Implementation/FramebufferState.h +++ b/src/Magnum/Implementation/FramebufferState.h @@ -25,18 +25,34 @@ DEALINGS IN THE SOFTWARE. */ -#include "Magnum/Magnum.h" -#include "Magnum/OpenGL.h" -#include "Magnum/Math/Range.h" +#include +#include + +#include "Magnum/Framebuffer.h" namespace Magnum { namespace Implementation { struct FramebufferState { - constexpr FramebufferState(): readBinding(0), drawBinding(0), renderbufferBinding(0), maxDrawBuffers(0), maxColorAttachments(0), maxRenderbufferSize(0), maxSamples(0) - #ifndef MAGNUM_TARGET_GLES - , maxDualSourceDrawBuffers(0) - #endif - {} + explicit FramebufferState(Context& context, std::vector& extensions); + + GLenum(AbstractFramebuffer::*checkStatusImplementation)(FramebufferTarget); + void(AbstractFramebuffer::*drawBuffersImplementation)(GLsizei, const GLenum*); + void(AbstractFramebuffer::*drawBufferImplementation)(GLenum); + void(AbstractFramebuffer::*readBufferImplementation)(GLenum); + + void(Framebuffer::*renderbufferImplementation)(Framebuffer::BufferAttachment, Renderbuffer&); + #ifndef MAGNUM_TARGET_GLES + void(Framebuffer::*texture1DImplementation)(Framebuffer::BufferAttachment, GLuint, GLint); + #endif + void(Framebuffer::*texture2DImplementation)(Framebuffer::BufferAttachment, GLenum, GLuint, GLint); + void(Framebuffer::*textureLayerImplementation)(Framebuffer::BufferAttachment, GLuint, GLint, GLint); + + void(Renderbuffer::*renderbufferStorageImplementation)(RenderbufferFormat, const Vector2i&); + void(Renderbuffer::*renderbufferStorageMultisampleImplementation)(GLsizei, RenderbufferFormat, const Vector2i&); + + void(*readImplementation)(const Vector2i&, const Vector2i&, ColorFormat, ColorType, std::size_t, GLvoid*); + + FramebufferTarget readTarget, drawTarget; GLuint readBinding, drawBinding, renderbufferBinding; GLint maxDrawBuffers, maxColorAttachments, maxRenderbufferSize, maxSamples; diff --git a/src/Magnum/Implementation/MeshState.cpp b/src/Magnum/Implementation/MeshState.cpp new file mode 100644 index 000000000..3c9ac875a --- /dev/null +++ b/src/Magnum/Implementation/MeshState.cpp @@ -0,0 +1,97 @@ +/* + 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 "MeshState.h" + +#include "Magnum/Context.h" +#include "Magnum/Extensions.h" + +namespace Magnum { namespace Implementation { + +MeshState::MeshState(Context& context, std::vector& extensions): currentVAO(0) + #ifndef MAGNUM_TARGET_GLES2 + , maxElementsIndices(0), maxElementsVertices(0) + #endif +{ + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) + #elif defined(MAGNUM_TARGET_GLES2) + if(context.isExtensionSupported()) + #else + static_cast(context); + static_cast(extensions); + #endif + { + #ifndef MAGNUM_TARGET_GLES + extensions.push_back(Extensions::GL::APPLE::vertex_array_object::string()); + #elif defined(MAGNUM_TARGET_GLES2) + extensions.push_back(Extensions::GL::OES::vertex_array_object::string()); + #endif + + createImplementation = &Mesh::createImplementationVAO; + destroyImplementation = &Mesh::destroyImplementationVAO; + + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::EXT::direct_state_access::string()); + + attributePointerImplementation = &Mesh::attributePointerImplementationDSA; + attributeIPointerImplementation = &Mesh::attributePointerImplementationDSA; + attributeLPointerImplementation = &Mesh::attributePointerImplementationDSA; + } else + #endif + { + attributePointerImplementation = &Mesh::attributePointerImplementationVAO; + #ifndef MAGNUM_TARGET_GLES2 + attributeIPointerImplementation = &Mesh::attributePointerImplementationVAO; + #ifndef MAGNUM_TARGET_GLES + attributeLPointerImplementation = &Mesh::attributePointerImplementationVAO; + #endif + #endif + } + + bindIndexBufferImplementation = &Mesh::bindIndexBufferImplementationVAO; + bindImplementation = &Mesh::bindImplementationVAO; + unbindImplementation = &Mesh::unbindImplementationVAO; + } + #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES2) + else { + createImplementation = &Mesh::createImplementationDefault; + destroyImplementation = &Mesh::destroyImplementationDefault; + attributePointerImplementation = &Mesh::attributePointerImplementationDefault; + #ifndef MAGNUM_TARGET_GLES2 + attributeIPointerImplementation = &Mesh::attributePointerImplementationDefault; + #ifndef MAGNUM_TARGET_GLES + attributeLPointerImplementation = &Mesh::attributePointerImplementationDefault; + #endif + #endif + bindIndexBufferImplementation = &Mesh::bindIndexBufferImplementationDefault; + bindImplementation = &Mesh::bindImplementationDefault; + unbindImplementation = &Mesh::unbindImplementationDefault; + } + #endif +} + +}} diff --git a/src/Magnum/Implementation/MeshState.h b/src/Magnum/Implementation/MeshState.h index f13964970..ea4885b4f 100644 --- a/src/Magnum/Implementation/MeshState.h +++ b/src/Magnum/Implementation/MeshState.h @@ -25,16 +25,28 @@ DEALINGS IN THE SOFTWARE. */ -#include "Magnum/Magnum.h" +#include +#include + +#include "Magnum/Mesh.h" namespace Magnum { namespace Implementation { struct MeshState { - constexpr MeshState(): currentVAO(0) - #ifndef MAGNUM_TARGET_GLES2 - , maxElementsIndices(0), maxElementsVertices(0) - #endif - {} + explicit MeshState(Context& context, std::vector& extensions); + + void(Mesh::*createImplementation)(); + void(Mesh::*destroyImplementation)(); + void(Mesh::*attributePointerImplementation)(const Mesh::Attribute&); + #ifndef MAGNUM_TARGET_GLES2 + void(Mesh::*attributeIPointerImplementation)(const Mesh::IntegerAttribute&); + #ifndef MAGNUM_TARGET_GLES + void(Mesh::*attributeLPointerImplementation)(const Mesh::LongAttribute&); + #endif + #endif + void(Mesh::*bindIndexBufferImplementation)(Buffer&); + void(Mesh::*bindImplementation)(); + void(Mesh::*unbindImplementation)(); GLuint currentVAO; #ifndef MAGNUM_TARGET_GLES2 diff --git a/src/Magnum/Implementation/RendererState.cpp b/src/Magnum/Implementation/RendererState.cpp new file mode 100644 index 000000000..13fc2dc7d --- /dev/null +++ b/src/Magnum/Implementation/RendererState.cpp @@ -0,0 +1,66 @@ +/* + 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 "RendererState.h" + +#include "Magnum/Context.h" +#include "Magnum/Extensions.h" + +namespace Magnum { namespace Implementation { + +RendererState::RendererState(Context& context, std::vector& extensions): resetNotificationStrategy() { + /* Float depth clear value implementation */ + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) + #endif + { + #ifndef MAGNUM_TARGET_GLES + extensions.push_back(Extensions::GL::ARB::ES2_compatibility::string()); + #endif + + clearDepthfImplementation = &Renderer::clearDepthfImplementationES; + } + #ifndef MAGNUM_TARGET_GLES + else clearDepthfImplementation = &Renderer::clearDepthfImplementationDefault; + #endif + + /* Graphics reset status implementation */ + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) + #else + if(context.isExtensionSupported()) + #endif + { + #ifndef MAGNUM_TARGET_GLES + extensions.push_back(Extensions::GL::ARB::robustness::string()); + #else + extensions.push_back(Extensions::GL::EXT::robustness::string()); + #endif + + graphicsResetStatusImplementation = &Renderer::graphicsResetStatusImplementationRobustness; + } else graphicsResetStatusImplementation = &Renderer::graphicsResetStatusImplementationDefault; +} + +}} diff --git a/src/Magnum/Implementation/RendererState.h b/src/Magnum/Implementation/RendererState.h index 962fa0587..33483e632 100644 --- a/src/Magnum/Implementation/RendererState.h +++ b/src/Magnum/Implementation/RendererState.h @@ -25,12 +25,18 @@ DEALINGS IN THE SOFTWARE. */ +#include +#include + #include "Magnum/Renderer.h" namespace Magnum { namespace Implementation { struct RendererState { - constexpr RendererState(): resetNotificationStrategy() {} + explicit RendererState(Context& context, std::vector& extensions); + + void(*clearDepthfImplementation)(GLfloat); + Renderer::GraphicsResetStatus(*graphicsResetStatusImplementation)(); Renderer::ResetNotificationStrategy resetNotificationStrategy; }; diff --git a/src/Magnum/Implementation/ShaderProgramState.cpp b/src/Magnum/Implementation/ShaderProgramState.cpp new file mode 100644 index 000000000..3e375e8c0 --- /dev/null +++ b/src/Magnum/Implementation/ShaderProgramState.cpp @@ -0,0 +1,188 @@ +/* + 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 "ShaderProgramState.h" + +#include "Magnum/AbstractShaderProgram.h" +#include "Magnum/Context.h" +#include "Magnum/Extensions.h" + +namespace Magnum { namespace Implementation { + +ShaderProgramState::ShaderProgramState(Context& context, std::vector& extensions): current(0), maxVertexAttributes(0) + #ifndef MAGNUM_TARGET_GLES + , maxAtomicCounterBufferSize(0), maxComputeSharedMemorySize(0), maxComputeWorkGroupInvocations(0), maxImageUnits(0), maxImageSamples(0), maxCombinedShaderOutputResources(0), maxUniformLocations(0), maxShaderStorageBlockSize(0) + #endif + #ifndef MAGNUM_TARGET_GLES2 + , minTexelOffset(0), maxTexelOffset(0), maxUniformBlockSize(0) + #endif +{ + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) + #else + if(context.isExtensionSupported()) + #endif + { + #ifndef MAGNUM_TARGET_GLES + extensions.push_back(Extensions::GL::ARB::separate_shader_objects::string()); + #else + extensions.push_back(Extensions::GL::EXT::separate_shader_objects::string()); + #endif + + uniform1fvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniform2fvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniform3fvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniform4fvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniform1ivImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniform2ivImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniform3ivImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniform4ivImplementation = &AbstractShaderProgram::uniformImplementationSSO; + #ifndef MAGNUM_TARGET_GLES2 + uniform1uivImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniform2uivImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniform3uivImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniform4uivImplementation = &AbstractShaderProgram::uniformImplementationSSO; + #endif + #ifndef MAGNUM_TARGET_GLES + uniform1dvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniform2dvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniform3dvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniform4dvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + #endif + + uniformMatrix2fvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniformMatrix3fvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniformMatrix4fvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + #ifndef MAGNUM_TARGET_GLES2 + uniformMatrix2x3fvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniformMatrix3x2fvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniformMatrix2x4fvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniformMatrix4x2fvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniformMatrix3x4fvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniformMatrix4x3fvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + #endif + #ifndef MAGNUM_TARGET_GLES + uniformMatrix2dvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniformMatrix3dvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniformMatrix4dvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniformMatrix2x3dvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniformMatrix3x2dvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniformMatrix2x4dvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniformMatrix4x2dvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniformMatrix3x4dvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + uniformMatrix4x3dvImplementation = &AbstractShaderProgram::uniformImplementationSSO; + #endif + } + + #ifndef MAGNUM_TARGET_GLES + else if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::EXT::direct_state_access::string()); + + uniform1fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniform2fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniform3fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniform4fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniform1ivImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniform2ivImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniform3ivImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniform4ivImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniform1uivImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniform2uivImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniform3uivImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniform4uivImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniform1dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniform2dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniform3dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniform4dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + + uniformMatrix2fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniformMatrix3fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniformMatrix4fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniformMatrix2x3fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniformMatrix3x2fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniformMatrix2x4fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniformMatrix4x2fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniformMatrix3x4fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniformMatrix4x3fvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniformMatrix2dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniformMatrix3dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniformMatrix4dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniformMatrix2x3dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniformMatrix3x2dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniformMatrix2x4dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniformMatrix4x2dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniformMatrix3x4dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + uniformMatrix4x3dvImplementation = &AbstractShaderProgram::uniformImplementationDSA; + } + #endif + + else { + uniform1fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniform2fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniform3fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniform4fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniform1ivImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniform2ivImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniform3ivImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniform4ivImplementation = &AbstractShaderProgram::uniformImplementationDefault; + #ifndef MAGNUM_TARGET_GLES2 + uniform1uivImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniform2uivImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniform3uivImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniform4uivImplementation = &AbstractShaderProgram::uniformImplementationDefault; + #endif + #ifndef MAGNUM_TARGET_GLES + uniform1dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniform2dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniform3dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniform4dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + #endif + + uniformMatrix2fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniformMatrix3fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniformMatrix4fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + #ifndef MAGNUM_TARGET_GLES2 + uniformMatrix2x3fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniformMatrix3x2fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniformMatrix2x4fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniformMatrix4x2fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniformMatrix3x4fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniformMatrix4x3fvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + #endif + #ifndef MAGNUM_TARGET_GLES + uniformMatrix2dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniformMatrix3dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniformMatrix4dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniformMatrix2x3dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniformMatrix3x2dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniformMatrix2x4dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniformMatrix4x2dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniformMatrix3x4dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + uniformMatrix4x3dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; + #endif + } +} + +}} diff --git a/src/Magnum/Implementation/ShaderProgramState.h b/src/Magnum/Implementation/ShaderProgramState.h index 477b85992..d2113052e 100644 --- a/src/Magnum/Implementation/ShaderProgramState.h +++ b/src/Magnum/Implementation/ShaderProgramState.h @@ -25,19 +25,60 @@ DEALINGS IN THE SOFTWARE. */ +#include +#include + +#include "Magnum/Magnum.h" #include "Magnum/OpenGL.h" namespace Magnum { namespace Implementation { struct ShaderProgramState { - constexpr ShaderProgramState(): current(0), maxVertexAttributes(0) - #ifndef MAGNUM_TARGET_GLES - , maxAtomicCounterBufferSize(0), maxComputeSharedMemorySize(0), maxComputeWorkGroupInvocations(0), maxImageUnits(0), maxImageSamples(0), maxCombinedShaderOutputResources(0), maxUniformLocations(0), maxShaderStorageBlockSize(0) - #endif - #ifndef MAGNUM_TARGET_GLES2 - , minTexelOffset(0), maxTexelOffset(0), maxUniformBlockSize(0) - #endif - {} + explicit ShaderProgramState(Context& context, std::vector& extensions); + + void(AbstractShaderProgram::*uniform1fvImplementation)(GLint, GLsizei, const GLfloat*); + void(AbstractShaderProgram::*uniform2fvImplementation)(GLint, GLsizei, const Math::Vector<2, GLfloat>*); + void(AbstractShaderProgram::*uniform3fvImplementation)(GLint, GLsizei, const Math::Vector<3, GLfloat>*); + void(AbstractShaderProgram::*uniform4fvImplementation)(GLint, GLsizei, const Math::Vector<4, GLfloat>*); + void(AbstractShaderProgram::*uniform1ivImplementation)(GLint, GLsizei, const GLint*); + void(AbstractShaderProgram::*uniform2ivImplementation)(GLint, GLsizei, const Math::Vector<2, GLint>*); + void(AbstractShaderProgram::*uniform3ivImplementation)(GLint, GLsizei, const Math::Vector<3, GLint>*); + void(AbstractShaderProgram::*uniform4ivImplementation)(GLint, GLsizei, const Math::Vector<4, GLint>*); + #ifndef MAGNUM_TARGET_GLES2 + void(AbstractShaderProgram::*uniform1uivImplementation)(GLint, GLsizei, const GLuint*); + void(AbstractShaderProgram::*uniform2uivImplementation)(GLint, GLsizei, const Math::Vector<2, GLuint>*); + void(AbstractShaderProgram::*uniform3uivImplementation)(GLint, GLsizei, const Math::Vector<3, GLuint>*); + void(AbstractShaderProgram::*uniform4uivImplementation)(GLint, GLsizei, const Math::Vector<4, GLuint>*); + #endif + #ifndef MAGNUM_TARGET_GLES + void(AbstractShaderProgram::*uniform1dvImplementation)(GLint, GLsizei, const GLdouble*); + void(AbstractShaderProgram::*uniform2dvImplementation)(GLint, GLsizei, const Math::Vector<2, GLdouble>*); + void(AbstractShaderProgram::*uniform3dvImplementation)(GLint, GLsizei, const Math::Vector<3, GLdouble>*); + void(AbstractShaderProgram::*uniform4dvImplementation)(GLint, GLsizei, const Math::Vector<4, GLdouble>*); + #endif + + void(AbstractShaderProgram::*uniformMatrix2fvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<2, 2, GLfloat>*); + void(AbstractShaderProgram::*uniformMatrix3fvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<3, 3, GLfloat>*); + void(AbstractShaderProgram::*uniformMatrix4fvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<4, 4, GLfloat>*); + #ifndef MAGNUM_TARGET_GLES2 + void(AbstractShaderProgram::*uniformMatrix2x3fvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<2, 3, GLfloat>*); + void(AbstractShaderProgram::*uniformMatrix3x2fvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<3, 2, GLfloat>*); + void(AbstractShaderProgram::*uniformMatrix2x4fvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<2, 4, GLfloat>*); + void(AbstractShaderProgram::*uniformMatrix4x2fvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<4, 2, GLfloat>*); + void(AbstractShaderProgram::*uniformMatrix3x4fvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<3, 4, GLfloat>*); + void(AbstractShaderProgram::*uniformMatrix4x3fvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<4, 3, GLfloat>*); + #endif + #ifndef MAGNUM_TARGET_GLES + void(AbstractShaderProgram::*uniformMatrix2dvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<2, 2, GLdouble>*); + void(AbstractShaderProgram::*uniformMatrix3dvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<3, 3, GLdouble>*); + void(AbstractShaderProgram::*uniformMatrix4dvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<4, 4, GLdouble>*); + void(AbstractShaderProgram::*uniformMatrix2x3dvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<2, 3, GLdouble>*); + void(AbstractShaderProgram::*uniformMatrix3x2dvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<3, 2, GLdouble>*); + void(AbstractShaderProgram::*uniformMatrix2x4dvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<2, 4, GLdouble>*); + void(AbstractShaderProgram::*uniformMatrix4x2dvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<4, 2, GLdouble>*); + void(AbstractShaderProgram::*uniformMatrix3x4dvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<3, 4, GLdouble>*); + void(AbstractShaderProgram::*uniformMatrix4x3dvImplementation)(GLint, GLsizei, const Math::RectangularMatrix<4, 3, GLdouble>*); + #endif /* Currently used program */ GLuint current; diff --git a/src/Magnum/Implementation/State.cpp b/src/Magnum/Implementation/State.cpp index 015773280..82354e734 100644 --- a/src/Magnum/Implementation/State.cpp +++ b/src/Magnum/Implementation/State.cpp @@ -25,6 +25,8 @@ #include "State.h" +#include + #include "Magnum/Context.h" #include "Magnum/Extensions.h" @@ -39,32 +41,31 @@ namespace Magnum { namespace Implementation { -State::State(Context& context): - buffer(new BufferState), - debug(new DebugState(context)), - framebuffer(new FramebufferState), - mesh(new MeshState), - renderer(new RendererState), - shader(new ShaderState), - shaderProgram(new ShaderProgramState), - texture(new TextureState) -{ +State::State(Context& context) { + /* List of extensions used in current context. Guesstimate count to avoid + unnecessary reallocations. */ + std::vector extensions; + #ifndef MAGNUM_TARGET_GLES + extensions.reserve(32); + #else + extensions.reserve(8); + #endif - Debug() << "Using optional features:"; + buffer = new BufferState(context, extensions); + debug = new DebugState(context, extensions); + framebuffer = new FramebufferState(context, extensions); + mesh = new MeshState(context, extensions); + renderer = new RendererState(context, extensions); + shader = new ShaderState; + shaderProgram = new ShaderProgramState(context, extensions); + texture = new TextureState(context, extensions); - if(context.isExtensionSupported()) - Debug() << " " << Extensions::GL::KHR::debug::string(); - else { - if(context.isExtensionSupported()) - Debug() << " " << Extensions::GL::EXT::debug_label::string(); + /* Sort the features and remove duplicates */ + std::sort(extensions.begin(), extensions.end()); + extensions.erase(std::unique(extensions.begin(), extensions.end()), extensions.end()); - if(context.isExtensionSupported()) - Debug() << " " << Extensions::GL::EXT::debug_marker::string(); - #ifndef MAGNUM_TARGET_GLES - else if(context.isExtensionSupported()) - Debug() << " " << Extensions::GL::GREMEDY::string_marker::string(); - #endif - } + Debug() << "Using optional features:"; + for(const auto& ext: extensions) Debug() << " " << ext; } State::~State() { diff --git a/src/Magnum/Implementation/State.h b/src/Magnum/Implementation/State.h index 61f34a546..207594cd2 100644 --- a/src/Magnum/Implementation/State.h +++ b/src/Magnum/Implementation/State.h @@ -44,14 +44,14 @@ struct State { ~State(); - BufferState* const buffer; - DebugState* const debug; - FramebufferState* const framebuffer; - MeshState* const mesh; - RendererState* const renderer; - ShaderState* const shader; - ShaderProgramState* const shaderProgram; - TextureState* const texture; + BufferState* buffer; + DebugState* debug; + FramebufferState* framebuffer; + MeshState* mesh; + RendererState* renderer; + ShaderState* shader; + ShaderProgramState* shaderProgram; + TextureState* texture; }; }} diff --git a/src/Magnum/Implementation/TextureState.cpp b/src/Magnum/Implementation/TextureState.cpp index 7f07c4664..5b9988bb4 100644 --- a/src/Magnum/Implementation/TextureState.cpp +++ b/src/Magnum/Implementation/TextureState.cpp @@ -25,13 +25,143 @@ #include "TextureState.h" +#include "Magnum/AbstractTexture.h" +#ifndef MAGNUM_TARGET_GLES +#include "Magnum/BufferTexture.h" +#endif +#include "Magnum/Context.h" +#include "Magnum/Extensions.h" + namespace Magnum { namespace Implementation { -TextureState::TextureState(): maxMaxAnisotropy(0.0f), currentLayer(0) +TextureState::TextureState(Context& context, std::vector& extensions): maxMaxAnisotropy(0.0f), currentLayer(0) #ifndef MAGNUM_TARGET_GLES , maxColorSamples(0), maxDepthSamples(0), maxIntegerSamples(0), bufferOffsetAlignment(0) #endif - {} +{ + /* DSA/non-DSA implementation */ + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::EXT::direct_state_access::string()); + + bindImplementation = &AbstractTexture::bindImplementationDSA; + parameteriImplementation = &AbstractTexture::parameterImplementationDSA; + parameterfImplementation = &AbstractTexture::parameterImplementationDSA; + parameterfvImplementation = &AbstractTexture::parameterImplementationDSA; + getLevelParameterivImplementation = &AbstractTexture::getLevelParameterImplementationDSA; + mipmapImplementation = &AbstractTexture::mipmapImplementationDSA; + getImageImplementation = &AbstractTexture::getImageImplementationDSA; + image1DImplementation = &AbstractTexture::imageImplementationDSA; + image2DImplementation = &AbstractTexture::imageImplementationDSA; + image3DImplementation = &AbstractTexture::imageImplementationDSA; + subImage1DImplementation = &AbstractTexture::subImageImplementationDSA; + subImage2DImplementation = &AbstractTexture::subImageImplementationDSA; + subImage3DImplementation = &AbstractTexture::subImageImplementationDSA; + + setBufferImplementation = &BufferTexture::setBufferImplementationDSA; + setBufferRangeImplementation = &BufferTexture::setBufferRangeImplementationDSA; + } else + #endif + { + bindImplementation = &AbstractTexture::bindImplementationDefault; + parameteriImplementation = &AbstractTexture::parameterImplementationDefault; + parameterfImplementation = &AbstractTexture::parameterImplementationDefault; + parameterfvImplementation = &AbstractTexture::parameterImplementationDefault; + #ifndef MAGNUM_TARGET_GLES + getLevelParameterivImplementation = &AbstractTexture::getLevelParameterImplementationDefault; + #endif + mipmapImplementation = &AbstractTexture::mipmapImplementationDefault; + #ifndef MAGNUM_TARGET_GLES + getImageImplementation = &AbstractTexture::getImageImplementationDefault; + image1DImplementation = &AbstractTexture::imageImplementationDefault; + #endif + image2DImplementation = &AbstractTexture::imageImplementationDefault; + image3DImplementation = &AbstractTexture::imageImplementationDefault; + #ifndef MAGNUM_TARGET_GLES + subImage1DImplementation = &AbstractTexture::subImageImplementationDefault; + #endif + subImage2DImplementation = &AbstractTexture::subImageImplementationDefault; + subImage3DImplementation = &AbstractTexture::subImageImplementationDefault; + + #ifndef MAGNUM_TARGET_GLES + setBufferImplementation = &BufferTexture::setBufferImplementationDefault; + setBufferRangeImplementation = &BufferTexture::setBufferRangeImplementationDefault; + #endif + } + + /* Data invalidation implementation */ + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::ARB::invalidate_subdata::string()); + + invalidateImageImplementation = &AbstractTexture::invalidateImageImplementationARB; + invalidateSubImageImplementation = &AbstractTexture::invalidateSubImageImplementationARB; + } else + #endif + { + invalidateImageImplementation = &AbstractTexture::invalidateImageImplementationNoOp; + invalidateSubImageImplementation = &AbstractTexture::invalidateSubImageImplementationNoOp; + } + + /* Image retrieval implementation */ + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported() && + !context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::ARB::robustness::string()); + + getImageImplementation = &AbstractTexture::getImageImplementationRobustness; + } else getImageImplementation = &AbstractTexture::getImageImplementationDefault; + #endif + + /* Texture storage implementation */ + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) + #elif defined(MAGNUM_TARGET_GLES2) + if(context.isExtensionSupported()) + #endif + { + #ifndef MAGNUM_TARGET_GLES + extensions.push_back(Extensions::GL::ARB::texture_storage::string()); + #elif defined(MAGNUM_TARGET_GLES2) + extensions.push_back(Extensions::GL::EXT::texture_storage::string()); + #endif + + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) { + storage1DImplementation = &AbstractTexture::storageImplementationDSA; + storage2DImplementation = &AbstractTexture::storageImplementationDSA; + storage3DImplementation = &AbstractTexture::storageImplementationDSA; + } else + #endif + { + #ifndef MAGNUM_TARGET_GLES + storage1DImplementation = &AbstractTexture::storageImplementationDefault; + #endif + storage2DImplementation = &AbstractTexture::storageImplementationDefault; + storage3DImplementation = &AbstractTexture::storageImplementationDefault; + } + } + #ifndef MAGNUM_TARGET_GLES3 + else { + #ifndef MAGNUM_TARGET_GLES + storage1DImplementation = &AbstractTexture::storageImplementationFallback; + #endif + storage2DImplementation = &AbstractTexture::storageImplementationFallback; + storage3DImplementation = &AbstractTexture::storageImplementationFallback; + } + #endif + + /* Anisotropic filter implementation */ + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::EXT::texture_filter_anisotropic::string()); + + setMaxAnisotropyImplementation = &AbstractTexture::setMaxAnisotropyImplementationExt; + } else setMaxAnisotropyImplementation = &AbstractTexture::setMaxAnisotropyImplementationNoOp; + + /* Resize bindings array to hold all possible layers */ + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxLayers); + bindings.resize(maxLayers); +} TextureState::~TextureState() = default; diff --git a/src/Magnum/Implementation/TextureState.h b/src/Magnum/Implementation/TextureState.h index 6eb4cbe23..3b766becb 100644 --- a/src/Magnum/Implementation/TextureState.h +++ b/src/Magnum/Implementation/TextureState.h @@ -25,16 +25,50 @@ DEALINGS IN THE SOFTWARE. */ +#include #include +#include "Magnum/Magnum.h" #include "Magnum/OpenGL.h" namespace Magnum { namespace Implementation { struct TextureState { - explicit TextureState(); + explicit TextureState(Context& context, std::vector& extensions); ~TextureState(); + void(AbstractTexture::*bindImplementation)(GLint); + void(AbstractTexture::*parameteriImplementation)(GLenum, GLint); + void(AbstractTexture::*parameterfImplementation)(GLenum, GLfloat); + void(AbstractTexture::*parameterfvImplementation)(GLenum, const GLfloat*); + void(AbstractTexture::*setMaxAnisotropyImplementation)(GLfloat); + void(AbstractTexture::*getLevelParameterivImplementation)(GLenum, GLint, GLenum, GLint*); + void(AbstractTexture::*mipmapImplementation)(); + #ifndef MAGNUM_TARGET_GLES + void(AbstractTexture::*storage1DImplementation)(GLenum, GLsizei, TextureFormat, const Math::Vector<1, GLsizei>&); + #endif + void(AbstractTexture::*storage2DImplementation)(GLenum, GLsizei, TextureFormat, const Vector2i&); + void(AbstractTexture::*storage3DImplementation)(GLenum, GLsizei, TextureFormat, const Vector3i&); + #ifndef MAGNUM_TARGET_GLES + void(AbstractTexture::*getImageImplementation)(GLenum, GLint, ColorFormat, ColorType, std::size_t, GLvoid*); + void(AbstractTexture::*image1DImplementation)(GLenum, GLint, TextureFormat, const Math::Vector<1, GLsizei>&, ColorFormat, ColorType, const GLvoid*); + #endif + void(AbstractTexture::*image2DImplementation)(GLenum, GLint, TextureFormat, const Vector2i&, ColorFormat, ColorType, const GLvoid*); + void(AbstractTexture::*image3DImplementation)(GLenum, GLint, TextureFormat, const Vector3i&, ColorFormat, ColorType, const GLvoid*); + #ifndef MAGNUM_TARGET_GLES + void(AbstractTexture::*subImage1DImplementation)(GLenum, GLint, const Math::Vector<1, GLint>&, const Math::Vector<1, GLsizei>&, ColorFormat, ColorType, const GLvoid*); + #endif + void(AbstractTexture::*subImage2DImplementation)(GLenum, GLint, const Vector2i&, const Vector2i&, ColorFormat, ColorType, const GLvoid*); + void(AbstractTexture::*subImage3DImplementation)(GLenum, GLint, const Vector3i&, const Vector3i&, ColorFormat, ColorType, const GLvoid*); + void(AbstractTexture::*invalidateImageImplementation)(GLint); + void(AbstractTexture::*invalidateSubImageImplementation)(GLint, const Vector3i&, const Vector3i&); + + #ifndef MAGNUM_TARGET_GLES + void(BufferTexture::*setBufferImplementation)(BufferTextureFormat, Buffer&); + void(BufferTexture::*setBufferRangeImplementation)(BufferTextureFormat, Buffer&, GLintptr, GLsizeiptr); + #endif + + GLint maxLayers; GLfloat maxMaxAnisotropy; GLint currentLayer; #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/Magnum.h b/src/Magnum/Magnum.h index bfb0120b3..48b868124 100644 --- a/src/Magnum/Magnum.h +++ b/src/Magnum/Magnum.h @@ -563,13 +563,11 @@ enum class ColorType: GLenum; /** @todo Remove this when dropping backward compatibility */ typedef ColorFormat ImageFormat; typedef ColorType ColorType; - -enum class Version: Int; #endif class Context; -class CubeMapTexture; +class CubeMapTexture; #ifndef MAGNUM_TARGET_GLES class CubeMapTextureArray; #endif @@ -597,11 +595,19 @@ enum class MeshPrimitive: GLenum; class Mesh; class MeshView; +#ifndef MAGNUM_TARGET_GLES +template class MultisampleTexture; +typedef MultisampleTexture<2> MultisampleTexture2D; +typedef MultisampleTexture<3> MultisampleTexture2DArray; +#endif + /* AbstractQuery is not used directly */ class PrimitiveQuery; class SampleQuery; class TimeQuery; +class RectangleTexture; + class Renderbuffer; #ifndef CORRADE_GCC45_COMPATIBILITY enum class RenderbufferFormat: GLenum; @@ -626,12 +632,24 @@ typedef Texture<1> Texture1D; typedef Texture<2> Texture2D; typedef Texture<3> Texture3D; +#ifndef MAGNUM_TARGET_GLES2 +template class TextureArray; +#ifndef MAGNUM_TARGET_GLES +typedef TextureArray<1> Texture1DArray; +#endif +typedef TextureArray<2> Texture2DArray; +#endif + #ifndef CORRADE_GCC45_COMPATIBILITY enum class TextureFormat: GLenum; #endif class Timeline; +#ifndef CORRADE_GCC45_COMPATIBILITY +enum class Version: Int; +#endif + } #endif diff --git a/src/Magnum/Mesh.cpp b/src/Magnum/Mesh.cpp index e86a6a5bd..82ecdbc43 100644 --- a/src/Magnum/Mesh.cpp +++ b/src/Magnum/Mesh.cpp @@ -38,19 +38,6 @@ namespace Magnum { -Mesh::CreateImplementation Mesh::createImplementation = &Mesh::createImplementationDefault; -Mesh::DestroyImplementation Mesh::destroyImplementation = &Mesh::destroyImplementationDefault; -Mesh::AttributePointerImplementation Mesh::attributePointerImplementation = &Mesh::attributePointerImplementationDefault; -#ifndef MAGNUM_TARGET_GLES2 -Mesh::AttributeIPointerImplementation Mesh::attributeIPointerImplementation = &Mesh::attributePointerImplementationDefault; -#ifndef MAGNUM_TARGET_GLES -Mesh::AttributeLPointerImplementation Mesh::attributeLPointerImplementation = &Mesh::attributePointerImplementationDefault; -#endif -#endif -Mesh::BindIndexBufferImplementation Mesh::bindIndexBufferImplementation = &Mesh::bindIndexBufferImplementationDefault; -Mesh::BindImplementation Mesh::bindImplementation = &Mesh::bindImplementationDefault; -Mesh::UnbindImplementation Mesh::unbindImplementation = &Mesh::unbindImplementationDefault; - Int Mesh::maxVertexAttributes() { return AbstractShaderProgram::maxVertexAttributes(); } #ifndef MAGNUM_TARGET_GLES2 @@ -91,7 +78,7 @@ Mesh::Mesh(MeshPrimitive primitive): _primitive(primitive), _vertexCount(0), _in #endif , _indexOffset(0), _indexType(IndexType::UnsignedInt), _indexBuffer(nullptr) { - (this->*createImplementation)(); + (this->*Context::current()->state().mesh->createImplementation)(); } Mesh::~Mesh() { @@ -102,7 +89,7 @@ Mesh::~Mesh() { GLuint& current = Context::current()->state().mesh->currentVAO; if(current == _id) current = 0; - (this->*destroyImplementation)(); + (this->*Context::current()->state().mesh->destroyImplementation)(); } Mesh::Mesh(Mesh&& other) noexcept: _id(other._id), _primitive(other._primitive), _vertexCount(other._vertexCount), _indexCount(other._indexCount) @@ -175,7 +162,7 @@ Mesh& Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, IndexType type, Unsi static_cast(start); static_cast(end); #endif - (this->*bindIndexBufferImplementation)(buffer); + (this->*Context::current()->state().mesh->bindIndexBufferImplementation)(buffer); return *this; } @@ -188,7 +175,7 @@ void Mesh::drawInternal(Int firstVertex, Int vertexCount, GLintptr indexOffset, /* Nothing to draw */ if(!vertexCount && !indexCount) return; - (this->*bindImplementation)(); + (this->*Context::current()->state().mesh->bindImplementation)(); /* Non-indexed mesh */ if(!indexCount) @@ -204,7 +191,7 @@ void Mesh::drawInternal(Int firstVertex, Int vertexCount, GLintptr indexOffset, else glDrawElements(GLenum(_primitive), indexCount, GLenum(_indexType), reinterpret_cast(indexOffset)); - (this->*unbindImplementation)(); + (this->*Context::current()->state().mesh->unbindImplementation)(); } void Mesh::bindVAO(GLuint vao) { @@ -220,6 +207,22 @@ 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); @@ -242,56 +245,15 @@ void Mesh::vertexAttribPointer(const LongAttribute& attribute) { #endif #endif -void Mesh::initializeContextBasedFunctionality(Context& context) { - /** @todo Enable when some extension wrangler is available in ES 2.0 */ - #ifndef MAGNUM_TARGET_GLES - if(context.isExtensionSupported()) - #elif defined(MAGNUM_TARGET_GLES2) - if(context.isExtensionSupported()) - #else - static_cast(context); - #endif - { - #ifndef MAGNUM_TARGET_GLES - Debug() << "Mesh: using" << Extensions::GL::APPLE::vertex_array_object::string() << "features"; - #elif defined(MAGNUM_TARGET_GLES2) - Debug() << "Mesh: using" << Extensions::GL::OES::vertex_array_object::string() << "features"; - #endif - - createImplementation = &Mesh::createImplementationVAO; - destroyImplementation = &Mesh::destroyImplementationVAO; - - #ifndef MAGNUM_TARGET_GLES - if(context.isExtensionSupported()) { - Debug() << "Mesh: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; - - attributePointerImplementation = &Mesh::attributePointerImplementationDSA; - attributeIPointerImplementation = &Mesh::attributePointerImplementationDSA; - attributeLPointerImplementation = &Mesh::attributePointerImplementationDSA; - } else - #endif - { - attributePointerImplementation = &Mesh::attributePointerImplementationVAO; - #ifndef MAGNUM_TARGET_GLES2 - attributeIPointerImplementation = &Mesh::attributePointerImplementationVAO; - #ifndef MAGNUM_TARGET_GLES - attributeLPointerImplementation = &Mesh::attributePointerImplementationVAO; - #endif - #endif - } - - bindIndexBufferImplementation = &Mesh::bindIndexBufferImplementationVAO; - bindImplementation = &Mesh::bindImplementationVAO; - unbindImplementation = &Mesh::unbindImplementationVAO; - } -} - void Mesh::createImplementationDefault() { _id = 0; } void Mesh::createImplementationVAO() { /** @todo Get some extension wrangler instead to avoid linker errors to glGenVertexArrays() on ES2 */ #ifndef MAGNUM_TARGET_GLES2 glGenVertexArrays(1, &_id); + #else + //glGenVertexArraysOES(1, &_id); + CORRADE_INTERNAL_ASSERT(false); #endif } @@ -301,6 +263,9 @@ void Mesh::destroyImplementationVAO() { /** @todo Get some extension wrangler instead to avoid linker errors to glDeleteVertexArrays() on ES2 */ #ifndef MAGNUM_TARGET_GLES2 glDeleteVertexArrays(1, &_id); + #else + //glDeleteVertexArraysOES(1, &_id); + CORRADE_INTERNAL_ASSERT(false); #endif } diff --git a/src/Magnum/Mesh.h b/src/Magnum/Mesh.h index 4330ed735..87b6e25c6 100644 --- a/src/Magnum/Mesh.h +++ b/src/Magnum/Mesh.h @@ -115,6 +115,8 @@ enum class MeshPrimitive: GLenum { #endif }; +namespace Implementation { struct MeshState; } + /** @brief %Mesh @@ -294,10 +296,11 @@ for more infromation) and call @ref Mesh::draw(). If @extension{APPLE,vertex_array_object} (part of OpenGL 3.0), OpenGL ES 3.0 or @es_extension{OES,vertex_array_object} on OpenGL ES 2.0 is supported, VAOs are used instead of binding the buffers and specifying vertex attribute pointers -in each @ref draw() call. The engine tracks currently bound VAO to avoid -unnecessary calls to @fn_gl{BindVertexArray}. %Mesh limits and -implementation-defined values (such as @ref maxVertexAttributes()) are cached, -so repeated queries don't result in repeated @fn_gl{Get} calls. +in each @ref draw() call. The engine tracks currently bound VAO and currently +active shader program to avoid unnecessary calls to @fn_gl{BindVertexArray} and +@fn_gl{UseProgram}. %Mesh limits and implementation-defined values (such as +@ref maxVertexAttributes()) are cached, so repeated queries don't result in +repeated @fn_gl{Get} calls. If extension @extension{EXT,direct_state_access} and VAOs are available, DSA functions are used for specifying attribute locations to avoid unnecessary @@ -308,13 +311,12 @@ 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 Support for indirect draw buffer (OpenGL 4.0, @extension{ARB,draw_indirect}) @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 Context; friend class MeshView; + friend struct Implementation::MeshState; public: #ifdef MAGNUM_BUILD_DEPRECATED @@ -337,6 +339,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { /** * Unsigned int * @requires_gles30 %Extension @es_extension{OES,element_index_uint} + * in OpenGL ES 2.0 */ UnsignedInt = GL_UNSIGNED_INT }; @@ -424,9 +427,9 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { * @brief %Mesh label * * The result is *not* cached, repeated queries will result in repeated - * OpenGL calls. If neither @extension{KHR,debug} nor - * @extension2{EXT,debug_label} desktop or ES extension is available, - * this function returns empty string. + * OpenGL calls. If OpenGL 4.3 is not supported and neither + * @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES + * extension is available, this function returns empty string. * @see @fn_gl{GetObjectLabel} with @def_gl{VERTEX_ARRAY} or * @fn_gl_extension2{GetObjectLabel,EXT,debug_label} with * @def_gl{VERTEX_ARRAY_OBJECT_EXT} @@ -437,9 +440,9 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { * @brief Set mesh label * @return Reference to self (for method chaining) * - * Default is empty string. If neither @extension{KHR,debug} nor - * @extension2{EXT,debug_label} desktop or ES extension is available, - * this function does nothing. + * Default is empty string. If OpenGL 4.3 is not supported and neither + * @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES + * extension is available, this function does nothing. * @see @ref maxLabelLength(), @fn_gl{ObjectLabel} with * @def_gl{VERTEX_ARRAY} or @fn_gl_extension2{LabelObject,EXT,debug_label} * with @def_gl{VERTEX_ARRAY_OBJECT_EXT} @@ -605,14 +608,34 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { /** * @brief Draw the mesh + * @param shader Shader to use for drawing * - * Expects an active shader with all uniforms set. See + * Expects that the shader is compatible with this mesh and is fully + * set up. See also * @ref AbstractShaderProgram-rendering-workflow "AbstractShaderProgram documentation" * for more information. - * @see @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 @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}. + */ + void draw(AbstractShaderProgram& shader) { + shader.use(); + + #ifndef MAGNUM_TARGET_GLES2 + drawInternal(0, _vertexCount, _indexOffset, _indexCount, _indexStart, _indexEnd); + #else + drawInternal(0, _vertexCount, _indexOffset, _indexCount); + #endif + } + + void draw(AbstractShaderProgram&& shader) { draw(shader); } /**< @overload */ + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @copybrief draw(AbstractShaderProgram&) + * @deprecated Use @ref Magnum::Mesh::draw(AbstractShaderProgram&) instead. */ void draw() { #ifndef MAGNUM_TARGET_GLES2 @@ -621,6 +644,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { drawInternal(0, _vertexCount, _indexOffset, _indexCount); #endif } + #endif private: #ifndef DOXYGEN_GENERATING_OUTPUT @@ -657,8 +681,6 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { #endif #endif - static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context); - /* Computing stride of interleaved vertex attributes */ template inline static GLsizei strideOfInterleaved(const AbstractShaderProgram::Attribute& attribute, const U&... attributes) { return attribute.vectorSize()*AbstractShaderProgram::Attribute::VectorCount + strideOfInterleaved(attributes...); @@ -683,7 +705,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { template inline void addVertexAttribute(typename std::enable_if::Type, Float>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { for(UnsignedInt i = 0; i != AbstractShaderProgram::Attribute::VectorCount; ++i) - (this->*attributePointerImplementation)(Attribute{ + attributePointerInternal(Attribute{ &buffer, location+i, GLint(attribute.components()), @@ -696,7 +718,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { #ifndef MAGNUM_TARGET_GLES2 template inline void addVertexAttribute(typename std::enable_if::Type>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { - (this->*attributeIPointerImplementation)(IntegerAttribute{ + attributePointerInternal(IntegerAttribute{ &buffer, location, GLint(attribute.components()), @@ -709,7 +731,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { #ifndef MAGNUM_TARGET_GLES template inline void addVertexAttribute(typename std::enable_if::Type, Double>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { for(UnsignedInt i = 0; i != AbstractShaderProgram::Attribute::VectorCount; ++i) - (this->*attributeLPointerImplementation)(LongAttribute{ + attributePointerInternal(LongAttribute{ &buffer, location+i, GLint(attribute.components()), @@ -723,6 +745,14 @@ 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); @@ -737,56 +767,40 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { void drawInternal(Int firstVertex, Int vertexCount, GLintptr indexOffset, Int indexCount); #endif - typedef void(Mesh::*CreateImplementation)(); void MAGNUM_LOCAL createImplementationDefault(); void MAGNUM_LOCAL createImplementationVAO(); - static MAGNUM_LOCAL CreateImplementation createImplementation; - typedef void(Mesh::*DestroyImplementation)(); void MAGNUM_LOCAL destroyImplementationDefault(); void MAGNUM_LOCAL destroyImplementationVAO(); - static MAGNUM_LOCAL DestroyImplementation destroyImplementation; - typedef void(Mesh::*AttributePointerImplementation)(const 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 - static AttributePointerImplementation attributePointerImplementation; #ifndef MAGNUM_TARGET_GLES2 - typedef void(Mesh::*AttributeIPointerImplementation)(const IntegerAttribute&); 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 - static AttributeIPointerImplementation attributeIPointerImplementation; #ifndef MAGNUM_TARGET_GLES - typedef void(Mesh::*AttributeLPointerImplementation)(const LongAttribute&); void MAGNUM_LOCAL attributePointerImplementationDefault(const LongAttribute& attribute); void MAGNUM_LOCAL attributePointerImplementationVAO(const LongAttribute& attribute); void MAGNUM_LOCAL attributePointerImplementationDSA(const LongAttribute& attribute); - static AttributeLPointerImplementation attributeLPointerImplementation; #endif #endif - typedef void(Mesh::*BindIndexBufferImplementation)(Buffer&); void MAGNUM_LOCAL bindIndexBufferImplementationDefault(Buffer& buffer); void MAGNUM_LOCAL bindIndexBufferImplementationVAO(Buffer& buffer); - static MAGNUM_LOCAL BindIndexBufferImplementation bindIndexBufferImplementation; - typedef void(Mesh::*BindImplementation)(); void MAGNUM_LOCAL bindImplementationDefault(); void MAGNUM_LOCAL bindImplementationVAO(); - static MAGNUM_LOCAL BindImplementation bindImplementation; - typedef void(Mesh::*UnbindImplementation)(); void MAGNUM_LOCAL unbindImplementationDefault(); void MAGNUM_LOCAL unbindImplementationVAO(); - static MAGNUM_LOCAL UnbindImplementation unbindImplementation; GLuint _id; MeshPrimitive _primitive; diff --git a/src/Magnum/MeshTools/CMakeLists.txt b/src/Magnum/MeshTools/CMakeLists.txt index 7a1033dfc..f4e9587e2 100644 --- a/src/Magnum/MeshTools/CMakeLists.txt +++ b/src/Magnum/MeshTools/CMakeLists.txt @@ -31,6 +31,7 @@ set(MagnumMeshTools_SRCS # Files compiled with different flags for main library and unit test library set(MagnumMeshTools_GracefulAssert_SRCS + CombineIndexedArrays.cpp FlipNormals.cpp GenerateFlatNormals.cpp) diff --git a/src/Magnum/MeshTools/CombineIndexedArrays.cpp b/src/Magnum/MeshTools/CombineIndexedArrays.cpp new file mode 100644 index 000000000..57e918e8b --- /dev/null +++ b/src/Magnum/MeshTools/CombineIndexedArrays.cpp @@ -0,0 +1,159 @@ +/* + 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 "CombineIndexedArrays.h" + +#include +#include +#include +#include + +#include "Magnum/Magnum.h" + +namespace Magnum { namespace MeshTools { + +namespace Implementation { + +std::pair, std::vector> interleaveAndCombineIndexArrays(const std::reference_wrapper>* begin, const std::reference_wrapper>* end) { + /* Array stride and size */ + const UnsignedInt stride = end - begin; + const UnsignedInt inputSize = begin->get().size(); + #ifndef CORRADE_NO_ASSERT + for(auto it = begin; it != end; ++it) + CORRADE_ASSERT(it->get().size() == inputSize, "MeshTools::combineIndexArrays(): the arrays don't have the same size", {}); + #endif + + /* Interleave the arrays */ + std::vector interleavedArrays; + interleavedArrays.resize(inputSize*stride); + for(UnsignedInt offset = 0; offset != stride; ++offset) { + const auto& array = (begin+offset)->get(); + for(UnsignedInt i = 0; i != inputSize; ++i) + interleavedArrays[offset + i*stride] = array[i]; + } + + /* Combine them */ + std::vector combinedIndices; + std::tie(combinedIndices, interleavedArrays) = combineIndexArrays(interleavedArrays, stride); + return {combinedIndices, interleavedArrays}; +} + +} + +std::vector combineIndexArrays(const std::initializer_list>> arrays) { + /* Interleave and combine the arrays */ + std::vector combinedIndices; + std::vector interleavedCombinedArrays; + std::tie(combinedIndices, interleavedCombinedArrays) = Implementation::interleaveAndCombineIndexArrays( + /* This will bite me hard once. */ + reinterpret_cast>*>(arrays.begin()), + reinterpret_cast>*>(arrays.end())); + + /* Update the original indices */ + const UnsignedInt stride = arrays.size(); + const UnsignedInt outputSize = interleavedCombinedArrays.size()/stride; + for(UnsignedInt offset = 0; offset != stride; ++offset) { + auto& array = (arrays.begin()+offset)->get(); + CORRADE_INTERNAL_ASSERT(array.size() >= outputSize); + array.resize(outputSize); + for(UnsignedInt i = 0; i != outputSize; ++i) + array[i] = interleavedCombinedArrays[offset + i*stride]; + } + + return combinedIndices; +} + +namespace { + +class IndexHash { + public: + explicit IndexHash(const std::vector& indices, UnsignedInt stride): indices(indices), stride(stride) {} + + std::size_t operator()(UnsignedInt key) const { + return *reinterpret_cast(Utility::MurmurHash2()(reinterpret_cast(indices.data()+key*stride), sizeof(UnsignedInt)*stride).byteArray()); + } + + private: + const std::vector& indices; + UnsignedInt stride; +}; + +class IndexEqual { + public: + explicit IndexEqual(const std::vector& indices, UnsignedInt stride): indices(indices), stride(stride) {} + + bool operator()(UnsignedInt a, UnsignedInt b) const { + return std::memcmp(indices.data()+a*stride, indices.data()+b*stride, sizeof(UnsignedInt)*stride) == 0; + } + + private: + const std::vector& indices; + UnsignedInt stride; +}; + +} + +std::pair, std::vector> combineIndexArrays(const std::vector& interleavedArrays, const UnsignedInt stride) { + CORRADE_ASSERT(interleavedArrays.size() % stride == 0, "MeshTools::combineIndexArrays(): array size is not divisible by stride", {}); + + /* Hash map with index combinations, containing just indices into + interleavedArrays vector, hashing and comparison is done using IndexHash + and IndexEqual functors. Reserving more buckets than necessary (i.e. as + if each combination was unique). */ + std::unordered_map indexCombinations( + interleavedArrays.size()/stride, + IndexHash(interleavedArrays, stride), + IndexEqual(interleavedArrays, stride)); + + /* Make the index combinations unique. Original indices into original + `interleavedArrays` array were 0, 1, 2, 3, ..., `combinedIndices` + contains new ones into new (shorter) `newInterleavedArrays` array. */ + std::vector combinedIndices; + combinedIndices.reserve(interleavedArrays.size()/stride); + std::vector newInterleavedArrays; + for(std::size_t oldIndex = 0, end = interleavedArrays.size()/stride; oldIndex != end; ++oldIndex) { + /* Try to insert new index combination to the map */ + #ifndef CORRADE_GCC46_COMPATIBILITY + const auto result = indexCombinations.emplace(oldIndex, indexCombinations.size()); + #else + const auto result = indexCombinations.insert({oldIndex, indexCombinations.size()}); + #endif + + /* Add the (either new or already existing) index to resulting index array */ + combinedIndices.push_back(result.first->second); + + /* If this is new combination, copy it to new interleaved arrays */ + if(result.second) newInterleavedArrays.insert(newInterleavedArrays.end(), + interleavedArrays.begin()+oldIndex*stride, + interleavedArrays.begin()+(oldIndex+1)*stride); + } + + CORRADE_INTERNAL_ASSERT(combinedIndices.size() == interleavedArrays.size()/stride && + newInterleavedArrays.size() <= interleavedArrays.size()); + + return {std::move(combinedIndices), std::move(newInterleavedArrays)}; +} + +}} diff --git a/src/Magnum/MeshTools/CombineIndexedArrays.h b/src/Magnum/MeshTools/CombineIndexedArrays.h index 6af94c479..c52b72199 100644 --- a/src/Magnum/MeshTools/CombineIndexedArrays.h +++ b/src/Magnum/MeshTools/CombineIndexedArrays.h @@ -26,74 +26,105 @@ */ /** @file - * @brief Function Magnum::MeshTools::combineIndexedArrays() + * @brief Function @ref Magnum::MeshTools::combineIndexArrays(), @ref Magnum::MeshTools::combineIndexedArrays() */ -#include -#include +#include #include +#include -#include "Magnum/Math/Vector.h" -#include "Magnum/MeshTools/RemoveDuplicates.h" +#include "Magnum/Types.h" +#include "Magnum/MeshTools/visibility.h" + +#ifdef MAGNUM_BUILD_DEPRECATED +#include +#endif namespace Magnum { namespace MeshTools { -namespace Implementation { +/** +@brief Combine index arrays + +Creates new combined index array and updates the original ones with translation +to new ones. For example, when you have position and normal array, each indexed +with separate indices and you want to index both of them with single index +array: + + a b c d e f // positions + A B C D E F G // normals + + 0 2 5 0 0 1 3 2 2 // position indices + 1 3 4 1 4 6 1 3 1 // normal indices + +In particular, first triangle in the mesh will have positions `a c f` and +normals `B D E`. You can see that not all combinations are unique and also that +there are some vertices unused. When you pass the two index arrays above to +this function, the following combined index array is returned: + + 0 1 2 0 3 4 5 1 6 + +And the original arrays are cleaned up to have only unique combinations: + + 0 2 5 0 1 3 2 + 1 3 4 4 6 1 1 + +You can use these as translation table to create new vertex and normal arrays +which can be then indexed with the combined index array: + + a c f a b d c + B D E E G B B -class CombineIndexedArrays { - public: - template std::vector operator()(const std::tuple&, std::vector&>&... indexedArrays) { - /* Compute index count */ - std::size_t _indexCount = indexCount(std::get<0>(indexedArrays)...); +Again, first triangle in the mesh will have positions `a c f` and normals +`B D E`. - /* Resulting index array */ - std::vector result; - result.resize(_indexCount); - std::iota(result.begin(), result.end(), 0); +This function calls @ref combineIndexArrays(const std::vector&, UnsignedInt) +internally. See also @ref combineIndexedArrays() which does the vertex data +reordering automatically. +*/ +MAGNUM_MESHTOOLS_EXPORT std::vector combineIndexArrays(std::initializer_list>> arrays); + +/** +@brief Combine index arrays + +Unlike above, this function takes one interleaved array instead of separate +index arrays. Continuing with the above example, you would call this function +with the following array (odd value is vertex index, even is normal index, +@p stride is thus 2): - /* All index combinations */ - std::vector > indexCombinations(_indexCount); - writeCombinedIndices(indexCombinations, std::get<0>(indexedArrays)...); + 0 1 2 3 5 4 0 1 0 4 1 6 3 1 2 3 2 1 - /* Make the combinations unique */ - MeshTools::removeDuplicates(result, indexCombinations); +Similarly to above this function will return the following combined index +array as first pair value: - /* Write combined arrays */ - writeCombinedArrays(indexCombinations, std::get<1>(indexedArrays)...); + 0 1 2 0 3 4 5 1 6 - return result; - } +And second pair value is the cleaned up interleaved array: - private: - template static std::size_t indexCount(const std::vector& first, const std::vector&... next) { - CORRADE_ASSERT(sizeof...(next) == 0 || indexCount(next...) == first.size(), "MeshTools::combineIndexedArrays(): index arrays don't have the same length, nothing done.", 0); + 0 1 2 3 5 4 0 4 1 6 3 1 2 1 - return first.size(); - } +@see @ref combineIndexedArrays() +*/ +MAGNUM_MESHTOOLS_EXPORT std::pair, std::vector> combineIndexArrays(const std::vector& interleavedArrays, UnsignedInt stride); - template static void writeCombinedIndices(std::vector>& output, const std::vector& first, const std::vector&... next) { - /* Copy the data to output */ - for(std::size_t i = 0; i != output.size(); ++i) - output[i][size-sizeof...(next)-1] = first[i]; +namespace Implementation { - writeCombinedIndices(output, next...); - } +MAGNUM_MESHTOOLS_EXPORT std::pair, std::vector> interleaveAndCombineIndexArrays(const std::reference_wrapper>* begin, const std::reference_wrapper>* end); - template static void writeCombinedArrays(const std::vector>& combinedIndices, std::vector& first, std::vector&... next) { - /* Rewrite output array */ - std::vector output; - for(std::size_t i = 0; i != combinedIndices.size(); ++i) - output.push_back(first[combinedIndices[i][size-sizeof...(next)-1]]); - std::swap(output, first); +template void writeCombinedArray(const UnsignedInt stride, const UnsignedInt offset, const std::vector& interleavedCombinedIndexArrays, std::vector& array) { + std::vector output; + output.reserve(interleavedCombinedIndexArrays.size()/stride); + for(std::size_t i = 0, max = interleavedCombinedIndexArrays.size()/stride; i != max; ++i) + output.push_back(array[interleavedCombinedIndexArrays[offset + i*stride]]); + std::swap(output, array); +} - writeCombinedArrays(combinedIndices, next...); - } +/* Terminator for recursive calls */ +inline void writeCombinedArrays(UnsignedInt, UnsignedInt, const std::vector&) {} - /* Terminator functions for recursive calls */ - static std::size_t indexCount() { return 0; } - template static void writeCombinedIndices(std::vector>&) {} - template static void writeCombinedArrays(const std::vector>&) {} -}; +template inline void writeCombinedArrays(UnsignedInt stride, UnsignedInt offset, const std::vector& interleavedCombinedIndexArrays, std::vector& first, std::vector&... next) { + writeCombinedArray(stride, offset, interleavedCombinedIndexArrays, first); + writeCombinedArrays(stride, offset + 1, interleavedCombinedIndexArrays, next...); +} } @@ -102,15 +133,13 @@ class CombineIndexedArrays { @param[in,out] indexedArrays Index and attribute arrays @return %Array with resulting indices -When you have e.g. vertex, normal and texture array, each indexed with -different indices, you can use this function to combine them to use the same -indices. The function returns array with resulting indices and replaces -original attribute arrays with combined ones. +Creates new combined index array and reorders original attribute arrays so they +can be indexed with the new single index array. The index array must be passed as const reference (to avoid copying) and attribute array as reference, so it can be replaced with combined data. To avoid explicit verbose specification of tuple type, you can write it with help -of some STL functions like shown below. Also if one index array is shader by +of some STL functions like shown below. Also if one index array is shared by more than one attribute array, just pass the index array more times. Example: @code std::vector vertexIndices; @@ -120,25 +149,43 @@ std::vector normals; std::vector textureCoordinates; std::vector indices = MeshTools::combineIndexedArrays( - std::make_tuple(std::cref(vertexIndices), std::ref(positions)), - std::make_tuple(std::cref(normalTextureIndices), std::ref(normals)), - std::make_tuple(std::cref(normalTextureIndices), std::ref(textureCoordinates)) + std::make_pair(std::cref(vertexIndices), std::ref(positions)), + std::make_pair(std::cref(normalTextureIndices), std::ref(normals)), + std::make_pair(std::cref(normalTextureIndices), std::ref(textureCoordinates)) ); @endcode -`positions`, `normals` and `textureCoordinates` will then contain combined -attributes indexed with `indices`. -@attention The function expects that all arrays have the same size. -@todo Use `std::pair` (to avoid `std::make_tuple`), make this usable also at - runtime +See @ref combineIndexArrays() documentation for more information about the +procedure. +@todo Invent a way which avoids these overly verbose parameters (`std::pair` + doesn't help) */ /* Implementation note: It's done using tuples because it is more clear which parameter is index array and which is attribute array, mainly when both are of the same type. */ -template std::vector combineIndexedArrays(const std::tuple&, std::vector&>&... indexedArrays) { - return Implementation::CombineIndexedArrays()(indexedArrays...); +template std::vector combineIndexedArrays(const std::pair&, std::vector&>&... indexedArrays) { + /* Interleave and combine index arrays */ + std::vector combinedIndices; + std::vector interleavedCombinedIndexArrays; + auto i = {std::ref(indexedArrays.first)...}; + std::tie(combinedIndices, interleavedCombinedIndexArrays) = Implementation::interleaveAndCombineIndexArrays(i.begin(), i.end()); + + /* Write combined arrays */ + Implementation::writeCombinedArrays(sizeof...(T), 0, interleavedCombinedIndexArrays, indexedArrays.second...); + + return combinedIndices; } +#ifdef MAGNUM_BUILD_DEPRECATED +/** + * @copybrief combineIndexedArrays(const std::pair&, std::vector&>&...) + * @deprecated Use @ref Magnum::MeshTools::combineIndexedArrays(const std::pair&, std::vector&>&...) "combineIndexedArrays(const std::pair&, std::vector&>&...)" instead. + */ +template inline CORRADE_DEPRECATED("use combineIndexedArrays(const std::pair&, std::vector&>&...) instead") std::vector combineIndexedArrays(const std::tuple&, std::vector&>&... indexedArrays) { + return combineIndexedArrays(std::make_pair(std::cref(std::get<0>(indexedArrays)), std::ref(std::get<1>(indexedArrays)))...); +} +#endif + }} #endif diff --git a/src/Magnum/MeshTools/Duplicate.h b/src/Magnum/MeshTools/Duplicate.h index bc8414ea2..94fdff10e 100644 --- a/src/Magnum/MeshTools/Duplicate.h +++ b/src/Magnum/MeshTools/Duplicate.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Function Magnum::MeshTools::duplicate() + * @brief Function @ref Magnum::MeshTools::duplicate() */ #include @@ -36,18 +36,18 @@ namespace Magnum { namespace MeshTools { /** -@brief Duplicate vertices using index array +@brief Duplicate data using index array -Converts indexed array to non-indexed, for example vertices `{a, b, c, d}` with +Converts indexed array to non-indexed, for example data `{a, b, c, d}` with index array `{1, 1, 0, 3, 2, 2}` will be converted to `{b, b, a, d, c, c}`. -@see removeDuplicates() +@see @ref removeDuplicates(), @ref combineIndexedArrays() */ -template std::vector duplicate(const std::vector& indices, const std::vector& vertices) { +template std::vector duplicate(const std::vector& indices, const std::vector& data) { std::vector out; out.reserve(indices.size()); for(auto it = indices.begin(); it != indices.end(); ++it) - out.push_back(vertices[*it]); - return std::move(out); + out.push_back(data[*it]); + return out; } }} diff --git a/src/Magnum/MeshTools/GenerateFlatNormals.cpp b/src/Magnum/MeshTools/GenerateFlatNormals.cpp index bbda7a9b8..c4b78db09 100644 --- a/src/Magnum/MeshTools/GenerateFlatNormals.cpp +++ b/src/Magnum/MeshTools/GenerateFlatNormals.cpp @@ -26,6 +26,7 @@ #include "GenerateFlatNormals.h" #include "Magnum/Math/Vector3.h" +#include "Magnum/MeshTools/Duplicate.h" #include "Magnum/MeshTools/RemoveDuplicates.h" namespace Magnum { namespace MeshTools { @@ -50,7 +51,7 @@ std::tuple, std::vector> generateFlatNormals(c } /* Remove duplicate normals and return */ - MeshTools::removeDuplicates(normalIndices, normals); + normalIndices = MeshTools::duplicate(normalIndices, MeshTools::removeDuplicates(normals)); return std::make_tuple(std::move(normalIndices), std::move(normals)); } diff --git a/src/Magnum/MeshTools/RemoveDuplicates.h b/src/Magnum/MeshTools/RemoveDuplicates.h index ac3c93506..4107420cd 100644 --- a/src/Magnum/MeshTools/RemoveDuplicates.h +++ b/src/Magnum/MeshTools/RemoveDuplicates.h @@ -26,10 +26,11 @@ */ /** @file - * @brief Function Magnum::MeshTools::removeDuplicates() + * @brief Function @ref Magnum::MeshTools::removeDuplicates() */ #include +#include #include #include #include @@ -37,122 +38,146 @@ #include "Magnum/Magnum.h" #include "Magnum/Math/Functions.h" -namespace Magnum { namespace MeshTools { - -namespace Implementation { - -template class RemoveDuplicates { - public: - RemoveDuplicates(std::vector& indices, std::vector& vertices): indices(indices), vertices(vertices) {} - - void operator()(typename Vertex::Type epsilon = Math::TypeTraits::epsilon()); - - private: - class IndexHash { - public: - std::size_t operator()(const Math::Vector& data) const { - return *reinterpret_cast(Utility::MurmurHash2()(reinterpret_cast(&data), sizeof(data)).byteArray()); - } - }; - - struct HashedVertex { - UnsignedInt oldIndex, newIndex; +#ifdef MAGNUM_BUILD_DEPRECATED +#include - HashedVertex(UnsignedInt oldIndex, UnsignedInt newIndex): oldIndex(oldIndex), newIndex(newIndex) {} - }; +#include "Magnum/MeshTools/Duplicate.h" +#endif - std::vector& indices; - std::vector& vertices; -}; +namespace Magnum { namespace MeshTools { +namespace Implementation { + template class VectorHash { + public: + std::size_t operator()(const Math::Vector& data) const { + return *reinterpret_cast(Utility::MurmurHash2()(reinterpret_cast(&data), sizeof(data)).byteArray()); + } + }; } /** -@brief %Remove duplicate vertices from the mesh -@tparam Vertex Vertex data type -@tparam vertexSize How many initial vertex fields are important (for - example, when dealing with perspective in 3D space, only first three - fields of otherwise 4D vertex are important) -@param[in,out] indices Index array to operate on -@param[in,out] vertices Vertex array to operate on -@param[in] epsilon Epsilon value, vertices nearer than this distance will - be melt together. - -Removes duplicate vertices from the mesh. -@see duplicate() - -@todo Different (no cycle) implementation for integral vertices -@todo Interpolate vertices, not collapse them to first in the cell -@todo Ability to specify other attributes for interpolation +@brief %Remove duplicate floating-point vector data from given array +@param[in,out] data Input data array +@param[out] epsilon Epsilon value, vertices nearer than this distance will be + melt together +@return Index array and unique data + +Removes duplicate data from the array by collapsing them into buckets of size +@p epsilon. First vector in given bucket is used, other ones are thrown away, +no interpolation is done. Note that this function is meant to be used for +floating-point data (or generally with non-zero @p epsilon), for discrete data +the usual sorting method is much more efficient. + +If you want to remove duplicate data from already indexed array, first remove +duplicates as if the array wasn't indexed at all and then use @ref duplicate() +to combine the two index arrays: +@code +std::vector indices; +std::vector positions; + +indices = MeshTools::duplicate(indices, MeshTools::removeDuplicates(positions)); +@endcode + +Removing duplicates in multiple indcidental arrays is also possible -- first +remove duplicates in each array separately and then use @ref combineIndexedArrays() +to combine the resulting index arrays to single index array and reorder the +data accordingly: +@code +std::vector positions; +std::vector texCoords; + +std::vector positionIndices; +std::tie(positionIndices, positions) = MeshTools::removeDuplicates(positions); + +std::vector texCoordIndices; +std::tie(texCoordIndices, texCoords) = MeshTools::removeDuplicates(texCoords); + +std::vector indices = MeshTools::combineIndexedArrays( + std::make_pair(std::cref(positionIndices), std::ref(positions)), + std::make_pair(std::cref(texCoordIndices), std::ref(texCoords)) +); +@endcode */ -template inline void removeDuplicates(std::vector& indices, std::vector& vertices, typename Vertex::Type epsilon = Math::TypeTraits::epsilon()) { - Implementation::RemoveDuplicates(indices, vertices)(epsilon); -} - -namespace Implementation { - -template void RemoveDuplicates::operator()(typename Vertex::Type epsilon) { - if(indices.empty()) return; - - /* Get mesh bounds */ - Vertex min = vertices[0], max = vertices[0]; - for(auto it = vertices.begin(); it != vertices.end(); ++it) { - min = Math::min(*it, min); - max = Math::max(*it, max); +template std::vector removeDuplicates(std::vector& data, typename Vector::Type epsilon = Math::TypeTraits::epsilon()) { + /* Get bounds */ + Vector min = data[0], max = data[0]; + for(const auto& v: data) { + min = Math::min(v, min); + max = Math::max(v, max); } - /* Make epsilon so large that std::size_t can index all vertices inside - mesh bounds. */ - epsilon = Math::max(epsilon, static_cast((max-min).max()/std::numeric_limits::max())); - - /* First go with original vertex coordinates, then move them by - epsilon/2 in each direction. */ - Vertex moved; - for(std::size_t moving = 0; moving <= vertexSize; ++moving) { - - /* Under each index is pointer to face which contains given vertex - and index of vertex in the face. */ - std::unordered_map, HashedVertex, IndexHash> table; - - #ifndef CORRADE_GCC44_COMPATIBILITY - /* Reserve space for all vertices */ - table.reserve(vertices.size()); - #endif - - /* Go through all faces' vertices */ - for(auto it = indices.begin(); it != indices.end(); ++it) { - /* Index of a vertex in vertexSize-dimensional table */ - std::size_t index[vertexSize]; - for(std::size_t ii = 0; ii != vertexSize; ++ii) - index[ii] = std::size_t((vertices[*it][ii]+moved[ii]-min[ii])/epsilon); - - /* Try inserting the vertex into table, if it already - exists, change vertex pointer of the face to already - existing vertex */ - HashedVertex v(*it, table.size()); + /* Make epsilon so large that std::size_t can index all vectors inside the + bounds. */ + epsilon = Math::max(epsilon, typename Vector::Type((max-min).max()/std::numeric_limits::max())); + + /* Resulting index array */ + std::vector resultIndices(data.size()); + std::iota(resultIndices.begin(), resultIndices.end(), 0); + + /* Table containing original vector index for each discretized vector. + Reserving more buckets than necessary (i.e. as if each vector was + unique). */ + std::unordered_map, UnsignedInt, Implementation::VectorHash> table(data.size()); + + /* Index array for each pass, new data array */ + std::vector indices; + indices.reserve(data.size()); + + /* First go with original coordinates, then move them by epsilon/2 in each + direction. */ + Vector moved; + for(std::size_t moving = 0; moving <= Vector::Size; ++moving) { + /* Go through all vectors */ + for(std::size_t i = 0; i != data.size(); ++i) { + /* Try to insert new vertex to the table */ + const Math::Vector v((data[i] + moved - min)/epsilon); #ifndef CORRADE_GCC46_COMPATIBILITY - auto result = table.emplace(Math::Vector::from(index), v); + const auto result = table.emplace(v, table.size()); #else - auto result = table.insert({Math::Vector::from(index), v}); + const auto result = table.insert({v, table.size()}); #endif - *it = result.first->second.newIndex; + + /* Add the (either new or already existing) index to index array */ + indices.push_back(result.first->second); + + /* If this is new combination, copy the data to new (earlier) + possition in the array */ + if(result.second && i != table.size()-1) data[table.size()-1] = data[i]; } - /* Shrink vertices array */ - std::vector newVertices(table.size()); - for(auto it = table.cbegin(); it != table.cend(); ++it) - newVertices[it->second.newIndex] = vertices[it->second.oldIndex]; - std::swap(newVertices, vertices); + /* Shrink the data array */ + CORRADE_INTERNAL_ASSERT(data.size() >= table.size()); + data.resize(table.size()); + + /* Remap the resulting index array */ + for(auto& i: resultIndices) i = indices[i]; + + /* Finished */ + if(moving == Vector::Size) continue; /* Move vertex coordinates by epsilon/2 in next direction */ - if(moving != Vertex::Size) { - moved = Vertex(); - moved[moving] = epsilon/2; - } + moved = Vector(); + moved[moving] = epsilon/2; + + /* Clear the structures for next pass */ + table.clear(); + indices.clear(); } + + return resultIndices; } +#ifdef MAGNUM_BUILD_DEPRECATED +/** +@copybrief removeDuplicates(std::vector&, typename Vector::Type) +@deprecated Use @ref Magnum::MeshTools::removeDuplicates(std::vector&, typename Vector::Type) "removeDuplicates(std::vector&, typename Vector::Type)" instead. +*/ +template void removeDuplicates(std::vector& indices, std::vector& data, typename Vector::Type epsilon = Math::TypeTraits::epsilon()) { + std::vector uniqueIndices; + std::tie(uniqueIndices, data) = removeDuplicates(data, epsilon); + indices = MeshTools::duplicate(indices, uniqueIndices); } +#endif }} diff --git a/src/Magnum/MeshTools/Test/CMakeLists.txt b/src/Magnum/MeshTools/Test/CMakeLists.txt index b461a79b3..ec7cfe6b9 100644 --- a/src/Magnum/MeshTools/Test/CMakeLists.txt +++ b/src/Magnum/MeshTools/Test/CMakeLists.txt @@ -23,13 +23,13 @@ # DEALINGS IN THE SOFTWARE. # -corrade_add_test(MeshToolsCombineIndexedArraysTest CombineIndexedArraysTest.cpp) +corrade_add_test(MeshToolsCombineIndexedArraysTest CombineIndexedArraysTest.cpp LIBRARIES MagnumMeshToolsTestLib) corrade_add_test(MeshToolsCompressIndicesTest CompressIndicesTest.cpp LIBRARIES MagnumMeshTools) corrade_add_test(MeshToolsDuplicateTest DuplicateTest.cpp) corrade_add_test(MeshToolsFlipNormalsTest FlipNormalsTest.cpp LIBRARIES MagnumMeshToolsTestLib) corrade_add_test(MeshToolsGenerateFlatNormalsTest GenerateFlatNormalsTest.cpp LIBRARIES MagnumMeshToolsTestLib) corrade_add_test(MeshToolsInterleaveTest InterleaveTest.cpp) -corrade_add_test(MeshToolsRemoveDuplicatesTest RemoveDuplicatesTest.cpp) +corrade_add_test(MeshToolsRemoveDuplicatesTest RemoveDuplicatesTest.cpp LIBRARIES Magnum) corrade_add_test(MeshToolsSubdivideTest SubdivideTest.cpp) # corrade_add_test(MeshToolsSubdivideRemoveDuplicatesBenchmark SubdivideRemoveDuplicatesBenchmark.h SubdivideRemoveDuplicatesBenchmark.cpp MagnumPrimitives) corrade_add_test(MeshToolsTipsifyTest TipsifyTest.cpp LIBRARIES MagnumMeshTools) diff --git a/src/Magnum/MeshTools/Test/CombineIndexedArraysTest.cpp b/src/Magnum/MeshTools/Test/CombineIndexedArraysTest.cpp index 510e342c4..2e5675ec4 100644 --- a/src/Magnum/MeshTools/Test/CombineIndexedArraysTest.cpp +++ b/src/Magnum/MeshTools/Test/CombineIndexedArraysTest.cpp @@ -27,7 +27,7 @@ #include #include -#include "Magnum/Types.h" +#include "Magnum/Magnum.h" #include "Magnum/MeshTools/CombineIndexedArrays.h" namespace Magnum { namespace MeshTools { namespace Test { @@ -37,12 +37,14 @@ class CombineIndexedArraysTest: public TestSuite::Tester { CombineIndexedArraysTest(); void wrongIndexCount(); - void combine(); + void indexArrays(); + void indexedArrays(); }; CombineIndexedArraysTest::CombineIndexedArraysTest() { addTests({&CombineIndexedArraysTest::wrongIndexCount, - &CombineIndexedArraysTest::combine}); + &CombineIndexedArraysTest::indexArrays, + &CombineIndexedArraysTest::indexedArrays}); } void CombineIndexedArraysTest::wrongIndexCount() { @@ -50,16 +52,24 @@ void CombineIndexedArraysTest::wrongIndexCount() { Error::setOutput(&ss); std::vector a{0, 1, 0}; std::vector b{3, 4}; - std::vector array; - std::vector result = MeshTools::combineIndexedArrays( - std::make_tuple(std::cref(a), std::ref(array)), - std::make_tuple(std::cref(b), std::ref(array))); + std::vector result = MeshTools::combineIndexArrays({a, b}); + + CORRADE_COMPARE(ss.str(), "MeshTools::combineIndexArrays(): the arrays don't have the same size\n"); +} + +void CombineIndexedArraysTest::indexArrays() { + std::vector a{0, 1, 0}; + std::vector b{3, 4, 3}; + std::vector c{6, 7, 6}; - CORRADE_COMPARE(result.size(), 0); - CORRADE_COMPARE(ss.str(), "MeshTools::combineIndexedArrays(): index arrays don't have the same length, nothing done.\n"); + std::vector result = MeshTools::combineIndexArrays({a, b, c}); + CORRADE_COMPARE(result, (std::vector{0, 1, 0})); + CORRADE_COMPARE(a, (std::vector{0, 1})); + CORRADE_COMPARE(b, (std::vector{3, 4})); + CORRADE_COMPARE(c, (std::vector{6, 7})); } -void CombineIndexedArraysTest::combine() { +void CombineIndexedArraysTest::indexedArrays() { std::vector a{0, 1, 0}; std::vector b{3, 4, 3}; std::vector c{6, 7, 6}; @@ -68,9 +78,9 @@ void CombineIndexedArraysTest::combine() { std::vector array3{ 0, 1, 2, 3, 4, 5, 6, 7 }; std::vector result = MeshTools::combineIndexedArrays( - std::make_tuple(std::cref(a), std::ref(array1)), - std::make_tuple(std::cref(b), std::ref(array2)), - std::make_tuple(std::cref(c), std::ref(array3))); + std::make_pair(std::cref(a), std::ref(array1)), + std::make_pair(std::cref(b), std::ref(array2)), + std::make_pair(std::cref(c), std::ref(array3))); CORRADE_COMPARE(result, (std::vector{0, 1, 0})); CORRADE_COMPARE(array1, (std::vector{0, 1})); diff --git a/src/Magnum/MeshTools/Test/RemoveDuplicatesTest.cpp b/src/Magnum/MeshTools/Test/RemoveDuplicatesTest.cpp index 2561ed7d5..fd6a9da0b 100644 --- a/src/Magnum/MeshTools/Test/RemoveDuplicatesTest.cpp +++ b/src/Magnum/MeshTools/Test/RemoveDuplicatesTest.cpp @@ -25,6 +25,7 @@ #include +#include "Magnum/Math/Vector2.h" #include "Magnum/MeshTools/RemoveDuplicates.h" namespace Magnum { namespace MeshTools { namespace Test { @@ -33,23 +34,30 @@ class RemoveDuplicatesTest: public TestSuite::Tester { public: RemoveDuplicatesTest(); - void cleanMesh(); + void removeDuplicates(); }; -typedef Math::Vector<1, int> Vector1; - RemoveDuplicatesTest::RemoveDuplicatesTest() { - addTests({&RemoveDuplicatesTest::cleanMesh}); + addTests({&RemoveDuplicatesTest::removeDuplicates}); } -void RemoveDuplicatesTest::cleanMesh() { - std::vector positions{1, 2, 1, 4}; - std::vector indices{0, 1, 2, 1, 2, 3}; - MeshTools::removeDuplicates(indices, positions); +void RemoveDuplicatesTest::removeDuplicates() { + /* Numbers with distance 1 should be merged, numbers with distance 2 should + be kept. Testing both even-odd and odd-even sequence to verify that + half-epsilon translations are applied properly. */ + std::vector data{ + {1, 0}, + {2, 1}, + {0, 4}, + {1, 5} + }; - /* Verify cleanup */ - CORRADE_VERIFY(positions == (std::vector{1, 2, 4})); - CORRADE_COMPARE(indices, (std::vector{0, 1, 0, 1, 0, 2})); + const std::vector indices = MeshTools::removeDuplicates(data, 2); + CORRADE_COMPARE(indices, (std::vector{0, 0, 1, 1})); + CORRADE_COMPARE(data, (std::vector{ + {1, 0}, + {0, 4} + })); } }}} diff --git a/src/Magnum/MeshTools/Test/SubdivideTest.cpp b/src/Magnum/MeshTools/Test/SubdivideTest.cpp index e3fdf4c01..56095c4be 100644 --- a/src/Magnum/MeshTools/Test/SubdivideTest.cpp +++ b/src/Magnum/MeshTools/Test/SubdivideTest.cpp @@ -71,11 +71,6 @@ void SubdivideTest::subdivide() { CORRADE_VERIFY(positions == (std::vector{0, 2, 6, 8, 1, 4, 3, 4, 7, 5})); CORRADE_COMPARE(indices, (std::vector{4, 5, 6, 7, 8, 9, 0, 4, 6, 4, 1, 5, 6, 5, 2, 1, 7, 9, 7, 2, 8, 9, 8, 3})); - - MeshTools::removeDuplicates(indices, positions); - - /* Positions 0, 1, 2, 3, 4, 5, 6, 7, 8 */ - CORRADE_COMPARE(positions.size(), 9); } }}} diff --git a/src/Magnum/MeshTools/Tipsify.cpp b/src/Magnum/MeshTools/Tipsify.cpp index 86e6bffac..96277bc5a 100644 --- a/src/Magnum/MeshTools/Tipsify.cpp +++ b/src/Magnum/MeshTools/Tipsify.cpp @@ -61,7 +61,9 @@ void Tipsify::operator()(std::size_t cacheSize) { emitted[t] = true; /* Write all vertices of the triangle to output buffer */ - for(UnsignedInt vi = 0, v = indices[t*3]; vi != 3; v = indices[++vi+t*3]) { + for(UnsignedInt vi = 0; vi != 3; ++vi) { + const UnsignedInt v = indices[vi + t*3]; + outputIndices.push_back(v); /* Add to dead end stack and candidates array */ diff --git a/src/Magnum/MeshView.cpp b/src/Magnum/MeshView.cpp index ac8ea04a4..893b50c02 100644 --- a/src/Magnum/MeshView.cpp +++ b/src/Magnum/MeshView.cpp @@ -44,6 +44,17 @@ MeshView& MeshView::setIndexRange(Int first, Int count, UnsignedInt, UnsignedInt return *this; } +void MeshView::draw(AbstractShaderProgram& shader) { + shader.use(); + + #ifndef MAGNUM_TARGET_GLES2 + _original->drawInternal(_firstVertex, _vertexCount, _indexOffset, _indexCount, _indexStart, _indexEnd); + #else + _original->drawInternal(_firstVertex, _vertexCount, _indexOffset, _indexCount); + #endif +} + +#ifdef MAGNUM_BUILD_DEPRECATED void MeshView::draw() { #ifndef MAGNUM_TARGET_GLES2 _original->drawInternal(_firstVertex, _vertexCount, _indexOffset, _indexCount, _indexStart, _indexEnd); @@ -51,5 +62,6 @@ void MeshView::draw() { _original->drawInternal(_firstVertex, _vertexCount, _indexOffset, _indexCount); #endif } +#endif } diff --git a/src/Magnum/MeshView.h b/src/Magnum/MeshView.h index cde4452fc..4b137ea17 100644 --- a/src/Magnum/MeshView.h +++ b/src/Magnum/MeshView.h @@ -120,7 +120,16 @@ class MAGNUM_EXPORT MeshView { * * See @ref Mesh::draw() for more information. */ - void draw(); + void draw(AbstractShaderProgram& shader); + void draw(AbstractShaderProgram&& shader) { draw(shader); } /**< @overload */ + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @copybrief draw(AbstractShaderProgram&) + * @deprecated Use + */ + CORRADE_DEPRECATED("use draw(AbstractShaderProgram&) instead") void draw(); + #endif private: Mesh* _original; diff --git a/src/Magnum/MultisampleTexture.h b/src/Magnum/MultisampleTexture.h new file mode 100644 index 000000000..97c986b6d --- /dev/null +++ b/src/Magnum/MultisampleTexture.h @@ -0,0 +1,115 @@ +#ifndef Magnum_MultisampleTexture_h +#define Magnum_MultisampleTexture_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. +*/ + +#ifndef MAGNUM_TARGET_GLES +/** @file + * @brief Class @ref Magnum::MultisampleTexture, typedef @ref Magnum::MultisampleTexture2D, @ref Magnum::MultisampleTexture2DArray + */ +#endif + +#include "Magnum/AbstractTexture.h" +#include "Magnum/DimensionTraits.h" +#include "Magnum/Math/Vector3.h" + +#ifndef MAGNUM_TARGET_GLES +namespace Magnum { + +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; } +} + +/** +@brief Mulitsample texture + +Template class for 2D mulitsample texture and 2D multisample texture array. See +also @ref AbstractTexture documentation for more information. + +@todoc Finish when fully implemented + +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. + +@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 Constructor + * + * Creates new OpenGL texture object. + * @see @fn_gl{GenTextures} with @def_gl{TEXTURE_2D_MULTISAMPLE} or + * @def_gl{TEXTURE_2D_MULTISAMPLE_ARRAY} + */ + explicit MultisampleTexture(): AbstractTexture(Implementation::multisampleTextureTarget()) {} + + #ifndef MAGNUM_TARGET_GLES + /** @copydoc Texture::imageSize() */ + typename DimensionTraits::VectorType imageSize(Int level) { + return DataHelper::imageSize(*this, _target, level); + } + #endif + + /** @copydoc Texture::invalidateImage() */ + void invalidateImage(Int level) { AbstractTexture::invalidateImage(level); } + + /** @copydoc Texture::invalidateSubImage() */ + void invalidateSubImage(Int level, const typename DimensionTraits::VectorType& offset, const typename DimensionTraits::VectorType& size) { + DataHelper::invalidateSubImage(*this, level, offset, size); + } + + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + MultisampleTexture& setLabel(const std::string& label) { + AbstractTexture::setLabel(label); + return *this; + } + #endif +}; + +/** @brief Two-dimensional multisample texture */ +typedef MultisampleTexture<2> MultisampleTexture2D; + +/** @brief Two-dimensional multisample texture array */ +typedef MultisampleTexture<3> MultisampleTexture2DArray; + +} +#else +#error this header is available only on desktop OpenGL build +#endif + +#endif diff --git a/src/Magnum/Primitives/Icosphere.cpp b/src/Magnum/Primitives/Icosphere.cpp index aa0e42fc2..93203ac68 100644 --- a/src/Magnum/Primitives/Icosphere.cpp +++ b/src/Magnum/Primitives/Icosphere.cpp @@ -27,8 +27,9 @@ #include "Magnum/Mesh.h" #include "Magnum/Math/Vector3.h" -#include "Magnum/MeshTools/Subdivide.h" +#include "Magnum/MeshTools/Duplicate.h" #include "Magnum/MeshTools/RemoveDuplicates.h" +#include "Magnum/MeshTools/Subdivide.h" #include "Magnum/Trade/MeshData3D.h" namespace Magnum { namespace Primitives { @@ -81,7 +82,7 @@ Trade::MeshData3D Icosphere::solid(const UnsignedInt subdivisions) { for(std::size_t i = 0; i != subdivisions; ++i) MeshTools::subdivide(indices, positions, interpolator); - MeshTools::removeDuplicates(indices, positions); + indices = MeshTools::duplicate(indices, MeshTools::removeDuplicates(positions)); std::vector normals(positions); return Trade::MeshData3D(MeshPrimitive::Triangles, std::move(indices), {std::move(positions)}, {std::move(normals)}, std::vector>{}); diff --git a/src/Magnum/Query.h b/src/Magnum/Query.h index c093c948a..45934a5b7 100644 --- a/src/Magnum/Query.h +++ b/src/Magnum/Query.h @@ -41,7 +41,6 @@ namespace Magnum { See @ref PrimitiveQuery, @ref SampleQuery and @ref TimeQuery documentation for more information. -@todo Support for AMD's query buffer (@extension{AMD,query_buffer_object}) @todo `QUERY_COUNTER_BITS` (not sure since when this is supported) */ class MAGNUM_EXPORT AbstractQuery: public AbstractObject { @@ -65,9 +64,9 @@ class MAGNUM_EXPORT AbstractQuery: public AbstractObject { * @brief %Query label * * The result is *not* cached, repeated queries will result in repeated - * OpenGL calls. If neither @extension{KHR,debug} nor - * @extension2{EXT,debug_label} desktop or ES extension is available, - * this function returns empty string. + * OpenGL calls. If OpenGL 4.3 is not supported and neither + * @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES + * extension is available, this function returns empty string. * @see @fn_gl{GetObjectLabel} with @def_gl{QUERY} or * @fn_gl_extension2{GetObjectLabel,EXT,debug_label} with * @def_gl{QUERY_OBJECT_EXT} @@ -78,9 +77,9 @@ class MAGNUM_EXPORT AbstractQuery: public AbstractObject { * @brief Set query label * @return Reference to self (for method chaining) * - * Default is empty string. If neither @extension{KHR,debug} nor - * @extension2{EXT,debug_label} desktop or ES extension is available, - * this function does nothing. + * Default is empty string. If OpenGL 4.3 is not supported and neither + * @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES + * extension is available, this function does nothing. * @see @ref maxLabelLength(), @fn_gl{ObjectLabel} with * @def_gl{QUERY} or @fn_gl_extension2{LabelObject,EXT,debug_label} * with @def_gl{QUERY_OBJECT_EXT} @@ -262,8 +261,9 @@ q.beginConditionalRender(SampleQuery::ConditionalRenderMode::Wait); // render full version of the object only if the query returns nonzero result q.endConditionalRender(); @endcode -@requires_gles30 %Extension @es_extension{EXT,occlusion_query_boolean} +@requires_gles30 %Extension @es_extension{EXT,occlusion_query_boolean} in + OpenGL ES 2.0 @see @ref PrimitiveQuery, @ref TimeQuery */ class SampleQuery: public AbstractQuery { diff --git a/src/Magnum/RectangleTexture.h b/src/Magnum/RectangleTexture.h new file mode 100644 index 000000000..2d8c76c6c --- /dev/null +++ b/src/Magnum/RectangleTexture.h @@ -0,0 +1,322 @@ +#ifndef Magnum_RectangleTexture_h +#define Magnum_RectangleTexture_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. +*/ + +#ifndef MAGNUM_TARGET_GLES +/** @file + * @brief Class @ref Magnum::RectangleTexture + */ +#endif + +#include "Magnum/AbstractTexture.h" +#include "Magnum/Array.h" +#include "Magnum/Math/Vector2.h" + +#ifndef MAGNUM_TARGET_GLES +namespace Magnum { + +/** +@brief Rectangle texture + +See also @ref AbstractTexture documentation for more information. + +@section RectangleTexture-usage Usage + +Common usage is to fully configure all texture parameters and then set the +data from e.g. @ref Image2D. Example configuration: +@code +Image2D image(ColorFormat::RGBA, ColorType::UnsignedByte, {526, 137}, data); + +RectangleTexture texture; +texture.setMagnificationFilter(Sampler::Filter::Linear) + .setMinificationFilter(Sampler::Filter::Linear) + .setWrapping(Sampler::Wrapping::ClampToEdge) + .setMaxAnisotropy(Sampler::maxMaxAnisotropy()) + .setStorage(TextureFormat::RGBA8, {526, 137}) + .setSubImage({}, image); +@endcode + +In shader, the texture is used via sampler2DRect`, `sampler2DRectShadow`, +`isampler2DRect` or `usampler2DRect`. See @ref AbstractShaderProgram +documentation for more information about usage in shaders. + +@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 { + public: + /** + * @brief Constructor + * + * Creates new OpenGL texture object. + * @see @fn_gl{GenTextures} with @def_gl{TEXTURE_RECTANGLE} + */ + explicit RectangleTexture(): AbstractTexture(GL_TEXTURE_RECTANGLE) {} + + /** + * @brief Set minification filter + * @param filter Filter + * @return Reference to self (for method chaining) + * + * Sets filter used when the object pixel size is smaller than the + * texture size. If @extension{EXT,direct_state_access} is not + * available, the texture is bound to some layer 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_MIN_FILTER} + */ + RectangleTexture& setMinificationFilter(Sampler::Filter filter) { + AbstractTexture::setMinificationFilter(filter, Sampler::Mipmap::Base); + return *this; + } + + /** @copydoc Texture::setMagnificationFilter() */ + RectangleTexture& setMagnificationFilter(Sampler::Filter filter) { + AbstractTexture::setMagnificationFilter(filter); + return *this; + } + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief %Image size + * + * The result is not cached in any way. If + * @extension{EXT,direct_state_access} is not available, the texture + * is bound to some layer before the operation. + * @see @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} + * @requires_gl %Texture image queries are not available in OpenGL ES. + */ + Vector2i imageSize() { return DataHelper<2>::imageSize(*this, _target, 0); } + #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 (0, textureSizeInGivenDirection-1) + * range for rectangle textures. If @extension{EXT,direct_state_access} + * is not available, the texture is bound to some layer 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}, + * @def_gl{TEXTURE_WRAP_R} + */ + RectangleTexture& setWrapping(const Array2D& wrapping) { + DataHelper<2>::setWrapping(*this, wrapping); + return *this; + } + + /** @copydoc Texture::setBorderColor() */ + RectangleTexture& setBorderColor(const Color4& color) { + AbstractTexture::setBorderColor(color); + return *this; + } + + /** @copydoc Texture::setMaxAnisotropy() */ + RectangleTexture& setMaxAnisotropy(Float anisotropy) { + AbstractTexture::setMaxAnisotropy(anisotropy); + return *this; + } + + /** + * @brief Set storage + * @param internalFormat Internal format + * @param size Size + * @return Reference to self (for method chaining) + * + * Specifies entire structure of a texture at once, removing the need + * for additional consistency checks and memory reallocations when + * updating the data later. After calling this function the texture + * is immutable and calling @ref setStorage() or @ref setImage() is not + * allowed. + * + * If @extension{EXT,direct_state_access} is not available, the texture + * is bound to some layer before the operation. If @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}, + * eventually @fn_gl{TexImage2D} or + * @fn_gl_extension{TextureImage2D,EXT,direct_state_access}. + */ + RectangleTexture& setStorage(TextureFormat internalFormat, const Vector2i& size) { + DataHelper<2>::setStorage(*this, _target, 1, internalFormat, size); + return *this; + } + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Read texture to image + * @param image %Image where to put the data + * + * %Image parameters like format and type of pixel data are taken from + * given image, image size is taken from the texture using + * @ref imageSize(). + * + * If @extension{EXT,direct_state_access} is not available, the + * texture is bound to some layer before the operation. If + * @extension{ARB,robustness} is available, the operation is protected + * from buffer overflow. However, if both @extension{EXT,direct_state_access} + * and @extension{ARB,robustness} are available, the DSA version is + * used, because it is better for performance and there isn't any + * function combining both features. + * @requires_gl %Texture image queries are not available in OpenGL ES. + * @see @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}, then + * @fn_gl{GetTexImage}, @fn_gl_extension{GetTextureImage,EXT,direct_state_access} + * or @fn_gl_extension{GetnTexImage,ARB,robustness} + */ + void image(Image2D& image) { + AbstractTexture::image<2>(_target, 0, image); + } + + /** + * @brief Read given mip level of texture to buffer image + * @param image %Buffer image where to put the data + * @param usage %Buffer usage + * + * See @ref image(Image2D&) for more information. + * @requires_gl %Texture image queries are not available in OpenGL ES. + */ + void image(BufferImage2D& image, BufferUsage usage) { + AbstractTexture::image<2>(_target, 0, image, usage); + } + #endif + + /** + * @brief Set image data + * @param internalFormat Internal format + * @param image @ref Image2D, @ref ImageReference2D or + * @ref Trade::ImageData2D + * @return Reference to self (for method chaining) + * + * For better performance when calling @ref setImage() more than once + * use @ref setStorage() and @ref setSubImage() instead. + * + * If @extension{EXT,direct_state_access} is not available, the + * texture is bound to some layer before the operation. + * @see @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); + return *this; + } + + #ifndef MAGNUM_TARGET_GLES2 + /** @overload */ + RectangleTexture& setImage(TextureFormat internalFormat, BufferImage2D& image) { + DataHelper<2>::setImage(*this, _target, 0, internalFormat, image); + return *this; + } + + /** @overload */ + RectangleTexture& setImage(TextureFormat internalFormat, BufferImage2D&& image) { + return setImage(internalFormat, image); + } + #endif + + /** + * @brief Set image subdata + * @param offset Offset where to put data in the texture + * @param image @ref Image2D, @ref ImageReference2D or + * @ref Trade::ImageData2D + * @return Reference to self (for method chaining) + * + * If @extension{EXT,direct_state_access} is not available, the + * texture is bound to some layer before the operation. + * @see @ref setStorage(), @ref setImage(), @fn_gl{ActiveTexture}, + * @fn_gl{BindTexture} and @fn_gl{TexSubImage2D} or + * @fn_gl_extension{TextureSubImage2D,EXT,direct_state_access} + */ + RectangleTexture& setSubImage(const Vector2i& offset, const ImageReference2D& image) { + DataHelper<2>::setSubImage(*this, _target, 0, offset, image); + return *this; + } + + #ifndef MAGNUM_TARGET_GLES2 + /** @overload */ + RectangleTexture& setSubImage(const Vector2i& offset, BufferImage2D& image) { + DataHelper<2>::setSubImage(*this, _target, 0, offset, image); + return *this; + } + + /** @overload */ + RectangleTexture& setSubImage(const Vector2i& offset, BufferImage2D&& image) { + return setSubImage(offset, image); + } + #endif + + /** + * @brief Invalidate texture image + * + * If running on OpenGL ES or extension @extension{ARB,invalidate_subdata} + * (part of OpenGL 4.3) is not available, this function does nothing. + * @see @ref invalidateSubImage(), @fn_gl{InvalidateTexImage} + */ + void invalidateImage() { AbstractTexture::invalidateImage(0); } + + /** + * @brief Invalidate texture subimage + * @param offset Offset into the texture + * @param size Size of invalidated data + * + * If running on OpenGL ES or extension @extension{ARB,invalidate_subdata} + * (part of OpenGL 4.3) is not available, this function does nothing. + * @see @ref invalidateImage(), @fn_gl{InvalidateTexSubImage} + */ + void invalidateSubImage(const Vector2i& offset, const Vector2i& size) { + DataHelper<2>::invalidateSubImage(*this, 0, offset, size); + } + + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + RectangleTexture& setLabel(const std::string& label) { + AbstractTexture::setLabel(label); + return *this; + } + #endif +}; + +} +#else +#error this header is available only on desktop OpenGL build +#endif + +#endif diff --git a/src/Magnum/Renderbuffer.cpp b/src/Magnum/Renderbuffer.cpp index 12f27a53a..47a99b4bb 100644 --- a/src/Magnum/Renderbuffer.cpp +++ b/src/Magnum/Renderbuffer.cpp @@ -34,14 +34,6 @@ namespace Magnum { -Renderbuffer::StorageImplementation Renderbuffer::storageImplementation = &Renderbuffer::storageImplementationDefault; -Renderbuffer::StorageMultisampleImplementation Renderbuffer::storageMultisampleImplementation = - #ifndef MAGNUM_TARGET_GLES2 - &Renderbuffer::storageMultisampleImplementationDefault; - #else - nullptr; - #endif - Int Renderbuffer::maxSize() { GLint& value = Context::current()->state().framebuffer->maxRenderbufferSize; @@ -94,6 +86,14 @@ Renderbuffer& Renderbuffer::setLabel(const std::string& label) { return *this; } +void Renderbuffer::setStorage(const RenderbufferFormat internalFormat, const Vector2i& size) { + (this->*Context::current()->state().framebuffer->renderbufferStorageImplementation)(internalFormat, size); +} + +void Renderbuffer::setStorageMultisample(const Int samples, const RenderbufferFormat internalFormat, const Vector2i& size) { + (this->*Context::current()->state().framebuffer->renderbufferStorageMultisampleImplementation)(samples, internalFormat, size); +} + void Renderbuffer::bind() { GLuint& binding = Context::current()->state().framebuffer->renderbufferBinding; @@ -103,29 +103,6 @@ void Renderbuffer::bind() { glBindRenderbuffer(GL_RENDERBUFFER, _id); } -void Renderbuffer::initializeContextBasedFunctionality(Context& context) { - #ifndef MAGNUM_TARGET_GLES - if(context.isExtensionSupported()) { - Debug() << "Renderbuffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; - - storageImplementation = &Renderbuffer::storageImplementationDSA; - storageMultisampleImplementation = &Renderbuffer::storageMultisampleImplementationDSA; - } - #elif !defined(MAGNUM_TARGET_GLES3) - if(context.isExtensionSupported()) { - Debug() << "Renderbuffer: using" << Extensions::GL::ANGLE::framebuffer_multisample::string() << "features"; - - storageMultisampleImplementation = &Renderbuffer::storageMultisampleImplementationANGLE; - } else if (context.isExtensionSupported()) { - Debug() << "Renderbuffer: using" << Extensions::GL::NV::framebuffer_multisample::string() << "features"; - - storageMultisampleImplementation = &Renderbuffer::storageMultisampleImplementationNV; - } - #else - static_cast(context); - #endif -} - void Renderbuffer::storageImplementationDefault(RenderbufferFormat internalFormat, const Vector2i& size) { bind(); glRenderbufferStorage(GL_RENDERBUFFER, GLenum(internalFormat), size.x(), size.y()); diff --git a/src/Magnum/Renderbuffer.h b/src/Magnum/Renderbuffer.h index df55798de..750cfa3d9 100644 --- a/src/Magnum/Renderbuffer.h +++ b/src/Magnum/Renderbuffer.h @@ -38,6 +38,8 @@ namespace Magnum { +namespace Implementation { struct FramebufferState; } + /** @brief %Renderbuffer @@ -58,7 +60,7 @@ See its documentation for more information. @requires_gl30 %Extension @extension{ARB,framebuffer_object} */ class MAGNUM_EXPORT Renderbuffer: public AbstractObject { - friend class Context; + friend struct Implementation::FramebufferState; public: /** @@ -117,9 +119,9 @@ class MAGNUM_EXPORT Renderbuffer: public AbstractObject { * @brief %Renderbuffer label * * The result is *not* cached, repeated queries will result in repeated - * OpenGL calls. If neither @extension{KHR,debug} nor - * @extension2{EXT,debug_label} desktop or ES extension is available, - * this function returns empty string. + * OpenGL calls. If OpenGL 4.3 is not supported and neither + * @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES + * extension is available, this function returns empty string. * @see @fn_gl{GetObjectLabel} or * @fn_gl_extension2{GetObjectLabel,EXT,debug_label} with * @def_gl{RENDERBUFFER} @@ -130,9 +132,9 @@ class MAGNUM_EXPORT Renderbuffer: public AbstractObject { * @brief Set renderbuffer label * @return Reference to self (for method chaining) * - * Default is empty string. If neither @extension{KHR,debug} nor - * @extension2{EXT,debug_label} desktop or ES extension is available, - * this function does nothing. + * Default is empty string. If OpenGL 4.3 is not supported and neither + * @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES + * extension is available, this function does nothing. * @see @ref maxLabelLength(), @fn_gl{ObjectLabel} or * @fn_gl_extension2{LabelObject,EXT,debug_label} with * @def_gl{RENDERBUFFER} @@ -150,9 +152,7 @@ class MAGNUM_EXPORT Renderbuffer: public AbstractObject { * @see @ref maxSize(), @fn_gl{BindRenderbuffer}, @fn_gl{RenderbufferStorage} * or @fn_gl_extension{NamedRenderbufferStorage,EXT,direct_state_access} */ - void setStorage(RenderbufferFormat internalFormat, const Vector2i& size) { - (this->*storageImplementation)(internalFormat, size); - } + void setStorage(RenderbufferFormat internalFormat, const Vector2i& size); /** * @brief Set multisample renderbuffer storage @@ -166,35 +166,27 @@ class MAGNUM_EXPORT Renderbuffer: public AbstractObject { * @see @ref maxSize(), @ref maxSamples(), @fn_gl{BindRenderbuffer}, * @fn_gl{RenderbufferStorageMultisample} or @fn_gl_extension{NamedRenderbufferStorageMultisample,EXT,direct_state_access} * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_multisample} - * or @es_extension{NV,framebuffer_multisample} + * or @es_extension{NV,framebuffer_multisample} in OpenGL ES 2.0 * @todo How about @es_extension{APPLE,framebuffer_multisample}? * @todo NaCl has @fn_gl_extension{RenderbufferStorageMultisample,EXT,multisampled_render_to_texture} */ - void setStorageMultisample(Int samples, RenderbufferFormat internalFormat, const Vector2i& size) { - (this->*storageMultisampleImplementation)(samples, internalFormat, size); - } + void setStorageMultisample(Int samples, RenderbufferFormat internalFormat, const Vector2i& size); private: - static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context); - - typedef void(Renderbuffer::*StorageImplementation)(RenderbufferFormat, const Vector2i&); void MAGNUM_LOCAL storageImplementationDefault(RenderbufferFormat internalFormat, const Vector2i& size); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL storageImplementationDSA(RenderbufferFormat internalFormat, const Vector2i& size); #endif - static StorageImplementation storageImplementation; - typedef void(Renderbuffer::*StorageMultisampleImplementation)(GLsizei, RenderbufferFormat, const Vector2i&); #ifndef MAGNUM_TARGET_GLES2 void MAGNUM_LOCAL storageMultisampleImplementationDefault(GLsizei samples, RenderbufferFormat internalFormat, const Vector2i& size); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL storageMultisampleImplementationDSA(GLsizei samples, RenderbufferFormat internalFormat, const Vector2i& size); + #endif #else void MAGNUM_LOCAL storageMultisampleImplementationANGLE(GLsizei samples, RenderbufferFormat internalFormat, const Vector2i& size); void MAGNUM_LOCAL storageMultisampleImplementationNV(GLsizei samples, RenderbufferFormat internalFormat, const Vector2i& size); #endif - #ifndef MAGNUM_TARGET_GLES - void MAGNUM_LOCAL storageMultisampleImplementationDSA(GLsizei samples, RenderbufferFormat internalFormat, const Vector2i& size); - #endif - static StorageMultisampleImplementation storageMultisampleImplementation; void MAGNUM_LOCAL bind(); diff --git a/src/Magnum/RenderbufferFormat.h b/src/Magnum/RenderbufferFormat.h index 06dd008ca..8a417cb73 100644 --- a/src/Magnum/RenderbufferFormat.h +++ b/src/Magnum/RenderbufferFormat.h @@ -55,7 +55,8 @@ enum class RenderbufferFormat: GLenum { /** * Red component, normalized unsigned byte. * @requires_gl30 %Extension @extension{ARB,texture_rg} - * @requires_gles30 %Extension @es_extension{EXT,texture_rg} + * @requires_gles30 %Extension @es_extension{EXT,texture_rg} in OpenGL ES + * 2.0 */ #ifndef MAGNUM_TARGET_GLES2 R8 = GL_R8, @@ -78,7 +79,8 @@ enum class RenderbufferFormat: GLenum { /** * Red and green component, each normalized unsigned byte. * @requires_gl30 %Extension @extension{ARB,texture_rg} - * @requires_gles30 %Extension @es_extension{EXT,texture_rg} + * @requires_gles30 %Extension @es_extension{EXT,texture_rg} in OpenGL ES + * 2.0 */ #ifndef MAGNUM_TARGET_GLES2 RG8 = GL_RG8, @@ -99,6 +101,7 @@ enum class RenderbufferFormat: GLenum { /** * RGBA, each component normalized unsigned byte. * @requires_gles30 %Extension @es_extension{ARM,rgba8} or @es_extension{OES,rgb8_rgba8} + * in OpenGL ES 2.0 */ #ifndef MAGNUM_TARGET_GLES2 RGBA8 = GL_RGBA8, @@ -372,7 +375,7 @@ enum class RenderbufferFormat: GLenum { /** * sRGBA, each component normalized unsigned byte. - * @requires_gles30 %Extension @es_extension{EXT,sRGB} + * @requires_gles30 %Extension @es_extension{EXT,sRGB} in OpenGL ES 2.0 */ #ifndef MAGNUM_TARGET_GLES2 SRGB8Alpha8 = GL_SRGB8_ALPHA8, @@ -396,7 +399,7 @@ enum class RenderbufferFormat: GLenum { /** * Depth component, 24bit. - * @requires_gles30 %Extension @es_extension{OES,depth24} + * @requires_gles30 %Extension @es_extension{OES,depth24} in OpenGL ES 2.0 */ #ifndef MAGNUM_TARGET_GLES2 DepthComponent24 = GL_DEPTH_COMPONENT24, @@ -475,7 +478,8 @@ enum class RenderbufferFormat: GLenum { /** * 24bit depth and 8bit stencil component. - * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil} + * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil} in + * OpenGL ES 2.0 */ #ifdef MAGNUM_TARGET_GLES2 Depth24Stencil8 = GL_DEPTH24_STENCIL8_OES diff --git a/src/Magnum/Renderer.cpp b/src/Magnum/Renderer.cpp index 78e0933b7..e35a83c7f 100644 --- a/src/Magnum/Renderer.cpp +++ b/src/Magnum/Renderer.cpp @@ -35,13 +35,6 @@ namespace Magnum { -#ifndef MAGNUM_TARGET_GLES -Renderer::ClearDepthfImplementation Renderer::clearDepthfImplementation = &Renderer::clearDepthfImplementationDefault; -#else -Renderer::ClearDepthfImplementation Renderer::clearDepthfImplementation = &Renderer::clearDepthfImplementationES; -#endif -Renderer::GraphicsResetStatusImplementation Renderer::graphicsResetStatusImplementation = &Renderer::graphicsResetStatusImplementationDefault; - void Renderer::setFeature(const Feature feature, const bool enabled) { enabled ? glEnable(GLenum(feature)) : glDisable(GLenum(feature)); } @@ -60,6 +53,10 @@ void Renderer::setClearDepth(const Double depth) { } #endif +void Renderer::setClearDepth(Float depth) { + Context::current()->state().renderer->clearDepthfImplementation(depth); +} + void Renderer::setClearStencil(const Int stencil) { glClearStencil(stencil); } @@ -163,6 +160,13 @@ void Renderer::setLogicOperation(const LogicOperation operation) { #endif Renderer::ResetNotificationStrategy Renderer::resetNotificationStrategy() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + #else + if(!Context::current()->isExtensionSupported()) + #endif + return ResetNotificationStrategy::NoResetNotification; + ResetNotificationStrategy& strategy = Context::current()->state().renderer->resetNotificationStrategy; if(strategy == ResetNotificationStrategy()) { @@ -176,30 +180,11 @@ Renderer::ResetNotificationStrategy Renderer::resetNotificationStrategy() { return strategy; } -void Renderer::initializeContextBasedFunctionality(Context& context) { - #ifndef MAGNUM_TARGET_GLES - if(context.isExtensionSupported()) { - Debug() << "Renderer: using" << Extensions::GL::ARB::ES2_compatibility::string() << "features"; - - clearDepthfImplementation = &Renderer::clearDepthfImplementationES; - } - #endif - - #ifndef MAGNUM_TARGET_GLES - if(context.isExtensionSupported()) - #else - if(context.isExtensionSupported()) - #endif - { - #ifndef MAGNUM_TARGET_GLES - Debug() << "Renderer: using" << Extensions::GL::ARB::robustness::string() << "features"; - #else - Debug() << "Renderer: using" << Extensions::GL::EXT::robustness::string() << "features"; - #endif - - graphicsResetStatusImplementation = &Renderer::graphicsResetStatusImplementationRobustness; - } +Renderer::GraphicsResetStatus Renderer::graphicsResetStatus() { + return Context::current()->state().renderer->graphicsResetStatusImplementation(); +} +void Renderer::initializeContextBasedFunctionality() { /* Set some "corporate identity" */ setClearColor(Color3(0.125f)); } diff --git a/src/Magnum/Renderer.h b/src/Magnum/Renderer.h index f09d271f2..d36e956b5 100644 --- a/src/Magnum/Renderer.h +++ b/src/Magnum/Renderer.h @@ -37,6 +37,8 @@ namespace Magnum { +namespace Implementation { struct RendererState; } + /** @nosubgrouping @brief Global renderer configuration. @@ -47,6 +49,7 @@ namespace Magnum { */ class MAGNUM_EXPORT Renderer { friend class Context; + friend struct Implementation::RendererState; public: Renderer() = delete; @@ -230,6 +233,7 @@ class MAGNUM_EXPORT Renderer { /** * Accuracy of derivative calculation in fragment shader. * @requires_gles30 %Extension @es_extension{OES,standard_derivatives} + * in OpenGL ES 2.0 */ #ifndef MAGNUM_TARGET_GLES2 FragmentShaderDerivative = GL_FRAGMENT_SHADER_DERIVATIVE_HINT @@ -287,9 +291,7 @@ class MAGNUM_EXPORT Renderer { * If OpenGL ES, OpenGL 4.1 or extension @extension{ARB,ES2_compatibility} * is not available, this function behaves exactly as setClearDepth(Double). */ - static void setClearDepth(Float depth) { - clearDepthfImplementation(depth); - } + static void setClearDepth(Float depth); /** * @brief Set clear stencil @@ -642,12 +644,14 @@ class MAGNUM_EXPORT Renderer { /** * `min(source, destination)` * @requires_gles30 %Extension @es_extension2{EXT,blend_minmax,blend_minmax} + * in OpenGL ES 2.0 */ Min = GL_MIN, /** * `max(source, destination)` * @requires_gles30 %Extension @es_extension2{EXT,blend_minmax,blend_minmax} + * in OpenGL ES 2.0 */ Max = GL_MAX #endif @@ -1037,26 +1041,20 @@ class MAGNUM_EXPORT Renderer { * is not available, this function always returns @ref GraphicsResetStatus::NoError. * @see @ref resetNotificationStrategy(), @fn_gl_extension{GetGraphicsResetStatus,ARB,robustness} */ - static GraphicsResetStatus graphicsResetStatus() { - return graphicsResetStatusImplementation(); - } + static GraphicsResetStatus graphicsResetStatus(); /*@}*/ private: - static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context& context); + static void MAGNUM_LOCAL initializeContextBasedFunctionality(); - typedef void(*ClearDepthfImplementation)(GLfloat); #ifndef MAGNUM_TARGET_GLES static void MAGNUM_LOCAL clearDepthfImplementationDefault(GLfloat depth); #endif static void MAGNUM_LOCAL clearDepthfImplementationES(GLfloat depth); - static ClearDepthfImplementation clearDepthfImplementation; - typedef GraphicsResetStatus(*GraphicsResetStatusImplementation)(); static GraphicsResetStatus MAGNUM_LOCAL graphicsResetStatusImplementationDefault(); static GraphicsResetStatus MAGNUM_LOCAL graphicsResetStatusImplementationRobustness(); - static GraphicsResetStatusImplementation graphicsResetStatusImplementation; }; /** @debugoperator{Renderer} */ diff --git a/src/Magnum/Resource.h b/src/Magnum/Resource.h index 28b225fd6..c50b7ba6a 100644 --- a/src/Magnum/Resource.h +++ b/src/Magnum/Resource.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::ResourceKey, Magnum::Resource, enum Magnum::ResourceState + * @brief Class @ref Magnum::ResourceKey, @ref Magnum::Resource, enum @ref Magnum::ResourceState */ #include @@ -39,11 +39,11 @@ namespace Magnum { -/** @relates Resource - * @brief %Resource state - * - * @see Resource::state(), ResourceManager::state() - */ +/** +@brief %Resource state + +@see @ref Resource::state(), @ref ResourceManager::state() +*/ enum class ResourceState: UnsignedByte { /** The resource is not yet loaded (and no fallback is available). */ NotLoaded, @@ -76,9 +76,7 @@ Debug MAGNUM_EXPORT operator<<(Debug debug, ResourceState value); /** @brief Key for accessing resource -See ResourceManager for more information. -@see ResourceManager::referenceCount(), ResourceManager::state(), - ResourceManager::get(), ResourceManager::set(), Resource::key() +See @ref ResourceManager for more information. */ class ResourceKey: public Utility::MurmurHash2::Digest { public: @@ -112,7 +110,7 @@ namespace Implementation { /** @brief %Resource reference -See ResourceManager for more information. +See @ref ResourceManager for more information. */ #ifdef DOXYGEN_GENERATING_OUTPUT template @@ -127,7 +125,7 @@ class Resource { * @brief Default constructor * * Creates empty resource. Resources are acquired from the manager by - * calling ResourceManager::get(). + * calling @ref ResourceManager::get(). */ explicit Resource(): manager(nullptr), lastCheck(0), _state(ResourceState::Final), data(nullptr) {} @@ -159,7 +157,7 @@ class Resource { /** * @brief %Resource state * - * @see operator bool(), ResourceManager::state() + * @see @ref operator bool(), @ref ResourceManager::state() */ ResourceState state() { acquire(); @@ -193,28 +191,39 @@ class Resource { * @brief Reference to resource data * * The resource must be loaded before accessing it. Use boolean - * conversion operator or state() for testing whether it is loaded. + * conversion operator or @ref state() for testing whether it is + * loaded. */ - operator U&() { + U& operator*() { acquire(); CORRADE_ASSERT(data, "Resource: accessing not loaded data with key" << key(), *static_cast(data)); return *static_cast(data); } - /** @overload */ + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @overload + * @deprecated Use the explicit @ref Magnum::Resource::operator*() "operator*()" or + * @ref Magnum::Resource::operator->() "operator->()" instead. + * Implicit conversion is no longer allowed if it might throw an + * assertion. + */ + CORRADE_DEPRECATED("use operator*() or operator->() instead") operator U&() { return **this; } + #endif + + /** + * @brief Access to resource data + * + * The resource must be loaded before accessing it. Use boolean + * conversion operator or @ref state() for testing whether it is + * loaded. + */ U* operator->() { acquire(); CORRADE_ASSERT(data, "Resource: accessing not loaded data with key" << key(), nullptr); return static_cast(data); } - /** @overload */ - U& operator*() { - acquire(); - CORRADE_ASSERT(data, "Resource: accessing not loaded data with key" << key(), *static_cast(data)); - return *static_cast(data); - } - private: Resource(Implementation::ResourceManagerData* manager, ResourceKey key): manager(manager), _key(key), lastCheck(0), _state(ResourceState::NotLoaded), data(nullptr) { manager->incrementReferenceCount(key); diff --git a/src/Magnum/ResourceManager.h b/src/Magnum/ResourceManager.h index b65376c75..a4b2ce0e5 100644 --- a/src/Magnum/ResourceManager.h +++ b/src/Magnum/ResourceManager.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::ResourceManager, enum Magnum::ResourceDataState, Magnum::ResourcePolicy + * @brief Class @ref Magnum::ResourceManager, @ref Magnum::ResourceDataState, @ref Magnum::ResourcePolicy */ #include @@ -35,44 +35,44 @@ namespace Magnum { -/** @relates ResourceManager - * @brief %Resource data state - * - * @see ResourceManager::set(), ResourceState - */ +/** +@brief %Resource data state + +@see @ref ResourceManager::set(), @ref ResourceState +*/ enum class ResourceDataState: UnsignedByte { /** - * The resource is currently loading. Parameter @p data in ResourceManager::set() - * should be set to `null`. + * The resource is currently loading. Parameter @p data in + * @ref ResourceManager::set() should be set to `nullptr`. */ Loading = UnsignedByte(ResourceState::Loading), /** - * The resource was not found. Parameter @p data in ResourceManager::set() - * should be set to `null`. + * The resource was not found. Parameter @p data in + * @ref ResourceManager::set() should be set to `nullptr`. */ NotFound = UnsignedByte(ResourceState::NotFound), /** * The resource can be changed by the manager in the future. This is - * slower, as Resource needs to ask the manager for new version every time - * the data are accessed, but allows changing the data for e.g. debugging - * purposes. + * slower, as @ref Resource needs to ask the manager for new version every + * time the data are accessed, but allows changing the data for e.g. + * debugging purposes. */ Mutable = UnsignedByte(ResourceState::Mutable), /** * The resource cannot be changed by the manager in the future. This is - * faster, as Resource instances will ask for the data only one time, thus - * suitable for production code. + * faster, as @ref Resource instances will ask for the data only one time, + * thus suitable for production code. */ Final = UnsignedByte(ResourceState::Final) }; -/** @relates ResourceManager +/** @brief %Resource policy -@see ResourceManager::set(), ResourceManager::free() +@see @ref ResourceManager::set(), @ref ResourceManager::free() */ enum class ResourcePolicy: UnsignedByte { /** The resource will stay resident for whole lifetime of resource manager. */ @@ -80,7 +80,7 @@ enum class ResourcePolicy: UnsignedByte { /** * The resource will be unloaded when manually calling - * ResourceManager::free() if nothing references it. + * @ref ResourceManager::free() if nothing references it. */ Manual, @@ -160,43 +160,43 @@ template class ResourceManagerData { @brief %Resource manager Provides storage for arbitrary set of types, accessible globally using -instance(). +@ref instance(). @section ResourceManager-usage Usage -Each resource is referenced from Resource class. For optimizing performance, -each resource can be set as mutable or final. Mutable resources can be -modified by the manager and thus each %Resource instance asks the manager for -modifications on each access. On the other hand, final resources cannot be -modified by the manager, so %Resource instances don't have to ask the manager -every time, which is faster. +Each resource is referenced from @ref Resource class. For optimizing +performance, each resource can be set as mutable or final. Mutable resources +can be modified by the manager and thus each @ref Resource instance asks the +manager for modifications on each access. On the other hand, final resources +cannot be modified by the manager, so @ref Resource instances don't have to ask +the manager every time, which is faster. It's possible to provide fallback for resources which are not available using -setFallback(). Accessing data of such resources will access the fallback +@ref setFallback(). Accessing data of such resources will access the fallback instead of failing on null pointer dereference. Availability and state of each -resource can be queried through function state() on the manager or -Resource::state() on each resource. +resource can be queried through function @ref state() on the manager or +@ref Resource::state() on each resource. The resources can be managed in three ways - resident resources, which stay in memory for whole lifetime of the manager, manually managed resources, which -can be deleted by calling free() if nothing references them anymore, and +can be deleted by calling @ref free() if nothing references them anymore, and reference counted resources, which are deleted as soon as the last reference to them is removed. %Resource state and policy is configured when setting the resource data in -set() and can be changed each time the data are updated, although already +@ref set() and can be changed each time the data are updated, although already final resources cannot obviously be set as mutable again. Basic usage is: -- Typedef'ing manager of desired types, creating its instance. +- Typedef'ing manager of desired types, creating its instance. @code typedef ResourceManager MyResourceManager; MyResourceManager manager; @endcode -- Filling the manager with resource data and acquiring the resources. Note - that a resource can be acquired with get() even before the manager contains - the data for it, as long as the resource data are not accessed (or fallback - is provided). +- Filling the manager with resource data and acquiring the resources. Note + that a resource can be acquired with @ref get() even before the manager + contains the data for it, as long as the resource data are not accessed (or + fallback is provided). @code MyResourceManager* manager = MyResourceManager::instance(); Resource texture(manager->get("texture")); @@ -210,14 +210,13 @@ if(!cube) { manager->set(cube.key(), mesh, ResourceDataState::Final, ResourcePolicy::Resident); } @endcode -- Using the resource data. +- Using the resource data. @code -shader->use(); -texture->bind(layer); -cube->draw(); +shader->setTexture(layer); +cube->draw(*shader); @endcode -- Destroying resource references and deleting manager instance when nothing - references the resources anymore. +- Destroying resource references and deleting manager instance when nothing + references the resources anymore. @see AbstractResourceLoader */ @@ -239,7 +238,7 @@ template class ResourceManager: private Implementation::Resource * Sets global instance pointer to itself. * @attention Only one instance of given ResourceManager type can be * created. - * @see instance() + * @see @ref instance() */ explicit ResourceManager(); @@ -247,7 +246,7 @@ template class ResourceManager: private Implementation::Resource * @brief Destructor * * Sets global instance pointer to `nullptr`. - * @see instance() + * @see @ref instance() */ ~ResourceManager(); @@ -275,7 +274,7 @@ template class ResourceManager: private Implementation::Resource /** * @brief Reference count of given resource * - * @see set() + * @see @ref set() */ template std::size_t referenceCount(ResourceKey key) const { return this->Implementation::ResourceManagerData::referenceCount(key); @@ -284,7 +283,7 @@ template class ResourceManager: private Implementation::Resource /** * @brief %Resource state * - * @see set(), Resource::state() + * @see @ref set(), @ref Resource::state() */ template ResourceState state(ResourceKey key) const { return this->Implementation::ResourceManagerData::state(key); @@ -294,20 +293,20 @@ template class ResourceManager: private Implementation::Resource * @brief Set resource data * @return Reference to self (for method chaining) * - * If @p policy is set to `ResourcePolicy::ReferenceCounted`, there + * If @p policy is set to @ref ResourcePolicy::ReferenceCounted, there * must be already at least one reference to given resource, otherwise - * the data will be deleted immediately and no resource will be - * added. To avoid spending unnecessary loading time, add - * reference-counted resources only if they are already referenced: + * the data will be deleted immediately and no resource will be added. + * To avoid spending unnecessary loading time, add reference-counted + * resources only if they are already referenced: * @code * if(manager.referenceCount("myresource")) { * // load data... * manager.set("myresource", data, state, ResourcePolicy::ReferenceCounted); * } * @endcode - * @attention If resource state is already `ResourceState::Final`, - * subsequent updates are not possible. - * @see referenceCount(), state() + * @attention Subsequent updates are not possible if resource state is + * already @ref ResourceState::Final. + * @see @ref referenceCount(), @ref state() */ template ResourceManager& set(ResourceKey key, T* data, ResourceDataState state, ResourcePolicy policy) { this->Implementation::ResourceManagerData::set(key, data, state, policy); @@ -381,7 +380,8 @@ template class ResourceManager: private Implementation::Resource * @brief Clear all resources of given type * @return Reference to self (for method chaining) * - * Unlike free() this function assumes that no resource is referenced. + * Unlike @ref free() this function assumes that no resource is + * referenced. */ template ResourceManager& clear() { this->Implementation::ResourceManagerData::clear(); @@ -392,7 +392,8 @@ template class ResourceManager: private Implementation::Resource * @brief Clear all resources * @return Reference to self (for method chaining) * - * Unlike free() this function assumes that no resource is referenced. + * Unlike @ref free() this function assumes that no resource is + * referenced. */ ResourceManager& clear() { clearInternal(); @@ -414,7 +415,7 @@ template class ResourceManager: private Implementation::Resource * @param loader Loader or `nullptr` if unsetting previous loader. * @return Reference to self (for method chaining) * - * See AbstractResourceLoader documentation for more information. + * See @ref AbstractResourceLoader documentation for more information. * @attention The loader is deleted on destruction before unloading * all resources. */ diff --git a/src/Magnum/Sampler.h b/src/Magnum/Sampler.h index a3bbb68de..b2c6e995a 100644 --- a/src/Magnum/Sampler.h +++ b/src/Magnum/Sampler.h @@ -57,7 +57,7 @@ class MAGNUM_EXPORT Sampler { * for linear interpolation of textures with * @ref Magnum::TextureFormat "TextureFormat::HalfFloat" / * @ref Magnum::TextureFormat "TextureFormat::Float" in OpenGL - * ES 2.0. + * ES 2.0 */ Linear = GL_LINEAR }; @@ -83,7 +83,7 @@ class MAGNUM_EXPORT Sampler { * for linear interpolation of textures with * @ref Magnum::TextureFormat "TextureFormat::HalfFloat" / * @ref Magnum::TextureFormat "TextureFormat::Float" in OpenGL - * ES 2.0. + * ES 2.0 */ Linear = GL_NEAREST_MIPMAP_LINEAR & ~GL_NEAREST }; @@ -122,7 +122,7 @@ class MAGNUM_EXPORT Sampler { #ifndef MAGNUM_TARGET_GLES /** * Mirror the texture once in negative coordinates and clamp to - * edge after that. + * edge after that. **Unavailable on rectangle textures.** * @requires_gl44 %Extension @extension{ARB,texture_mirror_clamp_to_edge}, * @extension{ATI,texture_mirror_once} or @extension{EXT,texture_mirror_clamp} * @requires_gl Only separate @ref Magnum::Sampler::Wrapping "Wrapping::MirroredRepeat" diff --git a/src/Magnum/SceneGraph/AbstractCamera.hpp b/src/Magnum/SceneGraph/AbstractCamera.hpp index 7819e3116..e1b72b520 100644 --- a/src/Magnum/SceneGraph/AbstractCamera.hpp +++ b/src/Magnum/SceneGraph/AbstractCamera.hpp @@ -94,9 +94,10 @@ template void AbstractCamera::dr AbstractFeature::object().setClean(); /* Compute transformations of all objects in the group relative to the camera */ - std::vector*> objects(group.size()); + std::vector>> objects; + objects.reserve(group.size()); for(std::size_t i = 0; i != group.size(); ++i) - objects[i] = &group[i].object(); + objects.push_back(group[i].object()); std::vector::MatrixType> transformations = scene->transformationMatrices(objects, _cameraMatrix); diff --git a/src/Magnum/SceneGraph/AbstractObject.h b/src/Magnum/SceneGraph/AbstractObject.h index 487a05948..d3e363ac6 100644 --- a/src/Magnum/SceneGraph/AbstractObject.h +++ b/src/Magnum/SceneGraph/AbstractObject.h @@ -26,9 +26,10 @@ */ /** @file - * @brief Class Magnum::SceneGraph::AbstractObject, alias Magnum::SceneGraph::AbstractBasicObject2D, Magnum::SceneGraph::AbstractBasicObject3D, typedef Magnum::SceneGraph::AbstractObject2D, Magnum::SceneGraph::AbstractObject3D + * @brief Class @ref Magnum::SceneGraph::AbstractObject, alias @ref Magnum::SceneGraph::AbstractBasicObject2D, @ref Magnum::SceneGraph::AbstractBasicObject3D, typedef @ref Magnum::SceneGraph::AbstractObject2D, @ref Magnum::SceneGraph::AbstractObject3D */ +#include #include #include @@ -129,7 +130,8 @@ template class AbstractObject /** * @brief Transformation matrix * - * @see Object::transformation() + * See also `transformation()` function of various transformation + * classes. */ MatrixType transformationMatrix() const { return doTransformationMatrix(); @@ -138,7 +140,7 @@ template class AbstractObject /** * @brief Transformation matrix relative to root object * - * @see Object::absoluteTransformation() + * @see @ref Object::absoluteTransformation() */ MatrixType absoluteTransformationMatrix() const { return doAbsoluteTransformationMatrix(); @@ -150,13 +152,31 @@ template class AbstractObject * All transformations are premultiplied with @p initialTransformationMatrix, * if specified. * @warning This function cannot check if all objects are of the same - * Object type, use typesafe Object::transformationMatrices() when - * possible. + * @ref Object type, use typesafe @ref Object::transformationMatrices() + * when possible. */ - std::vector transformationMatrices(const std::vector*>& objects, const MatrixType& initialTransformationMatrix = MatrixType()) const { + std::vector transformationMatrices(const std::vector>>& objects, const MatrixType& initialTransformationMatrix = MatrixType()) const { return doTransformationMatrices(objects, initialTransformationMatrix); } + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @copybrief transformationMatrices(const std::vector>>&, const MatrixType&) + * @deprecated Use @ref Magnum::SceneGraph::AbstractObject::transformationMatrices(const std::vector>>&, const MatrixType&) "transformationMatrices(const std::vector>>&, const MatrixType&)" instead. + * @todoc The `ref` works when `const` is added, but then the quoted thing is not taken as a part of the reference. The `copybrief` doesn't parse the `const` at all. Doxygen I hate you. + */ + CORRADE_DEPRECATED("use transformationMatrices(const std::vector>>&, const MatrixType&) instead") std::vector transformationMatrices(const std::vector*>& objects, const MatrixType& initialTransformationMatrix = MatrixType()) const; + + #ifdef CORRADE_GCC47_COMPATIBILITY + /* Workarounds to avoid ambiguous overload errors on GCC < 4.8. And I + thought 4.7 was bug-free. */ + std::vector transformationMatrices(std::initializer_list>>& objects, const MatrixType& initialTransformationMatrix = MatrixType()) { + return transformationMatrices(std::vector>>{objects}, initialTransformationMatrix); + } + CORRADE_DEPRECATED("use transformationMatrices(const std::vector>>&, const MatrixType&) instead") std::vector transformationMatrices(std::initializer_list*> objects, const MatrixType& initialTransformationMatrix = MatrixType()) const; + #endif + #endif + /*@}*/ /** @@ -170,21 +190,37 @@ template class AbstractObject * * Only dirty objects in the list are cleaned. * @warning This function cannot check if all objects are of the same - * Object type, use typesafe Object::setClean() when possible. + * @ref Object type, use typesafe @ref Object::setClean() when + * possible. */ - static void setClean(const std::vector*>& objects) { + static void setClean(const std::vector>>& objects) { if(objects.empty()) return; - objects.front()->doSetClean(objects); + objects.front().get().doSetClean(objects); } + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @copybrief setClean(const std::vector>>&) + * @deprecated Use @ref Magnum::SceneGraph::AbstractObject::setClean(const std::vector>>&) "setClean(const std::vector>>&)" instead. + */ + static CORRADE_DEPRECATED("use setClean(const std::vector>>&) instead") void setClean(const std::vector*>& objects); + + #ifdef CORRADE_GCC47_COMPATIBILITY + /* Workarounds to avoid ambiguous overload errors on GCC < 4.8. And I + thought 4.7 was bug-free. */ + static void setClean(std::initializer_list>> objects) { + return setClean(std::vector>>{objects}); + } + static CORRADE_DEPRECATED("use setClean(const std::vector>>&) instead") void setClean(std::initializer_list*> objects); + #endif + #endif + /** * @brief Whether absolute transformation is dirty * * Returns `true` if transformation of the object or any parent has - * changed since last call to setClean(), `false` otherwise. - * - * All objects are dirty by default. - * + * changed since last call to @ref setClean(), `false` otherwise. All + * objects are dirty by default. * @see @ref scenegraph-caching */ bool isDirty() const { return doIsDirty(); } @@ -192,26 +228,26 @@ template class AbstractObject /** * @brief Set object absolute transformation as dirty * - * Calls AbstractFeature::markDirty() on all object features and - * recursively calls setDirty() on every child object which is not + * Calls @ref AbstractFeature::markDirty() on all object features and + * recursively calls @ref setDirty() on every child object which is not * already dirty. If the object is already marked as dirty, the * function does nothing. - * @see @ref scenegraph-caching, setClean(), isDirty() + * @see @ref scenegraph-caching, @ref setClean(), @ref isDirty() */ void setDirty() { doSetDirty(); } /** * @brief Clean object absolute transformation * - * Calls AbstractFeature::clean() and/or AbstractFeature::cleanInverted() + * Calls @ref AbstractFeature::clean() and/or @ref AbstractFeature::cleanInverted() * on all object features which have caching enabled and recursively - * calls setClean() on every parent which is not already clean. If the - * object is already clean, the function does nothing. + * calls @ref setClean() on every parent which is not already clean. If + * the object is already clean, the function does nothing. * - * See also setClean(const std::vector& objects), which cleans given - * set of objects more efficiently than when calling setClean() on - * each object individually. - * @see @ref scenegraph-caching, setDirty(), isDirty() + * See also @ref setClean(const std::vector*>&), + * which cleans given set of objects more efficiently than when calling + * @ref setClean() on each object individually. + * @see @ref scenegraph-caching, @ref setDirty(), @ref isDirty() */ void setClean() { doSetClean(); } @@ -223,20 +259,20 @@ template class AbstractObject virtual MatrixType doTransformationMatrix() const = 0; virtual MatrixType doAbsoluteTransformationMatrix() const = 0; - virtual std::vector doTransformationMatrices(const std::vector*>& objects, const MatrixType& initialTransformationMatrix) const = 0; + virtual std::vector doTransformationMatrices(const std::vector>>& objects, const MatrixType& initialTransformationMatrix) const = 0; virtual bool doIsDirty() const = 0; virtual void doSetDirty() = 0; virtual void doSetClean() = 0; - virtual void doSetClean(const std::vector*>& objects) = 0; + virtual void doSetClean(const std::vector>>& objects) = 0; }; #ifndef CORRADE_GCC46_COMPATIBILITY /** @brief Base object for two-dimensional scenes -Convenience alternative to %AbstractObject<2, T>. See AbstractObject -for more information. +Convenience alternative to %AbstractObject<2, T>. See +@ref AbstractObject for more information. @note Not available on GCC < 4.7. Use %AbstractObject<2, T> instead. @see @ref AbstractObject2D, @ref AbstractBasicObject3D */ @@ -262,10 +298,10 @@ typedef AbstractObject<2, Float> AbstractObject2D; /** @brief Base object for three-dimensional scenes -Convenience alternative to %AbstractObject<3, T>. See AbstractObject -for more information. +Convenience alternative to %AbstractObject<3, T>. See +@ref AbstractObject for more information. @note Not available on GCC < 4.7. Use %AbstractObject<3, T> instead. -@see AbstractObject2D +@see @ref AbstractObject3D, @ref AbstractBasicObject2D */ #ifndef CORRADE_MSVC2013_COMPATIBILITY /* Apparently cannot have multiply defined aliases */ template using AbstractBasicObject3D = AbstractObject<3, T>; diff --git a/src/Magnum/SceneGraph/AbstractTransformation.h b/src/Magnum/SceneGraph/AbstractTransformation.h index 22ac3d1be..4745350c5 100644 --- a/src/Magnum/SceneGraph/AbstractTransformation.h +++ b/src/Magnum/SceneGraph/AbstractTransformation.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::SceneGraph::AbstractTransformation, alias Magnum::SceneGraph::AbstractBasicTransformation2D, Magnum::SceneGraph::AbstractBasicTransformation3D, typedef Magnum::SceneGraph::AbstractTransformation2D, Magnum::SceneGraph::AbstractTransformation3D, enum Magnum::SceneGraph::TransformationType + * @brief Class @ref Magnum::SceneGraph::AbstractTransformation, alias @ref Magnum::SceneGraph::AbstractBasicTransformation2D, @ref Magnum::SceneGraph::AbstractBasicTransformation3D, typedef @ref Magnum::SceneGraph::AbstractTransformation2D, @ref Magnum::SceneGraph::AbstractTransformation3D, enum @ref Magnum::SceneGraph::TransformationType */ #include "Magnum/SceneGraph/SceneGraph.h" @@ -80,7 +80,7 @@ template class AbstractTransformation { #else private: #endif - /** @brief Polymorphic implementation for resetTransformation() */ + /** @brief Polymorphic implementation for @ref resetTransformation() */ virtual void doResetTransformation() = 0; }; @@ -104,7 +104,7 @@ enum class TransformationType: UnsignedByte { @brief Base transformation for two-dimensional scenes Convenience alternative to %AbstractTransformation<2, T>. See -AbstractTransformation for more information. +@ref AbstractTransformation for more information. @note Not available on GCC < 4.7. Use %AbstractTransformation<2, T> instead. @see @ref AbstractTransformation2D, @ref AbstractBasicTransformation3D @@ -130,7 +130,7 @@ typedef AbstractTransformation<2, Float> AbstractTransformation2D; @brief Base transformation for three-dimensional scenes Convenience alternative to %AbstractTransformation<3, T>. See -AbstractTransformation for more information. +@ref AbstractTransformation for more information. @note Not available on GCC < 4.7. Use %AbstractTransformation<3, T> instead. @see @ref AbstractTransformation3D, @ref AbstractBasicTransformation2D diff --git a/src/Magnum/SceneGraph/AbstractTranslation.h b/src/Magnum/SceneGraph/AbstractTranslation.h index a317df728..ec80ad7bb 100644 --- a/src/Magnum/SceneGraph/AbstractTranslation.h +++ b/src/Magnum/SceneGraph/AbstractTranslation.h @@ -60,8 +60,9 @@ class AbstractTranslation: public AbstractTransformation { * @param type Transformation type * @return Reference to self (for method chaining) * - * @see @ref Vector2::xAxis(), @ref Vector2::yAxis(), @ref Vector3::xAxis(), - * @ref Vector3::yAxis(), @ref Vector3::zAxis() + * @see @ref Math::Vector2::xAxis(), @ref Math::Vector2::yAxis(), + * @ref Math::Vector3::xAxis(), @ref Math::Vector3::yAxis(), + * @ref Math::Vector3::zAxis() */ AbstractTranslation& translate(const typename DimensionTraits::VectorType& vector, TransformationType type = TransformationType::Global) { doTranslate(vector, type); @@ -76,7 +77,7 @@ class AbstractTranslation: public AbstractTransformation { #else private: #endif - /** @brief Polymorphic implementation for translate() */ + /** @brief Polymorphic implementation for @ref translate() */ virtual void doTranslate(const typename DimensionTraits::VectorType& vector, TransformationType type) = 0; }; diff --git a/src/Magnum/SceneGraph/AbstractTranslationRotation2D.h b/src/Magnum/SceneGraph/AbstractTranslationRotation2D.h index 3199ca6ab..b15162e5e 100644 --- a/src/Magnum/SceneGraph/AbstractTranslationRotation2D.h +++ b/src/Magnum/SceneGraph/AbstractTranslationRotation2D.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::SceneGraph::AbstractBasicTranslationRotation2D, typedef Magnum::SceneGraph::AbstractTranslationRotation2D + * @brief Class @ref Magnum::SceneGraph::AbstractBasicTranslationRotation2D, typedef @ref Magnum::SceneGraph::AbstractTranslationRotation2D */ #include "Magnum/SceneGraph/AbstractTranslation.h" @@ -70,7 +70,7 @@ template class AbstractBasicTranslationRotation2D: public AbstractTrans #else private: #endif - /** @brief Polymorphic implementation for rotate() */ + /** @brief Polymorphic implementation for @ref rotate() */ virtual void doRotate(Math::Rad angle, TransformationType type) = 0; }; diff --git a/src/Magnum/SceneGraph/AbstractTranslationRotation3D.h b/src/Magnum/SceneGraph/AbstractTranslationRotation3D.h index 4e8f9d837..664114a68 100644 --- a/src/Magnum/SceneGraph/AbstractTranslationRotation3D.h +++ b/src/Magnum/SceneGraph/AbstractTranslationRotation3D.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::SceneGraph::AbstractBasicTranslationRotation3D, typedef Magnum::SceneGraph::AbstractTranslationRotation3D + * @brief Class @ref Magnum::SceneGraph::AbstractBasicTranslationRotation3D, typedef @ref Magnum::SceneGraph::AbstractTranslationRotation3D */ #include "Magnum/SceneGraph/AbstractTranslation.h" @@ -50,8 +50,9 @@ template class AbstractBasicTranslationRotation3D: public AbstractTrans * @param type Transformation type * @return Reference to self (for method chaining) * - * @see rotateX(), rotateY(), rotateZ(), Vector3::xAxis(), - * Vector3::yAxis(), Vector3::zAxis() + * @see @ref rotateX(), @ref rotateY(), @ref rotateZ(), + * @ref Math::Vector3::xAxis(), @ref Math::Vector3::yAxis(), + * @ref Math::Vector3::zAxis() */ AbstractBasicTranslationRotation3D& rotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) { doRotate(angle, normalizedAxis, type); @@ -65,7 +66,8 @@ template class AbstractBasicTranslationRotation3D: public AbstractTrans * @return Reference to self (for method chaining) * * In some implementations faster than calling - * `rotate(angle, Vector3::xAxis())`. + * `rotate(angle, Vector3::xAxis())`, see subclasses for more + * information. */ AbstractBasicTranslationRotation3D& rotateX(Math::Rad angle, TransformationType type = TransformationType::Global) { doRotateX(angle, type); @@ -79,7 +81,8 @@ template class AbstractBasicTranslationRotation3D: public AbstractTrans * @return Reference to self (for method chaining) * * In some implementations faster than calling - * `rotate(angle, Vector3::yAxis())`. + * `rotate(angle, Vector3::yAxis())`, see subclasses for more + * information. */ AbstractBasicTranslationRotation3D& rotateY(Math::Rad angle, TransformationType type = TransformationType::Global) { doRotateX(angle, type); @@ -93,7 +96,8 @@ template class AbstractBasicTranslationRotation3D: public AbstractTrans * @return Reference to self (for method chaining) * * In some implementations faster than calling - * `rotate(angle, Vector3::zAxis())`. + * `rotate(angle, Vector3::zAxis())`, see subclasses for more + * information. */ AbstractBasicTranslationRotation3D& rotateZ(Math::Rad angle, TransformationType type = TransformationType::Global) { doRotateZ(angle, type); @@ -116,31 +120,34 @@ template class AbstractBasicTranslationRotation3D: public AbstractTrans #else private: #endif - /** @brief Polymorphic implementation for rotate() */ + /** @brief Polymorphic implementation for @ref rotate() */ virtual void doRotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type) = 0; /** - * @brief Polymorphic implementation for rotateX() + * @brief Polymorphic implementation for @ref rotateX() * - * Default implementation calls rotate() with Math::Vector3::xAxis(). + * Default implementation calls @ref rotate() with + * @ref Math::Vector3::xAxis(). */ virtual void doRotateX(Math::Rad angle, TransformationType type) { rotate(angle, Math::Vector3::xAxis(), type); } /** - * @brief Polymorphic implementation for rotateY() + * @brief Polymorphic implementation for @ref rotateY() * - * Default implementation calls rotate() with Math::Vector3::yAxis(). + * Default implementation calls @ref rotate() with + * @ref Math::Vector3::yAxis(). */ virtual void doRotateY(Math::Rad angle, TransformationType type) { rotate(angle, Math::Vector3::yAxis(), type); } /** - * @brief Polymorphic implementation for rotateZ() + * @brief Polymorphic implementation for @ref rotateZ() * - * Default implementation calls rotate() with Math::Vector3::zAxis(). + * Default implementation calls @ref rotate() with + * @ref Math::Vector3::zAxis(). */ virtual void doRotateZ(Math::Rad angle, TransformationType type) { rotate(angle, Math::Vector3::zAxis(), type); diff --git a/src/Magnum/SceneGraph/AbstractTranslationRotationScaling2D.h b/src/Magnum/SceneGraph/AbstractTranslationRotationScaling2D.h index 70e9bda4c..e790168cb 100644 --- a/src/Magnum/SceneGraph/AbstractTranslationRotationScaling2D.h +++ b/src/Magnum/SceneGraph/AbstractTranslationRotationScaling2D.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::SceneGraph::AbstractBasicTranslationRotationScaling2D, typedef Magnum::SceneGraph::AbstractTranslationRotationScaling2D + * @brief Class @ref Magnum::SceneGraph::AbstractBasicTranslationRotationScaling2D, typedef @ref Magnum::SceneGraph::AbstractTranslationRotationScaling2D */ #include "Magnum/SceneGraph/AbstractTranslationRotation2D.h" @@ -48,7 +48,7 @@ template class AbstractBasicTranslationRotationScaling2D: public Abstra * @param type Transformation type * @return Reference to self (for method chaining) * - * @see Vector2::xScale(), Vector2::yScale() + * @see @ref Math::Vector2::xScale(), @ref Math::Vector2::yScale() */ AbstractBasicTranslationRotationScaling2D& scale(const Math::Vector2& vector, TransformationType type = TransformationType::Global) { doScale(vector, type); @@ -79,7 +79,7 @@ template class AbstractBasicTranslationRotationScaling2D: public Abstra #else private: #endif - /** @brief Polymorphic implementation for scale() */ + /** @brief Polymorphic implementation for @ref scale() */ virtual void doScale(const Math::Vector2& vector, TransformationType type) = 0; }; diff --git a/src/Magnum/SceneGraph/AbstractTranslationRotationScaling3D.h b/src/Magnum/SceneGraph/AbstractTranslationRotationScaling3D.h index d10f0de8c..d39ff0edd 100644 --- a/src/Magnum/SceneGraph/AbstractTranslationRotationScaling3D.h +++ b/src/Magnum/SceneGraph/AbstractTranslationRotationScaling3D.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::SceneGraph::AbstractBasicTranslationRotationScaling3D, typedef Magnum::SceneGraph::AbstractTranslationRotationScaling3D + * @brief Class @ref Magnum::SceneGraph::AbstractBasicTranslationRotationScaling3D, typedef @ref Magnum::SceneGraph::AbstractTranslationRotationScaling3D */ #include "Magnum/SceneGraph/AbstractTranslationRotation3D.h" @@ -48,7 +48,8 @@ template class AbstractBasicTranslationRotationScaling3D: public Abstra * @param type Transformation type * @return Reference to self (for method chaining) * - * @see Vector3::xScale(), Vector3::yScale(), Vector3::zScale() + * @see @ref Math::Vector3::xScale(), @ref Math::Vector3::yScale(), + * @ref Math::Vector3::zScale() */ AbstractBasicTranslationRotationScaling3D& scale(const Math::Vector3& vector, TransformationType type = TransformationType::Global) { doScale(vector, type); @@ -91,7 +92,7 @@ template class AbstractBasicTranslationRotationScaling3D: public Abstra #else private: #endif - /** @brief Polymorphic implementation for scale() */ + /** @brief Polymorphic implementation for @ref scale() */ virtual void doScale(const Math::Vector3& vector, TransformationType type) = 0; }; diff --git a/src/Magnum/SceneGraph/DualComplexTransformation.h b/src/Magnum/SceneGraph/DualComplexTransformation.h index 10fe33d74..0681a6b2f 100644 --- a/src/Magnum/SceneGraph/DualComplexTransformation.h +++ b/src/Magnum/SceneGraph/DualComplexTransformation.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::SceneGraph::BasicDualComplexTransformation, typedef Magnum::SceneGraph::DualComplexTransformation + * @brief Class @ref Magnum::SceneGraph::BasicDualComplexTransformation, typedef @ref Magnum::SceneGraph::DualComplexTransformation */ #include "Magnum/Math/DualComplex.h" @@ -39,12 +39,13 @@ namespace Magnum { namespace SceneGraph { @brief Two-dimensional transformation implemented using dual complex numbers This class allows only rigid transformation (i.e. only rotation and -translation). -@see @ref DualComplexTransformation, @ref scenegraph, Math::DualComplex, @ref BasicDualQuaternionTransformation +translation). Uses @ref Math::DualComplex as underlying transformation type. +@see @ref DualComplexTransformation, @ref scenegraph, + @ref BasicDualQuaternionTransformation */ template class BasicDualComplexTransformation: public AbstractBasicTranslationRotation2D { public: - /** @brief Transformation type */ + /** @brief Underlying transformation type */ typedef Math::DualComplex DataType; /** @brief Object transformation */ @@ -55,7 +56,7 @@ template class BasicDualComplexTransformation: public AbstractBasicTran * @return Reference to self (for method chaining) * * Expects that the dual complex number is normalized. - * @see DualComplex::isNormalized() + * @see @ref Math::DualComplex::isNormalized() */ Object>& setTransformation(const Math::DualComplex& transformation) { CORRADE_ASSERT(transformation.isNormalized(), @@ -75,7 +76,7 @@ template class BasicDualComplexTransformation: public AbstractBasicTran * * Normalizes the rotation part to prevent rounding errors when rotating * the object subsequently. - * @see DualComplex::normalized() + * @see @ref Math::DualComplex::normalized() */ Object>& normalizeRotation() { return setTransformationInternal(_transformation.normalized()); @@ -88,7 +89,7 @@ template class BasicDualComplexTransformation: public AbstractBasicTran * @return Reference to self (for method chaining) * * Expects that the dual complex number is normalized. - * @see DualComplex::isNormalized() + * @see @ref Math::DualComplex::isNormalized() */ Object>& transform(const Math::DualComplex& transformation, TransformationType type = TransformationType::Global) { CORRADE_ASSERT(transformation.isNormalized(), @@ -99,7 +100,7 @@ template class BasicDualComplexTransformation: public AbstractBasicTran /** * @copydoc AbstractTranslationRotationScaling2D::translate() - * Same as calling transform() with DualComplex::translation(). + * Same as calling @ref transform() with @ref Math::DualComplex::translation(). */ Object>& translate(const Math::Vector2& vector, TransformationType type = TransformationType::Global) { return transformInternal(Math::DualComplex::translation(vector), type); @@ -111,8 +112,8 @@ template class BasicDualComplexTransformation: public AbstractBasicTran * @param type Transformation type * @return Reference to self (for method chaining) * - * Same as calling transform() with DualComplex::rotation(). - * @see normalizeRotation() + * Same as calling @ref transform() with @ref Math::DualComplex::rotation(). + * @see @ref normalizeRotation() */ Object>& rotate(Math::Rad angle, TransformationType type = TransformationType::Global) { return transformInternal(Math::DualComplex::rotation(angle), type); diff --git a/src/Magnum/SceneGraph/DualQuaternionTransformation.h b/src/Magnum/SceneGraph/DualQuaternionTransformation.h index f3b333ac5..126acb4b1 100644 --- a/src/Magnum/SceneGraph/DualQuaternionTransformation.h +++ b/src/Magnum/SceneGraph/DualQuaternionTransformation.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::SceneGraph::BasicDualQuaternionTransformation, typedef Magnum::SceneGraph::DualQuaternionTransformation + * @brief Class @ref Magnum::SceneGraph::BasicDualQuaternionTransformation, typedef @ref Magnum::SceneGraph::DualQuaternionTransformation */ #include "Magnum/Math/DualQuaternion.h" @@ -39,8 +39,9 @@ namespace Magnum { namespace SceneGraph { @brief Three-dimensional transformation implemented using dual quaternions This class allows only rigid transformation (i.e. only rotation and -translation). -@see @ref DualQuaternionTransformation @ref scenegraph, Math::DualQuaternion, @ref BasicDualComplexTransformation +translation). Uses @ref Math::DualQuaternion as underlying transformation type. +@see @ref DualQuaternionTransformation @ref scenegraph, + @ref BasicDualComplexTransformation */ template class BasicDualQuaternionTransformation: public AbstractBasicTranslationRotation3D { public: @@ -55,7 +56,7 @@ template class BasicDualQuaternionTransformation: public AbstractBasicT * @return Reference to self (for method chaining) * * Expects that the dual quaternion is normalized. - * @see DualQuaternion::isNormalized() + * @see @ref Math::DualQuaternion::isNormalized() */ Object>& setTransformation(const Math::DualQuaternion& transformation) { CORRADE_ASSERT(transformation.isNormalized(), @@ -75,7 +76,7 @@ template class BasicDualQuaternionTransformation: public AbstractBasicT * * Normalizes the rotation part to prevent rounding errors when rotating * the object subsequently. - * @see DualQuaternion::normalized() + * @see @ref Math::DualQuaternion::normalized() */ Object>& normalizeRotation() { return setTransformationInternal(_transformation.normalized()); @@ -88,7 +89,7 @@ template class BasicDualQuaternionTransformation: public AbstractBasicT * @return Reference to self (for method chaining) * * Expects that the dual quaternion is normalized. - * @see DualQuaternion::isNormalized() + * @see @ref Math::DualQuaternion::isNormalized() */ Object>& transform(const Math::DualQuaternion& transformation, TransformationType type = TransformationType::Global) { CORRADE_ASSERT(transformation.isNormalized(), @@ -99,7 +100,7 @@ template class BasicDualQuaternionTransformation: public AbstractBasicT /** * @copydoc AbstractTranslationRotationScaling3D::translate() - * Same as calling transform() with DualQuaternion::translation(). + * Same as calling @ref transform() with @ref Math::DualQuaternion::translation(). */ Object>& translate(const Math::Vector3& vector, TransformationType type = TransformationType::Global) { return transformInternal(Math::DualQuaternion::translation(vector), type); @@ -112,9 +113,9 @@ template class BasicDualQuaternionTransformation: public AbstractBasicT * @param type Transformation type * @return Reference to self (for method chaining) * - * Same as calling transform() with DualQuaternion::rotation(). - * @see Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis(), - * normalizeRotation() + * Same as calling @ref transform() with @ref Math::DualQuaternion::rotation(). + * @see @ref Math::Vector3::xAxis(), @ref Math::Vector3::yAxis(), + * @ref Math::Vector3::zAxis(), @ref normalizeRotation() */ Object>& rotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) { return transformInternal(Math::DualQuaternion::rotation(angle, normalizedAxis), type); diff --git a/src/Magnum/SceneGraph/FeatureGroup.h b/src/Magnum/SceneGraph/FeatureGroup.h index d55cf0989..6878dabb4 100644 --- a/src/Magnum/SceneGraph/FeatureGroup.h +++ b/src/Magnum/SceneGraph/FeatureGroup.h @@ -51,7 +51,7 @@ template class AbstractFeatureGroup { void add(AbstractFeature& feature); void remove(AbstractFeature& feature); - std::vector*> features; + std::vector>> features; }; /** @@ -86,12 +86,12 @@ template class FeatureGroup: pub /** @brief Feature at given index */ Feature& operator[](std::size_t index) { - return *static_cast(AbstractFeatureGroup::features[index]); + return static_cast(AbstractFeatureGroup::features[index].get()); } /** @overload */ const Feature& operator[](std::size_t index) const { - return *static_cast(AbstractFeatureGroup::features[index]); + return static_cast(AbstractFeatureGroup::features[index].get()); } /** @@ -171,7 +171,7 @@ template using FeatureGroup3D = BasicFeatureGroup3D FeatureGroup::~FeatureGroup() { for(auto it = this->features.begin(); it != this->features.end(); ++it) - static_cast(*it)->_group = nullptr; + static_cast(it->get())._group = nullptr; } template FeatureGroup& FeatureGroup::add(Feature& feature) { diff --git a/src/Magnum/SceneGraph/FeatureGroup.hpp b/src/Magnum/SceneGraph/FeatureGroup.hpp index 04efce52d..b09afd2d2 100644 --- a/src/Magnum/SceneGraph/FeatureGroup.hpp +++ b/src/Magnum/SceneGraph/FeatureGroup.hpp @@ -42,11 +42,12 @@ template AbstractFeatureGroup::A template AbstractFeatureGroup::~AbstractFeatureGroup() {} template void AbstractFeatureGroup::add(AbstractFeature& feature) { - features.push_back(&feature); + features.push_back(feature); } template void AbstractFeatureGroup::remove(AbstractFeature& feature) { - features.erase(std::find(features.begin(), features.end(), &feature)); + features.erase(std::find_if(features.begin(), features.end(), + [&feature](AbstractFeature& f) { return &f == &feature; })); } }} diff --git a/src/Magnum/SceneGraph/MatrixTransformation2D.h b/src/Magnum/SceneGraph/MatrixTransformation2D.h index 7ab4eaf6e..d4e07396b 100644 --- a/src/Magnum/SceneGraph/MatrixTransformation2D.h +++ b/src/Magnum/SceneGraph/MatrixTransformation2D.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::SceneGraph::BasicMatrixTransformation2D, typedef Magnum::SceneGraph::MatrixTransformation2D + * @brief Class @ref Magnum::SceneGraph::BasicMatrixTransformation2D, typedef @ref Magnum::SceneGraph::MatrixTransformation2D */ #include "Magnum/Math/Matrix3.h" @@ -38,8 +38,9 @@ namespace Magnum { namespace SceneGraph { /** @brief Two-dimensional transformation implemented using matrices -Uses Math::Matrix3 as underlying type. -@see @ref MatrixTransformation2D, @ref scenegraph, @ref BasicRigidMatrixTransformation2D, @ref BasicMatrixTransformation3D +Uses @ref Math::Matrix3 as underlying transformation type. +@see @ref MatrixTransformation2D, @ref scenegraph, + @ref BasicRigidMatrixTransformation2D, @ref BasicMatrixTransformation3D */ template class BasicMatrixTransformation2D: public AbstractBasicTranslationRotationScaling2D { public: @@ -83,7 +84,7 @@ template class BasicMatrixTransformation2D: public AbstractBasicTransla /** * @copydoc AbstractTranslationRotationScaling2D::translate() - * Same as calling transform() with Matrix3::translation(). + * Same as calling @ref transform() with @ref Math::Matrix3::translation(). */ Object>& translate(const Math::Vector2& vector, TransformationType type = TransformationType::Global) { return transform(Math::Matrix3::translation(vector), type); @@ -91,7 +92,7 @@ template class BasicMatrixTransformation2D: public AbstractBasicTransla /** * @copydoc AbstractTranslationRotationScaling2D::rotate() - * Same as calling transform() with Matrix3::rotation(). + * Same as calling @ref transform() with @ref Math::Matrix3::rotation(). */ Object>& rotate(Math::Rad angle, TransformationType type = TransformationType::Global) { return transform(Math::Matrix3::rotation(angle), type); @@ -99,7 +100,7 @@ template class BasicMatrixTransformation2D: public AbstractBasicTransla /** * @copydoc AbstractTranslationRotationScaling2D::scale() - * Same as calling transform() with Matrix3::scaling(). + * Same as calling @ref transform() with @ref Math::Matrix3::scaling(). */ Object>& scale(const Math::Vector2& vector, TransformationType type = TransformationType::Global) { return transform(Math::Matrix3::scaling(vector), type); @@ -112,7 +113,7 @@ template class BasicMatrixTransformation2D: public AbstractBasicTransla * @param type Transformation type * @return Reference to self (for method chaining) * - * Same as calling transform() with Matrix3::reflection(). + * Same as calling @ref transform() with @ref Math::Matrix3::reflection(). */ Object>& reflect(const Math::Vector2& normal, TransformationType type = TransformationType::Global) { return transform(Math::Matrix3::reflection(normal), type); diff --git a/src/Magnum/SceneGraph/MatrixTransformation3D.h b/src/Magnum/SceneGraph/MatrixTransformation3D.h index 4a12e677d..daa2043ec 100644 --- a/src/Magnum/SceneGraph/MatrixTransformation3D.h +++ b/src/Magnum/SceneGraph/MatrixTransformation3D.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::SceneGraph::BasicMatrixTransformation3D, typedef Magnum::SceneGraph::MatrixTransformation3D + * @brief Class @ref Magnum::SceneGraph::BasicMatrixTransformation3D, typedef @ref Magnum::SceneGraph::MatrixTransformation3D */ #include "Magnum/Math/Matrix4.h" @@ -38,7 +38,7 @@ namespace Magnum { namespace SceneGraph { /** @brief Three-dimensional transformation implemented using matrices -Uses Math::Matrix4 as underlying type. +Uses @ref Math::Matrix4 as underlying transformation type. @see @ref MatrixTransformation3D, @ref scenegraph, @ref BasicRigidMatrixTransformation3D, @ref BasicMatrixTransformation2D */ template class BasicMatrixTransformation3D: public AbstractBasicTranslationRotationScaling3D { @@ -83,7 +83,7 @@ template class BasicMatrixTransformation3D: public AbstractBasicTransla /** * @copydoc AbstractTranslationRotationScaling3D::translate() - * Same as calling transform() with Matrix4::translation(). + * Same as calling @ref transform() with @ref Math::Matrix4::translation(). */ Object>& translate(const Math::Vector3& vector, TransformationType type = TransformationType::Global) { return transform(Math::Matrix4::translation(vector), type); @@ -91,7 +91,7 @@ template class BasicMatrixTransformation3D: public AbstractBasicTransla /** * @copydoc AbstractTranslationRotationScaling3D::rotate() - * Same as calling transform() with Matrix4::rotation(). + * Same as calling @ref transform() with @ref Math::Matrix4::rotation(). */ Object>& rotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) { return transform(Math::Matrix4::rotation(angle, normalizedAxis), type); @@ -103,7 +103,7 @@ template class BasicMatrixTransformation3D: public AbstractBasicTransla * @param type Transformation type * @return Reference to self (for method chaining) * - * Same as calling transform() with Matrix4::rotationX(). + * Same as calling @ref transform() with @ref Math::Matrix4::rotationX(). */ Object>& rotateX(Math::Rad angle, TransformationType type = TransformationType::Global) { return transform(Math::Matrix4::rotationX(angle), type); @@ -115,7 +115,7 @@ template class BasicMatrixTransformation3D: public AbstractBasicTransla * @param type Transformation type * @return Reference to self (for method chaining) * - * Same as calling transform() with Matrix4::rotationY(). + * Same as calling @ref transform() with @ref Math::Matrix4::rotationY(). */ Object>& rotateY(Math::Rad angle, TransformationType type = TransformationType::Global) { return transform(Math::Matrix4::rotationY(angle), type); @@ -127,7 +127,7 @@ template class BasicMatrixTransformation3D: public AbstractBasicTransla * @param type Transformation type * @return Reference to self (for method chaining) * - * Same as calling transform() with Matrix4::rotationZ(). + * Same as calling @ref transform() with @ref Math::Matrix4::rotationZ(). */ Object>& rotateZ(Math::Rad angle, TransformationType type = TransformationType::Global) { return transform(Math::Matrix4::rotationZ(angle), type); @@ -135,7 +135,7 @@ template class BasicMatrixTransformation3D: public AbstractBasicTransla /** * @copydoc AbstractTranslationRotationScaling3D::scale() - * Same as calling transform() with Matrix4::scaling(). + * Same as calling @ref transform() with @ref Math::Matrix4::scaling(). */ Object>& scale(const Math::Vector3& vector, TransformationType type = TransformationType::Global) { return transform(Math::Matrix4::scaling(vector), type); @@ -148,7 +148,7 @@ template class BasicMatrixTransformation3D: public AbstractBasicTransla * @param type Transformation type * @return Reference to self (for method chaining) * - * Same as calling transform() with Matrix4::reflection(). + * Same as calling @ref transform() with @ref Math::Matrix4::reflection(). */ Object>& reflect(const Math::Vector3& normal, TransformationType type = TransformationType::Global) { return transform(Math::Matrix4::reflection(normal), type); diff --git a/src/Magnum/SceneGraph/Object.h b/src/Magnum/SceneGraph/Object.h index 64b9285e3..8c3ecbd41 100644 --- a/src/Magnum/SceneGraph/Object.h +++ b/src/Magnum/SceneGraph/Object.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::SceneGraph::Object + * @brief Class @ref Magnum::SceneGraph::Object */ #include @@ -93,6 +93,8 @@ class documentation or @ref compilation-speedup-hpp for more information. @see @ref Scene, @ref AbstractFeature, @ref AbstractTransformation, @ref DebugTools::ObjectRenderer +@todo Consider using `mutable` for flags to make transformation computation + available on const refs */ template class Object: public AbstractObject, public Transformation #ifndef DOXYGEN_GENERATING_OUTPUT @@ -196,7 +198,7 @@ template class Object: public AbstractObject& setParent(Object* parent); @@ -204,8 +206,9 @@ template class Object: public AbstractObject& setParentKeepTransformation(Object* parent); @@ -216,7 +219,8 @@ template class Object: public AbstractObject::toMatrix(Transformation::transformation()); @@ -225,7 +229,7 @@ template class Object: public AbstractObject::toMatrix(absoluteTransformation()); @@ -234,7 +238,7 @@ template class Object: public AbstractObject class Object: public AbstractObject transformationMatrices(const std::vector*>& objects, const MatrixType& initialTransformationMatrix = MatrixType()) const; + std::vector transformationMatrices(const std::vector>>& objects, const MatrixType& initialTransformationMatrix = MatrixType()) const; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @copybrief transformationMatrices(const std::vector>>&, const MatrixType&) + * @deprecated Use @ref Magnum::SceneGraph::Object::transformationMatrices(const std::vector>>&, const MatrixType&) "transformationMatrices(const std::vector>>&, const MatrixType&)" instead. + * @todoc fix this when Doxygen is sane (see this function in AbstractObject) + */ + CORRADE_DEPRECATED("use transformationMatrices(const std::vector>>&, const MatrixType&) instead") std::vector transformationMatrices(const std::vector*>& objects, const MatrixType& initialTransformationMatrix = MatrixType()) const; + + #ifdef CORRADE_GCC47_COMPATIBILITY + /* Workarounds to avoid ambiguous overload errors on GCC < 4.8. And I + thought 4.7 was bug-free. */ + std::vector transformationMatrices(std::initializer_list>> objects, const MatrixType& initialTransformationMatrix = MatrixType()) const { + return transformationMatrices(std::vector>>{objects}, initialTransformationMatrix); + } + CORRADE_DEPRECATED("use transformationMatrices(const std::vector>>&, const MatrixType&) instead") std::vector transformationMatrices(std::initializer_list*> objects, const MatrixType& initialTransformationMatrix = MatrixType()) const; + #endif + #endif /** * @brief Transformations of given group of objects relative to this object * * All transformations can be premultiplied with @p initialTransformation, * if specified. - * @see transformationMatrices() + * @see @ref transformationMatrices() */ /* `objects` passed by copy intentionally (to allow move from transformationMatrices() and avoid copy in the function itself) */ - #ifndef CORRADE_MSVC2013_COMPATIBILITY - std::vector transformations(std::vector*> objects, const typename Transformation::DataType& initialTransformation = typename Transformation::DataType()) const; - #else - std::vector transformations(std::vector*> objects, const typename Transformation::DataType& initialTransformation = Transformation::DataType()) const; + std::vector transformations(std::vector>> objects, const typename Transformation::DataType& initialTransformation = typename Transformation::DataType()) const; + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @copybrief transformations(std::vector>>, const typename Transformation::DataType&) + * @deprecated Use @ref Magnum::SceneGraph::Object::transformations(std::vector>>, const typename Transformation::DataType&) "transformations(std::vector>>, const typename Transformation::DataType&)" instead. + * @todoc fix this when Doxygen is sane (see related function in AbstractObject) + */ + CORRADE_DEPRECATED("use transformations(std::vector>>, const typename Transformation::DataType&) instead") std::vector transformations(const std::vector*>& objects, const typename Transformation::DataType& initialTransformation = typename Transformation::DataType()) const; + + #ifdef CORRADE_GCC47_COMPATIBILITY + /* Workarounds to avoid ambiguous overload errors on GCC < 4.8. And I + thought 4.7 was bug-free. */ + std::vector transformations(std::initializer_list>> objects, const typename Transformation::DataType& initialTransformation = typename Transformation::DataType()) const { + return transformations(std::vector>>{objects}, initialTransformation); + } + CORRADE_DEPRECATED("use transformations(std::vector>>, const typename Transformation::DataType&) instead") std::vector transformations(std::initializer_list*> objects, const typename Transformation::DataType& initialTransformation = typename Transformation::DataType()) const; + #endif #endif /*@}*/ @@ -274,10 +310,27 @@ template class Object: public AbstractObject*> objects); + static void setClean(std::vector>> objects); + + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @copybrief setClean(std::vector>>) + * @deprecated Use @ref Magnum::SceneGraph::Object::setClean(std::vector>> "setClean(std::vector>>" instead. + */ + CORRADE_DEPRECATED("use setClean(std::vector>>) instead") static void setClean(const std::vector*>& objects); + + #ifdef CORRADE_GCC47_COMPATIBILITY + /* Workarounds to avoid ambiguous overload errors on GCC < 4.8. And I + thought 4.7 was bug-free. */ + static void setClean(std::initializer_list>> objects) { + setClean(std::vector>>{objects}); + } + static CORRADE_DEPRECATED("use setClean(std::vector>>) instead") void setClean(std::initializer_list*> objects); + #endif + #endif /** @copydoc AbstractObject::isDirty() */ bool isDirty() const { return !!(flags & Flag::Dirty); } @@ -285,7 +338,20 @@ template class Object: public AbstractObject>>), + * which cleans given set of objects more efficiently than when calling + * @ref setClean() on each object individually. + * @see @ref scenegraph-caching, @ref setDirty(), @ref isDirty() + */ + /* note: doc verbatim copied from AbstractObject::setClean() */ void setClean(); /*@}*/ @@ -299,7 +365,7 @@ template class Object: public AbstractObject* o) const { return !o->isDirty(); } + inline bool operator()(Object& o) const { return !o.isDirty(); } }; #endif @@ -313,16 +379,16 @@ template class Object: public AbstractObject doTransformationMatrices(const std::vector*>& objects, const MatrixType& initialTransformationMatrix) const override final; + std::vector doTransformationMatrices(const std::vector>>& objects, const MatrixType& initialTransformationMatrix) const override final; - typename Transformation::DataType MAGNUM_SCENEGRAPH_LOCAL computeJointTransformation(const std::vector*>& jointObjects, std::vector& jointTransformations, const std::size_t joint, const typename Transformation::DataType& initialTransformation) const; + typename Transformation::DataType MAGNUM_SCENEGRAPH_LOCAL computeJointTransformation(const std::vector>>& jointObjects, std::vector& jointTransformations, const std::size_t joint, const typename Transformation::DataType& initialTransformation) const; bool MAGNUM_SCENEGRAPH_LOCAL doIsDirty() const override final { return isDirty(); } void MAGNUM_SCENEGRAPH_LOCAL doSetDirty() override final { setDirty(); } void MAGNUM_SCENEGRAPH_LOCAL doSetClean() override final { setClean(); } - void doSetClean(const std::vector*>& objects) override final; + void doSetClean(const std::vector>>& objects) override final; - void MAGNUM_SCENEGRAPH_LOCAL setClean(const typename Transformation::DataType& absoluteTransformation); + void MAGNUM_SCENEGRAPH_LOCAL setCleanInternal(const typename Transformation::DataType& absoluteTransformation); typedef Implementation::ObjectFlag Flag; typedef Implementation::ObjectFlags Flags; diff --git a/src/Magnum/SceneGraph/Object.hpp b/src/Magnum/SceneGraph/Object.hpp index dd5424079..6572333d7 100644 --- a/src/Magnum/SceneGraph/Object.hpp +++ b/src/Magnum/SceneGraph/Object.hpp @@ -38,9 +38,47 @@ namespace Magnum { namespace SceneGraph { +#ifdef MAGNUM_BUILD_DEPRECATED +template void AbstractObject::setClean(const std::vector*>& objects) { + std::vector>> references; + references.reserve(objects.size()); + for(auto o: objects) { + CORRADE_INTERNAL_ASSERT(o != nullptr); + references.push_back(*o); + } + + setClean(references); +} + +#ifdef CORRADE_GCC47_COMPATIBILITY +template void AbstractObject::setClean(std::initializer_list*> objects) { + return setClean(std::vector*>{objects}); +} +#endif +#endif + template AbstractObject::AbstractObject() {} template AbstractObject::~AbstractObject() {} +#ifdef MAGNUM_BUILD_DEPRECATED +template auto AbstractObject::transformationMatrices(const std::vector*>& objects, const MatrixType& initialTransformationMatrix) const -> std::vector { + std::vector>> references; + references.reserve(objects.size()); + for(auto o: objects) { + CORRADE_INTERNAL_ASSERT(o != nullptr); + references.push_back(*o); + } + + return transformationMatrices(references, initialTransformationMatrix); +} + +#ifdef CORRADE_GCC47_COMPATIBILITY +template auto AbstractObject::transformationMatrices(std::initializer_list*> objects, const MatrixType& initialTransformationMatrix) const -> std::vector { + return transformationMatrices(std::vector*>{objects}, initialTransformationMatrix); +} +#endif +#endif + template AbstractTransformation::AbstractTransformation() {} template Object::Object(Object* parent): counter(0xFFFFu), flags(Flag::Dirty) { @@ -160,22 +198,21 @@ template void Object::setClean() { /* Compose transformation and clean object */ absoluteTransformation = Implementation::Transformation::compose(absoluteTransformation, o->transformation()); CORRADE_INTERNAL_ASSERT(o->isDirty()); - o->setClean(absoluteTransformation); + o->setCleanInternal(absoluteTransformation); CORRADE_ASSERT(!o->isDirty(), "SceneGraph::Object::setClean(): original implementation was not called", ); } } -template auto Object::doTransformationMatrices(const std::vector*>& objects, const MatrixType& initialTransformationMatrix) const -> std::vector { - std::vector*> castObjects(objects.size()); - for(std::size_t i = 0; i != objects.size(); ++i) - /* Non-null is checked in transformations() */ - /** @todo Ensure this doesn't crash, somehow */ - castObjects[i] = static_cast*>(objects[i]); +template auto Object::doTransformationMatrices(const std::vector>>& objects, const MatrixType& initialTransformationMatrix) const -> std::vector { + std::vector>> castObjects; + castObjects.reserve(objects.size()); + /** @todo Ensure this doesn't crash, somehow */ + for(auto o: objects) castObjects.push_back(static_cast&>(o.get())); return transformationMatrices(std::move(castObjects), initialTransformationMatrix); } -template auto Object::transformationMatrices(const std::vector*>& objects, const MatrixType& initialTransformationMatrix) const -> std::vector { +template auto Object::transformationMatrices(const std::vector>>& objects, const MatrixType& initialTransformationMatrix) const -> std::vector { std::vector transformations = this->transformations(std::move(objects), Implementation::Transformation::fromMatrix(initialTransformationMatrix)); std::vector transformationMatrices(transformations.size()); for(std::size_t i = 0; i != objects.size(); ++i) @@ -184,6 +221,25 @@ template auto Object::transformationMatric return transformationMatrices; } +#ifdef MAGNUM_BUILD_DEPRECATED +template auto Object::transformationMatrices(const std::vector*>& objects, const MatrixType& initialTransformationMatrix) const -> std::vector { + std::vector>> references; + references.reserve(objects.size()); + for(auto o: objects) { + CORRADE_INTERNAL_ASSERT(o != nullptr); + references.push_back(*o); + } + + return transformationMatrices(references, initialTransformationMatrix); +} + +#ifdef CORRADE_GCC47_COMPATIBILITY +template auto Object::transformationMatrices(std::initializer_list*> objects, const MatrixType& initialTransformationMatrix) const -> std::vector { + return transformationMatrices(std::vector*>{objects}, initialTransformationMatrix); +} +#endif +#endif + /* Computing absolute transformations for given list of objects @@ -198,7 +254,7 @@ Then for all joints their transformation (relative to parent joint) is computed and recursively concatenated together. Resulting transformations for joints which were originally in `object` list is then returned. */ -template std::vector Object::transformations(std::vector*> objects, const typename Transformation::DataType& initialTransformation) const { +template std::vector Object::transformations(std::vector>> objects, const typename Transformation::DataType& initialTransformation) const { CORRADE_ASSERT(objects.size() < 0xFFFFu, "SceneGraph::Object::transformations(): too large scene", std::vector{}); /* Remember object count for later */ @@ -207,16 +263,14 @@ template std::vector Ob /* Mark all original objects as joints and create initial list of joints from them */ for(std::size_t i = 0; i != objects.size(); ++i) { - CORRADE_INTERNAL_ASSERT(objects[i]); - /* Multiple occurences of one object in the array, don't overwrite it with different counter */ - if(objects[i]->counter != 0xFFFFu) continue; + if(objects[i].get().counter != 0xFFFFu) continue; - objects[i]->counter = UnsignedShort(i); - objects[i]->flags |= Flag::Joint; + objects[i].get().counter = UnsignedShort(i); + objects[i].get().flags |= Flag::Joint; } - std::vector*> jointObjects(objects); + std::vector>> jointObjects(objects); /* Scene object */ const Scene* scene = this->scene(); @@ -228,19 +282,19 @@ template std::vector Ob auto it = objects.begin(); while(!objects.empty()) { /* Already visited, remove and continue to next (duplicate occurence) */ - if((*it)->flags & Flag::Visited) { + if(it->get().flags & Flag::Visited) { it = objects.erase(it); continue; } /* Mark the object as visited */ - (*it)->flags |= Flag::Visited; + it->get().flags |= Flag::Visited; - Object* parent = (*it)->parent(); + Object* parent = it->get().parent(); /* If this is root object, remove from list */ if(!parent) { - CORRADE_ASSERT(*it == scene, "SceneGraph::Object::transformations(): the objects are not part of the same tree", std::vector{}); + CORRADE_ASSERT(&it->get() == scene, "SceneGraph::Object::transformations(): the objects are not part of the same tree", std::vector{}); it = objects.erase(it); /* Parent is an joint or already visited - remove current from list */ @@ -255,11 +309,11 @@ template std::vector Ob CORRADE_INTERNAL_ASSERT(parent->counter == 0xFFFFu); parent->counter = UnsignedShort(jointObjects.size()); parent->flags |= Flag::Joint; - jointObjects.push_back(parent); + jointObjects.push_back(*parent); } /* Else go up the hierarchy */ - } else *it = parent; + } else *it = *parent; /* Cycle if reached end */ if(it == objects.end()) it = objects.begin(); @@ -275,24 +329,24 @@ template std::vector Ob /* Copy transformation for second or next occurences from first occurence of duplicate object */ for(std::size_t i = 0; i != objectCount; ++i) { - if(jointObjects[i]->counter != i) - jointTransformations[i] = jointTransformations[jointObjects[i]->counter]; + if(jointObjects[i].get().counter != i) + jointTransformations[i] = jointTransformations[jointObjects[i].get().counter]; } /* All visited marks are now cleaned, clean joint marks and counters */ for(auto it = jointObjects.begin(); it != jointObjects.end(); ++it) { /* All not-already cleaned objects (...duplicate occurences) should have joint mark */ - CORRADE_INTERNAL_ASSERT((*it)->counter == 0xFFFFu || (*it)->flags & Flag::Joint); + CORRADE_INTERNAL_ASSERT(it->get().counter == 0xFFFFu || it->get().flags & Flag::Joint); #ifndef CORRADE_GCC45_COMPATIBILITY - (*it)->flags &= ~Flag::Joint; + it->get().flags &= ~Flag::Joint; #else /* Miscompiled in Release build, causes ICE in Debug build: internal compiler error: in make_decl_rtl, at varasm.c:1318 http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43880 */ - (*it)->flags = (*it)->flags & ~Flag::Joint; + it->get().flags = it->get().flags & ~Flag::Joint; #endif - (*it)->counter = 0xFFFFu; + it->get().counter = 0xFFFFu; } /* Shrink the array to contain only transformations of requested objects and return */ @@ -300,33 +354,52 @@ template std::vector Ob return jointTransformations; } -template typename Transformation::DataType Object::computeJointTransformation(const std::vector*>& jointObjects, std::vector& jointTransformations, const std::size_t joint, const typename Transformation::DataType& initialTransformation) const { - Object* o = jointObjects[joint]; +#ifdef MAGNUM_BUILD_DEPRECATED +template std::vector Object::transformations(const std::vector*>& objects, const typename Transformation::DataType& initialTransformation) const { + std::vector>> references; + references.reserve(objects.size()); + for(auto o: objects) { + CORRADE_INTERNAL_ASSERT(o != nullptr); + references.push_back(*o); + } + + return transformations(std::move(references), initialTransformation); +} + +#ifdef CORRADE_GCC47_COMPATIBILITY +template std::vector Object::transformations(std::initializer_list*> objects, const typename Transformation::DataType& initialTransformation) const { + return transformations(std::vector*>{objects}, initialTransformation); +} +#endif +#endif + +template typename Transformation::DataType Object::computeJointTransformation(const std::vector>>& jointObjects, std::vector& jointTransformations, const std::size_t joint, const typename Transformation::DataType& initialTransformation) const { + std::reference_wrapper> o = jointObjects[joint]; /* Transformation already computed ("unvisited" by this function before either due to recursion or duplicate object occurences), done */ - if(!(o->flags & Flag::Visited)) return jointTransformations[joint]; + if(!(o.get().flags & Flag::Visited)) return jointTransformations[joint]; /* Initialize transformation */ - jointTransformations[joint] = o->transformation(); + jointTransformations[joint] = o.get().transformation(); /* Go up until next joint or root */ for(;;) { /* Clean visited mark */ - CORRADE_INTERNAL_ASSERT(o->flags & Flag::Visited); + CORRADE_INTERNAL_ASSERT(o.get().flags & Flag::Visited); #ifndef CORRADE_GCC45_COMPATIBILITY - o->flags &= ~Flag::Visited; + o.get().flags &= ~Flag::Visited; #else /* Miscompiled (the above assertion is triggered later), see above for more information */ - o->flags = o->flags & ~Flag::Visited; + o.get().flags = o.get().flags & ~Flag::Visited; #endif - Object* parent = o->parent(); + Object* parent = o.get().parent(); /* Root object, compose transformation with initial, done */ if(!parent) { - CORRADE_INTERNAL_ASSERT(o->isScene()); + CORRADE_INTERNAL_ASSERT(o.get().isScene()); return (jointTransformations[joint] = Implementation::Transformation::compose(initialTransformation, jointTransformations[joint])); @@ -338,21 +411,21 @@ template typename Transformation::DataType Object::compose(parent->transformation(), jointTransformations[joint]); - o = parent; + o = *parent; } } } -template void Object::doSetClean(const std::vector*>& objects) { - std::vector*> castObjects(objects.size()); - for(std::size_t i = 0; i != objects.size(); ++i) - /** @todo Ensure this doesn't crash, somehow */ - castObjects[i] = static_cast*>(objects[i]); +template void Object::doSetClean(const std::vector>>& objects) { + std::vector>> castObjects; + castObjects.reserve(objects.size()); + /** @todo Ensure this doesn't crash, somehow */ + for(auto o: objects) castObjects.push_back(static_cast&>(o.get())); setClean(std::move(castObjects)); } -template void Object::setClean(std::vector*> objects) { +template void Object::setClean(std::vector>> objects) { /* Remove all clean objects from the list */ auto firstClean = std::remove_if(objects.begin(), objects.end(), DirtyCheck()); objects.erase(firstClean, objects.end()); @@ -363,12 +436,12 @@ template void Object::setClean(std::vector /* Add non-clean parents to the list. Mark each added object as visited, so they aren't added more than once */ for(std::size_t end = objects.size(), i = 0; i != end; ++i) { - Object* o = objects[i]; - o->flags |= Flag::Visited; + Object& o = objects[i]; + o.flags |= Flag::Visited; - Object* parent = o->parent(); + Object* parent = o.parent(); while(parent && !(parent->flags & Flag::Visited) && parent->isDirty()) { - objects.push_back(parent); + objects.push_back(*parent); parent = parent->parent(); } } @@ -376,29 +449,48 @@ template void Object::setClean(std::vector /* Cleanup all marks */ for(auto it = objects.begin(); it != objects.end(); ++it) #ifndef CORRADE_GCC45_COMPATIBILITY - (*it)->flags &= ~Flag::Visited; + it->get().flags &= ~Flag::Visited; #else /* Miscompiled (not all objects are cleaned), see above for more information */ - (*it)->flags = (*it)->flags & ~Flag::Visited; + it->get().flags = it->get().flags & ~Flag::Visited; #endif /* Compute absolute transformations */ - Scene* scene = objects[0]->scene(); + Scene* scene = objects[0].get().scene(); CORRADE_ASSERT(scene, "Object::setClean(): objects must be part of some scene", ); std::vector transformations(scene->transformations(objects)); /* Go through all objects and clean them */ for(std::size_t i = 0; i != objects.size(); ++i) { /* The object might be duplicated in the list, don't clean it more than once */ - if(!objects[i]->isDirty()) continue; + if(!objects[i].get().isDirty()) continue; - objects[i]->setClean(transformations[i]); - CORRADE_ASSERT(!objects[i]->isDirty(), "SceneGraph::Object::setClean(): original implementation was not called", ); + objects[i].get().setCleanInternal(transformations[i]); + CORRADE_ASSERT(!objects[i].get().isDirty(), "SceneGraph::Object::setClean(): original implementation was not called", ); } } -template void Object::setClean(const typename Transformation::DataType& absoluteTransformation) { +#ifdef MAGNUM_BUILD_DEPRECATED +template void Object::setClean(const std::vector*>& objects) { + std::vector>> references; + references.reserve(objects.size()); + for(auto o: objects) { + CORRADE_INTERNAL_ASSERT(o != nullptr); + references.push_back(*o); + } + + setClean(std::move(references)); +} + +#ifdef CORRADE_GCC47_COMPATIBILITY +template void Object::setClean(std::initializer_list*> objects) { + setClean(std::vector*>{objects}); +} +#endif +#endif + +template void Object::setCleanInternal(const typename Transformation::DataType& absoluteTransformation) { /* "Lazy storage" for transformation matrix and inverted transformation matrix */ CachedTransformations cached; MatrixType matrix, invertedMatrix; diff --git a/src/Magnum/SceneGraph/RigidMatrixTransformation2D.h b/src/Magnum/SceneGraph/RigidMatrixTransformation2D.h index 6cb774e6b..40f98ce38 100644 --- a/src/Magnum/SceneGraph/RigidMatrixTransformation2D.h +++ b/src/Magnum/SceneGraph/RigidMatrixTransformation2D.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::SceneGraph::BasicRigidMatrixTransformation2D, typedef Magnum::SceneGraph::RigidMatrixTransformation2D + * @brief Class @ref Magnum::SceneGraph::BasicRigidMatrixTransformation2D, typedef @ref Magnum::SceneGraph::RigidMatrixTransformation2D */ #include "Magnum/Math/Matrix3.h" @@ -39,11 +39,12 @@ namespace Magnum { namespace SceneGraph { /** @brief Two-dimensional rigid transformation implemented using matrices -Unlike BasicMatrixTransformation2D this class allows only rotation, reflection -and translation (no scaling or setting arbitrary transformations). This allows -to use Matrix3::invertedRigid() for faster computation of inverse -transformations. -@see @ref RigidMatrixTransformation2D, @ref scenegraph, @ref BasicRigidMatrixTransformation3D +Unlike @ref BasicMatrixTransformation2D this class allows only rotation, +reflection and translation (no scaling or setting arbitrary transformations). +This allows to use @ref Math::Matrix3::invertedRigid() for faster computation +of inverse transformations. +@see @ref RigidMatrixTransformation2D, @ref scenegraph, + @ref BasicRigidMatrixTransformation3D */ template class BasicRigidMatrixTransformation2D: public AbstractBasicTranslationRotation2D { public: @@ -58,7 +59,7 @@ template class BasicRigidMatrixTransformation2D: public AbstractBasicTr * @return Reference to self (for method chaining) * * Expects that the matrix represents rigid transformation. - * @see Matrix3::isRigidTransformation() + * @see @ref Math::Matrix3::isRigidTransformation() */ Object>& setTransformation(const Math::Matrix3& transformation) { CORRADE_ASSERT(transformation.isRigidTransformation(), @@ -76,8 +77,9 @@ template class BasicRigidMatrixTransformation2D: public AbstractBasicTr * @brief Normalize rotation part * @return Reference to self (for method chaining) * - * Normalizes the rotation part using Math::Algorithms::gramSchmidt() - * to prevent rounding errors when rotating the object subsequently. + * Normalizes the rotation part using + * @ref Math::Algorithms::gramSchmidtOrthonormalize() to prevent + * rounding errors when rotating the object subsequently. */ Object>& normalizeRotation() { return setTransformationInternal(Math::Matrix3::from( @@ -92,7 +94,7 @@ template class BasicRigidMatrixTransformation2D: public AbstractBasicTr * @return Reference to self (for method chaining) * * Expects that the matrix represents rigid transformation. - * @see Matrix3::isRigidTransformation() + * @see @ref Math::Matrix3::isRigidTransformation() */ Object>& transform(const Math::Matrix3& transformation, TransformationType type = TransformationType::Global) { CORRADE_ASSERT(transformation.isRigidTransformation(), @@ -103,7 +105,7 @@ template class BasicRigidMatrixTransformation2D: public AbstractBasicTr /** * @copydoc AbstractTranslationRotationScaling2D::translate() - * Same as calling transform() with Matrix3::translation(). + * Same as calling @ref transform() with @ref Math::Matrix3::translation(). */ Object>& translate(const Math::Vector2& vector, TransformationType type = TransformationType::Global) { return transformInternal(Math::Matrix3::translation(vector), type); @@ -115,8 +117,8 @@ template class BasicRigidMatrixTransformation2D: public AbstractBasicTr * @param type Transformation type * @return Reference to self (for method chaining) * - * Same as calling transform() with Matrix3::rotation(). - * @see normalizeRotation() + * Same as calling @ref transform() with @ref Math::Matrix3::rotation(). + * @see @ref normalizeRotation() */ Object>& rotate(Math::Rad angle, TransformationType type = TransformationType::Global) { return transformInternal(Math::Matrix3::rotation(angle), type); @@ -129,7 +131,7 @@ template class BasicRigidMatrixTransformation2D: public AbstractBasicTr * @param type Transformation type * @return Reference to self (for method chaining) * - * Same as calling transform() with Matrix3::reflection(). + * Same as calling @ref transform() with @ref Math::Matrix3::reflection(). */ Object>& reflect(const Math::Vector2& normal, TransformationType type = TransformationType::Global) { return transformInternal(Math::Matrix3::reflection(normal), type); diff --git a/src/Magnum/SceneGraph/RigidMatrixTransformation3D.h b/src/Magnum/SceneGraph/RigidMatrixTransformation3D.h index fb02ccc4c..c07db2bbd 100644 --- a/src/Magnum/SceneGraph/RigidMatrixTransformation3D.h +++ b/src/Magnum/SceneGraph/RigidMatrixTransformation3D.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::SceneGraph::BasicRigidMatrixTransformation3D, typedef Magnum::SceneGraph::RigidMatrixTransformation3D + * @brief Class @ref Magnum::SceneGraph::BasicRigidMatrixTransformation3D, typedef @ref Magnum::SceneGraph::RigidMatrixTransformation3D */ #include "Magnum/Math/Matrix4.h" @@ -39,10 +39,10 @@ namespace Magnum { namespace SceneGraph { /** @brief Three-dimensional rigid transformation implemented using matrices -Unlike BasicMatrixTransformation3D this class allows only rotation, reflection -and translation (no scaling or setting arbitrary transformations). This allows -to use Matrix4::invertedRigid() for faster computation of inverse -transformations. +Unlike @ref BasicMatrixTransformation3D this class allows only rotation, +reflection and translation (no scaling or setting arbitrary transformations). +This allows to use @ref Math::Matrix4::invertedRigid() for faster computation +of inverse transformations. @see @ref RigidMatrixTransformation3D, @ref scenegraph, @ref BasicRigidMatrixTransformation2D */ template class BasicRigidMatrixTransformation3D: public AbstractBasicTranslationRotation3D { @@ -58,7 +58,7 @@ template class BasicRigidMatrixTransformation3D: public AbstractBasicTr * @return Reference to self (for method chaining) * * Expects that the matrix represents rigid transformation. - * @see Matrix4::isRigidTransformation() + * @see @ref Matrix4::isRigidTransformation() */ Object>& setTransformation(const Math::Matrix4& transformation) { CORRADE_ASSERT(transformation.isRigidTransformation(), @@ -76,7 +76,7 @@ template class BasicRigidMatrixTransformation3D: public AbstractBasicTr * @brief Normalize rotation part * @return Reference to self (for method chaining) * - * Normalizes the rotation part using Math::Algorithms::gramSchmidt() + * Normalizes the rotation part using @ref Math::Algorithms::gramSchmidtOrthonormalize() * to prevent rounding errors when rotating the object subsequently. */ Object>& normalizeRotation() { @@ -92,7 +92,7 @@ template class BasicRigidMatrixTransformation3D: public AbstractBasicTr * @return Reference to self (for method chaining) * * Expects that the matrix represents rigid transformation. - * @see Matrix4::isRigidTransformation() + * @see @ref Math::Matrix4::isRigidTransformation() */ Object>& transform(const Math::Matrix4& transformation, TransformationType type = TransformationType::Global) { CORRADE_ASSERT(transformation.isRigidTransformation(), @@ -103,7 +103,7 @@ template class BasicRigidMatrixTransformation3D: public AbstractBasicTr /** * @copydoc AbstractTranslationRotationScaling3D::translate() - * Same as calling transform() with Matrix4::translation(). + * Same as calling @ref transform() with @ref Math::Matrix4::translation(). */ Object>& translate(const Math::Vector3& vector, TransformationType type = TransformationType::Global) { return transformInternal(Math::Matrix4::translation(vector), type); @@ -116,9 +116,10 @@ template class BasicRigidMatrixTransformation3D: public AbstractBasicTr * @param type Transformation type * @return Reference to self (for method chaining) * - * Same as calling transform() with Matrix4::rotation(). - * @see rotateX(), rotateY(), rotateZ(), Vector3::xAxis(), - * Vector3::yAxis(), Vector3::zAxis(), normalizeRotation() + * Same as calling @ref transform() with @ref Math::Matrix4::rotation(). + * @see @ref rotateX(), @ref rotateY(), @ref rotateZ(), + * @ref normalizeRotation(), @ref Math::Vector3::xAxis(), + * @ref Math::Vector3::yAxis(), @ref Math::Vector3::zAxis() */ Object>& rotate(Math::Rad angle, const Math::Vector3& normalizedAxis, TransformationType type = TransformationType::Global) { return transformInternal(Math::Matrix4::rotation(angle, normalizedAxis), type); @@ -130,8 +131,8 @@ template class BasicRigidMatrixTransformation3D: public AbstractBasicTr * @param type Transformation type * @return Reference to self (for method chaining) * - * Same as calling transform() with Matrix4::rotationX(). - * @see normalizeRotation() + * Same as calling @ref transform() with @ref Math::Matrix4::rotationX(). + * @see @ref normalizeRotation() */ Object>& rotateX(Math::Rad angle, TransformationType type = TransformationType::Global) { return transformInternal(Math::Matrix4::rotationX(angle), type); @@ -143,8 +144,8 @@ template class BasicRigidMatrixTransformation3D: public AbstractBasicTr * @param type Transformation type * @return Reference to self (for method chaining) * - * Same as calling transform() with Matrix4::rotationY(). - * @see normalizeRotation() + * Same as calling @ref transform() with @ref Math::Matrix4::rotationY(). + * @see @ref normalizeRotation() */ Object>& rotateY(Math::Rad angle, TransformationType type = TransformationType::Global) { return transformInternal(Math::Matrix4::rotationY(angle), type); @@ -156,8 +157,8 @@ template class BasicRigidMatrixTransformation3D: public AbstractBasicTr * @param type Transformation type * @return Reference to self (for method chaining) * - * Same as calling transform() with Matrix4::rotationZ(). - * @see normalizeRotation() + * Same as calling @ref transform() with @ref Math::Matrix4::rotationZ(). + * @see @ref normalizeRotation() */ Object>& rotateZ(Math::Rad angle, TransformationType type = TransformationType::Global) { return transformInternal(Math::Matrix4::rotationZ(angle), type); @@ -170,7 +171,7 @@ template class BasicRigidMatrixTransformation3D: public AbstractBasicTr * @param type Transformation type * @return Reference to self (for method chaining) * - * Same as calling transform() with Matrix4::reflection(). + * Same as calling @ref transform() with @ref Math::Matrix4::reflection(). */ Object>& reflect(const Math::Vector3& normal, TransformationType type = TransformationType::Global) { return transformInternal(Math::Matrix4::reflection(normal), type); diff --git a/src/Magnum/SceneGraph/Scene.h b/src/Magnum/SceneGraph/Scene.h index b92059a40..be945ab07 100644 --- a/src/Magnum/SceneGraph/Scene.h +++ b/src/Magnum/SceneGraph/Scene.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::SceneGraph::Scene + * @brief Class @ref Magnum::SceneGraph::Scene */ #include "Magnum/SceneGraph/Object.h" @@ -36,7 +36,7 @@ namespace Magnum { namespace SceneGraph { /** @brief %Scene -Basically Object which cannot have parent or non-default transformation. +Basically @ref Object which cannot have parent or non-default transformation. See @ref scenegraph for introduction. */ template class Scene: public Object { diff --git a/src/Magnum/SceneGraph/SceneGraph.h b/src/Magnum/SceneGraph/SceneGraph.h index 33408b191..969117f2e 100644 --- a/src/Magnum/SceneGraph/SceneGraph.h +++ b/src/Magnum/SceneGraph/SceneGraph.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Forward declarations for Magnum::SceneGraph namespace + * @brief Forward declarations for @ref Magnum::SceneGraph namespace */ #include diff --git a/src/Magnum/SceneGraph/Test/ObjectTest.cpp b/src/Magnum/SceneGraph/Test/ObjectTest.cpp index e6616c9ae..5139c4b12 100644 --- a/src/Magnum/SceneGraph/Test/ObjectTest.cpp +++ b/src/Magnum/SceneGraph/Test/ObjectTest.cpp @@ -174,22 +174,26 @@ void ObjectTest::transformations() { Matrix4 initial = Matrix4::rotationX(Deg(90.0f)).inverted(); /* Empty list */ - CORRADE_COMPARE(s.transformations(std::vector(), initial), std::vector()); + #ifndef MAGNUM_BUILD_DEPRECATED + CORRADE_COMPARE(s.transformations({}, initial), std::vector()); + #else + CORRADE_COMPARE(s.transformations(std::vector>{}, initial), std::vector()); + #endif /* Scene alone */ - CORRADE_COMPARE(s.transformations({&s}, initial), std::vector{initial}); + CORRADE_COMPARE(s.transformations({s}, initial), std::vector{initial}); /* One object */ Object3D first(&s); first.rotateZ(Deg(30.0f)); Object3D second(&first); second.scale(Vector3(0.5f)); - CORRADE_COMPARE(s.transformations({&second}, initial), std::vector{ + CORRADE_COMPARE(s.transformations({second}, initial), std::vector{ initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)) }); /* One object and scene */ - CORRADE_COMPARE(s.transformations({&second, &s}, initial), (std::vector{ + CORRADE_COMPARE(s.transformations({second, s}, initial), (std::vector{ initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)), initial })); @@ -197,13 +201,13 @@ void ObjectTest::transformations() { /* Two objects with foreign joint */ Object3D third(&first); third.translate(Vector3::xAxis(5.0f)); - CORRADE_COMPARE(s.transformations({&second, &third}, initial), (std::vector{ + CORRADE_COMPARE(s.transformations({second, third}, initial), (std::vector{ initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)), initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::translation(Vector3::xAxis(5.0f)), })); /* Three objects with joint as one of them */ - CORRADE_COMPARE(s.transformations({&second, &third, &first}, initial), (std::vector{ + CORRADE_COMPARE(s.transformations({second, third, first}, initial), (std::vector{ initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)), initial*Matrix4::rotationZ(Deg(30.0f))*Matrix4::translation(Vector3::xAxis(5.0f)), initial*Matrix4::rotationZ(Deg(30.0f)), @@ -222,7 +226,7 @@ void ObjectTest::transformationsRelative() { third.translate(Vector3::xAxis(5.0f)); /* Transformation relative to another object */ - CORRADE_COMPARE(second.transformations({&third}), std::vector{ + CORRADE_COMPARE(second.transformations({third}), std::vector{ Matrix4::scaling(Vector3(0.5f)).inverted()*Matrix4::translation(Vector3::xAxis(5.0f)) }); @@ -234,7 +238,7 @@ void ObjectTest::transformationsRelative() { orphan1.scale(Vector3::xScale(3.0f)); Object3D orphan2(&orphanParent); orphan2.translate(Vector3::zAxis(5.0f)); - CORRADE_COMPARE(orphan1.transformations({&orphan2}), std::vector{ + CORRADE_COMPARE(orphan1.transformations({orphan2}), std::vector{ Matrix4::scaling(Vector3::xScale(3.0f)).inverted()*Matrix4::translation(Vector3::zAxis(5.0f)) }); } @@ -246,7 +250,7 @@ void ObjectTest::transformationsOrphan() { /* Transformation of objects not part of the same scene */ Scene3D s; Object3D orphan; - CORRADE_COMPARE(s.transformations({&orphan}), std::vector()); + CORRADE_COMPARE(s.transformations({orphan}), std::vector()); CORRADE_COMPARE(o.str(), "SceneGraph::Object::transformations(): the objects are not part of the same tree\n"); } @@ -262,7 +266,7 @@ void ObjectTest::transformationsDuplicate() { Matrix4 firstExpected = Matrix4::rotationZ(Deg(30.0f)); Matrix4 secondExpected = Matrix4::rotationZ(Deg(30.0f))*Matrix4::scaling(Vector3(0.5f)); Matrix4 thirdExpected = Matrix4::rotationZ(Deg(30.0f))*Matrix4::translation(Vector3::xAxis(5.0f)); - CORRADE_COMPARE(s.transformations({&second, &third, &second, &first, &third}), (std::vector{ + CORRADE_COMPARE(s.transformations({second, third, second, first, third}), (std::vector{ secondExpected, thirdExpected, secondExpected, firstExpected, thirdExpected })); } @@ -392,7 +396,7 @@ void ObjectTest::setCleanListHierarchy() { childThree->rotate(Deg(90.0f), Vector3::yAxis()); /* Clean the object and all its dirty parents (but not children) */ - Scene3D::setClean(std::vector{childTwo}); + Scene3D::setClean({*childTwo}); CORRADE_VERIFY(!scene.isDirty()); CORRADE_VERIFY(!childOne->isDirty()); CORRADE_VERIFY(!childTwo->isDirty()); @@ -406,19 +410,23 @@ void ObjectTest::setCleanListHierarchy() { /* If the object itself is already clean, it shouldn't clean it again */ childOne->cleanedAbsoluteTransformation = Matrix4(Matrix4::Zero); CORRADE_VERIFY(!childOne->isDirty()); - Scene3D::setClean(std::vector{childOne}); + Scene3D::setClean({*childOne}); CORRADE_COMPARE(childOne->cleanedAbsoluteTransformation, Matrix4(Matrix4::Zero)); /* If any object in the hierarchy is already clean, it shouldn't clean it again */ CORRADE_VERIFY(!childOne->isDirty()); childTwo->setDirty(); - Scene3D::setClean(std::vector{childTwo}); + Scene3D::setClean({*childTwo}); CORRADE_COMPARE(childOne->cleanedAbsoluteTransformation, Matrix4(Matrix4::Zero)); } void ObjectTest::setCleanListBulk() { /* Verify it doesn't crash when passed empty list */ - Object3D::setClean(std::vector()); + #ifndef MAGNUM_BUILD_DEPRECATED + Object3D::setClean({}); + #else + Object3D::setClean(std::vector>{}); + #endif Scene3D scene; Object3D a(&scene); @@ -429,7 +437,6 @@ void ObjectTest::setCleanListBulk() { CachingObject d(&c); d.scale(Vector3(-2.0f)); Object3D e(&scene); - std::vector cleanAll{&a, &b, &c, &d, &e}; /* All objects should be cleaned */ CORRADE_VERIFY(a.isDirty()); @@ -437,7 +444,7 @@ void ObjectTest::setCleanListBulk() { CORRADE_VERIFY(c.isDirty()); CORRADE_VERIFY(d.isDirty()); CORRADE_VERIFY(e.isDirty()); - Object3D::setClean(cleanAll); + Object3D::setClean({a, b, c, d, e}); CORRADE_VERIFY(!a.isDirty()); CORRADE_VERIFY(!b.isDirty()); CORRADE_VERIFY(!c.isDirty()); diff --git a/src/Magnum/SceneGraph/TranslationTransformation.h b/src/Magnum/SceneGraph/TranslationTransformation.h index 6931dc03b..5397fb6c9 100644 --- a/src/Magnum/SceneGraph/TranslationTransformation.h +++ b/src/Magnum/SceneGraph/TranslationTransformation.h @@ -103,8 +103,9 @@ class TranslationTransformation: public AbstractTranslation>& translate(const typename DimensionTraits::VectorType& vector, TransformationType = TransformationType::Global) { _transformation += vector; diff --git a/src/Magnum/Shader.cpp b/src/Magnum/Shader.cpp index ceab4c910..defdb90bc 100644 --- a/src/Magnum/Shader.cpp +++ b/src/Magnum/Shader.cpp @@ -559,11 +559,11 @@ Shader::Shader(const Version version, const Type type): _type(type), _id(0) { case Version::GLES300: _sources.push_back("#version 300\n"); return; #endif - case Version::None: - CORRADE_ASSERT(false, "Shader::Shader(): unsupported version" << version, ); + /* The user is responsible for (not) adding #version directive */ + case Version::None: return; } - CORRADE_ASSERT_UNREACHABLE(); + CORRADE_ASSERT(false, "Shader::Shader(): unsupported version" << version, ); } Shader::~Shader() { diff --git a/src/Magnum/Shader.h b/src/Magnum/Shader.h index 487add2a1..0c64d26ab 100644 --- a/src/Magnum/Shader.h +++ b/src/Magnum/Shader.h @@ -440,8 +440,10 @@ class MAGNUM_EXPORT Shader: public AbstractObject { * @param version Target version * @param type %Shader type * - * Creates empty OpenGL shader and adds @c \#version directive at the - * beginning. + * Creates empty OpenGL shader and adds @c \#version directive + * corresponding to @p version parameter at the beginning. If + * @ref Version::None is specified, (not) adding the @c \#version + * directive is left to the user. * @see @fn_gl{CreateShader} */ explicit Shader(Version version, Type type); @@ -473,9 +475,9 @@ class MAGNUM_EXPORT Shader: public AbstractObject { * @brief %Shader label * * The result is *not* cached, repeated queries will result in repeated - * OpenGL calls. If neither @extension{KHR,debug} nor - * @extension2{EXT,debug_label} desktop or ES extension is available, - * this function returns empty string. + * OpenGL calls. If OpenGL 4.3 is not supported and neither + * @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES + * extension is available, this function returns empty string. * @see @fn_gl{GetObjectLabel} with @def_gl{SHADER} or * @fn_gl_extension2{GetObjectLabel,EXT,debug_label} with * @def_gl{SHADER_OBJECT_EXT} @@ -486,9 +488,9 @@ class MAGNUM_EXPORT Shader: public AbstractObject { * @brief Set shader label * @return Reference to self (for method chaining) * - * Default is empty string. If neither @extension{KHR,debug} nor - * @extension2{EXT,debug_label} desktop or ES extension is available, - * this function does nothing. + * Default is empty string. If OpenGL 4.3 is not supported and neither + * @extension{KHR,debug} nor @extension2{EXT,debug_label} desktop or ES + * extension is available, this function does nothing. * @see @ref maxLabelLength(), @fn_gl{ObjectLabel} with * @def_gl{SHADER} or @fn_gl_extension2{LabelObject,EXT,debug_label} * with @def_gl{SHADER_OBJECT_EXT} diff --git a/src/Magnum/Shaders/AbstractVector.cpp b/src/Magnum/Shaders/AbstractVector.cpp new file mode 100644 index 000000000..e06d09cc9 --- /dev/null +++ b/src/Magnum/Shaders/AbstractVector.cpp @@ -0,0 +1,43 @@ +/* + 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 "AbstractVector.h" + +#include "Magnum/Texture.h" +#include "Magnum/Shaders/visibility.h" + +namespace Magnum { namespace Shaders { + +template AbstractVector& AbstractVector::setVectorTexture(Texture2D& texture) { + texture.bind(VectorTextureLayer); + return *this; +} + +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_SHADERS_EXPORT AbstractVector<2>; +template class MAGNUM_SHADERS_EXPORT AbstractVector<3>; +#endif + +}} diff --git a/src/Magnum/Shaders/AbstractVector.h b/src/Magnum/Shaders/AbstractVector.h index 7c8cb7366..a1a843bf4 100644 --- a/src/Magnum/Shaders/AbstractVector.h +++ b/src/Magnum/Shaders/AbstractVector.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::Shaders::AbstractVector, typedef Magnum::Shaders::AbstractVector2D, Magnum::Shaders::AbstractVector3D + * @brief Class @ref Magnum::Shaders::AbstractVector, typedef @ref Magnum::Shaders::AbstractVector2D, @ref Magnum::Shaders::AbstractVector3D */ #include "Magnum/Shaders/Generic.h" @@ -36,7 +36,7 @@ namespace Magnum { namespace Shaders { /** @brief Base for vector shaders -@see AbstractVector2D, AbstractVector3D +@see @ref AbstractVector2D, @ref AbstractVector3D */ template class AbstractVector: public AbstractShaderProgram { public: @@ -46,13 +46,29 @@ template class AbstractVector: public AbstractShaderProg /** @brief Texture coordinates */ typedef typename Generic::TextureCoordinates TextureCoordinates; + #ifdef MAGNUM_BUILD_DEPRECATED enum: Int { - VectorTextureLayer = 16 /**< Layer for vector texture */ + /** + * Layer for vector texture + * @deprecated Use @ref Magnum::Shaders::AbstractVector::setVectorTexture() "setVectorTexture()" instead. + */ + VectorTextureLayer = 16 }; + #endif + + /** + * @brief Set vector texture + * @return Reference to self (for method chaining) + */ + AbstractVector& setVectorTexture(Texture2D& texture); protected: explicit AbstractVector(); ~AbstractVector(); + + #ifndef MAGNUM_BUILD_DEPRECATED + enum: Int { VectorTextureLayer = 16 }; + #endif }; /** @brief Base for two-dimensional text shaders */ diff --git a/src/Magnum/Shaders/CMakeLists.txt b/src/Magnum/Shaders/CMakeLists.txt index 90714d0b4..0405f7529 100644 --- a/src/Magnum/Shaders/CMakeLists.txt +++ b/src/Magnum/Shaders/CMakeLists.txt @@ -26,6 +26,7 @@ corrade_add_resource(MagnumShaders_RCS resources.conf) set(MagnumShaders_SRCS + AbstractVector.cpp DistanceFieldVector.cpp Flat.cpp MeshVisualizer.cpp diff --git a/src/Magnum/Shaders/DistanceFieldVector.h b/src/Magnum/Shaders/DistanceFieldVector.h index de8316074..9512c212b 100644 --- a/src/Magnum/Shaders/DistanceFieldVector.h +++ b/src/Magnum/Shaders/DistanceFieldVector.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::Shaders::DistanceFieldVector, typedef Magnum::Shaders::DistanceFieldVector2D, Magnum::Shaders::DistanceFieldVector3D + * @brief Class @ref Magnum::Shaders::DistanceFieldVector, typedef @ref Magnum::Shaders::DistanceFieldVector2D, @ref Magnum::Shaders::DistanceFieldVector3D */ #include "Magnum/Color.h" @@ -41,10 +41,10 @@ namespace Magnum { namespace Shaders { /** @brief Distance field vector shader -Renders vector art in form of signed distance field. See TextureTools::distanceField() +Renders vector art in form of signed distance field. See @ref TextureTools::distanceField() for more information. Note that the final rendered outlook will greatly depend -on radius of input distance field and value passed to setSmoothness(). -@see DistanceFieldVector2D, DistanceFieldVector3D +on radius of input distance field and value passed to @ref setSmoothness(). +@see @ref DistanceFieldVector2D, @ref DistanceFieldVector3D @todo Use fragment shader derivations to have proper smoothness in perspective/ large zoom levels, make it optional as it might have negative performance impact @@ -66,7 +66,7 @@ template class MAGNUM_SHADERS_EXPORT DistanceFieldVector * @brief Set fill color * @return Reference to self (for method chaining) * - * @see setOutlineColor() + * @see @ref setOutlineColor() */ DistanceFieldVector& setColor(const Color4& color) { AbstractShaderProgram::setUniform(colorUniform, color); @@ -77,7 +77,7 @@ template class MAGNUM_SHADERS_EXPORT DistanceFieldVector * @brief Set outline color * @return Reference to self (for method chaining) * - * @see setOutlineRange(), setColor() + * @see @ref setOutlineRange(), @ref setColor() */ DistanceFieldVector& setOutlineColor(const Color4& color) { AbstractShaderProgram::setUniform(outlineColorUniform, color); @@ -96,7 +96,7 @@ template class MAGNUM_SHADERS_EXPORT DistanceFieldVector * larger than @p start the outline is not drawn. Initial value is * `1.0f`. * - * @see setOutlineColor() + * @see @ref setOutlineColor() */ DistanceFieldVector& setOutlineRange(Float start, Float end) { AbstractShaderProgram::setUniform(outlineRangeUniform, Vector2(start, end)); @@ -107,15 +107,23 @@ template class MAGNUM_SHADERS_EXPORT DistanceFieldVector * @brief Set smoothness radius * @return Reference to self (for method chaining) * - * Larger values will make edges look less aliased (but blurry), smaller - * values will make them look more crisp (but possibly aliased). Initial - * value is `0.04f`. + * Larger values will make edges look less aliased (but blurry), + * smaller values will make them look more crisp (but possibly + * aliased). Initial value is `0.04f`. */ DistanceFieldVector& setSmoothness(Float value) { AbstractShaderProgram::setUniform(smoothnessUniform, value); return *this; } + #ifndef DOXYGEN_GENERATING_OUTPUT + /* Overloads to remove WTF-factor from method chaining order */ + DistanceFieldVector& setVectorTexture(Texture2D& texture) { + AbstractVector::setVectorTexture(texture); + return *this; + } + #endif + private: Int transformationProjectionMatrixUniform, colorUniform, diff --git a/src/Magnum/Shaders/Flat.cpp b/src/Magnum/Shaders/Flat.cpp index 748d9724a..7e487927c 100644 --- a/src/Magnum/Shaders/Flat.cpp +++ b/src/Magnum/Shaders/Flat.cpp @@ -30,10 +30,13 @@ #include "Magnum/Context.h" #include "Magnum/Extensions.h" #include "Magnum/Shader.h" +#include "Magnum/Texture.h" namespace Magnum { namespace Shaders { namespace { + enum: Int { TextureLayer = 0 }; + template constexpr const char* vertexShaderName(); template<> constexpr const char* vertexShaderName<2>() { return "Flat2D.vert"; } template<> constexpr const char* vertexShaderName<3>() { return "Flat3D.vert"; } @@ -99,6 +102,11 @@ template Flat::Flat(const Flags flags): tran #endif } +template Flat& Flat::setTexture(Texture2D& texture) { + if(_flags & Flag::Textured) texture.bind(TextureLayer); + return *this; +} + template class Flat<2>; template class Flat<3>; diff --git a/src/Magnum/Shaders/Flat.h b/src/Magnum/Shaders/Flat.h index ffbc7c4d6..e64afdd2a 100644 --- a/src/Magnum/Shaders/Flat.h +++ b/src/Magnum/Shaders/Flat.h @@ -52,15 +52,9 @@ need to provide @ref Position attribute in your triangle mesh and call at least If you want to use texture instead of color, you need to provide also @ref TextureCoordinates attribute. Pass @ref Flag::Textured to constructor and -then at render time bind the texture to its respective layer instead of calling -@ref setColor(). Example: -@code -Shaders::Flat2D shader(Shaders::Flat2D::Flag::Textured); - -// ... - -myTexture.bind(Shaders::Flat2D::TextureLayer); -@endcode +then at render time don't forget to set also the texture via @ref setTexture(). +The texture will be multiplied with the color (which is white by default, thus +it doesn't change texture color). For coloring the texture based on intensity you can use the @ref Vector shader. @see @ref Flat2D, @ref Flat3D @@ -77,10 +71,15 @@ template class MAGNUM_SHADERS_EXPORT Flat: public Abstra */ typedef typename Generic::TextureCoordinates TextureCoordinates; + #ifdef MAGNUM_BUILD_DEPRECATED enum: Int { - /** Layer for color texture. Used only if @ref Flag::Textured is set. */ + /** + * Layer for color texture. Used only if @ref Flag::Textured is set. + * @deprecated use @ref Magnum::Shaders::Flat::setTexture() "setTexture()" instead. + */ TextureLayer = 0 }; + #endif #ifdef DOXYGEN_GENERATING_OUTPUT /** @@ -125,11 +124,21 @@ template class MAGNUM_SHADERS_EXPORT Flat: public Abstra * @brief Set color * @return Reference to self (for method chaining) * - * Color will be multiplied with texture - * if @ref Flag::Textured is set. + * If not set, default value is fully opaque white. Color will be + * multiplied with texture if @ref Flag::Textured is set. + * @see @ref setTexture() */ Flat& setColor(const Color4& color); + /** + * @brief Set texture + * @return Reference to self (for method chaining) + * + * Has effect only if @ref Flag::Textured is set. + * @see @ref setColor() + */ + Flat& setTexture(Texture2D& texture); + private: Int transformationProjectionMatrixUniform, colorUniform; diff --git a/src/Magnum/Shaders/Generic.h b/src/Magnum/Shaders/Generic.h index f3090256e..315a0e851 100644 --- a/src/Magnum/Shaders/Generic.h +++ b/src/Magnum/Shaders/Generic.h @@ -54,8 +54,7 @@ mesh.addVertexBuffer(vertexBuffer, 0, Shaders::Phong phong; // ... -phong.use(); -mesh.draw(); +mesh.draw(phong); @endcode @see @ref Generic2D, @ref Generic3D diff --git a/src/Magnum/Shaders/MeshVisualizer.h b/src/Magnum/Shaders/MeshVisualizer.h index 867165b8f..7239e7caa 100644 --- a/src/Magnum/Shaders/MeshVisualizer.h +++ b/src/Magnum/Shaders/MeshVisualizer.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::Shaders::MeshVisualizer + * @brief Class @ref Magnum::Shaders::MeshVisualizer */ #include "Magnum/Math/Matrix4.h" @@ -56,9 +56,9 @@ If you have geometry shaders available, you don't need to do anything else. If you don't have geometry shaders, you need to set @ref Flag::NoGeometryShader (it's enabled by default in OpenGL ES) and use only **non-indexed** triangle -meshes (see MeshTools::duplicate() for possible solution). Additionaly, if you -have OpenGL < 3.1 or OpenGL ES 2.0, you need to provide also @ref VertexIndex -attribute. +meshes (see @ref MeshTools::duplicate() for possible solution). Additionaly, if +you have OpenGL < 3.1 or OpenGL ES 2.0, you need to provide also +@ref VertexIndex attribute. @requires_es_extension %Extension @extension{OES,standard_derivatives} for wireframe rendering. @@ -83,7 +83,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizer: public AbstractShaderProgram { /** * @brief %Flag * - * @see Flags, MeshVisualizer() + * @see @ref Flags, @ref MeshVisualizer() */ enum class Flag: UnsignedByte { /** @@ -98,8 +98,9 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizer: public AbstractShaderProgram { /** * Don't use geometry shader for wireframe visualization. If - * enabled, you might need to provide also VertexIndex attribute in - * the mesh. In OpenGL ES enabled alongside @ref Flag::Wireframe. + * enabled, you might need to provide also @ref VertexIndex + * attribute in the mesh. In OpenGL ES enabled alongside + * @ref Flag::Wireframe. */ NoGeometryShader = 1 << 1 }; diff --git a/src/Magnum/Shaders/Phong.cpp b/src/Magnum/Shaders/Phong.cpp index feb810a6c..bb88002c3 100644 --- a/src/Magnum/Shaders/Phong.cpp +++ b/src/Magnum/Shaders/Phong.cpp @@ -30,9 +30,18 @@ #include "Magnum/Context.h" #include "Magnum/Extensions.h" #include "Magnum/Shader.h" +#include "Magnum/Texture.h" namespace Magnum { namespace Shaders { +namespace { + enum: Int { + AmbientTextureLayer = 0, + DiffuseTextureLayer = 1, + SpecularTextureLayer = 2 + }; +} + Phong::Phong(const Flags flags): transformationMatrixUniform(0), projectionMatrixUniform(1), normalMatrixUniform(2), lightUniform(3), diffuseColorUniform(4), ambientColorUniform(5), specularColorUniform(6), lightColorUniform(7), shininessUniform(8), _flags(flags) { Utility::Resource rs("MagnumShaders"); @@ -105,4 +114,19 @@ Phong::Phong(const Flags flags): transformationMatrixUniform(0), projectionMatri #endif } +Phong& Phong::setAmbientTexture(Texture2D& texture) { + if(_flags & Flag::AmbientTexture) texture.bind(AmbientTextureLayer); + return *this; +} + +Phong& Phong::setDiffuseTexture(Texture2D& texture) { + if(_flags & Flag::DiffuseTexture) texture.bind(DiffuseTextureLayer); + return *this; +} + +Phong& Phong::setSpecularTexture(Texture2D& texture) { + if(_flags & Flag::SpecularTexture) texture.bind(SpecularTextureLayer); + return *this; +} + }} diff --git a/src/Magnum/Shaders/Phong.h b/src/Magnum/Shaders/Phong.h index 42bff2819..f07967cfc 100644 --- a/src/Magnum/Shaders/Phong.h +++ b/src/Magnum/Shaders/Phong.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::Shaders::Phong + * @brief Class @ref Magnum::Shaders::Phong */ #include "Magnum/Color.h" @@ -46,15 +46,8 @@ call at least @ref setTransformationMatrix(), @ref setNormalMatrix(), If you want to use texture instead of color, you need to provide also @ref TextureCoordinates attribute. Pass appropriate flags to constructor and -then at render time bind the texture to its respective layer instead of setting -the color. Example: -@code -Shaders::Phong shader(Shaders::Phong::Flag::DiffuseTexture); - -// ... - -myDiffuseTexture.bind(Shaders::Phong::DiffuseTextureLayer); -@endcode +then at render time don't forget to also call appropriate subset of +@ref setAmbientTexture(), @ref setDiffuseTexture() and @ref setSpecularTexture(). */ class MAGNUM_SHADERS_EXPORT Phong: public AbstractShaderProgram { public: @@ -69,25 +62,33 @@ class MAGNUM_SHADERS_EXPORT Phong: public AbstractShaderProgram { */ typedef Generic3D::TextureCoordinates TextureCoordinates; + #ifdef MAGNUM_BUILD_DEPRECATED enum: Int { /** * Layer for ambient texture. Used only if @ref Flag::AmbientTexture * is set. + * @deprecated Use @ref Magnum::Shaders::Phong::setAmbientTexture() "setAmbientTexture()" + * instead. */ AmbientTextureLayer = 0, /** * Layer for diffuse texture. Used only if @ref Flag::DiffuseTexture * is set. + * @deprecated Use @ref Magnum::Shaders::Phong::setDiffuseTexture() "setDiffuseTexture()" + * instead. */ DiffuseTextureLayer = 1, /** * Layer for specular texture. Used only if @ref Flag::SpecularTexture * is set. + * @deprecated Use @ref Magnum::Shaders::Phong::setSpecularTexture() "setSpecularTexture()" + * instead. */ SpecularTextureLayer = 2 }; + #endif /** * @brief Shader flag @@ -122,26 +123,56 @@ class MAGNUM_SHADERS_EXPORT Phong: public AbstractShaderProgram { * * If not set, default value is `(0.0f, 0.0f, 0.0f)`. Has no effect if * @ref Flag::AmbientTexture is set. + * @see @ref setAmbientTexture() */ Phong& setAmbientColor(const Color3& color); + /** + * @brief Set ambient texture + * @return Reference to self (for method chaining) + * + * Has effect only if @ref Flag::AmbientTexture is set. + * @see @ref setAmbientColor() + */ + Phong& setAmbientTexture(Texture2D& texture); + /** * @brief Set diffuse color * @return Reference to self (for method chaining) * - * Has no effect if @ref Flag::AmbientTexture is used. + * Has no effect if @ref Flag::DiffuseTexture is used. + * @see @ref setDiffuseTexture() */ Phong& setDiffuseColor(const Color3& color); + /** + * @brief Set diffuse texture + * @return Reference to self (for method chaining) + * + * Has effect only if @ref Flag::DiffuseTexture is set. + * @see @ref setDiffuseColor() + */ + Phong& setDiffuseTexture(Texture2D& texture); + /** * @brief Set specular color * @return Reference to self (for method chaining) * * If not set, default value is `(1.0f, 1.0f, 1.0f)`. Has no effect if * @ref Flag::SpecularTexture is set. + * @see @ref setSpecularTexture() */ Phong& setSpecularColor(const Color3& color); + /** + * @brief Set specular texture + * @return Reference to self (for method chaining) + * + * Has effect only if @ref Flag::SpecularTexture is set. + * @see @ref setSpecularColor() + */ + Phong& setSpecularTexture(Texture2D& texture); + /** * @brief Set shininess * @return Reference to self (for method chaining) diff --git a/src/Magnum/Shaders/Shaders.h b/src/Magnum/Shaders/Shaders.h index af355f7dd..d3fd54b2f 100644 --- a/src/Magnum/Shaders/Shaders.h +++ b/src/Magnum/Shaders/Shaders.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Forward declarations for Magnum::Shaders namespace + * @brief Forward declarations for @ref Magnum::Shaders namespace */ #include "Magnum/Types.h" diff --git a/src/Magnum/Shaders/Vector.h b/src/Magnum/Shaders/Vector.h index 72d934183..ae73cf8d0 100644 --- a/src/Magnum/Shaders/Vector.h +++ b/src/Magnum/Shaders/Vector.h @@ -82,6 +82,14 @@ template class MAGNUM_SHADERS_EXPORT Vector: public Abst return *this; } + #ifndef DOXYGEN_GENERATING_OUTPUT + /* Overloads to remove WTF-factor from method chaining order */ + Vector& setVectorTexture(Texture2D& texture) { + AbstractVector::setVectorTexture(texture); + return *this; + } + #endif + private: Int transformationProjectionMatrixUniform, backgroundColorUniform, diff --git a/src/Magnum/Shaders/VertexColor.h b/src/Magnum/Shaders/VertexColor.h index 1cbc4d0f1..4cb7cc865 100644 --- a/src/Magnum/Shaders/VertexColor.h +++ b/src/Magnum/Shaders/VertexColor.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class Magnum::Shaders::VertexColor + * @brief Class @ref Magnum::Shaders::VertexColor */ #include "Magnum/Color.h" @@ -42,7 +42,7 @@ namespace Magnum { namespace Shaders { @brief Vertex color shader Draws vertex-colored mesh. -@see VertexColor2D, VertexColor3D +@see @ref VertexColor2D, @ref VertexColor3D */ template class MAGNUM_SHADERS_EXPORT VertexColor: public AbstractShaderProgram { public: diff --git a/src/Magnum/Shapes/ShapeGroup.cpp b/src/Magnum/Shapes/ShapeGroup.cpp index 64648f9db..aebee420d 100644 --- a/src/Magnum/Shapes/ShapeGroup.cpp +++ b/src/Magnum/Shapes/ShapeGroup.cpp @@ -32,9 +32,10 @@ namespace Magnum { namespace Shapes { template void ShapeGroup::setClean() { /* Clean all objects */ if(!this->isEmpty()) { - std::vector*> objects(this->size()); + std::vector>> objects; + objects.reserve(this->size()); for(std::size_t i = 0; i != this->size(); ++i) - objects[i] = &(*this)[i].object(); + objects.push_back((*this)[i].object()); SceneGraph::AbstractObject::setClean(objects); } diff --git a/src/Magnum/Test/AbstractShaderProgramGLTest.cpp b/src/Magnum/Test/AbstractShaderProgramGLTest.cpp index 4d9bdcd5e..22a609535 100644 --- a/src/Magnum/Test/AbstractShaderProgramGLTest.cpp +++ b/src/Magnum/Test/AbstractShaderProgramGLTest.cpp @@ -213,10 +213,6 @@ void AbstractShaderProgramGLTest::create() { CORRADE_VERIFY(multiplierUniform >= 0); CORRADE_VERIFY(colorUniform >= 0); CORRADE_VERIFY(additionsUniform >= 0); - - program.use(); - - MAGNUM_VERIFY_NO_ERROR(); } void AbstractShaderProgramGLTest::createMultipleOutputs() { @@ -250,10 +246,6 @@ void AbstractShaderProgramGLTest::createMultipleOutputs() { MAGNUM_VERIFY_NO_ERROR(); CORRADE_VERIFY(linked); CORRADE_VERIFY(valid); - - program.use(); - - MAGNUM_VERIFY_NO_ERROR(); #elif !defined(MAGNUM_TARGET_GLES2) CORRADE_SKIP("Only explicit location specification supported in ES 3.0."); #else @@ -292,10 +284,6 @@ void AbstractShaderProgramGLTest::createMultipleOutputsIndexed() { MAGNUM_VERIFY_NO_ERROR(); CORRADE_VERIFY(linked); CORRADE_VERIFY(valid); - - program.use(); - - MAGNUM_VERIFY_NO_ERROR(); } #endif diff --git a/src/Magnum/Test/BufferGLTest.cpp b/src/Magnum/Test/BufferGLTest.cpp index c4d0355d5..632201876 100644 --- a/src/Magnum/Test/BufferGLTest.cpp +++ b/src/Magnum/Test/BufferGLTest.cpp @@ -53,9 +53,7 @@ class BufferGLTest: public AbstractOpenGLTester { #ifndef MAGNUM_TARGET_GLES2 void copy(); #endif - #ifndef MAGNUM_TARGET_GLES2 void invalidate(); - #endif }; BufferGLTest::BufferGLTest() { @@ -71,10 +69,7 @@ BufferGLTest::BufferGLTest() { #ifndef MAGNUM_TARGET_GLES2 &BufferGLTest::copy, #endif - #ifndef MAGNUM_TARGET_GLES - &BufferGLTest::invalidate - #endif - }); + &BufferGLTest::invalidate}); } void BufferGLTest::construct() { @@ -352,11 +347,7 @@ void BufferGLTest::copy() { } #endif -#ifndef MAGNUM_TARGET_GLES void BufferGLTest::invalidate() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::invalidate_subdata::string() + std::string(" is not supported")); - Buffer buffer; constexpr char data[] = {2, 7, 5, 13, 25}; buffer.setData(data, BufferUsage::StaticDraw); @@ -369,7 +360,6 @@ void BufferGLTest::invalidate() { buffer.invalidateData(); MAGNUM_VERIFY_NO_ERROR(); } -#endif }} diff --git a/src/Magnum/Test/BufferImageGLTest.cpp b/src/Magnum/Test/BufferImageGLTest.cpp index 06bd5cf9a..19369972d 100644 --- a/src/Magnum/Test/BufferImageGLTest.cpp +++ b/src/Magnum/Test/BufferImageGLTest.cpp @@ -51,7 +51,7 @@ BufferImageTest::BufferImageTest() { } void BufferImageTest::construct() { - const unsigned char data[] = { 'a', 'b', 'c' }; + const unsigned char data[] = { 'a', 0, 0, 0, 'b', 0, 0, 0, 'c', 0, 0, 0 }; BufferImage2D a(ColorFormat::Red, ColorType::UnsignedByte, {1, 3}, data, BufferUsage::StaticDraw); #ifndef MAGNUM_TARGET_GLES @@ -67,7 +67,7 @@ void BufferImageTest::construct() { /** @todo How to verify the contents in ES? */ #ifndef MAGNUM_TARGET_GLES CORRADE_COMPARE_AS(std::vector(imageData.begin(), imageData.end()), - std::vector(data, data + 3), + std::vector(data, data + 12), TestSuite::Compare::Container); #endif } diff --git a/src/Magnum/Test/CMakeLists.txt b/src/Magnum/Test/CMakeLists.txt index 04ccc8a94..76f3eafa3 100644 --- a/src/Magnum/Test/CMakeLists.txt +++ b/src/Magnum/Test/CMakeLists.txt @@ -77,12 +77,15 @@ if(BUILD_GL_TESTS) corrade_add_test(ShaderGLTest ShaderGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) if(NOT MAGNUM_TARGET_GLES2) + corrade_add_test(TextureArrayGLTest TextureArrayGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) corrade_add_test(BufferImageGLTest BufferImageGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) endif() if(NOT MAGNUM_TARGET_GLES) corrade_add_test(BufferTextureGLTest BufferTextureGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) corrade_add_test(CubeMapTextureArrayGLTest CubeMapTextureArrayGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) + corrade_add_test(MultisampleTextureGLTest MultisampleTextureGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) + corrade_add_test(RectangleTextureGLTest RectangleTextureGLTest.cpp LIBRARIES ${GL_TEST_LIBRARIES}) endif() endif() diff --git a/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp b/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp index c04774c45..e3da6a916 100644 --- a/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp +++ b/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp @@ -26,9 +26,10 @@ #include #include "Magnum/BufferImage.h" +#include "Magnum/Color.h" #include "Magnum/ColorFormat.h" -#include "Magnum/Image.h" #include "Magnum/CubeMapTextureArray.h" +#include "Magnum/Image.h" #include "Magnum/TextureFormat.h" #include "Magnum/Test/AbstractOpenGLTester.h" diff --git a/src/Magnum/Test/CubeMapTextureGLTest.cpp b/src/Magnum/Test/CubeMapTextureGLTest.cpp index a7ba9d9e8..6e4d75a77 100644 --- a/src/Magnum/Test/CubeMapTextureGLTest.cpp +++ b/src/Magnum/Test/CubeMapTextureGLTest.cpp @@ -29,9 +29,10 @@ #ifndef MAGNUM_TARGET_GLES2 #include "Magnum/BufferImage.h" #endif +#include "Magnum/Color.h" #include "Magnum/ColorFormat.h" -#include "Magnum/Image.h" #include "Magnum/CubeMapTexture.h" +#include "Magnum/Image.h" #include "Magnum/TextureFormat.h" #include "Magnum/Test/AbstractOpenGLTester.h" diff --git a/src/Magnum/Test/FramebufferGLTest.cpp b/src/Magnum/Test/FramebufferGLTest.cpp index dc6af749e..6e4641c5a 100644 --- a/src/Magnum/Test/FramebufferGLTest.cpp +++ b/src/Magnum/Test/FramebufferGLTest.cpp @@ -24,9 +24,7 @@ */ #include "Magnum/configure.h" -#ifndef MAGNUM_TARGET_GLES2 -#include "Magnum/BufferImage.h" -#endif +#include "Magnum/Color.h" #include "Magnum/ColorFormat.h" #include "Magnum/Context.h" #include "Magnum/Extensions.h" @@ -38,6 +36,16 @@ #include "Magnum/TextureFormat.h" #include "Magnum/Test/AbstractOpenGLTester.h" +#ifndef MAGNUM_TARGET_GLES2 +#include "Magnum/BufferImage.h" +#include "Magnum/TextureArray.h" +#endif + +#ifndef MAGNUM_TARGET_GLES +#include "Magnum/CubeMapTextureArray.h" +#include "Magnum/RectangleTexture.h" +#endif + namespace Magnum { namespace Test { class FramebufferGLTest: public AbstractOpenGLTester { @@ -302,8 +310,8 @@ void FramebufferGLTest::attachTexture1D() { depthStencil.setStorage(1, TextureFormat::Depth24Stencil8, 128); Framebuffer framebuffer({{}, {128, 1}}); - framebuffer.attachTexture1D(Framebuffer::ColorAttachment(0), color, 0) - .attachTexture1D(Framebuffer::BufferAttachment::DepthStencil, depthStencil, 0); + framebuffer.attachTexture(Framebuffer::ColorAttachment(0), color, 0) + .attachTexture(Framebuffer::BufferAttachment::DepthStencil, depthStencil, 0); MAGNUM_VERIFY_NO_ERROR(); CORRADE_COMPARE(framebuffer.checkStatus(FramebufferTarget::ReadDraw), Framebuffer::Status::Complete); @@ -331,7 +339,7 @@ void FramebufferGLTest::attachTexture2D() { MAGNUM_VERIFY_NO_ERROR(); - framebuffer.attachTexture2D(Framebuffer::ColorAttachment(0), color, 0); + framebuffer.attachTexture(Framebuffer::ColorAttachment(0), color, 0); MAGNUM_VERIFY_NO_ERROR(); @@ -346,11 +354,11 @@ void FramebufferGLTest::attachTexture2D() { Texture2D depthStencil; #ifndef MAGNUM_TARGET_GLES2 depthStencil.setStorage(1, TextureFormat::Depth24Stencil8, Vector2i(128)); - framebuffer.attachTexture2D(Framebuffer::BufferAttachment::DepthStencil, depthStencil, 0); + framebuffer.attachTexture(Framebuffer::BufferAttachment::DepthStencil, depthStencil, 0); #else depthStencil.setStorage(1, TextureFormat::DepthStencil, Vector2i(128)); - framebuffer.attachTexture2D(Framebuffer::BufferAttachment::Depth, depthStencil, 0) - .attachTexture2D(Framebuffer::BufferAttachment::Stencil, depthStencil, 0); + framebuffer.attachTexture(Framebuffer::BufferAttachment::Depth, depthStencil, 0) + .attachTexture(Framebuffer::BufferAttachment::Stencil, depthStencil, 0); #endif } @@ -360,7 +368,7 @@ void FramebufferGLTest::attachTexture2D() { Texture2D depth; depth.setStorage(1, TextureFormat::DepthComponent16, Vector2i(128)); - framebuffer.attachTexture2D(Framebuffer::BufferAttachment::Depth, depth, 0); + framebuffer.attachTexture(Framebuffer::BufferAttachment::Depth, depth, 0); } #endif @@ -375,8 +383,6 @@ void FramebufferGLTest::attachTexture3D() { #elif defined(MAGNUM_TARGET_GLES2) if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::OES::texture_3D::string() + std::string(" is not available.")); - #else - CORRADE_SKIP("Not properly implemented yet."); #endif Texture3D color; @@ -387,7 +393,7 @@ void FramebufferGLTest::attachTexture3D() { #endif Framebuffer framebuffer({{}, Vector2i(128)}); - framebuffer.attachTexture3D(Framebuffer::ColorAttachment(0), color, 0, 0); + framebuffer.attachTextureLayer(Framebuffer::ColorAttachment(0), color, 0, 0); MAGNUM_VERIFY_NO_ERROR(); CORRADE_COMPARE(framebuffer.checkStatus(FramebufferTarget::ReadDraw), Framebuffer::Status::Complete); @@ -398,17 +404,16 @@ void FramebufferGLTest::attachTexture1DArray() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not available.")); - Texture2D color(Texture2D::Target::Texture1DArray); + Texture1DArray color; color.setStorage(1, TextureFormat::RGBA8, {128, 8}); - Texture2D depthStencil(Texture2D::Target::Texture1DArray); + Texture1DArray depthStencil; depthStencil.setStorage(1, TextureFormat::Depth24Stencil8, {128, 8}); Framebuffer framebuffer({{}, {128, 1}}); - framebuffer.attachTexture2D(Framebuffer::ColorAttachment(0), color, 0) - .attachTexture2D(Framebuffer::BufferAttachment::DepthStencil, depthStencil, 0); + framebuffer.attachTextureLayer(Framebuffer::ColorAttachment(0), color, 0, 3) + .attachTextureLayer(Framebuffer::BufferAttachment::DepthStencil, depthStencil, 0, 3); - CORRADE_EXPECT_FAIL("Not properly implemented yet."); MAGNUM_VERIFY_NO_ERROR(); CORRADE_COMPARE(framebuffer.checkStatus(FramebufferTarget::ReadDraw), Framebuffer::Status::Complete); } @@ -419,21 +424,20 @@ void FramebufferGLTest::attachTexture2DArray() { #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not available.")); - #else - CORRADE_SKIP("Not properly implemented yet."); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not available.")); #endif - Texture3D color(Texture3D::Target::Texture2DArray); + Texture2DArray color; color.setStorage(1, TextureFormat::RGBA8, {128, 128, 8}); - Texture3D depthStencil(Texture3D::Target::Texture2DArray); + Texture2DArray depthStencil; depthStencil.setStorage(1, TextureFormat::Depth24Stencil8, {128, 128, 8}); Framebuffer framebuffer({{}, Vector2i(128)}); - framebuffer.attachTexture3D(Framebuffer::ColorAttachment(0), color, 0, 0) - .attachTexture3D(Framebuffer::BufferAttachment::DepthStencil, depthStencil, 0, 0); + framebuffer.attachTextureLayer(Framebuffer::ColorAttachment(0), color, 0, 3) + .attachTextureLayer(Framebuffer::BufferAttachment::DepthStencil, depthStencil, 0, 3); - CORRADE_EXPECT_FAIL("Not properly implemented yet."); MAGNUM_VERIFY_NO_ERROR(); CORRADE_COMPARE(framebuffer.checkStatus(FramebufferTarget::ReadDraw), Framebuffer::Status::Complete); } @@ -454,15 +458,15 @@ void FramebufferGLTest::attachRectangleTexture() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not available.")); - Texture2D color(Texture2D::Target::Rectangle); - color.setStorage(1, TextureFormat::RGBA8, Vector2i(128)); + RectangleTexture color; + color.setStorage(TextureFormat::RGBA8, Vector2i(128)); - Texture2D depthStencil(Texture2D::Target::Rectangle); - depthStencil.setStorage(1, TextureFormat::Depth24Stencil8, Vector2i(128)); + RectangleTexture depthStencil; + depthStencil.setStorage(TextureFormat::Depth24Stencil8, Vector2i(128)); Framebuffer framebuffer({{}, Vector2i(128)}); - framebuffer.attachTexture2D(Framebuffer::ColorAttachment(0), color, 0) - .attachTexture2D(Framebuffer::BufferAttachment::DepthStencil, depthStencil, 0); + framebuffer.attachTexture(Framebuffer::ColorAttachment(0), color, 0) + .attachTexture(Framebuffer::BufferAttachment::DepthStencil, depthStencil, 0); MAGNUM_VERIFY_NO_ERROR(); CORRADE_COMPARE(framebuffer.checkStatus(FramebufferTarget::ReadDraw), Framebuffer::Status::Complete); @@ -520,7 +524,23 @@ void FramebufferGLTest::attachCubeMapTexture() { #ifndef MAGNUM_TARGET_GLES void FramebufferGLTest::attachCubeMapTextureArray() { - CORRADE_SKIP("Not implemented yet."); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not available.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_cube_map_array::string() + std::string(" is not available.")); + + CubeMapTextureArray color; + color.setStorage(1, TextureFormat::RGBA8, {128, 128, 18}); + + CubeMapTextureArray depthStencil; + depthStencil.setStorage(1, TextureFormat::Depth24Stencil8, {128, 128, 18}); + + Framebuffer framebuffer({{}, Vector2i(128)}); + framebuffer.attachTextureLayer(Framebuffer::ColorAttachment(0), color, 0, 3) + .attachTextureLayer(Framebuffer::BufferAttachment::DepthStencil, depthStencil, 0, 3); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(framebuffer.checkStatus(FramebufferTarget::ReadDraw), Framebuffer::Status::Complete); } #endif @@ -551,8 +571,8 @@ void FramebufferGLTest::multipleColorOutputs() { depth.setStorage(RenderbufferFormat::DepthComponent16, Vector2i(128)); Framebuffer framebuffer({{}, Vector2i(128)}); - framebuffer.attachTexture2D(Framebuffer::ColorAttachment(0), color1, 0) - .attachTexture2D(Framebuffer::ColorAttachment(1), color2, 0) + framebuffer.attachTexture(Framebuffer::ColorAttachment(0), color1, 0) + .attachTexture(Framebuffer::ColorAttachment(1), color2, 0) .attachRenderbuffer(Framebuffer::BufferAttachment::Depth, depth) .mapForDraw({{0, Framebuffer::ColorAttachment(1)}, {1, Framebuffer::ColorAttachment(0)}}); @@ -863,7 +883,7 @@ void FramebufferGLTest::blit() { CORRADE_COMPARE(image.data()[0], Color4ub()); /* And have given color after */ - Framebuffer::blit(a, b, a.viewport(), FramebufferBlit::ColorBuffer); + Framebuffer::blit(a, b, a.viewport(), FramebufferBlit::Color); b.read({}, Vector2i(1), image); MAGNUM_VERIFY_NO_ERROR(); diff --git a/src/Magnum/Test/MeshGLTest.cpp b/src/Magnum/Test/MeshGLTest.cpp index 80ad00d3f..00ddb979e 100644 --- a/src/Magnum/Test/MeshGLTest.cpp +++ b/src/Magnum/Test/MeshGLTest.cpp @@ -24,6 +24,7 @@ */ #include "Magnum/Buffer.h" +#include "Magnum/Color.h" #include "Magnum/ColorFormat.h" #include "Magnum/Framebuffer.h" #include "Magnum/Image.h" @@ -396,12 +397,11 @@ Checker::Checker(AbstractShaderProgram&& shader, RenderbufferFormat format, Mesh framebuffer.attachRenderbuffer(Framebuffer::ColorAttachment(0), renderbuffer); framebuffer.bind(FramebufferTarget::ReadDraw); - shader.use(); mesh.setVertexCount(2) .setPrimitive(MeshPrimitive::Points); /* Skip first vertex so we test also offsets */ - MeshView(mesh).setVertexRange(1, 1).draw(); + MeshView(mesh).setVertexRange(1, 1).draw(shader); } template T Checker::get(ColorFormat format, ColorType type) { @@ -1151,13 +1151,11 @@ IndexChecker::IndexChecker(Mesh& mesh): framebuffer({{}, Vector2i(1)}) { framebuffer.attachRenderbuffer(Framebuffer::ColorAttachment(0), renderbuffer); framebuffer.bind(FramebufferTarget::ReadDraw); - MultipleShader shader; - shader.use(); mesh.setIndexCount(2) .setPrimitive(MeshPrimitive::Points); /* Skip first vertex so we test also offsets */ - MeshView(mesh).setIndexRange(1, 1).draw(); + MeshView(mesh).setIndexRange(1, 1).draw(MultipleShader{}); } Color4ub IndexChecker::get() { diff --git a/src/Magnum/Test/MultisampleTextureGLTest.cpp b/src/Magnum/Test/MultisampleTextureGLTest.cpp new file mode 100644 index 000000000..6c5e959cc --- /dev/null +++ b/src/Magnum/Test/MultisampleTextureGLTest.cpp @@ -0,0 +1,212 @@ +/* + 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 + +#include "Magnum/MultisampleTexture.h" +#include "Magnum/Test/AbstractOpenGLTester.h" + +namespace Magnum { namespace Test { + +class MultisampleTextureGLTest: public AbstractOpenGLTester { + public: + explicit MultisampleTextureGLTest(); + + void construct2D(); + void construct2DArray(); + + void storage2D(); + void storage2DArray(); + + void image2D(); + void image2DBuffer(); + void image2DArray(); + void image2DArrayBuffer(); + + void subImage2D(); + void subImage2DBuffer(); + void subImage2DArray(); + void subImage2DArrayBuffer(); + + void invalidateImage2D(); + void invalidateImage2DArray(); + + void invalidateSubImage2D(); + void invalidateSubImage2DArray(); +}; + +MultisampleTextureGLTest::MultisampleTextureGLTest() { + addTests({&MultisampleTextureGLTest::construct2D, + &MultisampleTextureGLTest::construct2DArray, + + &MultisampleTextureGLTest::storage2D, + &MultisampleTextureGLTest::storage2DArray, + + &MultisampleTextureGLTest::image2D, + &MultisampleTextureGLTest::image2DBuffer, + &MultisampleTextureGLTest::image2DArray, + &MultisampleTextureGLTest::image2DArrayBuffer, + + &MultisampleTextureGLTest::subImage2D, + &MultisampleTextureGLTest::subImage2DBuffer, + &MultisampleTextureGLTest::subImage2DArray, + &MultisampleTextureGLTest::subImage2DArrayBuffer, + + &MultisampleTextureGLTest::invalidateImage2D, + &MultisampleTextureGLTest::invalidateImage2DArray, + + &MultisampleTextureGLTest::invalidateSubImage2D, + &MultisampleTextureGLTest::invalidateSubImage2DArray}); +} + +void MultisampleTextureGLTest::construct2D() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); + + { + MultisampleTexture2D texture; + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_VERIFY(texture.id() > 0); + } + + MAGNUM_VERIFY_NO_ERROR(); +} + +void MultisampleTextureGLTest::construct2DArray() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); + + { + MultisampleTexture2DArray texture; + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_VERIFY(texture.id() > 0); + } + + MAGNUM_VERIFY_NO_ERROR(); +} + +void MultisampleTextureGLTest::storage2D() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); + + CORRADE_SKIP("Not implemented yet."); +} + +void MultisampleTextureGLTest::storage2DArray() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); + + CORRADE_SKIP("Not implemented yet."); +} + +void MultisampleTextureGLTest::image2D() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); + + CORRADE_SKIP("Not implemented yet."); +} + +void MultisampleTextureGLTest::image2DBuffer() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); + + CORRADE_SKIP("Not implemented yet."); +} + +void MultisampleTextureGLTest::image2DArray() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); + + CORRADE_SKIP("Not implemented yet."); +} + +void MultisampleTextureGLTest::image2DArrayBuffer() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); + + CORRADE_SKIP("Not implemented yet."); +} + +void MultisampleTextureGLTest::subImage2D() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); + + CORRADE_SKIP("Not implemented yet."); +} + +void MultisampleTextureGLTest::subImage2DBuffer() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); + + CORRADE_SKIP("Not implemented yet."); +} + +void MultisampleTextureGLTest::subImage2DArray() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); + + CORRADE_SKIP("Not implemented yet."); +} + +void MultisampleTextureGLTest::subImage2DArrayBuffer() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); + + CORRADE_SKIP("Not implemented yet."); +} + +void MultisampleTextureGLTest::invalidateImage2D() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); + + CORRADE_SKIP("Multisample storage is not implemented yet."); +} + +void MultisampleTextureGLTest::invalidateImage2DArray() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); + + CORRADE_SKIP("Multisample storage is not implemented yet."); +} + +void MultisampleTextureGLTest::invalidateSubImage2D() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); + + CORRADE_SKIP("Multisample storage is not implemented yet."); +} + +void MultisampleTextureGLTest::invalidateSubImage2DArray() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); + + CORRADE_SKIP("Multisample storage is not implemented yet."); +} + +}} + +CORRADE_TEST_MAIN(Magnum::Test::MultisampleTextureGLTest) diff --git a/src/Magnum/Test/PrimitiveQueryGLTest.cpp b/src/Magnum/Test/PrimitiveQueryGLTest.cpp index cd017599b..d2509454e 100644 --- a/src/Magnum/Test/PrimitiveQueryGLTest.cpp +++ b/src/Magnum/Test/PrimitiveQueryGLTest.cpp @@ -97,8 +97,7 @@ void PrimitiveQueryGLTest::query() { q.begin(PrimitiveQuery::Target::PrimitivesGenerated); framebuffer.bind(FramebufferTarget::ReadDraw); - shader.use(); - mesh.draw(); + mesh.draw(shader); q.end(); const bool availableBefore = q.resultAvailable(); diff --git a/src/Magnum/Test/RectangleTextureGLTest.cpp b/src/Magnum/Test/RectangleTextureGLTest.cpp new file mode 100644 index 000000000..e4ff02c4e --- /dev/null +++ b/src/Magnum/Test/RectangleTextureGLTest.cpp @@ -0,0 +1,250 @@ +/* + 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 + +#include "Magnum/configure.h" +#include "Magnum/BufferImage.h" +#include "Magnum/Color.h" +#include "Magnum/ColorFormat.h" +#include "Magnum/Image.h" +#include "Magnum/RectangleTexture.h" +#include "Magnum/TextureFormat.h" +#include "Magnum/Test/AbstractOpenGLTester.h" + +namespace Magnum { namespace Test { + +class TextureGLTest: public AbstractOpenGLTester { + public: + explicit TextureGLTest(); + + void construct(); + void sampling(); + void storage(); + + void image(); + void imageBuffer(); + + void subImage(); + void subImageBuffer(); + + void invalidateImage(); + void invalidateSubImage(); +}; + +TextureGLTest::TextureGLTest() { + addTests({&TextureGLTest::construct, + &TextureGLTest::sampling, + &TextureGLTest::storage, + + &TextureGLTest::image, + &TextureGLTest::imageBuffer, + + &TextureGLTest::subImage, + &TextureGLTest::subImageBuffer, + + &TextureGLTest::invalidateImage, + &TextureGLTest::invalidateSubImage}); +} + +void TextureGLTest::construct() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); + + { + RectangleTexture texture; + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_VERIFY(texture.id() > 0); + } + + MAGNUM_VERIFY_NO_ERROR(); +} + +void TextureGLTest::sampling() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); + + RectangleTexture texture; + texture.setMinificationFilter(Sampler::Filter::Linear) + .setMagnificationFilter(Sampler::Filter::Linear) + .setWrapping(Sampler::Wrapping::ClampToBorder) + .setBorderColor(Color3(0.5f)) + .setMaxAnisotropy(Sampler::maxMaxAnisotropy()); + + MAGNUM_VERIFY_NO_ERROR(); +} + +void TextureGLTest::storage() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); + + RectangleTexture texture; + texture.setStorage(TextureFormat::RGBA8, Vector2i(32)); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(texture.imageSize(), Vector2i(32)); + + MAGNUM_VERIFY_NO_ERROR(); +} + +void TextureGLTest::image() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); + + constexpr UnsignedByte data[] = { 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }; + RectangleTexture texture; + texture.setImage(TextureFormat::RGBA8, + ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(2), data)); + + MAGNUM_VERIFY_NO_ERROR(); + + Image2D image(ColorFormat::RGBA, ColorType::UnsignedByte); + texture.image(image); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector2i(2)); + CORRADE_COMPARE_AS(std::vector(image.data(), image.data()+image.pixelSize()*image.size().product()), + std::vector(data, data + 16), TestSuite::Compare::Container); +} + +void TextureGLTest::imageBuffer() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); + + constexpr UnsignedByte data[] = { 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }; + RectangleTexture texture; + texture.setImage(TextureFormat::RGBA8, + BufferImage2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(2), data, BufferUsage::StaticDraw)); + + MAGNUM_VERIFY_NO_ERROR(); + + BufferImage2D image(ColorFormat::RGBA, ColorType::UnsignedByte); + texture.image(image, BufferUsage::StaticRead); + const auto imageData = image.buffer().data(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector2i(2)); + CORRADE_COMPARE_AS(std::vector(imageData.begin(), imageData.end()), + std::vector(data, data+16), TestSuite::Compare::Container); +} + +void TextureGLTest::subImage() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); + + constexpr UnsignedByte zero[4*4*4] = {}; + constexpr UnsignedByte subData[] = { 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }; + RectangleTexture texture; + texture.setImage(TextureFormat::RGBA8, + ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(4), zero)); + texture.setSubImage(Vector2i(1), + ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(2), subData)); + + MAGNUM_VERIFY_NO_ERROR(); + + Image2D image(ColorFormat::RGBA, ColorType::UnsignedByte); + texture.image(image); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector2i(4)); + CORRADE_COMPARE_AS(std::vector(image.data(), image.data()+image.pixelSize()*image.size().product()), (std::vector{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0, 0, 0, 0, + 0, 0, 0, 0, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }), TestSuite::Compare::Container); +} + +void TextureGLTest::subImageBuffer() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); + + constexpr UnsignedByte zero[4*4*4] = {}; + constexpr UnsignedByte subData[] = { 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }; + RectangleTexture texture; + texture.setImage(TextureFormat::RGBA8, + ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(4), zero)); + texture.setSubImage(Vector2i(1), + BufferImage2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(2), subData, BufferUsage::StaticDraw)); + + MAGNUM_VERIFY_NO_ERROR(); + + BufferImage2D image(ColorFormat::RGBA, ColorType::UnsignedByte); + texture.image(image, BufferUsage::StaticRead); + const auto imageData = image.buffer().data(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector2i(4)); + CORRADE_COMPARE_AS(std::vector(imageData.begin(), imageData.end()), (std::vector{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0, 0, 0, 0, + 0, 0, 0, 0, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }), TestSuite::Compare::Container); +} + +void TextureGLTest::invalidateImage() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); + + RectangleTexture texture; + texture.setStorage(TextureFormat::RGBA8, Vector2i(32)); + texture.invalidateImage(); + + MAGNUM_VERIFY_NO_ERROR(); +} + +void TextureGLTest::invalidateSubImage() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); + + RectangleTexture texture; + texture.setStorage(TextureFormat::RGBA8, Vector2i(32)); + texture.invalidateSubImage(Vector2i(4), Vector2i(16)); + + MAGNUM_VERIFY_NO_ERROR(); +} + +}} + +CORRADE_TEST_MAIN(Magnum::Test::TextureGLTest) diff --git a/src/Magnum/Test/ResourceManagerTest.cpp b/src/Magnum/Test/ResourceManagerTest.cpp index 126e8576d..2971c0226 100644 --- a/src/Magnum/Test/ResourceManagerTest.cpp +++ b/src/Magnum/Test/ResourceManagerTest.cpp @@ -43,6 +43,7 @@ class ResourceManagerTest: public TestSuite::Tester { void residentPolicy(); void referenceCountedPolicy(); void manualPolicy(); + void defaults(); void clear(); void clearWhileReferenced(); void loader(); @@ -68,6 +69,7 @@ ResourceManagerTest::ResourceManagerTest() { &ResourceManagerTest::residentPolicy, &ResourceManagerTest::referenceCountedPolicy, &ResourceManagerTest::manualPolicy, + &ResourceManagerTest::defaults, &ResourceManagerTest::clear, &ResourceManagerTest::clearWhileReferenced, &ResourceManagerTest::loader}); @@ -229,6 +231,12 @@ void ResourceManagerTest::manualPolicy() { CORRADE_COMPARE(Data::count, 1); } +void ResourceManagerTest::defaults() { + ResourceManager rm; + rm.set("data", new Data); + CORRADE_COMPARE(rm.state("data"), ResourceState::Final); +} + void ResourceManagerTest::clear() { ResourceManager rm; diff --git a/src/Magnum/Test/SampleQueryGLTest.cpp b/src/Magnum/Test/SampleQueryGLTest.cpp index cb62b80b5..39b6ffdd6 100644 --- a/src/Magnum/Test/SampleQueryGLTest.cpp +++ b/src/Magnum/Test/SampleQueryGLTest.cpp @@ -127,8 +127,7 @@ void SampleQueryGLTest::querySamplesPassed() { #endif framebuffer.bind(FramebufferTarget::ReadDraw); - shader.use(); - mesh.draw(); + mesh.draw(shader); q.end(); const bool availableBefore = q.resultAvailable(); @@ -167,7 +166,6 @@ void SampleQueryGLTest::conditionalRender() { MyShader shader; framebuffer.bind(FramebufferTarget::ReadDraw); - shader.use(); MAGNUM_VERIFY_NO_ERROR(); @@ -175,13 +173,13 @@ void SampleQueryGLTest::conditionalRender() { /* This should generate some samples */ qYes.begin(SampleQuery::Target::SamplesPassed); - mesh.draw(); + mesh.draw(shader); qYes.end(); /* Thus this should be rendered */ qYes.beginConditionalRender(SampleQuery::ConditionalRenderMode::Wait); q.begin(SampleQuery::Target::SamplesPassed); - mesh.draw(); + mesh.draw(shader); q.end(); qYes.endConditionalRender(); @@ -196,7 +194,7 @@ void SampleQueryGLTest::conditionalRender() { /* Thus this should not be rendered */ qNo.beginConditionalRender(SampleQuery::ConditionalRenderMode::Wait); q.begin(SampleQuery::Target::SamplesPassed); - mesh.draw(); + mesh.draw(shader); q.end(); qNo.endConditionalRender(); diff --git a/src/Magnum/Test/ShaderGLTest.cpp b/src/Magnum/Test/ShaderGLTest.cpp index eb4742935..447253fe2 100644 --- a/src/Magnum/Test/ShaderGLTest.cpp +++ b/src/Magnum/Test/ShaderGLTest.cpp @@ -39,6 +39,7 @@ class ShaderGLTest: public AbstractOpenGLTester { explicit ShaderGLTest(); void construct(); + void constructNoVersion(); void constructCopy(); void constructMove(); @@ -51,6 +52,7 @@ class ShaderGLTest: public AbstractOpenGLTester { ShaderGLTest::ShaderGLTest() { addTests({&ShaderGLTest::construct, + &ShaderGLTest::constructNoVersion, &ShaderGLTest::constructCopy, &ShaderGLTest::constructMove, @@ -82,6 +84,11 @@ void ShaderGLTest::construct() { MAGNUM_VERIFY_NO_ERROR(); } +void ShaderGLTest::constructNoVersion() { + const Shader shader(Version::None, Shader::Type::Fragment); + CORRADE_VERIFY(shader.sources().empty()); +} + void ShaderGLTest::constructCopy() { #ifndef CORRADE_GCC44_COMPATIBILITY CORRADE_VERIFY(!(std::is_constructible::value)); diff --git a/src/Magnum/Test/TextureArrayGLTest.cpp b/src/Magnum/Test/TextureArrayGLTest.cpp new file mode 100644 index 000000000..2c2eccfde --- /dev/null +++ b/src/Magnum/Test/TextureArrayGLTest.cpp @@ -0,0 +1,683 @@ +/* + 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 + +#include "Magnum/configure.h" +#include "Magnum/BufferImage.h" +#include "Magnum/Color.h" +#include "Magnum/ColorFormat.h" +#include "Magnum/Image.h" +#include "Magnum/TextureArray.h" +#include "Magnum/TextureFormat.h" +#include "Magnum/Test/AbstractOpenGLTester.h" + +namespace Magnum { namespace Test { + +class TextureGLTest: public AbstractOpenGLTester { + public: + explicit TextureGLTest(); + + #ifndef MAGNUM_TARGET_GLES + void construct1DArray(); + #endif + void construct2DArray(); + + #ifndef MAGNUM_TARGET_GLES + void sampling1DArray(); + #endif + void sampling2DArray(); + + #ifdef MAGNUM_TARGET_GLES + void samplingBorder2DArray(); + #endif + + #ifndef MAGNUM_TARGET_GLES + void storage1DArray(); + #endif + void storage2DArray(); + + #ifndef MAGNUM_TARGET_GLES + void image1DArray(); + void image1DArrayBuffer(); + #endif + #ifndef MAGNUM_TARGET_GLES2 + void image2DArray(); + void image2DArrayBuffer(); + #endif + + #ifndef MAGNUM_TARGET_GLES + void subImage1DArray(); + void subImage1DArrayBuffer(); + #endif + void subImage2DArray(); + void subImage2DArrayBuffer(); + + #ifndef MAGNUM_TARGET_GLES + void generateMipmap1DArray(); + #endif + void generateMipmap2DArray(); + + #ifndef MAGNUM_TARGET_GLES + void invalidateImage1DArray(); + #endif + void invalidateImage2DArray(); + + #ifndef MAGNUM_TARGET_GLES + void invalidateSubImage1DArray(); + #endif + void invalidateSubImage2DArray(); +}; + +TextureGLTest::TextureGLTest() { + addTests({ + #ifndef MAGNUM_TARGET_GLES + &TextureGLTest::construct1DArray, + #endif + &TextureGLTest::construct2DArray, + + #ifndef MAGNUM_TARGET_GLES + &TextureGLTest::sampling1DArray, + #endif + &TextureGLTest::sampling2DArray, + + #ifdef MAGNUM_TARGET_GLES + &TextureGLTest::samplingBorder2DArray, + #endif + + #ifndef MAGNUM_TARGET_GLES + &TextureGLTest::storage1DArray, + #endif + &TextureGLTest::storage2DArray, + + #ifndef MAGNUM_TARGET_GLES + &TextureGLTest::image1DArray, + &TextureGLTest::image1DArrayBuffer, + #endif + &TextureGLTest::image2DArray, + &TextureGLTest::image2DArrayBuffer, + + #ifndef MAGNUM_TARGET_GLES + &TextureGLTest::subImage1DArray, + &TextureGLTest::subImage1DArrayBuffer, + #endif + &TextureGLTest::subImage2DArray, + &TextureGLTest::subImage2DArrayBuffer, + + #ifndef MAGNUM_TARGET_GLES + &TextureGLTest::generateMipmap1DArray, + #endif + &TextureGLTest::generateMipmap2DArray, + + #ifndef MAGNUM_TARGET_GLES + &TextureGLTest::invalidateImage1DArray, + #endif + &TextureGLTest::invalidateImage2DArray, + + #ifndef MAGNUM_TARGET_GLES + &TextureGLTest::invalidateSubImage1DArray, + #endif + &TextureGLTest::invalidateSubImage2DArray + }); +} + +#ifndef MAGNUM_TARGET_GLES +void TextureGLTest::construct1DArray() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + + { + Texture1DArray texture; + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_VERIFY(texture.id() > 0); + } + + MAGNUM_VERIFY_NO_ERROR(); +} +#endif + +void TextureGLTest::construct2DArray() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + #endif + + { + Texture2DArray texture; + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_VERIFY(texture.id() > 0); + } + + MAGNUM_VERIFY_NO_ERROR(); +} + +#ifndef MAGNUM_TARGET_GLES +void TextureGLTest::sampling1DArray() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + + Texture1DArray texture; + texture.setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) + .setMagnificationFilter(Sampler::Filter::Linear) + .setWrapping(Sampler::Wrapping::ClampToBorder) + .setBorderColor(Color3(0.5f)) + .setMaxAnisotropy(Sampler::maxMaxAnisotropy()); + + MAGNUM_VERIFY_NO_ERROR(); +} +#endif + +void TextureGLTest::sampling2DArray() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + #endif + + Texture2DArray texture; + texture.setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) + .setMagnificationFilter(Sampler::Filter::Linear) + #ifndef MAGNUM_TARGET_GLES + .setWrapping(Sampler::Wrapping::ClampToBorder) + .setBorderColor(Color3(0.5f)) + #else + .setWrapping(Sampler::Wrapping::ClampToEdge) + #endif + .setMaxAnisotropy(Sampler::maxMaxAnisotropy()); + + MAGNUM_VERIFY_NO_ERROR(); +} + +#ifdef MAGNUM_TARGET_GLES +void TextureGLTest::samplingBorder2DArray() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::NV::texture_border_clamp::string() + std::string(" is not supported.")); + + Texture2DArray texture; + texture.setWrapping(Sampler::Wrapping::ClampToBorder) + .setBorderColor(Color3(0.5f)); + + MAGNUM_VERIFY_NO_ERROR(); +} +#endif + +#ifndef MAGNUM_TARGET_GLES +void TextureGLTest::storage1DArray() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + + Texture1DArray texture; + texture.setStorage(5, TextureFormat::RGBA8, Vector2i(32)); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(texture.imageSize(0), Vector2i(32, 32)); + CORRADE_COMPARE(texture.imageSize(1), Vector2i(16, 32)); + CORRADE_COMPARE(texture.imageSize(2), Vector2i( 8, 32)); + CORRADE_COMPARE(texture.imageSize(3), Vector2i( 4, 32)); + CORRADE_COMPARE(texture.imageSize(4), Vector2i( 2, 32)); + CORRADE_COMPARE(texture.imageSize(5), Vector2i( 0, 0)); /* not available */ + + MAGNUM_VERIFY_NO_ERROR(); +} +#endif + +void TextureGLTest::storage2DArray() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + #endif + + Texture2DArray texture; + texture.setStorage(5, TextureFormat::RGBA8, Vector3i(32)); + + MAGNUM_VERIFY_NO_ERROR(); + + /** @todo How to test this on ES? */ + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(texture.imageSize(0), Vector3i(32, 32, 32)); + CORRADE_COMPARE(texture.imageSize(1), Vector3i(16, 16, 32)); + CORRADE_COMPARE(texture.imageSize(2), Vector3i( 8, 8, 32)); + CORRADE_COMPARE(texture.imageSize(3), Vector3i( 4, 4, 32)); + CORRADE_COMPARE(texture.imageSize(4), Vector3i( 2, 2, 32)); + CORRADE_COMPARE(texture.imageSize(5), Vector3i( 0, 0, 0)); /* not available */ + + MAGNUM_VERIFY_NO_ERROR(); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void TextureGLTest::image1DArray() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + + constexpr UnsignedByte data[] = { 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }; + Texture1DArray texture; + texture.setImage(0, TextureFormat::RGBA8, + ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(2), data)); + + MAGNUM_VERIFY_NO_ERROR(); + + Image2D image(ColorFormat::RGBA, ColorType::UnsignedByte); + texture.image(0, image); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector2i(2)); + CORRADE_COMPARE_AS(std::vector(image.data(), image.data()+image.pixelSize()*image.size().product()), + std::vector(data, data + 16), TestSuite::Compare::Container); +} + +void TextureGLTest::image1DArrayBuffer() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + + constexpr UnsignedByte data[] = { 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }; + Texture1DArray texture; + texture.setImage(0, TextureFormat::RGBA8, + BufferImage2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(2), data, BufferUsage::StaticDraw)); + + MAGNUM_VERIFY_NO_ERROR(); + + BufferImage2D image(ColorFormat::RGBA, ColorType::UnsignedByte); + texture.image(0, image, BufferUsage::StaticRead); + const auto imageData = image.buffer().data(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector2i(2)); + CORRADE_COMPARE_AS(std::vector(imageData.begin(), imageData.end()), + std::vector(data, data + 16), TestSuite::Compare::Container); +} +#endif + +void TextureGLTest::image2DArray() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + #endif + + constexpr UnsignedByte data[] = { 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f }; + Texture2DArray texture; + texture.setImage(0, TextureFormat::RGBA8, + ImageReference3D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector3i(2), data)); + + MAGNUM_VERIFY_NO_ERROR(); + + /** @todo How to test this on ES? */ + #ifndef MAGNUM_TARGET_GLES + Image3D image(ColorFormat::RGBA, ColorType::UnsignedByte); + texture.image(0, image); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector3i(2)); + CORRADE_COMPARE_AS(std::vector(image.data(), image.data()+image.pixelSize()*image.size().product()), + std::vector(data, data + 32), TestSuite::Compare::Container); + #endif +} + +void TextureGLTest::image2DArrayBuffer() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + #endif + + constexpr UnsignedByte data[] = { 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f }; + Texture2DArray texture; + texture.setImage(0, TextureFormat::RGBA8, + BufferImage3D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector3i(2), data, BufferUsage::StaticDraw)); + + MAGNUM_VERIFY_NO_ERROR(); + + /** @todo How to test this on ES? */ + #ifndef MAGNUM_TARGET_GLES + BufferImage3D image(ColorFormat::RGBA, ColorType::UnsignedByte); + texture.image(0, image, BufferUsage::StaticRead); + const auto imageData = image.buffer().data(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector3i(2)); + CORRADE_COMPARE_AS(std::vector(imageData.begin(), imageData.end()), + std::vector(data, data + 32), TestSuite::Compare::Container); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void TextureGLTest::subImage1DArray() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + + constexpr UnsignedByte zero[4*4*4] = {}; + constexpr UnsignedByte subData[] = { 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }; + Texture1DArray texture; + texture.setImage(0, TextureFormat::RGBA8, + ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(4), zero)); + texture.setSubImage(0, Vector2i(1), + ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(2), subData)); + + MAGNUM_VERIFY_NO_ERROR(); + + Image2D image(ColorFormat::RGBA, ColorType::UnsignedByte); + texture.image(0, image); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector2i(4)); + CORRADE_COMPARE_AS(std::vector(image.data(), image.data()+image.pixelSize()*image.size().product()), (std::vector{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0, 0, 0, 0, + 0, 0, 0, 0, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }), TestSuite::Compare::Container); +} + +void TextureGLTest::subImage1DArrayBuffer() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + + constexpr UnsignedByte zero[4*4*4] = {}; + constexpr UnsignedByte subData[] = { 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }; + Texture1DArray texture; + texture.setImage(0, TextureFormat::RGBA8, + ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(4), zero)); + texture.setSubImage(0, Vector2i(1), + BufferImage2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(2), subData, BufferUsage::StaticDraw)); + + MAGNUM_VERIFY_NO_ERROR(); + + BufferImage2D image(ColorFormat::RGBA, ColorType::UnsignedByte); + texture.image(0, image, BufferUsage::StaticRead); + const auto imageData = image.buffer().data(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector2i(4)); + CORRADE_COMPARE_AS(std::vector(imageData.begin(), imageData.end()), (std::vector{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0, 0, 0, 0, + 0, 0, 0, 0, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }), TestSuite::Compare::Container); +} +#endif + +void TextureGLTest::subImage2DArray() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + #endif + + constexpr UnsignedByte zero[4*4*4*4] = {}; + constexpr UnsignedByte subData[] = { 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f }; + Texture2DArray texture; + texture.setImage(0, TextureFormat::RGBA8, + ImageReference3D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector3i(4), zero)); + texture.setSubImage(0, Vector3i(1), + ImageReference3D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector3i(2), subData)); + + MAGNUM_VERIFY_NO_ERROR(); + + /** @todo How to test this on ES? */ + #ifndef MAGNUM_TARGET_GLES + Image3D image(ColorFormat::RGBA, ColorType::UnsignedByte); + texture.image(0, image); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector3i(4)); + CORRADE_COMPARE_AS(std::vector(image.data(), image.data()+image.pixelSize()*image.size().product()), (std::vector{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0, 0, 0, 0, + 0, 0, 0, 0, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0, 0, 0, 0, + 0, 0, 0, 0, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }), TestSuite::Compare::Container); + #endif +} + +void TextureGLTest::subImage2DArrayBuffer() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + #endif + + constexpr UnsignedByte zero[4*4*4*4] = {}; + constexpr UnsignedByte subData[] = { 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f }; + Texture2DArray texture; + texture.setImage(0, TextureFormat::RGBA8, + ImageReference3D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector3i(4), zero)); + texture.setSubImage(0, Vector3i(1), + BufferImage3D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector3i(2), subData, BufferUsage::StaticDraw)); + + MAGNUM_VERIFY_NO_ERROR(); + + /** @todo How to test this on ES? */ + #ifndef MAGNUM_TARGET_GLES + BufferImage3D image(ColorFormat::RGBA, ColorType::UnsignedByte); + texture.image(0, image, BufferUsage::StaticRead); + const auto imageData = image.buffer().data(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(image.size(), Vector3i(4)); + CORRADE_COMPARE_AS(std::vector(imageData.begin(), imageData.end()), (std::vector{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0, 0, 0, 0, + 0, 0, 0, 0, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0, 0, 0, 0, + 0, 0, 0, 0, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }), TestSuite::Compare::Container); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void TextureGLTest::generateMipmap1DArray() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + + Texture1DArray texture; + texture.setImage(0, TextureFormat::RGBA8, + ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(32))); + + CORRADE_COMPARE(texture.imageSize(0), Vector2i(32)); + CORRADE_COMPARE(texture.imageSize(1), Vector2i( 0)); + + texture.generateMipmap(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(texture.imageSize(0), Vector2i(32, 32)); + CORRADE_COMPARE(texture.imageSize(1), Vector2i(16, 32)); + CORRADE_COMPARE(texture.imageSize(2), Vector2i( 8, 32)); + CORRADE_COMPARE(texture.imageSize(3), Vector2i( 4, 32)); + CORRADE_COMPARE(texture.imageSize(4), Vector2i( 2, 32)); + CORRADE_COMPARE(texture.imageSize(5), Vector2i( 1, 32)); + + MAGNUM_VERIFY_NO_ERROR(); +} +#endif + +void TextureGLTest::generateMipmap2DArray() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + #endif + + Texture2DArray texture; + texture.setImage(0, TextureFormat::RGBA8, + ImageReference3D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector3i(32))); + + /** @todo How to test this on ES? */ + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(texture.imageSize(0), Vector3i(32)); + CORRADE_COMPARE(texture.imageSize(1), Vector3i( 0)); + #endif + + texture.generateMipmap(); + + MAGNUM_VERIFY_NO_ERROR(); + + #ifndef MAGNUM_TARGET_GLES + CORRADE_COMPARE(texture.imageSize(0), Vector3i(32, 32, 32)); + CORRADE_COMPARE(texture.imageSize(1), Vector3i(16, 16, 32)); + CORRADE_COMPARE(texture.imageSize(2), Vector3i( 8, 8, 32)); + CORRADE_COMPARE(texture.imageSize(3), Vector3i( 4, 4, 32)); + CORRADE_COMPARE(texture.imageSize(4), Vector3i( 2, 2, 32)); + CORRADE_COMPARE(texture.imageSize(5), Vector3i( 1, 1, 32)); + + MAGNUM_VERIFY_NO_ERROR(); + #endif +} + +#ifndef MAGNUM_TARGET_GLES +void TextureGLTest::invalidateImage1DArray() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + + Texture1DArray texture; + texture.setStorage(2, TextureFormat::RGBA8, Vector2i(32)); + texture.invalidateImage(1); + + MAGNUM_VERIFY_NO_ERROR(); +} +#endif + +void TextureGLTest::invalidateImage2DArray() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + #endif + + Texture2DArray texture; + texture.setStorage(2, TextureFormat::RGBA8, Vector3i(32)); + texture.invalidateImage(1); + + MAGNUM_VERIFY_NO_ERROR(); +} + +#ifndef MAGNUM_TARGET_GLES +void TextureGLTest::invalidateSubImage1DArray() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + + Texture1DArray texture; + texture.setStorage(2, TextureFormat::RGBA8, Vector2i(32)); + texture.invalidateSubImage(1, Vector2i(2), Vector2i(8)); + + MAGNUM_VERIFY_NO_ERROR(); +} +#endif + +void TextureGLTest::invalidateSubImage2DArray() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); + #endif + + Texture2DArray texture; + texture.setStorage(2, TextureFormat::RGBA8, Vector3i(32)); + texture.invalidateSubImage(1, Vector3i(2), Vector3i(8)); + + MAGNUM_VERIFY_NO_ERROR(); +} + +}} + +CORRADE_TEST_MAIN(Magnum::Test::TextureGLTest) diff --git a/src/Magnum/Test/TextureGLTest.cpp b/src/Magnum/Test/TextureGLTest.cpp index 1da5b1264..79a9368ae 100644 --- a/src/Magnum/Test/TextureGLTest.cpp +++ b/src/Magnum/Test/TextureGLTest.cpp @@ -29,6 +29,7 @@ #ifndef MAGNUM_TARGET_GLES2 #include "Magnum/BufferImage.h" #endif +#include "Magnum/Color.h" #include "Magnum/ColorFormat.h" #include "Magnum/Image.h" #include "Magnum/Texture.h" @@ -46,39 +47,16 @@ class TextureGLTest: public AbstractOpenGLTester { #endif void construct2D(); void construct3D(); - #ifndef MAGNUM_TARGET_GLES - void construct1DArray(); - #endif - #ifndef MAGNUM_TARGET_GLES2 - void construct2DArray(); - #endif - #ifndef MAGNUM_TARGET_GLES - void construct2DMultisample(); - void construct2DMultisampleArray(); - void constructRectangle(); - #endif #ifndef MAGNUM_TARGET_GLES void sampling1D(); #endif void sampling2D(); void sampling3D(); - #ifndef MAGNUM_TARGET_GLES - void sampling1DArray(); - #endif - #ifndef MAGNUM_TARGET_GLES2 - void sampling2DArray(); - #endif - #ifndef MAGNUM_TARGET_GLES - void samplingRectangle(); - #endif #ifdef MAGNUM_TARGET_GLES void samplingBorder2D(); void samplingBorder3D(); - #ifndef MAGNUM_TARGET_GLES2 - void samplingBorder2DArray(); - #endif #endif #ifndef MAGNUM_TARGET_GLES @@ -86,17 +64,6 @@ class TextureGLTest: public AbstractOpenGLTester { #endif void storage2D(); void storage3D(); - #ifndef MAGNUM_TARGET_GLES - void storage1DArray(); - #endif - #ifndef MAGNUM_TARGET_GLES2 - void storage2DArray(); - #endif - #ifndef MAGNUM_TARGET_GLES - void storage2DMultisample(); - void storage2DMultisampleArray(); - void storageRectangle(); - #endif #ifndef MAGNUM_TARGET_GLES void image1D(); @@ -112,22 +79,6 @@ class TextureGLTest: public AbstractOpenGLTester { #ifndef MAGNUM_TARGET_GLES2 void image3DBuffer(); #endif - #ifndef MAGNUM_TARGET_GLES - void image1DArray(); - void image1DArrayBuffer(); - #endif - #ifndef MAGNUM_TARGET_GLES2 - void image2DArray(); - void image2DArrayBuffer(); - #endif - #ifndef MAGNUM_TARGET_GLES - void image2DMultisample(); - void image2DMultisampleBuffer(); - void image2DMultisampleArray(); - void image2DMultisampleArrayBuffer(); - void imageRectangle(); - void imageRectangleBuffer(); - #endif #ifndef MAGNUM_TARGET_GLES void subImage1D(); @@ -141,68 +92,24 @@ class TextureGLTest: public AbstractOpenGLTester { #ifndef MAGNUM_TARGET_GLES2 void subImage3DBuffer(); #endif - #ifndef MAGNUM_TARGET_GLES - void subImage1DArray(); - void subImage1DArrayBuffer(); - #endif - #ifndef MAGNUM_TARGET_GLES2 - void subImage2DArray(); - void subImage2DArrayBuffer(); - #endif - #ifndef MAGNUM_TARGET_GLES - void subImage2DMultisample(); - void subImage2DMultisampleBuffer(); - void subImage2DMultisampleArray(); - void subImage2DMultisampleArrayBuffer(); - void subImageRectangle(); - void subImageRectangleBuffer(); - #endif #ifndef MAGNUM_TARGET_GLES void generateMipmap1D(); #endif void generateMipmap2D(); void generateMipmap3D(); - #ifndef MAGNUM_TARGET_GLES - void generateMipmap1DArray(); - #endif - #ifndef MAGNUM_TARGET_GLES2 - void generateMipmap2DArray(); - #endif #ifndef MAGNUM_TARGET_GLES void invalidateImage1D(); #endif void invalidateImage2D(); void invalidateImage3D(); - #ifndef MAGNUM_TARGET_GLES - void invalidateImage1DArray(); - #endif - #ifndef MAGNUM_TARGET_GLES2 - void invalidateImage2DArray(); - #endif - #ifndef MAGNUM_TARGET_GLES - void invalidateImage2DMultisample(); - void invalidateImage2DMultisampleArray(); - void invalidateImageRectangle(); - #endif #ifndef MAGNUM_TARGET_GLES void invalidateSubImage1D(); #endif void invalidateSubImage2D(); void invalidateSubImage3D(); - #ifndef MAGNUM_TARGET_GLES - void invalidateSubImage1DArray(); - #endif - #ifndef MAGNUM_TARGET_GLES2 - void invalidateSubImage2DArray(); - #endif - #ifndef MAGNUM_TARGET_GLES - void invalidateSubImage2DMultisample(); - void invalidateSubImage2DMultisampleArray(); - void invalidateSubImageRectangle(); - #endif }; TextureGLTest::TextureGLTest() { @@ -212,39 +119,16 @@ TextureGLTest::TextureGLTest() { #endif &TextureGLTest::construct2D, &TextureGLTest::construct3D, - #ifndef MAGNUM_TARGET_GLES - &TextureGLTest::construct1DArray, - #endif - #ifndef MAGNUM_TARGET_GLES2 - &TextureGLTest::construct2DArray, - #endif - #ifndef MAGNUM_TARGET_GLES - &TextureGLTest::construct2DMultisample, - &TextureGLTest::construct2DMultisampleArray, - &TextureGLTest::constructRectangle, - #endif #ifndef MAGNUM_TARGET_GLES &TextureGLTest::sampling1D, #endif &TextureGLTest::sampling2D, &TextureGLTest::sampling3D, - #ifndef MAGNUM_TARGET_GLES - &TextureGLTest::sampling1DArray, - #endif - #ifndef MAGNUM_TARGET_GLES2 - &TextureGLTest::sampling2DArray, - #endif - #ifndef MAGNUM_TARGET_GLES - &TextureGLTest::samplingRectangle, - #endif #ifdef MAGNUM_TARGET_GLES &TextureGLTest::samplingBorder2D, &TextureGLTest::samplingBorder3D, - #ifndef MAGNUM_TARGET_GLES2 - &TextureGLTest::samplingBorder2DArray, - #endif #endif #ifndef MAGNUM_TARGET_GLES @@ -252,17 +136,6 @@ TextureGLTest::TextureGLTest() { #endif &TextureGLTest::storage2D, &TextureGLTest::storage3D, - #ifndef MAGNUM_TARGET_GLES - &TextureGLTest::storage1DArray, - #endif - #ifndef MAGNUM_TARGET_GLES2 - &TextureGLTest::storage2DArray, - #endif - #ifndef MAGNUM_TARGET_GLES - &TextureGLTest::storage2DMultisample, - &TextureGLTest::storage2DMultisampleArray, - &TextureGLTest::storageRectangle, - #endif #ifndef MAGNUM_TARGET_GLES &TextureGLTest::image1D, @@ -276,22 +149,6 @@ TextureGLTest::TextureGLTest() { #ifndef MAGNUM_TARGET_GLES2 &TextureGLTest::image3DBuffer, #endif - #ifndef MAGNUM_TARGET_GLES - &TextureGLTest::image1DArray, - &TextureGLTest::image1DArrayBuffer, - #endif - #ifndef MAGNUM_TARGET_GLES2 - &TextureGLTest::image2DArray, - &TextureGLTest::image2DArrayBuffer, - #endif - #ifndef MAGNUM_TARGET_GLES - &TextureGLTest::image2DMultisample, - &TextureGLTest::image2DMultisampleBuffer, - &TextureGLTest::image2DMultisampleArray, - &TextureGLTest::image2DMultisampleArrayBuffer, - &TextureGLTest::imageRectangle, - &TextureGLTest::imageRectangleBuffer, - #endif #ifndef MAGNUM_TARGET_GLES &TextureGLTest::subImage1D, @@ -305,68 +162,24 @@ TextureGLTest::TextureGLTest() { #ifndef MAGNUM_TARGET_GLES2 &TextureGLTest::subImage3DBuffer, #endif - #ifndef MAGNUM_TARGET_GLES - &TextureGLTest::subImage1DArray, - &TextureGLTest::subImage1DArrayBuffer, - #endif - #ifndef MAGNUM_TARGET_GLES2 - &TextureGLTest::subImage2DArray, - &TextureGLTest::subImage2DArrayBuffer, - #endif - #ifndef MAGNUM_TARGET_GLES - &TextureGLTest::subImage2DMultisample, - &TextureGLTest::subImage2DMultisampleBuffer, - &TextureGLTest::subImage2DMultisampleArray, - &TextureGLTest::subImage2DMultisampleArrayBuffer, - &TextureGLTest::subImageRectangle, - &TextureGLTest::subImageRectangleBuffer, - #endif #ifndef MAGNUM_TARGET_GLES &TextureGLTest::generateMipmap1D, #endif &TextureGLTest::generateMipmap2D, &TextureGLTest::generateMipmap3D, - #ifndef MAGNUM_TARGET_GLES - &TextureGLTest::generateMipmap1DArray, - #endif - #ifndef MAGNUM_TARGET_GLES2 - &TextureGLTest::generateMipmap2DArray, - #endif #ifndef MAGNUM_TARGET_GLES &TextureGLTest::invalidateImage1D, #endif &TextureGLTest::invalidateImage2D, &TextureGLTest::invalidateImage3D, - #ifndef MAGNUM_TARGET_GLES - &TextureGLTest::invalidateImage1DArray, - #endif - #ifndef MAGNUM_TARGET_GLES2 - &TextureGLTest::invalidateImage2DArray, - #endif - #ifndef MAGNUM_TARGET_GLES - &TextureGLTest::invalidateImage2DMultisample, - &TextureGLTest::invalidateImage2DMultisampleArray, - &TextureGLTest::invalidateImageRectangle, - #endif #ifndef MAGNUM_TARGET_GLES &TextureGLTest::invalidateSubImage1D, #endif &TextureGLTest::invalidateSubImage2D, &TextureGLTest::invalidateSubImage3D, - #ifndef MAGNUM_TARGET_GLES - &TextureGLTest::invalidateSubImage1DArray, - #endif - #ifndef MAGNUM_TARGET_GLES2 - &TextureGLTest::invalidateSubImage2DArray, - #endif - #ifndef MAGNUM_TARGET_GLES - &TextureGLTest::invalidateSubImage2DMultisample, - &TextureGLTest::invalidateSubImage2DMultisampleArray, - &TextureGLTest::invalidateSubImageRectangle - #endif }); } @@ -410,84 +223,6 @@ void TextureGLTest::construct3D() { MAGNUM_VERIFY_NO_ERROR(); } -#ifndef MAGNUM_TARGET_GLES -void TextureGLTest::construct1DArray() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - - { - Texture2D texture(Texture2D::Target::Texture1DArray); - - MAGNUM_VERIFY_NO_ERROR(); - CORRADE_VERIFY(texture.id() > 0); - } - - MAGNUM_VERIFY_NO_ERROR(); -} -#endif - -#ifndef MAGNUM_TARGET_GLES2 -void TextureGLTest::construct2DArray() { - #ifndef MAGNUM_TARGET_GLES - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - #endif - - { - Texture3D texture(Texture3D::Target::Texture2DArray); - - MAGNUM_VERIFY_NO_ERROR(); - CORRADE_VERIFY(texture.id() > 0); - } - - MAGNUM_VERIFY_NO_ERROR(); -} -#endif - -#ifndef MAGNUM_TARGET_GLES -void TextureGLTest::construct2DMultisample() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - - { - Texture2D texture(Texture2D::Target::Texture2DMultisample); - - MAGNUM_VERIFY_NO_ERROR(); - CORRADE_VERIFY(texture.id() > 0); - } - - MAGNUM_VERIFY_NO_ERROR(); -} - -void TextureGLTest::construct2DMultisampleArray() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - - { - Texture3D texture(Texture3D::Target::Texture2DMultisampleArray); - - MAGNUM_VERIFY_NO_ERROR(); - CORRADE_VERIFY(texture.id() > 0); - } - - MAGNUM_VERIFY_NO_ERROR(); -} - -void TextureGLTest::constructRectangle() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); - - { - Texture2D texture(Texture2D::Target::Rectangle); - - MAGNUM_VERIFY_NO_ERROR(); - CORRADE_VERIFY(texture.id() > 0); - } - - MAGNUM_VERIFY_NO_ERROR(); -} -#endif - #ifndef MAGNUM_TARGET_GLES void TextureGLTest::sampling1D() { Texture1D texture; @@ -567,73 +302,6 @@ void TextureGLTest::samplingBorder3D() { } #endif -#ifndef MAGNUM_TARGET_GLES -void TextureGLTest::sampling1DArray() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - - Texture2D texture(Texture2D::Target::Texture1DArray); - texture.setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) - .setMagnificationFilter(Sampler::Filter::Linear) - .setWrapping(Sampler::Wrapping::ClampToBorder) - .setBorderColor(Color3(0.5f)) - .setMaxAnisotropy(Sampler::maxMaxAnisotropy()); - - MAGNUM_VERIFY_NO_ERROR(); -} -#endif - -#ifndef MAGNUM_TARGET_GLES2 -void TextureGLTest::sampling2DArray() { - #ifndef MAGNUM_TARGET_GLES - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - #endif - - Texture3D texture(Texture3D::Target::Texture2DArray); - texture.setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) - .setMagnificationFilter(Sampler::Filter::Linear) - #ifndef MAGNUM_TARGET_GLES - .setWrapping(Sampler::Wrapping::ClampToBorder) - .setBorderColor(Color3(0.5f)) - #else - .setWrapping(Sampler::Wrapping::ClampToEdge) - #endif - .setMaxAnisotropy(Sampler::maxMaxAnisotropy()); - - MAGNUM_VERIFY_NO_ERROR(); -} - -#ifdef MAGNUM_TARGET_GLES -void TextureGLTest::samplingBorder2DArray() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::NV::texture_border_clamp::string() + std::string(" is not supported.")); - - Texture3D texture(Texture3D::Target::Texture2DArray); - texture.setWrapping(Sampler::Wrapping::ClampToBorder) - .setBorderColor(Color3(0.5f)); - - MAGNUM_VERIFY_NO_ERROR(); -} -#endif -#endif - -#ifndef MAGNUM_TARGET_GLES -void TextureGLTest::samplingRectangle() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); - - Texture2D texture(Texture2D::Target::Rectangle); - texture.setMinificationFilter(Sampler::Filter::Linear) - .setMagnificationFilter(Sampler::Filter::Linear) - .setWrapping(Sampler::Wrapping::ClampToBorder) - .setBorderColor(Color3(0.5f)) - .setMaxAnisotropy(Sampler::maxMaxAnisotropy()); - - MAGNUM_VERIFY_NO_ERROR(); -} -#endif - #ifndef MAGNUM_TARGET_GLES void TextureGLTest::storage1D() { Texture1D texture; @@ -695,87 +363,6 @@ void TextureGLTest::storage3D() { #endif } -#ifndef MAGNUM_TARGET_GLES -void TextureGLTest::storage1DArray() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - - Texture2D texture(Texture2D::Target::Texture1DArray); - texture.setStorage(5, TextureFormat::RGBA8, Vector2i(32)); - - MAGNUM_VERIFY_NO_ERROR(); - - /** @todo How to test this on ES? */ - #ifndef MAGNUM_TARGET_GLES - CORRADE_COMPARE(texture.imageSize(0), Vector2i(32, 32)); - CORRADE_COMPARE(texture.imageSize(1), Vector2i(16, 32)); - CORRADE_COMPARE(texture.imageSize(2), Vector2i( 8, 32)); - CORRADE_COMPARE(texture.imageSize(3), Vector2i( 4, 32)); - CORRADE_COMPARE(texture.imageSize(4), Vector2i( 2, 32)); - CORRADE_COMPARE(texture.imageSize(5), Vector2i( 0, 0)); /* not available */ - - MAGNUM_VERIFY_NO_ERROR(); - #endif -} -#endif - -#ifndef MAGNUM_TARGET_GLES2 -void TextureGLTest::storage2DArray() { - #ifndef MAGNUM_TARGET_GLES - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - #endif - - Texture3D texture(Texture3D::Target::Texture2DArray); - texture.setStorage(5, TextureFormat::RGBA8, Vector3i(32)); - - MAGNUM_VERIFY_NO_ERROR(); - - /** @todo How to test this on ES? */ - #ifndef MAGNUM_TARGET_GLES - CORRADE_COMPARE(texture.imageSize(0), Vector3i(32, 32, 32)); - CORRADE_COMPARE(texture.imageSize(1), Vector3i(16, 16, 32)); - CORRADE_COMPARE(texture.imageSize(2), Vector3i( 8, 8, 32)); - CORRADE_COMPARE(texture.imageSize(3), Vector3i( 4, 4, 32)); - CORRADE_COMPARE(texture.imageSize(4), Vector3i( 2, 2, 32)); - CORRADE_COMPARE(texture.imageSize(5), Vector3i( 0, 0, 0)); /* not available */ - - MAGNUM_VERIFY_NO_ERROR(); - #endif -} -#endif - -#ifndef MAGNUM_TARGET_GLES -void TextureGLTest::storage2DMultisample() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - - CORRADE_SKIP("Not implemented yet."); -} - -void TextureGLTest::storage2DMultisampleArray() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - - CORRADE_SKIP("Not implemented yet."); -} - -void TextureGLTest::storageRectangle() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); - - Texture2D texture(Texture2D::Target::Rectangle); - texture.setStorage(1, TextureFormat::RGBA8, Vector2i(32)); - - MAGNUM_VERIFY_NO_ERROR(); - - CORRADE_COMPARE(texture.imageSize(0), Vector2i(32)); - CORRADE_COMPARE(texture.imageSize(1), Vector2i( 0)); /* not available */ - - MAGNUM_VERIFY_NO_ERROR(); -} -#endif - #ifndef MAGNUM_TARGET_GLES void TextureGLTest::image1D() { constexpr UnsignedByte data[] = { 0x00, 0x01, 0x02, 0x03, @@ -932,205 +519,6 @@ void TextureGLTest::image3DBuffer() { } #endif -#ifndef MAGNUM_TARGET_GLES -void TextureGLTest::image1DArray() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - - constexpr UnsignedByte data[] = { 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f }; - Texture2D texture(Texture2D::Target::Texture1DArray); - texture.setImage(0, TextureFormat::RGBA8, - ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(2), data)); - - MAGNUM_VERIFY_NO_ERROR(); - - Image2D image(ColorFormat::RGBA, ColorType::UnsignedByte); - texture.image(0, image); - - MAGNUM_VERIFY_NO_ERROR(); - - CORRADE_COMPARE(image.size(), Vector2i(2)); - CORRADE_COMPARE_AS(std::vector(image.data(), image.data()+image.pixelSize()*image.size().product()), - std::vector(data, data + 16), TestSuite::Compare::Container); -} - -void TextureGLTest::image1DArrayBuffer() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - - constexpr UnsignedByte data[] = { 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f }; - Texture2D texture(Texture2D::Target::Texture1DArray); - texture.setImage(0, TextureFormat::RGBA8, - BufferImage2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(2), data, BufferUsage::StaticDraw)); - - MAGNUM_VERIFY_NO_ERROR(); - - BufferImage2D image(ColorFormat::RGBA, ColorType::UnsignedByte); - texture.image(0, image, BufferUsage::StaticRead); - const auto imageData = image.buffer().data(); - - MAGNUM_VERIFY_NO_ERROR(); - - CORRADE_COMPARE(image.size(), Vector2i(2)); - CORRADE_COMPARE_AS(std::vector(imageData.begin(), imageData.end()), - std::vector(data, data + 16), TestSuite::Compare::Container); -} -#endif - -#ifndef MAGNUM_TARGET_GLES2 -void TextureGLTest::image2DArray() { - #ifndef MAGNUM_TARGET_GLES - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - #endif - - constexpr UnsignedByte data[] = { 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1e, 0x1f }; - Texture3D texture(Texture3D::Target::Texture2DArray); - texture.setImage(0, TextureFormat::RGBA8, - ImageReference3D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector3i(2), data)); - - MAGNUM_VERIFY_NO_ERROR(); - - /** @todo How to test this on ES? */ - #ifndef MAGNUM_TARGET_GLES - Image3D image(ColorFormat::RGBA, ColorType::UnsignedByte); - texture.image(0, image); - - MAGNUM_VERIFY_NO_ERROR(); - - CORRADE_COMPARE(image.size(), Vector3i(2)); - CORRADE_COMPARE_AS(std::vector(image.data(), image.data()+image.pixelSize()*image.size().product()), - std::vector(data, data + 32), TestSuite::Compare::Container); - #endif -} - -void TextureGLTest::image2DArrayBuffer() { - #ifndef MAGNUM_TARGET_GLES - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - #endif - - constexpr UnsignedByte data[] = { 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1e, 0x1f }; - Texture3D texture(Texture3D::Target::Texture2DArray); - texture.setImage(0, TextureFormat::RGBA8, - BufferImage3D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector3i(2), data, BufferUsage::StaticDraw)); - - MAGNUM_VERIFY_NO_ERROR(); - - /** @todo How to test this on ES? */ - #ifndef MAGNUM_TARGET_GLES - BufferImage3D image(ColorFormat::RGBA, ColorType::UnsignedByte); - texture.image(0, image, BufferUsage::StaticRead); - const auto imageData = image.buffer().data(); - - MAGNUM_VERIFY_NO_ERROR(); - - CORRADE_COMPARE(image.size(), Vector3i(2)); - CORRADE_COMPARE_AS(std::vector(imageData.begin(), imageData.end()), - std::vector(data, data + 32), TestSuite::Compare::Container); - #endif -} -#endif - -#ifndef MAGNUM_TARGET_GLES -void TextureGLTest::image2DMultisample() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - - CORRADE_SKIP("Not implemented yet."); -} - -void TextureGLTest::image2DMultisampleBuffer() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - - CORRADE_SKIP("Not implemented yet."); -} - -void TextureGLTest::image2DMultisampleArray() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - - CORRADE_SKIP("Not implemented yet."); -} - -void TextureGLTest::image2DMultisampleArrayBuffer() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - - CORRADE_SKIP("Not implemented yet."); -} - -void TextureGLTest::imageRectangle() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); - - constexpr UnsignedByte data[] = { 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f }; - Texture2D texture(Texture2D::Target::Rectangle); - texture.setImage(0, TextureFormat::RGBA8, - ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(2), data)); - - MAGNUM_VERIFY_NO_ERROR(); - - Image2D image(ColorFormat::RGBA, ColorType::UnsignedByte); - texture.image(0, image); - - MAGNUM_VERIFY_NO_ERROR(); - - CORRADE_COMPARE(image.size(), Vector2i(2)); - CORRADE_COMPARE_AS(std::vector(image.data(), image.data()+image.pixelSize()*image.size().product()), - std::vector(data, data + 16), TestSuite::Compare::Container); -} - -void TextureGLTest::imageRectangleBuffer() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); - - constexpr UnsignedByte data[] = { 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f }; - Texture2D texture; - texture.setImage(0, TextureFormat::RGBA8, - BufferImage2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(2), data, BufferUsage::StaticDraw)); - - MAGNUM_VERIFY_NO_ERROR(); - - BufferImage2D image(ColorFormat::RGBA, ColorType::UnsignedByte); - texture.image(0, image, BufferUsage::StaticRead); - const auto imageData = image.buffer().data(); - - MAGNUM_VERIFY_NO_ERROR(); - - CORRADE_COMPARE(image.size(), Vector2i(2)); - CORRADE_COMPARE_AS(std::vector(imageData.begin(), imageData.end()), - std::vector(data, data+16), TestSuite::Compare::Container); -} -#endif - #ifndef MAGNUM_TARGET_GLES void TextureGLTest::subImage1D() { constexpr UnsignedByte zero[4*4] = {}; @@ -1353,277 +741,6 @@ void TextureGLTest::subImage3DBuffer() { } #endif -#ifndef MAGNUM_TARGET_GLES -void TextureGLTest::subImage1DArray() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - - constexpr UnsignedByte zero[4*4*4] = {}; - constexpr UnsignedByte subData[] = { 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f }; - Texture2D texture(Texture2D::Target::Texture1DArray); - texture.setImage(0, TextureFormat::RGBA8, - ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(4), zero)); - texture.setSubImage(0, Vector2i(1), - ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(2), subData)); - - MAGNUM_VERIFY_NO_ERROR(); - - Image2D image(ColorFormat::RGBA, ColorType::UnsignedByte); - texture.image(0, image); - - MAGNUM_VERIFY_NO_ERROR(); - - CORRADE_COMPARE(image.size(), Vector2i(4)); - CORRADE_COMPARE_AS(std::vector(image.data(), image.data()+image.pixelSize()*image.size().product()), (std::vector{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0, 0, 0, 0, - 0, 0, 0, 0, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }), TestSuite::Compare::Container); -} - -void TextureGLTest::subImage1DArrayBuffer() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - - constexpr UnsignedByte zero[4*4*4] = {}; - constexpr UnsignedByte subData[] = { 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f }; - Texture2D texture(Texture2D::Target::Texture1DArray); - texture.setImage(0, TextureFormat::RGBA8, - ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(4), zero)); - texture.setSubImage(0, Vector2i(1), - BufferImage2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(2), subData, BufferUsage::StaticDraw)); - - MAGNUM_VERIFY_NO_ERROR(); - - BufferImage2D image(ColorFormat::RGBA, ColorType::UnsignedByte); - texture.image(0, image, BufferUsage::StaticRead); - const auto imageData = image.buffer().data(); - - MAGNUM_VERIFY_NO_ERROR(); - - CORRADE_COMPARE(image.size(), Vector2i(4)); - CORRADE_COMPARE_AS(std::vector(imageData.begin(), imageData.end()), (std::vector{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0, 0, 0, 0, - 0, 0, 0, 0, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }), TestSuite::Compare::Container); -} -#endif - -#ifndef MAGNUM_TARGET_GLES2 -void TextureGLTest::subImage2DArray() { - #ifndef MAGNUM_TARGET_GLES - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - #endif - - constexpr UnsignedByte zero[4*4*4*4] = {}; - constexpr UnsignedByte subData[] = { 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1e, 0x1f }; - Texture3D texture(Texture3D::Target::Texture2DArray); - texture.setImage(0, TextureFormat::RGBA8, - ImageReference3D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector3i(4), zero)); - texture.setSubImage(0, Vector3i(1), - ImageReference3D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector3i(2), subData)); - - MAGNUM_VERIFY_NO_ERROR(); - - /** @todo How to test this on ES? */ - #ifndef MAGNUM_TARGET_GLES - Image3D image(ColorFormat::RGBA, ColorType::UnsignedByte); - texture.image(0, image); - - MAGNUM_VERIFY_NO_ERROR(); - - CORRADE_COMPARE(image.size(), Vector3i(4)); - CORRADE_COMPARE_AS(std::vector(image.data(), image.data()+image.pixelSize()*image.size().product()), (std::vector{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0, 0, 0, 0, - 0, 0, 0, 0, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0, 0, 0, 0, - 0, 0, 0, 0, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }), TestSuite::Compare::Container); - #endif -} - -void TextureGLTest::subImage2DArrayBuffer() { - #ifndef MAGNUM_TARGET_GLES - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - #endif - - constexpr UnsignedByte zero[4*4*4*4] = {}; - constexpr UnsignedByte subData[] = { 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1e, 0x1f }; - Texture3D texture(Texture3D::Target::Texture2DArray); - texture.setImage(0, TextureFormat::RGBA8, - ImageReference3D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector3i(4), zero)); - texture.setSubImage(0, Vector3i(1), - BufferImage3D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector3i(2), subData, BufferUsage::StaticDraw)); - - MAGNUM_VERIFY_NO_ERROR(); - - /** @todo How to test this on ES? */ - #ifndef MAGNUM_TARGET_GLES - BufferImage3D image(ColorFormat::RGBA, ColorType::UnsignedByte); - texture.image(0, image, BufferUsage::StaticRead); - const auto imageData = image.buffer().data(); - - MAGNUM_VERIFY_NO_ERROR(); - - CORRADE_COMPARE(image.size(), Vector3i(4)); - CORRADE_COMPARE_AS(std::vector(imageData.begin(), imageData.end()), (std::vector{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0, 0, 0, 0, - 0, 0, 0, 0, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0, 0, 0, 0, - 0, 0, 0, 0, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }), TestSuite::Compare::Container); - #endif -} -#endif - -#ifndef MAGNUM_TARGET_GLES -void TextureGLTest::subImage2DMultisample() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - - CORRADE_SKIP("Not implemented yet."); -} - -void TextureGLTest::subImage2DMultisampleBuffer() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - - CORRADE_SKIP("Not implemented yet."); -} - -void TextureGLTest::subImage2DMultisampleArray() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - - CORRADE_SKIP("Not implemented yet."); -} - -void TextureGLTest::subImage2DMultisampleArrayBuffer() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - - CORRADE_SKIP("Not implemented yet."); -} - -void TextureGLTest::subImageRectangle() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); - - constexpr UnsignedByte zero[4*4*4] = {}; - constexpr UnsignedByte subData[] = { 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f }; - Texture2D texture(Texture2D::Target::Rectangle); - texture.setImage(0, TextureFormat::RGBA8, - ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(4), zero)); - texture.setSubImage(0, Vector2i(1), - ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(2), subData)); - - MAGNUM_VERIFY_NO_ERROR(); - - Image2D image(ColorFormat::RGBA, ColorType::UnsignedByte); - texture.image(0, image); - - MAGNUM_VERIFY_NO_ERROR(); - - CORRADE_COMPARE(image.size(), Vector2i(4)); - CORRADE_COMPARE_AS(std::vector(image.data(), image.data()+image.pixelSize()*image.size().product()), (std::vector{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0, 0, 0, 0, - 0, 0, 0, 0, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }), TestSuite::Compare::Container); -} - -void TextureGLTest::subImageRectangleBuffer() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); - - constexpr UnsignedByte zero[4*4*4] = {}; - constexpr UnsignedByte subData[] = { 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f }; - Texture2D texture(Texture2D::Target::Rectangle); - texture.setImage(0, TextureFormat::RGBA8, - ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(4), zero)); - texture.setSubImage(0, Vector2i(1), - BufferImage2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(2), subData, BufferUsage::StaticDraw)); - - MAGNUM_VERIFY_NO_ERROR(); - - BufferImage2D image(ColorFormat::RGBA, ColorType::UnsignedByte); - texture.image(0, image, BufferUsage::StaticRead); - const auto imageData = image.buffer().data(); - - MAGNUM_VERIFY_NO_ERROR(); - - CORRADE_COMPARE(image.size(), Vector2i(4)); - CORRADE_COMPARE_AS(std::vector(imageData.begin(), imageData.end()), (std::vector{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0, 0, 0, 0, - 0, 0, 0, 0, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }), TestSuite::Compare::Container); -} -#endif - #ifndef MAGNUM_TARGET_GLES void TextureGLTest::generateMipmap1D() { if(!Context::current()->isExtensionSupported()) @@ -1720,72 +837,6 @@ void TextureGLTest::generateMipmap3D() { #endif } -#ifndef MAGNUM_TARGET_GLES -void TextureGLTest::generateMipmap1DArray() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not supported.")); - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - - Texture2D texture(Texture2D::Target::Texture1DArray); - texture.setImage(0, TextureFormat::RGBA8, - ImageReference2D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector2i(32))); - - CORRADE_COMPARE(texture.imageSize(0), Vector2i(32)); - CORRADE_COMPARE(texture.imageSize(1), Vector2i( 0)); - - texture.generateMipmap(); - - MAGNUM_VERIFY_NO_ERROR(); - - CORRADE_COMPARE(texture.imageSize(0), Vector2i(32, 32)); - CORRADE_COMPARE(texture.imageSize(1), Vector2i(16, 32)); - CORRADE_COMPARE(texture.imageSize(2), Vector2i( 8, 32)); - CORRADE_COMPARE(texture.imageSize(3), Vector2i( 4, 32)); - CORRADE_COMPARE(texture.imageSize(4), Vector2i( 2, 32)); - CORRADE_COMPARE(texture.imageSize(5), Vector2i( 1, 32)); - - MAGNUM_VERIFY_NO_ERROR(); -} -#endif - -#ifndef MAGNUM_TARGET_GLES2 -void TextureGLTest::generateMipmap2DArray() { - #ifndef MAGNUM_TARGET_GLES - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::framebuffer_object::string() + std::string(" is not supported.")); - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - #endif - - Texture3D texture(Texture3D::Target::Texture2DArray); - texture.setImage(0, TextureFormat::RGBA8, - ImageReference3D(ColorFormat::RGBA, ColorType::UnsignedByte, Vector3i(32))); - - /** @todo How to test this on ES? */ - #ifndef MAGNUM_TARGET_GLES - CORRADE_COMPARE(texture.imageSize(0), Vector3i(32)); - CORRADE_COMPARE(texture.imageSize(1), Vector3i( 0)); - #endif - - texture.generateMipmap(); - - MAGNUM_VERIFY_NO_ERROR(); - - /** @todo How to test this on ES? */ - #ifndef MAGNUM_TARGET_GLES - CORRADE_COMPARE(texture.imageSize(0), Vector3i(32, 32, 32)); - CORRADE_COMPARE(texture.imageSize(1), Vector3i(16, 16, 32)); - CORRADE_COMPARE(texture.imageSize(2), Vector3i( 8, 8, 32)); - CORRADE_COMPARE(texture.imageSize(3), Vector3i( 4, 4, 32)); - CORRADE_COMPARE(texture.imageSize(4), Vector3i( 2, 2, 32)); - CORRADE_COMPARE(texture.imageSize(5), Vector3i( 1, 1, 32)); - - MAGNUM_VERIFY_NO_ERROR(); - #endif -} -#endif - #ifndef MAGNUM_TARGET_GLES void TextureGLTest::invalidateImage1D() { Texture1D texture; @@ -1817,61 +868,6 @@ void TextureGLTest::invalidateImage3D() { MAGNUM_VERIFY_NO_ERROR(); } -#ifndef MAGNUM_TARGET_GLES -void TextureGLTest::invalidateImage1DArray() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - - Texture2D texture(Texture2D::Target::Texture1DArray); - texture.setStorage(2, TextureFormat::RGBA8, Vector2i(32)); - texture.invalidateImage(1); - - MAGNUM_VERIFY_NO_ERROR(); -} -#endif - -#ifndef MAGNUM_TARGET_GLES2 -void TextureGLTest::invalidateImage2DArray() { - #ifndef MAGNUM_TARGET_GLES - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - #endif - - Texture3D texture(Texture3D::Target::Texture2DArray); - texture.setStorage(2, TextureFormat::RGBA8, Vector3i(32)); - texture.invalidateImage(1); - - MAGNUM_VERIFY_NO_ERROR(); -} -#endif - -#ifndef MAGNUM_TARGET_GLES -void TextureGLTest::invalidateImage2DMultisample() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - - CORRADE_SKIP("Multisample storage is not implemented yet."); -} - -void TextureGLTest::invalidateImage2DMultisampleArray() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - - CORRADE_SKIP("Multisample storage is not implemented yet."); -} - -void TextureGLTest::invalidateImageRectangle() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); - - Texture2D texture(Texture2D::Target::Rectangle); - texture.setStorage(1, TextureFormat::RGBA8, Vector2i(32)); - texture.invalidateImage(0); - - MAGNUM_VERIFY_NO_ERROR(); -} -#endif - #ifndef MAGNUM_TARGET_GLES void TextureGLTest::invalidateSubImage1D() { Texture1D texture; @@ -1903,61 +899,6 @@ void TextureGLTest::invalidateSubImage3D() { MAGNUM_VERIFY_NO_ERROR(); } -#ifndef MAGNUM_TARGET_GLES -void TextureGLTest::invalidateSubImage1DArray() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - - Texture2D texture(Texture2D::Target::Texture1DArray); - texture.setStorage(2, TextureFormat::RGBA8, Vector2i(32)); - texture.invalidateSubImage(1, Vector2i(2), Vector2i(8)); - - MAGNUM_VERIFY_NO_ERROR(); -} -#endif - -#ifndef MAGNUM_TARGET_GLES2 -void TextureGLTest::invalidateSubImage2DArray() { - #ifndef MAGNUM_TARGET_GLES - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); - #endif - - Texture3D texture(Texture3D::Target::Texture2DArray); - texture.setStorage(2, TextureFormat::RGBA8, Vector3i(32)); - texture.invalidateSubImage(1, Vector3i(2), Vector3i(8)); - - MAGNUM_VERIFY_NO_ERROR(); -} -#endif - -#ifndef MAGNUM_TARGET_GLES -void TextureGLTest::invalidateSubImage2DMultisample() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - - CORRADE_SKIP("Multisample storage is not implemented yet."); -} - -void TextureGLTest::invalidateSubImage2DMultisampleArray() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - - CORRADE_SKIP("Multisample storage is not implemented yet."); -} - -void TextureGLTest::invalidateSubImageRectangle() { - if(!Context::current()->isExtensionSupported()) - CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); - - Texture2D texture(Texture2D::Target::Rectangle); - texture.setStorage(1, TextureFormat::RGBA8, Vector2i(32)); - texture.invalidateSubImage(0, Vector2i(4), Vector2i(16)); - - MAGNUM_VERIFY_NO_ERROR(); -} -#endif - }} CORRADE_TEST_MAIN(Magnum::Test::TextureGLTest) diff --git a/src/Magnum/Text/AbstractFont.cpp b/src/Magnum/Text/AbstractFont.cpp index a3a047e11..341401b71 100644 --- a/src/Magnum/Text/AbstractFont.cpp +++ b/src/Magnum/Text/AbstractFont.cpp @@ -29,6 +29,7 @@ #include #include +#include "Magnum/Math/Functions.h" #include "Magnum/Text/GlyphCache.h" namespace Magnum { namespace Text { diff --git a/src/Magnum/Text/Renderer.cpp b/src/Magnum/Text/Renderer.cpp index 5c8d65d8c..a26a9dfc9 100644 --- a/src/Magnum/Text/Renderer.cpp +++ b/src/Magnum/Text/Renderer.cpp @@ -28,6 +28,7 @@ #include "Magnum/Context.h" #include "Magnum/Extensions.h" #include "Magnum/Mesh.h" +#include "Magnum/Math/Functions.h" #include "Magnum/Shaders/AbstractVector.h" #include "Magnum/Text/AbstractFont.h" diff --git a/src/Magnum/Text/Renderer.h b/src/Magnum/Text/Renderer.h index 0ca6f2a8c..d9bdcc6ae 100644 --- a/src/Magnum/Text/Renderer.h +++ b/src/Magnum/Text/Renderer.h @@ -173,8 +173,8 @@ depends on features supported by particular font and its layouter. Immutable text (e.g. menu items, credits) can be simply rendered using static methods, returning result either as data arrays or as fully configured mesh. -The text can be then drawn by configuring text shader, binding font texture -and drawing the mesh: +The text can be then drawn as usual by configuring the shader and drawing the +mesh: @code Text::AbstractFont* font; Text::GlyphCache cache; @@ -190,10 +190,9 @@ std::tie(mesh, rectangle) = Text::Renderer2D::render(*font, cache, 0.15f, // Draw white text centered on the screen shader.setTransformationProjectionMatrix(projection*Matrix3::translation(-rectangle.width()/2.0f)) - .setColor(Color3(1.0f)); - .use(); -glyphCache->texture()->bind(Shaders::VectorShader2D::FontTextureLayer); -mesh.draw(); + .setColor(Color3(1.0f)) + .setVectorTexture(glyphCache->texture()); +mesh.draw(shader); @endcode See @ref render(AbstractFont&, const GlyphCache&, Float, const std::string&, Alignment) and @ref render(AbstractFont&, const GlyphCache&, Float, const std::string&, Buffer&, Buffer&, BufferUsage, Alignment) @@ -216,10 +215,9 @@ renderer.render("Hello World Countdown: 10"); // Draw the text centered on the screen shader.setTransformationProjectionMatrix(projection*Matrix3::translation(-renderer.rectangle().width()/2.0f)) - .setColor(Color3(1.0f)); - .use(); -glyphCache->texture()->bind(Shaders::VectorShader2D::FontTextureLayer); -renderer.mesh().draw(); + .setColor(Color3(1.0f)) + .setVectorTexture(glyphCache->texture()); +renderer.mesh().draw(shader); @endcode @section Renderer-extensions Required OpenGL functionality diff --git a/src/Magnum/Text/Test/AbstractFontTest.cpp b/src/Magnum/Text/Test/AbstractFontTest.cpp index cf12e1d9e..ea60e38d0 100644 --- a/src/Magnum/Text/Test/AbstractFontTest.cpp +++ b/src/Magnum/Text/Test/AbstractFontTest.cpp @@ -27,6 +27,7 @@ #include #include +#include "Magnum/Math/Vector2.h" #include "Magnum/Text/AbstractFont.h" #include "configure.h" diff --git a/src/Magnum/Text/Test/GlyphCacheGLTest.cpp b/src/Magnum/Text/Test/GlyphCacheGLTest.cpp index fee673255..c07aeb3c9 100644 --- a/src/Magnum/Text/Test/GlyphCacheGLTest.cpp +++ b/src/Magnum/Text/Test/GlyphCacheGLTest.cpp @@ -23,6 +23,8 @@ DEALINGS IN THE SOFTWARE. */ +#include + #include "Magnum/Test/AbstractOpenGLTester.h" #include "Magnum/Text/GlyphCache.h" diff --git a/src/Magnum/Text/fontconverter.cpp b/src/Magnum/Text/fontconverter.cpp index fb7b6782b..df510b7aa 100644 --- a/src/Magnum/Text/fontconverter.cpp +++ b/src/Magnum/Text/fontconverter.cpp @@ -72,21 +72,15 @@ int FontConverter::exec() { /* Load font */ PluginManager::Manager fontManager(Utility::Directory::join(MAGNUM_PLUGINS_DIR, "fonts/")); - std::unique_ptr font; - if(!(fontManager.load(args.value("font")) & PluginManager::LoadState::Loaded) || - !(font = fontManager.instance(args.value("font")))) { - Error() << "Cannot load plugin" << args.value("font") << "from" << fontManager.pluginDirectory(); + if(!(fontManager.load(args.value("font")) & PluginManager::LoadState::Loaded)) std::exit(1); - } + std::unique_ptr font = fontManager.instance(args.value("font")); /* Load font converter */ PluginManager::Manager converterManager(Utility::Directory::join(MAGNUM_PLUGINS_DIR, "fontconverters/")); - std::unique_ptr converter; - if(!(converterManager.load(args.value("converter")) & PluginManager::LoadState::Loaded) || - !(converter = converterManager.instance(args.value("converter")))) { - Error() << "Cannot load plugin" << args.value("converter") << "from" << converterManager.pluginDirectory(); + if(!(converterManager.load(args.value("converter")) & PluginManager::LoadState::Loaded)) std::exit(1); - } + std::unique_ptr converter = converterManager.instance(args.value("converter")); /* Open font */ if(!font->openFile(args.value("input"), args.value("font-size"))) { diff --git a/src/Magnum/Texture.h b/src/Magnum/Texture.h index f54275741..4a48754c3 100644 --- a/src/Magnum/Texture.h +++ b/src/Magnum/Texture.h @@ -29,11 +29,30 @@ * @brief Class @ref Magnum::Texture, typedef @ref Magnum::Texture1D, @ref Magnum::Texture2D, @ref Magnum::Texture3D */ +#include + #include "Magnum/AbstractTexture.h" +#include "Magnum/Array.h" #include "Magnum/DimensionTraits.h" +#include "Magnum/Math/Vector3.h" namespace Magnum { +namespace Implementation { + template constexpr GLenum textureTarget(); + #ifndef MAGNUM_TARGET_GLES + template<> inline constexpr GLenum textureTarget<1>() { return GL_TEXTURE_1D; } + #endif + template<> inline constexpr GLenum textureTarget<2>() { return GL_TEXTURE_2D; } + template<> inline constexpr GLenum textureTarget<3>() { + #ifndef MAGNUM_TARGET_GLES2 + return GL_TEXTURE_3D; + #else + return GL_TEXTURE_3D_OES; + #endif + } +} + /** @brief %Texture @@ -58,177 +77,75 @@ texture.setMagnificationFilter(Sampler::Filter::Linear) .generateMipmap(); @endcode -@attention Don't forget to fully configure the texture before use. Note that - default configuration (if @ref setMinificationFilter() is not called with - another value) is to use mipmaps, so be sure to either call @ref setMinificationFilter(), - explicitly specify all mip levels with @ref setStorage() and @ref setImage() - or call @ref generateMipmap(). If using rectangle texture, you must also - call @ref setWrapping(), because the initial value is not supported on - rectangle textures. See also @ref setMagnificationFilter() and - @ref setBorderColor(). - -The texture is bound to layer specified by shader via @ref bind(). In shader, -the texture is used via `sampler2D` and friends, see @ref Target enum -documentation for more information. See also AbstractShaderProgram -documentation for more information about usage in shaders. - -@section Texture-array Texture arrays - -You can create texture arrays by passing -@ref Target::Texture1DArray "Texture2D::Target::Texture1DArray" or -@ref Target::Texture2DArray "Texture3D::Target::Texture2DArray" to constructor. - -It is possible to specify each layer separately using @ref setSubImage(), but -you have to allocate the memory for all layers first by calling @ref setStorage(). -Example: 2D texture array with 16 layers of 64x64 images: -@code -Texture3D texture(Texture3D::Target::Texture2DArray); -texture.setMagnificationFilter(Sampler::Filter::Linear) - // ... - .setStorage(levels, TextureFormat::RGBA8, {64, 64,16}); - -for(std::size_t i = 0; i != 16; ++i) { - // ... - Image2D image(ColorFormat::RGBA, ColorType::UnsignedByte, {64, 64}, data[i]); - texture.setSubImage(0, Vector3i::zAxis(i), image); -} - -// ... -@endcode - -Similar approach can be used for any other texture types (e.g. setting -@ref Texture3D data using 2D layers, @ref Texture2D data using one-dimensional -chunks etc.). - -@requires_gl30 %Extension @extension{EXT,texture_array} for texture arrays. -@requires_gles30 %Array textures are not available in OpenGL ES 2.0. - -@section Texture-multisample Multisample textures - -You can create multisample textures by passing -@ref Target::Texture2DMultisample "Texture2D::Target::Texture2DMultisample" or -@ref Target::Texture2DMultisampleArray "Texture3D::Target::Texture2DMultisampleArray" -to constructor. - -@todoc finish this when fully implemented - -@requires_gl32 %Extension @extension{ARB,texture_multisample} for multisample - textures. -@requires_gl Multisample textures are not available in OpenGL ES. +@attention Note that default configuration (if @ref setMinificationFilter() is + not called with another value) is to use mipmaps, so be sure to either call + @ref setMinificationFilter(), explicitly specify all mip levels with + @ref setStorage() and @ref setImage() or call @ref generateMipmap(). -@section Texture-rectangle Rectangle textures +In shader, the texture is used via `sampler1D`/`sampler2D`/`sampler3D`, +`sampler1DShadow`/`sampler2DShadow`/`sampler3DShadow`, +`isampler1D`/`isampler2D`/`isampler3D` or `usampler1D`/`usampler2D`/`usampler3D`. +See @ref AbstractShaderProgram documentation for more information about usage +in shaders. -Rectangle texture is created by passing @ref Target::Rectangle "Texture2D::Target::Rectangle" -to constructor. In shader, the texture is used via `sampler2DRect` and friends. -Unlike `sampler2D`, which accepts coordinates between 0 and 1, `sampler2DRect` -accepts coordinates between 0 and `textureSizeInGivenDirection-1`. Note that -rectangle textures don't support mipmapping and repeating wrapping modes, see -@ref Sampler::Filter, @ref Sampler::Mipmap and @ref generateMipmap() -documentation for more information. +@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. -@requires_gl31 %Extension @extension{ARB,texture_rectangle} for rectangle - textures. -@requires_gl Rectangle textures are not available in OpenGL ES. - -@see @ref Texture1D, @ref Texture2D, @ref Texture3D, @ref CubeMapTexture, - @ref CubeMapTextureArray, @ref BufferTexture -@todo @extension{AMD,sparse_texture} -@todo Separate multisample, array and rectangle texture classes to avoid confusion, then remove Target enum +@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: static const UnsignedInt Dimensions = dimensions; /**< @brief %Texture dimension count */ - #ifdef DOXYGEN_GENERATING_OUTPUT + #ifdef MAGNUM_BUILD_DEPRECATED /** * @brief %Texture target * - * Each dimension has its own unique subset of these targets. + * @deprecated Use dedicated classes instead, see documentation of + * particular enum value for more information. */ + #ifdef DOXYGEN_GENERATING_OUTPUT enum class Target: GLenum { - /** - * One-dimensional texture. Use `sampler1D`, `sampler1DShadow`, - * `isampler1D` or `usampler1D` in shader. - * @requires_gl Only 2D and 3D textures are available in OpenGL - * ES. - */ + /** @deprecated Used implicitly in @ref Magnum::Texture1D "Texture1D" class. */ Texture1D = GL_TEXTURE_1D, - /** - * Two-dimensional texture. Use `sampler2D`, `sampler2DShadow`, - * `isampler2D` or `usampler2D` in shader. - */ + /** @deprecated Used implicitly in @ref Magnum::Texture2D "Texture2D" class. */ Texture2D = GL_TEXTURE_2D, - /** - * Three-dimensional texture. Use `sampler3D`, `isampler3D` or - * `usampler3D` in shader. - * @requires_gles30 %Extension @es_extension{OES,texture_3D} - */ + /** @deprecated Used implicitly in @ref Magnum::Texture3D "Texture3D" class. */ Texture3D = GL_TEXTURE_3D, - /** - * One-dimensional texture array (i.e. two dimensions in total). - * Use `sampler1DArray`, `sampler1DArrayShadow`, `isampler1DArray` - * or `usampler1DArray` in shader. - * @requires_gl30 %Extension @extension{EXT,texture_array} - * @requires_gl Only 2D and 3D textures are available in OpenGL - * ES. - */ + /** @deprecated Use @ref Magnum::Texture1DArray "Texture1DArray" class instead. */ Texture1DArray = GL_TEXTURE_1D_ARRAY, - /** - * Two-dimensional texture array (i.e. three dimensions in total). - * Use `sampler2DArray`, `sampler2DArrayShadow`, `isampler2DArray` - * or `usampler2DArray` in shader. - * @requires_gl30 %Extension @extension{EXT,texture_array} - * @requires_gles30 %Array textures are not available in OpenGL ES - * 2.0. - */ + /** @deprecated Use @ref Magnum::Texture2DArray "Texture2DArray" class instead. */ Texture2DArray = GL_TEXTURE_2D_ARRAY, - /** - * Multisampled two-dimensional texture. Use `sampler2DMS`, - * `isampler2DMS` or `usampler2DMS` in shader. - * @requires_gl32 %Extension @extension{ARB,texture_multisample} - * @requires_gl Multisample textures are not available in OpenGL - * ES. - */ + /** @deprecated Use @ref Magnum::MultisampleTexture2D "MultisampleTexture2D" class instead. */ Texture2DMultisample = GL_TEXTURE_2D_MULTISAMPLE, - /** - * Multisampled two-dimensional texture array (i.e. three - * dimensions in total). Use `sampler2DMSArray`, - * `isampler2DMSArray` or `usampler2DMSArray` in shader. - * @requires_gl32 %Extension @extension{ARB,texture_multisample} - * @requires_gl Multisample textures are not available in OpenGL - * ES. - */ + /** @deprecated Use @ref Magnum::MultisampleTexture2DArray "MultisampleTexture2DArray" class instead. */ Texture2DMultisampleArray = GL_TEXTURE_2D_MULTISAMPLE_ARRAY, - /** - * Rectangle texture (i.e. two dimensions). Use `sampler2DRect`, - * `sampler2DRectShadow`, `isampler2DRect` or `usampler2DRect` in - * shader. - * @requires_gl31 %Extension @extension{ARB,texture_rectangle} - * @requires_gl Rectangle textures are not available in OpenGL ES. - */ + /** @deprecated Use @ref Magnum::RectangleTexture "RectangleTexture" class instead. */ Rectangle = GL_TEXTURE_RECTANGLE }; #else - typedef typename DataHelper::Target Target; /**< @brief %Texture target */ + typedef typename DataHelper::Target Target; + #endif #endif /** * @brief Constructor - * @param target %Texture target. If not set, default value - * is `Target::Texture1D`, `Target::Texture2D` or - * `Target::Texture3D` based on dimension count. * - * Creates new OpenGL texture. - * @see @fn_gl{GenTextures} + * Creates new OpenGL texture object. + * @see @fn_gl{GenTextures} with @def_gl{TEXTURE_1D}, @def_gl{TEXTURE_2D} + * or @def_gl{TEXTURE_3D} */ - explicit Texture(Target target = DataHelper::target()): AbstractTexture(GLenum(target)) {} + explicit Texture(): AbstractTexture(Implementation::textureTarget()) {} #ifdef CORRADE_GCC45_COMPATIBILITY Texture(const Texture&) = delete; @@ -240,8 +157,25 @@ template class Texture: public AbstractTexture { } #endif - /** @brief %Texture target */ - constexpr Target target() const { return static_cast(_target); } + #ifdef MAGNUM_BUILD_DEPRECATED + /** @copybrief Texture() + * @deprecated Use the parameterless @ref Magnum::Texture::Texture() "Texture()" + * constructor or dedicated @ref Magnum::TextureArray "TextureArray", + * @ref Magnum::MultisampleTexture "MultisampleTexture", + * @ref Magnum::RectangleTexture "RectangleTexture" classes + * instead. + */ + explicit CORRADE_DEPRECATED("use the parameterless constructor or dedicated TextureArray, MultisampleTexture, RectangleTexture classes instead") Texture(Target target): AbstractTexture(GLenum(target)) {} + + /** @brief %Texture target + * @deprecated Use dedicated @ref Magnum::Texture "Texture", + * @ref Magnum::TextureArray "TextureArray", + * @ref Magnum::MultisampleTexture "MultisampleTexture", + * @ref Magnum::RectangleTexture "RectangleTexture" classes + * instead. + */ + constexpr CORRADE_DEPRECATED("use dedicated Texture, TextureArray, MultisampleTexture, RectangleTexture classes instead") Target target() const { return static_cast(_target); } + #endif #ifndef MAGNUM_TARGET_GLES /** @@ -255,11 +189,50 @@ template class Texture: public AbstractTexture { * with @def_gl{TEXTURE_WIDTH}, @def_gl{TEXTURE_HEIGHT} or @def_gl{TEXTURE_DEPTH}. * @requires_gl %Texture image queries are not available in OpenGL ES. */ - typename DimensionTraits::VectorType imageSize(Int level) { - return DataHelper::imageSize(this, _target, level); + typename DimensionTraits::VectorType imageSize(Int level) { + return DataHelper::imageSize(*this, _target, level); } #endif + /** + * @brief Set minification filter + * @param filter Filter + * @param mipmap Mipmap filtering. If set to anything else than + * @ref Sampler::Mipmap::Base, make sure textures for all mip + * levels are set or call @ref generateMipmap(). + * @return Reference to self (for method chaining) + * + * Sets filter used when the object pixel size is smaller than the + * texture size. If @extension{EXT,direct_state_access} is not + * available, the texture is bound to some layer before the operation. + * Initial value is (@ref Sampler::Filter::Nearest, @ref Sampler::Mipmap::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_MIN_FILTER} + */ + Texture& setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) { + AbstractTexture::setMinificationFilter(filter, mipmap); + return *this; + } + + /** + * @brief Set magnification filter + * @param filter Filter + * @return Reference to self (for method chaining) + * + * Sets filter used when the object pixel size is larger than largest + * texture size. If @extension{EXT,direct_state_access} is not + * available, the texture is bound to some layer 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} + */ + Texture& setMagnificationFilter(Sampler::Filter filter) { + AbstractTexture::setMagnificationFilter(filter); + return *this; + } + /** * @brief Set wrapping * @param wrapping Wrapping type for all texture dimensions @@ -270,15 +243,51 @@ template class Texture: public AbstractTexture { * textures. If @extension{EXT,direct_state_access} is not available, * the texture is bound to some layer before the operation. Initial * value is @ref Sampler::Wrapping::Repeat. - * @attention For rectangle textures only some modes are supported, - * see @ref Sampler::Wrapping documentation for more information. * @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}, * @def_gl{TEXTURE_WRAP_R} */ - Texture& setWrapping(const Array& wrapping) { - DataHelper::setWrapping(this, wrapping); + Texture& setWrapping(const Array& wrapping) { + DataHelper::setWrapping(*this, wrapping); + return *this; + } + + /** + * @brief Set border color + * @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 layer 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} + * @requires_es_extension %Extension @es_extension{NV,texture_border_clamp} + */ + Texture& setBorderColor(const Color4& color) { + AbstractTexture::setBorderColor(color); + return *this; + } + + /** + * @brief Set max anisotropy + * @return Reference to self (for method chaining) + * + * Default value is `1.0f`, which means no anisotropy. Set to value + * greater than `1.0f` for anisotropic filtering. If extension + * @extension{EXT,texture_filter_anisotropic} (desktop or ES) is not + * available, this function does nothing. If + * @extension{EXT,direct_state_access} is not available, the texture is + * bound to some layer before the operation. + * @see @ref Sampler::maxMaxAnisotropy(), @fn_gl{ActiveTexture}, + * @fn_gl{BindTexture} and @fn_gl{TexParameter} or + * @fn_gl_extension{TextureParameter,EXT,direct_state_access} with + * @def_gl{TEXTURE_MAX_ANISOTROPY_EXT} + */ + Texture& setMaxAnisotropy(Float anisotropy) { + AbstractTexture::setMaxAnisotropy(anisotropy); return *this; } @@ -295,9 +304,9 @@ template class Texture: public AbstractTexture { * is immutable and calling @ref setStorage() or @ref setImage() is not * allowed. * - * If @extension{EXT,direct_state_access} is not available, the - * texture is bound to some layer before the operation. If - * OpenGL 4.2, @extension{ARB,texture_storage}, OpenGL ES 3.0 or @es_extension{EXT,texture_storage} + * If @extension{EXT,direct_state_access} is not available, the texture + * is bound to some layer before the operation. If @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 * sequence of @ref setImage() calls. * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @@ -310,8 +319,8 @@ template class Texture: public AbstractTexture { * @fn_gl_extension{TextureImage2D,EXT,direct_state_access}/ * @fn_gl_extension{TextureImage3D,EXT,direct_state_access}. */ - Texture& setStorage(Int levels, TextureFormat internalFormat, const typename DimensionTraits::VectorType& size) { - DataHelper::setStorage(this, _target, levels, internalFormat, size); + Texture& setStorage(Int levels, TextureFormat internalFormat, const typename DimensionTraits::VectorType& size) { + DataHelper::setStorage(*this, _target, levels, internalFormat, size); return *this; } @@ -377,20 +386,20 @@ template class Texture: public AbstractTexture { * @fn_gl_extension{TextureImage2D,EXT,direct_state_access}/ * @fn_gl_extension{TextureImage3D,EXT,direct_state_access} */ - Texture& setImage(Int level, TextureFormat internalFormat, const ImageReference& image) { - DataHelper::setImage(this, _target, level, internalFormat, image); + Texture& setImage(Int level, TextureFormat internalFormat, const ImageReference& image) { + DataHelper::setImage(*this, _target, level, internalFormat, image); return *this; } #ifndef MAGNUM_TARGET_GLES2 /** @overload */ - Texture& setImage(Int level, TextureFormat internalFormat, BufferImage& image) { - DataHelper::setImage(this, _target, level, internalFormat, image); + Texture& setImage(Int level, TextureFormat internalFormat, BufferImage& image) { + DataHelper::setImage(*this, _target, level, internalFormat, image); return *this; } /** @overload */ - Texture& setImage(Int level, TextureFormat internalFormat, BufferImage&& image) { + Texture& setImage(Int level, TextureFormat internalFormat, BufferImage&& image) { return setImage(level, internalFormat, image); } #endif @@ -412,24 +421,50 @@ template class Texture: public AbstractTexture { * @fn_gl_extension{TextureSubImage2D,EXT,direct_state_access}/ * @fn_gl_extension{TextureSubImage3D,EXT,direct_state_access} */ - Texture& setSubImage(Int level, const typename DimensionTraits::VectorType& offset, const ImageReference& image) { - DataHelper::setSubImage(this, _target, level, offset, image); + Texture& setSubImage(Int level, const typename DimensionTraits::VectorType& offset, const ImageReference& image) { + DataHelper::setSubImage(*this, _target, level, offset, image); return *this; } #ifndef MAGNUM_TARGET_GLES2 /** @overload */ - Texture& setSubImage(Int level, const typename DimensionTraits::VectorType& offset, BufferImage& image) { - DataHelper::setSubImage(this, _target, level, offset, image); + Texture& setSubImage(Int level, const typename DimensionTraits::VectorType& offset, BufferImage& image) { + DataHelper::setSubImage(*this, _target, level, offset, image); return *this; } /** @overload */ - Texture& setSubImage(Int level, const typename DimensionTraits::VectorType& offset, BufferImage&& image) { + Texture& setSubImage(Int level, const typename DimensionTraits::VectorType& offset, BufferImage&& image) { return setSubImage(level, offset, image); } #endif + /** + * @brief Generate mipmap + * @return Reference to self (for method chaining) + * + * If @extension{EXT,direct_state_access} is not available, the texture + * is bound to some layer before the operation. + * @see setMinificationFilter(), @fn_gl{ActiveTexture}, + * @fn_gl{BindTexture} and @fn_gl{GenerateMipmap} or + * @fn_gl_extension{GenerateTextureMipmap,EXT,direct_state_access} + * @requires_gl30 %Extension @extension{ARB,framebuffer_object} + */ + Texture& generateMipmap() { + AbstractTexture::generateMipmap(); + return *this; + } + + /** + * @brief Invalidate texture image + * @param level Mip level + * + * If running on OpenGL ES or extension @extension{ARB,invalidate_subdata} + * (part of OpenGL 4.3) is not available, this function does nothing. + * @see @ref invalidateSubImage(), @fn_gl{InvalidateTexImage} + */ + void invalidateImage(Int level) { AbstractTexture::invalidateImage(level); } + /** * @brief Invalidate texture subimage * @param level Mip level @@ -440,36 +475,16 @@ template class Texture: public AbstractTexture { * (part of OpenGL 4.3) is not available, this function does nothing. * @see @ref invalidateImage(), @fn_gl{InvalidateTexSubImage} */ - void invalidateSubImage(Int level, const typename DimensionTraits::VectorType& offset, const typename DimensionTraits::VectorType& size) { - DataHelper::invalidateSubImage(this, level, offset, size); + void invalidateSubImage(Int level, const typename DimensionTraits::VectorType& offset, const typename DimensionTraits::VectorType& size) { + DataHelper::invalidateSubImage(*this, level, offset, size); } /* Overloads to remove WTF-factor from method chaining order */ #ifndef DOXYGEN_GENERATING_OUTPUT - Texture& setLabel(const std::string& label) { + Texture& setLabel(const std::string& label) { AbstractTexture::setLabel(label); return *this; } - Texture& setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) { - AbstractTexture::setMinificationFilter(filter, mipmap); - return *this; - } - Texture& setMagnificationFilter(Sampler::Filter filter) { - AbstractTexture::setMagnificationFilter(filter); - return *this; - } - Texture& setBorderColor(const Color4& color) { - AbstractTexture::setBorderColor(color); - return *this; - } - Texture& setMaxAnisotropy(Float anisotropy) { - AbstractTexture::setMaxAnisotropy(anisotropy); - return *this; - } - Texture& generateMipmap() { - AbstractTexture::generateMipmap(); - return *this; - } #endif }; @@ -488,7 +503,7 @@ typedef Texture<2> Texture2D; /** @brief Three-dimensional texture -@requires_gles30 %Extension @es_extension{OES,texture_3D} +@requires_gles30 %Extension @es_extension{OES,texture_3D} in OpenGL ES 2.0 */ typedef Texture<3> Texture3D; diff --git a/src/Magnum/TextureArray.h b/src/Magnum/TextureArray.h new file mode 100644 index 000000000..412bf6503 --- /dev/null +++ b/src/Magnum/TextureArray.h @@ -0,0 +1,301 @@ +#ifndef Magnum_TextureArray_h +#define Magnum_TextureArray_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. +*/ + +#ifndef MAGNUM_TARGET_GLES2 +/** @file + * @brief Class @ref Magnum::TextureArray, typedef @ref Magnum::Texture1DArray, @ref Magnum::Texture2DArray + */ +#endif + +#include "Magnum/AbstractTexture.h" +#include "Magnum/Array.h" +#include "Magnum/DimensionTraits.h" +#include "Magnum/Math/Vector3.h" + +#ifndef MAGNUM_TARGET_GLES2 +namespace Magnum { + +namespace Implementation { + template constexpr GLenum textureArrayTarget(); + #ifndef MAGNUM_TARGET_GLES + template<> inline constexpr GLenum textureArrayTarget<1>() { return GL_TEXTURE_1D_ARRAY; } + #endif + template<> inline constexpr GLenum textureArrayTarget<2>() { return GL_TEXTURE_2D_ARRAY; } +} + +/** +@brief %Texture array + +Template class for one- and two-dimensional texture arrays. See also +@ref AbstractTexture documentation for more information. + +@section Texture-usage Usage + +Common usage is to fully configure all texture parameters and then set the +data. Example configuration: +@code +Texture2DArray texture; +texture.setMagnificationFilter(Sampler::Filter::Linear) + .setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) + .setWrapping(Sampler::Wrapping::ClampToEdge) + .setMaxAnisotropy(Sampler::maxMaxAnisotropy());; +@endcode + +It is often more convenient to first allocate the memory for all layers by +calling @ref setStorage() and then specify each layer separately using +@ref setSubImage(): +@code +texture.setStorage(levels, TextureFormat::RGBA8, {64, 64, 16}); + +for(std::size_t i = 0; i != 16; ++i) { + Image3D image(ColorFormat::RGBA, ColorType::UnsignedByte, {64, 64, 1}, ...); + texture.setSubImage(0, Vector3i::zAxis(i), image); +} +@endcode + +@attention Note that default configuration (if @ref setMinificationFilter() is + not called with another value) is to use mipmaps, so be sure to either call + @ref setMinificationFilter(), explicitly specify all mip levels with + @ref setStorage() and @ref setImage() or call @ref generateMipmap(). + +In shader, the texture is used via `sampler1DArray`/`sampler2DArray`, +`sampler1DArrayShadow`/`sampler1DArrayShadow`, `isampler1DArray`/`isampler2DArray` +or `usampler1DArray`/`usampler2DArray`. See @ref AbstractShaderProgram +documentation for more information about usage in shaders. + +@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 + */ +template class TextureArray: public AbstractTexture { + public: + static const UnsignedInt Dimensions = dimensions; /**< @brief %Texture dimension count */ + + /** + * @brief Constructor + * + * Creates new OpenGL texture object. + * @see @fn_gl{GenTextures} with @def_gl{TEXTURE_1D_ARRAY} or @def_gl{TEXTURE_2D_ARRAY} + */ + explicit TextureArray(): AbstractTexture(Implementation::textureArrayTarget()) {} + + /** @copydoc Texture::setMinificationFilter() */ + TextureArray& setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) { + AbstractTexture::setMinificationFilter(filter, mipmap); + return *this; + } + + /** @copydoc Texture::setMagnificationFilter() */ + TextureArray& setMagnificationFilter(Sampler::Filter filter) { + AbstractTexture::setMagnificationFilter(filter); + return *this; + } + + /** @copydoc Texture::setWrapping() */ + TextureArray& setWrapping(const Array& wrapping) { + DataHelper::setWrapping(*this, wrapping); + return *this; + } + + /** @copydoc Texture::setBorderColor() */ + TextureArray& setBorderColor(const Color4& color) { + AbstractTexture::setBorderColor(color); + return *this; + } + + /** @copydoc Texture::setMaxAnisotropy() */ + TextureArray& setMaxAnisotropy(Float anisotropy) { + AbstractTexture::setMaxAnisotropy(anisotropy); + return *this; + } + + #ifndef MAGNUM_TARGET_GLES + /** @copydoc Texture::imageSize() */ + typename DimensionTraits::VectorType imageSize(Int level) { + return DataHelper::imageSize(*this, _target, level); + } + #endif + + /** + * @brief Set storage + * @param levels Mip level count + * @param internalFormat Internal format + * @param size Size of largest mip level + * @return Reference to self (for method chaining) + * + * Specifies entire structure of a texture at once, removing the need + * for additional consistency checks and memory reallocations when + * updating the data later. After calling this function the texture + * is immutable and calling @ref setStorage() or @ref setImage() is not + * allowed. + * + * If @extension{EXT,direct_state_access} is not available, the texture + * is bound to some layer before the operation. If + * @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 + * @fn_gl{TexStorage2D}/@fn_gl{TexStorage3D} or + * @fn_gl_extension{TextureStorage2D,EXT,direct_state_access}/ + * @fn_gl_extension{TextureStorage3D,EXT,direct_state_access}, + * eventually @fn_gl{TexImage2D}/@fn_gl{TexImage3D} or + * @fn_gl_extension{TextureImage2D,EXT,direct_state_access}/ + * @fn_gl_extension{TextureImage3D,EXT,direct_state_access}. + */ + TextureArray& setStorage(Int levels, TextureFormat internalFormat, const typename DimensionTraits::VectorType& size) { + DataHelper::setStorage(*this, _target, levels, internalFormat, size); + return *this; + } + + #ifndef MAGNUM_TARGET_GLES + /** @copydoc Texture::image(Int, Image&) */ + void image(Int level, Image& image) { + AbstractTexture::image(_target, level, image); + } + + /** @copydoc Texture::imate(Int, BufferImage&, BufferUsage) */ + void image(Int level, BufferImage& image, BufferUsage usage) { + AbstractTexture::image(_target, level, image, usage); + } + #endif + + /** + * @brief Set image data + * @param level Mip level + * @param internalFormat Internal format + * @param image @ref Image, @ref ImageReference or + * @ref Trade::ImageData of the same dimension count + * @return Reference to self (for method chaining) + * + * For better performance when generating mipmaps using + * @ref generateMipmap() or calling @ref setImage() more than once use + * @ref setStorage() and @ref setSubImage() instead. + * + * If @extension{EXT,direct_state_access} is not available, the + * texture is bound to some layer before the operation. + * @see @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} + */ + TextureArray& setImage(Int level, TextureFormat internalFormat, const ImageReference& image) { + DataHelper::setImage(*this, _target, level, internalFormat, image); + return *this; + } + + #ifndef MAGNUM_TARGET_GLES2 + /** @overload */ + TextureArray& setImage(Int level, TextureFormat internalFormat, BufferImage& image) { + DataHelper::setImage(*this, _target, level, internalFormat, image); + return *this; + } + + /** @overload */ + TextureArray& setImage(Int level, TextureFormat internalFormat, BufferImage&& image) { + return setImage(level, internalFormat, image); + } + #endif + + /** + * @brief Set image subdata + * @param level Mip level + * @param offset Offset where to put data in the texture + * @param image @ref Image, @ref ImageReference or + * @ref Trade::ImageData of the same dimension count + * @return Reference to self (for method chaining) + * + * If @extension{EXT,direct_state_access} is not available, the + * texture is bound to some layer before the operation. + * @see @ref setStorage(), @ref setImage(), @fn_gl{ActiveTexture}, + * @fn_gl{BindTexture} and @fn_gl{TexSubImage2D}/@fn_gl{TexSubImage3D} + * or @fn_gl_extension{TextureSubImage2D,EXT,direct_state_access}/ + * @fn_gl_extension{TextureSubImage3D,EXT,direct_state_access} + */ + TextureArray& setSubImage(Int level, const typename DimensionTraits::VectorType& offset, const ImageReference& image) { + DataHelper::setSubImage(*this, _target, level, offset, image); + return *this; + } + + #ifndef MAGNUM_TARGET_GLES2 + /** @overload */ + TextureArray& setSubImage(Int level, const typename DimensionTraits::VectorType& offset, BufferImage& image) { + DataHelper::setSubImage(*this, _target, level, offset, image); + return *this; + } + + /** @overload */ + TextureArray& setSubImage(Int level, const typename DimensionTraits::VectorType& offset, BufferImage&& image) { + return setSubImage(level, offset, image); + } + #endif + + /** @copydoc Texture::generateMipmap() */ + TextureArray& generateMipmap() { + AbstractTexture::generateMipmap(); + return *this; + } + + /** @copydoc Texture::invalidateImage() */ + void invalidateImage(Int level) { AbstractTexture::invalidateImage(level); } + + /** @copydoc Texture::invalidateSubImage() */ + void invalidateSubImage(Int level, const typename DimensionTraits::VectorType& offset, const typename DimensionTraits::VectorType& size) { + DataHelper::invalidateSubImage(*this, level, offset, size); + } + + /* Overloads to remove WTF-factor from method chaining order */ + #ifndef DOXYGEN_GENERATING_OUTPUT + TextureArray& setLabel(const std::string& label) { + AbstractTexture::setLabel(label); + return *this; + } + #endif +}; + +#ifndef MAGNUM_TARGET_GLES +/** +@brief One-dimensional texture array + +@requires_gl Only @ref Magnum::Texture2DArray "Texture2DArray" is available in + OpenGL ES. +*/ +typedef TextureArray<1> Texture1DArray; +#endif + +/** @brief Two-dimensional texture array */ +typedef TextureArray<2> Texture2DArray; + +} +#else +#error this header is not available on OpenGL ES 2.0 build +#endif + +#endif diff --git a/src/Magnum/TextureFormat.h b/src/Magnum/TextureFormat.h index a9a358b7d..a1387b240 100644 --- a/src/Magnum/TextureFormat.h +++ b/src/Magnum/TextureFormat.h @@ -53,7 +53,8 @@ enum class TextureFormat: GLenum { * @deprecated_gl Prefer to use the exactly specified version of this * format, e.g. @ref Magnum::TextureFormat::R8 "TextureFormat::R8". * @requires_gl30 %Extension @extension{ARB,texture_rg} - * @requires_gles30 %Extension @es_extension{EXT,texture_rg} + * @requires_gles30 %Extension @es_extension{EXT,texture_rg} in OpenGL ES + * 2.0 */ #ifndef MAGNUM_TARGET_GLES2 Red = GL_RED, @@ -78,7 +79,8 @@ enum class TextureFormat: GLenum { * @deprecated_gl Prefer to use the exactly specified version of this * format, e.g. @ref Magnum::TextureFormat::RG8 "TextureFormat::RG8". * @requires_gl30 %Extension @extension{ARB,texture_rg} - * @requires_gles30 %Extension @es_extension{EXT,texture_rg} + * @requires_gles30 %Extension @es_extension{EXT,texture_rg} in OpenGL ES + * 2.0 */ #ifndef MAGNUM_TARGET_GLES2 RG = GL_RG, @@ -107,6 +109,7 @@ enum class TextureFormat: GLenum { /** * RGB, each component normalized unsigned byte. * @requires_gles30 %Extension @es_extension{OES,required_internalformat} + * in OpenGL ES 2.0 */ #ifndef MAGNUM_TARGET_GLES2 RGB8 = GL_RGB8, @@ -125,6 +128,7 @@ enum class TextureFormat: GLenum { /** * RGBA, each component normalized unsigned byte. * @requires_gles30 %Extension @es_extension{OES,required_internalformat} + * in OpenGL ES 2.0 */ #ifndef MAGNUM_TARGET_GLES2 RGBA8 = GL_RGBA8, @@ -532,6 +536,7 @@ enum class TextureFormat: GLenum { /** * RGB, normalized unsigned, red and blue component 5bit, green 6bit. * @requires_gles30 %Extension @es_extension{OES,required_internalformat} + * in OpenGL ES 2.0 */ RGB565 = GL_RGB565, @@ -605,19 +610,21 @@ enum class TextureFormat: GLenum { /** * RGBA, normalized unsigned, each component 4bit. * @requires_gles30 %Extension @es_extension{OES,required_internalformat} + * in OpenGL ES 2.0 */ RGBA4 = GL_RGBA4, /** * RGBA, normalized unsigned, each RGB component 5bit, alpha 1bit. * @requires_gles30 %Extension @es_extension{OES,required_internalformat} + * in OpenGL ES 2.0 */ RGB5A1 = GL_RGB5_A1, /** * RGBA, normalized unsigned, each RGB component 10bit, alpha 2bit. * @requires_gles30 %Extension @es_extension{OES,required_internalformat} - * and @es_extension{EXT,texture_type_2_10_10_10_REV} + * and @es_extension{EXT,texture_type_2_10_10_10_REV} in OpenGL ES 2.0 */ #ifndef MAGNUM_TARGET_GLES2 RGB10A2 = GL_RGB10_A2, @@ -756,7 +763,7 @@ enum class TextureFormat: GLenum { * @deprecated_gl Prefer to use the exactly specified version of this * format, e.g. @ref Magnum::TextureFormat::DepthComponent16 "TextureFormat::DepthComponent16". * @requires_gles30 %Extension @es_extension{OES,depth_texture} or - * @es_extension{ANGLE,depth_texture} + * @es_extension{ANGLE,depth_texture} in OpenGL ES 2.0 */ DepthComponent = GL_DEPTH_COMPONENT, @@ -764,14 +771,15 @@ enum class TextureFormat: GLenum { * Depth component, 16bit. Not supported in 3D textures. * @requires_gles30 %Extension (@es_extension{OES,required_internalformat} * and @es_extension{OES,depth_texture}) or (@es_extension{EXT,texture_storage} - * and @es_extension{ANGLE,depth_texture}) + * and @es_extension{ANGLE,depth_texture}) in OpenGL ES 2.0 */ DepthComponent16 = GL_DEPTH_COMPONENT16, /** * Depth component, 24bit. Not supported in 3D textures. * @requires_gles30 %Extension @es_extension{OES,required_internalformat}, - * @es_extension{OES,depth_texture} and @es_extension{OES,depth24} + * @es_extension{OES,depth_texture} and @es_extension{OES,depth24} in + * OpenGL ES 2.0 */ #ifndef MAGNUM_TARGET_GLES2 DepthComponent24 = GL_DEPTH_COMPONENT24, @@ -816,7 +824,8 @@ enum class TextureFormat: GLenum { * @ref Texture::setStorage() "*Texture::setStorage()" calls. * @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} + * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil} or + * @es_extension{ANGLE,depth_texture} in OpenGL ES 2.0 */ #ifndef MAGNUM_TARGET_GLES2 DepthStencil = GL_DEPTH_STENCIL, @@ -830,6 +839,7 @@ enum class TextureFormat: GLenum { * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil} and * (@es_extension{OES,required_internalformat} or * (@es_extension{EXT,texture_storage} and @es_extension{ANGLE,depth_texture})) + * in OpenGL ES 2.0 */ #ifdef MAGNUM_TARGET_GLES2 Depth24Stencil8 = GL_DEPTH24_STENCIL8_OES diff --git a/src/Magnum/TextureTools/DistanceField.cpp b/src/Magnum/TextureTools/DistanceField.cpp index b76bbd05e..a68959db2 100644 --- a/src/Magnum/TextureTools/DistanceField.cpp +++ b/src/Magnum/TextureTools/DistanceField.cpp @@ -45,10 +45,6 @@ class DistanceFieldShader: public AbstractShaderProgram { public: typedef Attribute<0, Vector2> Position; - enum: Int { - TextureLayer = 8 - }; - explicit DistanceFieldShader(); DistanceFieldShader& setRadius(Int radius) { @@ -66,7 +62,14 @@ class DistanceFieldShader: public AbstractShaderProgram { return *this; } + DistanceFieldShader& setTexture(Texture2D& texture) { + texture.bind(TextureLayer); + return *this; + } + private: + enum: Int { TextureLayer = 8 }; + Int radiusUniform, scalingUniform, imageSizeInvertedUniform; @@ -149,7 +152,7 @@ void distanceField(Texture2D& input, Texture2D& output, const Range2Di& rectangl #endif Framebuffer framebuffer(rectangle); - framebuffer.attachTexture2D(Framebuffer::ColorAttachment(0), output, 0); + framebuffer.attachTexture(Framebuffer::ColorAttachment(0), output, 0); framebuffer.bind(FramebufferTarget::Draw); framebuffer.clear(FramebufferClear::Color); @@ -163,9 +166,7 @@ void distanceField(Texture2D& input, Texture2D& output, const Range2Di& rectangl DistanceFieldShader shader; shader.setRadius(radius) .setScaling(Vector2(imageSize)/Vector2(rectangle.size())) - .use(); - - input.bind(DistanceFieldShader::TextureLayer); + .setTexture(input); #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isVersionSupported(Version::GL300)) @@ -198,7 +199,7 @@ void distanceField(Texture2D& input, Texture2D& output, const Range2Di& rectangl } /* Draw the mesh */ - mesh.draw(); + mesh.draw(shader); } }} diff --git a/src/Magnum/TextureTools/distancefieldconverter.cpp b/src/Magnum/TextureTools/distancefieldconverter.cpp index 073b6bd0a..bc386bb31 100644 --- a/src/Magnum/TextureTools/distancefieldconverter.cpp +++ b/src/Magnum/TextureTools/distancefieldconverter.cpp @@ -66,23 +66,17 @@ DistanceFieldConverter::DistanceFieldConverter(const Arguments& arguments): Wind } int DistanceFieldConverter::exec() { - /* Load plugins */ + /* Load importer plugin */ PluginManager::Manager importerManager(MAGNUM_IMPORTER_PLUGIN_DIR); - if(!(importerManager.load(args.value("importer")) & PluginManager::LoadState::Loaded)) { - Error() << "Cannot load importer plugin" << args.value("importer") << "from" << MAGNUM_IMPORTER_PLUGIN_DIR; + if(!(importerManager.load(args.value("importer")) & PluginManager::LoadState::Loaded)) return 1; - } + std::unique_ptr importer = importerManager.instance(args.value("importer")); + + /* Load converter plugin */ PluginManager::Manager converterManager(MAGNUM_IMAGECONVERTER_PLUGIN_DIR); - if(!(converterManager.load(args.value("converter")) & PluginManager::LoadState::Loaded)) { - Error() << "Cannot load converter plugin" << args.value("converter") << "from" << MAGNUM_IMAGECONVERTER_PLUGIN_DIR; + if(!(converterManager.load(args.value("converter")) & PluginManager::LoadState::Loaded)) return 1; - } - - /* Instance plugins */ - std::unique_ptr importer = importerManager.instance(args.value("importer")); - CORRADE_INTERNAL_ASSERT(importer); std::unique_ptr converter = converterManager.instance(args.value("converter")); - CORRADE_INTERNAL_ASSERT(converter); /* Open input file */ std::optional image; diff --git a/src/Magnum/Trade/MeshObjectData2D.cpp b/src/Magnum/Trade/MeshObjectData2D.cpp index 541a3537f..1ae62b65b 100644 --- a/src/Magnum/Trade/MeshObjectData2D.cpp +++ b/src/Magnum/Trade/MeshObjectData2D.cpp @@ -27,7 +27,7 @@ namespace Magnum { namespace Trade { -MeshObjectData2D::MeshObjectData2D(std::vector children, const Matrix3& transformation, UnsignedInt instance, UnsignedInt material): ObjectData2D(std::move(children), transformation, ObjectInstanceType2D::Mesh, instance), _material(material) {} +MeshObjectData2D::MeshObjectData2D(std::vector children, const Matrix3& transformation, UnsignedInt instance, Int material): ObjectData2D(std::move(children), transformation, ObjectInstanceType2D::Mesh, instance), _material(material) {} /* GCC 4.4 doesn't like it defaulted */ MeshObjectData2D::MeshObjectData2D(MeshObjectData2D&& other): ObjectData2D(std::move(other)), _material(other._material) {} diff --git a/src/Magnum/Trade/MeshObjectData2D.h b/src/Magnum/Trade/MeshObjectData2D.h index f0756692c..12388cce2 100644 --- a/src/Magnum/Trade/MeshObjectData2D.h +++ b/src/Magnum/Trade/MeshObjectData2D.h @@ -46,11 +46,11 @@ class MAGNUM_EXPORT MeshObjectData2D: public ObjectData2D { * @param children Child objects * @param transformation Transformation (relative to parent) * @param instance Instance ID - * @param material Material ID + * @param material Material ID or `-1` * * Creates object with mesh instance type. */ - explicit MeshObjectData2D(std::vector children, const Matrix3& transformation, UnsignedInt instance, UnsignedInt material); + explicit MeshObjectData2D(std::vector children, const Matrix3& transformation, UnsignedInt instance, Int material); /** @brief Copying is not allowed */ MeshObjectData2D(const MeshObjectData2D&) = delete; @@ -64,11 +64,15 @@ class MAGNUM_EXPORT MeshObjectData2D: public ObjectData2D { /** @brief Move assignment */ MeshObjectData2D& operator=(MeshObjectData2D&&); - /** @brief Material ID */ - UnsignedInt material() const { return _material; } + /** + * @brief Material ID + * + * Returns `-1` if the object has no material assigned. + */ + Int material() const { return _material; } private: - UnsignedInt _material; + Int _material; }; }} diff --git a/src/Magnum/Trade/MeshObjectData3D.cpp b/src/Magnum/Trade/MeshObjectData3D.cpp index ebb1d54e1..5da1654d9 100644 --- a/src/Magnum/Trade/MeshObjectData3D.cpp +++ b/src/Magnum/Trade/MeshObjectData3D.cpp @@ -27,7 +27,7 @@ namespace Magnum { namespace Trade { -MeshObjectData3D::MeshObjectData3D(std::vector children, const Matrix4& transformation, UnsignedInt instance, UnsignedInt material): ObjectData3D(std::move(children), transformation, ObjectInstanceType3D::Mesh, instance), _material(material) {} +MeshObjectData3D::MeshObjectData3D(std::vector children, const Matrix4& transformation, UnsignedInt instance, Int material): ObjectData3D(std::move(children), transformation, ObjectInstanceType3D::Mesh, instance), _material(material) {} /* GCC 4.4 doesn't like it defaulted */ MeshObjectData3D::MeshObjectData3D(MeshObjectData3D&& other): ObjectData3D(std::move(other)), _material(other._material) {} diff --git a/src/Magnum/Trade/MeshObjectData3D.h b/src/Magnum/Trade/MeshObjectData3D.h index 5277f67fe..0e6c33428 100644 --- a/src/Magnum/Trade/MeshObjectData3D.h +++ b/src/Magnum/Trade/MeshObjectData3D.h @@ -46,11 +46,11 @@ class MAGNUM_EXPORT MeshObjectData3D: public ObjectData3D { * @param children Child objects * @param transformation Transformation (relative to parent) * @param instance Instance ID - * @param material Material ID + * @param material Material ID or `-1` * * Creates object with mesh instance type. */ - explicit MeshObjectData3D(std::vector children, const Matrix4& transformation, UnsignedInt instance, UnsignedInt material); + explicit MeshObjectData3D(std::vector children, const Matrix4& transformation, UnsignedInt instance, Int material); /** @brief Copying is not allowed */ MeshObjectData3D(const MeshObjectData3D&) = delete; @@ -64,11 +64,15 @@ class MAGNUM_EXPORT MeshObjectData3D: public ObjectData3D { /** @brief Move assignment */ MeshObjectData3D& operator=(MeshObjectData3D&&); - /** @brief Material ID */ - UnsignedInt material() const { return _material; } + /** + * @brief Material ID + * + * Returns `-1` if the object has no material assigned. + */ + Int material() const { return _material; } private: - UnsignedInt _material; + Int _material; }; }}